function Window_BattleResult() {
    this.initialize.apply(this, arguments);
}
Window_BattleResult.prototype = Object.create(Window_Base.prototype);
Window_BattleResult.prototype.constructor = Window_BattleResult;

(function(){
    const __updatePosition = Sprite_Battler.prototype.updatePosition;
    Sprite_Battler.prototype.updatePosition = function() {
        __updatePosition.apply(this, arguments);
        this.scale.x = this.scale.y = 2;
    };
    Sprite_Enemy.prototype.updateStateSprite = function() {
        this._stateIconSprite.scale.x = this._stateIconSprite.scale.y = 0.5;
        this._stateIconSprite.y = -this.bitmap.height-10;
    };

    // Sprite_Damage
    const __dmgInitialize = Sprite_Damage.prototype.initialize;
    Sprite_Damage.prototype.initialize = function() {
        __dmgInitialize.apply(this, arguments);
        this.scale.x = this.scale.y = 2;
    };

    // Window_BattleLog
    Window_BattleLog.prototype.standardFontSize = function() {
        return 10;
    };
    Window_BattleLog.prototype.backPaintOpacity = function() {
        return 192;
    };
    Window_BattleLog.prototype.drawLineText = function(index) {
        const rect = this.itemRectForText(index);
        this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);

        const text = this._lines[index];
        if (!text.includes("|")){ rect.y += 12; }
        this.drawTextEx(text, rect.x, rect.y, rect.width);
    };

    // Window_ActorCommand
    Window_ActorCommand.prototype.lineHeight = function(){ return 33; };
    Window_ActorCommand.prototype.standardFontSize = function(){ return romanLanguage() ? 10 : 20; };

    // Window_PartyCommand
    Window_PartyCommand.prototype.lineHeight = function(){ return 66; };
    Window_PartyCommand.prototype.standardFontSize = function(){ return romanLanguage() ? 10 : 20; };
    Window_PartyCommand.prototype.numVisibleRows = function(){ return 2; };


    // Window_BattleStatus
    Window_BattleStatus.prototype.maxCols = function(){ return 4; };
    Window_BattleStatus.prototype.spacing = function(){ return 0; };
    Window_BattleStatus.prototype.windowHeight = function(){ return 138; }

    Window_BattleStatus.prototype.drawItem = function(index) {
        const actor = $gameParty.battleMembers()[index];
        const rect = this.itemRectForText(index);
        rect.x -= 4;
        this.drawActorFace(actor, rect.x, rect.y,30,26);
        this.drawBasicArea(rect, actor);
        this.drawGaugeArea(rect, actor);
    };
  
    Window_BattleStatus.prototype.itemRect = function(index) {
        const rect = new Rectangle();
        const maxCols = this.maxCols();
        rect.width = this.itemWidth();
        rect.height = this.windowHeight() - this.standardPadding() * 2;
        rect.x = index % maxCols * (rect.width + this.spacing()) - this._scrollX;
        rect.y = Math.floor(index / maxCols) * rect.height - this._scrollY;
        return rect;
    };
  
    Window_BattleStatus.prototype.drawBasicArea = function(rect, actor) {
        this.drawActorIcons(actor, rect.x, rect.y-2, rect.width);
    };
  
    Window_BattleStatus.prototype.drawGaugeArea = function(rect, actor) {
      const y = rect.y + this.lineHeight() * 2+2;
      rect.width += 4;
      this.drawActorHp(actor, rect.x, y, rect.width);
      this.drawActorMp(actor, rect.x, y + 16, rect.width);
    };


    // Window_BattleEnemy
    Window_BattleEnemy.prototype.lineHeight = function() {
        return 38;
    };
    Window_BattleEnemy.prototype.maxCols = function() {
        return 1;
    };
    Window_BattleEnemy.prototype.numVisibleRows = function() {
        return 3;
    };
    Window_BattleEnemy.prototype.drawItem = function(index) {
        this.resetTextColor();
        const enemy = this._enemies[index];
        const rect = this.itemRectForText(index);
        rect.y -= 4;
        this.drawText(enemy.name(), rect.x, rect.y, rect.width);
        const iconWidth = 96;
        const hpGauge = rect.width-iconWidth;
        this.drawActorIcons(enemy, hpGauge, rect.y+6, iconWidth)
        this.drawActorHp(enemy, rect.x, rect.y+16, hpGauge-16);
    };

    // Scene_Map
    Scene_Map.prototype.snapForBattleBackground = function() {
        SceneManager.snapForBackground();
    };
    
    Scene_Map.prototype.startEncounterEffect = function() {
        this._encounterEffectDuration = this.encounterEffectSpeed();
    };
    const __start = Scene_Map.prototype.start;
    Scene_Map.prototype.start = function() {
        __start.apply(this, arguments);
        const wid = Graphics.width>>1, hei = Graphics.height>>1;
        this._fadeBattleSprite = new Sprite(new Bitmap(wid, hei));
        this._fadeBattleSprite.bitmap.fillRect(0,0,8,hei,"black");
        this._fadeBattleSprite.bitmap.fillRect(wid-8,0,8,hei,"black");
        this._fadeBattleSprite.visible = false;
        this._fadeBattleSprite.scale.x = this._fadeBattleSprite.scale.y = 2;
        this.addChild(this._fadeBattleSprite);

        this.patternCanvas = document.createElement("canvas");
        this.patternCanvas.width = this.patternCanvas.height = 8;
        const ctx = this.patternCanvas.getContext('2d');
        ctx.fillStyle = "black";
        for (let y = 0; y < 8; y++){
            for (let x = y % 2; x < 8; x+=2){ ctx.fillRect(x,y,1,1); };
        };
    };
    Scene_Map.prototype.updateEncounterEffect = function() {
        if (this._encounterEffectDuration > 0) {
            this._fadeBattleSprite.visible = true;
            this._encounterEffectDuration--;
            const ctx = this._fadeBattleSprite.bitmap._context;
            const wid = this._fadeBattleSprite.bitmap.width;
            const hei = this._fadeBattleSprite.bitmap.height-1;

            const max = this.encounterEffectSpeed() - this._encounterEffectDuration;
            let x = max * 8;
            let y = 0;
            function fillTone(x,y,pat){ ctx.drawImage(pat,x,y,8,8); };
            for (let i = 0; i < max; i++){
                fillTone(x,y,this.patternCanvas);
                fillTone(wid-x,hei-y,this.patternCanvas);
                x -= 8;
                y += 8;
            }
            this._fadeBattleSprite.bitmap._setDirty();

            const speed = this.encounterEffectSpeed();
            const n = speed - this._encounterEffectDuration;
            if (n === 2) { this.snapForBattleBackground(); }
            if (n === Math.floor(speed / 2)) { BattleManager.playBattleBgm(); }
        }
    };


    // Scene_Battle
    Scene_Battle.prototype.setFadePattern = function(type){
        if (type == -1){
            this._fadeSprite.bitmap = null;
            this._fadeSprite.scale.x = this._fadeSprite.scale.y = 1;
        }else{
            this._fadeSprite.bitmap = ImageManager.loadPicture("fade"+type);
            this._fadeSprite.scale.x = this._fadeSprite.scale.y = type == 5 ? 20 : 2;
        }
        this._fadeSprite.opacity = 255;
    }
    Scene_Battle.prototype.createFadeSprite = function(white) {
        if (!this._fadeSprite) {
            this._fadeSprite = new Sprite();
            this.addChild(this._fadeSprite);
        }
    };
    const __startFadeIn = Scene_Battle.prototype.startFadeIn;
    Scene_Battle.prototype.startFadeIn = function(duration, white) {
        __startFadeIn.apply(this, arguments);
        this.setFadePattern(5);
    };
    const __startFadeOut = Scene_Battle.prototype.startFadeOut;
    Scene_Battle.prototype.startFadeOut = function(duration, white) {
        __startFadeOut.apply(this, arguments);
        this.setFadePattern(-1);
    };

    Scene_Battle.prototype.updateFade = function() {
        if (this._fadeDuration > 0) {
            if (this._fadeSign > 0) {
                switch (this._fadeDuration){
                    case 30: this.setFadePattern(5);break;
                    case 25: this.setFadePattern(0);break;
                    case 20: this.setFadePattern(1);break;
                    case 15: this.setFadePattern(2);break;
                    case 10: this.setFadePattern(3);break;
                    case  5: this.setFadePattern(4);break;
                    case  1: this.setFadePattern(-1);break;
                }
            } else {
                switch (this._fadeDuration){
                    case 30: this.setFadePattern(-1);break;
                    case 25: this.setFadePattern(4);break;
                    case 20: this.setFadePattern(3);break;
                    case 15: this.setFadePattern(2);break;
                    case 10: this.setFadePattern(1);break;
                    case  5: this.setFadePattern(0);break;
                    case  1: this.setFadePattern(5);break;
                }
            }
            this._fadeDuration--;
        }
    };

    const __isAnyInputWindowActive = Scene_Battle.prototype.isAnyInputWindowActive;
    Scene_Battle.prototype.isAnyInputWindowActive = function() {
        return __isAnyInputWindowActive.call(this);
    };

    const __isBusy = Scene_Base.prototype.isBusy;
    Scene_Battle.prototype.isBusy = function() {
        return __isBusy.call(this) || (
            this._resultWindow && this._resultWindow.phase !== 'end'
        );
    };

    // Window_BattleResult
    Window_BattleResult.prototype.initialize = function(w,h){
        Window_Base.prototype.initialize.call(this, (Graphics.width-w)>>1,0,w,h);
        this.cntList = {};
        BattleManager._rewards.items.forEach(function(item){
            let id = item.id;
            if (!this.cntList[id]){ this.cntList[id] = 0; };
            this.cntList[id]++;
        }, this);

        this.refCnt = 4;
        this.phase = 'wait1';

        this._members = $gameParty.members()
        BattleManager._rewards.oldActors = {}
        this._members.forEach(function(actor){
            if (actor.faceName()){
                ImageManager.loadFace(actor.faceName());
            }
            BattleManager._rewards.oldActors[actor.actorId()] = [
                actor.level,
                actor.skills().map(function(skill){ return skill.id; }),
                [...new Array(8)].map(function(a,b){ return actor.param(b); }),
            ];
        });
        this._exp  = BattleManager._rewards.exp;
        this._expCnt = 10**Math.max(Math.floor(Math.log10(this._exp)),0) >> 1;
        this.openness = 0;
        this.refresh();
        this.open();
    }

    Window_BattleResult.prototype.refresh = function(){
        this.contents.clear();
        this.changeTextColor(this.systemColor());
        this.drawText(TextManager._battleResult1,0,-2,this.contents.width);
        for (let i = 0; i < $gameParty.size(); i++){ this.drawExpMember.call(this, i); };

        let y = 150;
        let w = this.contents.width;
        this.changeTextColor(this.systemColor());
        this.drawText(TextManager._battleResult2,0,y,w);
        this.drawText(TextManager.currencyUnit,0,y,w,"right");
        this.changeTextColor(this.normalColor());
        this.drawText(BattleManager._rewards.gold,-16,y,w,"right");
        y+=20;
        Object.keys(this.cntList).forEach(function(id){
            const item = $dataItems[id];
            this.drawItemName(item, -4, y);
            this.drawText(
                $gameParty.numItems(item)+"+"+("  "+this.cntList[id]).slice(-2),
                0,y,w,"right"
            );
            y+=32;
        }, this);
        this.changeTextColor(this.normalColor());
    }

    Window_BattleResult.prototype.drawExpMember = function(i){
        let y = 16 + i * 32;
        let w = this.contents.width;
        const actor = $gameParty.members()[i];
        this.drawActorName(actor,0,y,w);
        this.drawActorLevel(actor,186,y,w);
        this.changeTextColor(this.systemColor());
        this.drawText("→",w-64,y,32);
        this.drawExpGaugeMember(actor, i);
    }

    Window_BattleResult.prototype.drawExpGaugeMember = function (actor, i){
        let y = 32 + i * 32;
        let w = this.contents.width;
        this.contents.clearRect(0,y+6,w,16);
        this.contents.clearRect(w-48,y-10,48,16);

        this.drawActorExp(actor,0,y,w-100);
        const exp = Math.round(this._exp * actor.finalExpRate());
        this.drawText("+"+("     "+exp).slice(-5),0,y,w,'right');

        if (actor.level !== BattleManager._rewards.oldActors[actor.actorId()][0]){
            this.changeTextColor(this.textColor(2));
        }
        this.drawText(actor.level,0,y-16,w,"right");
    }

    Window_BattleResult.prototype.update = function(){
        Window_Base.prototype.update.call(this);
        switch (this.phase){
        case "wait1":
            if (!$gameMessage.isBusy()){
                AudioManager.playSe({name:'Saint4', volume:100, pitch:100});
                this.phase = "exp";
            }
            break;
        case "exp":
            if (this._exp == 0){
                if (!this.isInput()) { return };
                this._members = this._members.filter(function(actor){
                    return actor.level != BattleManager._rewards.oldActors[actor.actorId()][0];
                });
                this.refCnt = 0;
                if (this.refCnt < this._members.length){
                    this.phase = "levelup";
                    this.drawProfile(0);
                }else{
                    this.phase = "end";
                }
                return;
            }
            if (this.refCnt!==0){
                this.refCnt--;
                return;
            }
            this.refCnt = Input.isPressed("ok") || TouchInput.isPressed() ? 1 : 4;
            let gain = Math.min(this._exp, this._expCnt);
            this._exp -= gain;
            for (let i = 0; i < this._members.length; i++){
                const actor = this._members[i];
                const lvl = actor.level;
                actor.gainExp(gain);
                this.drawExpGaugeMember(actor, i);
                if (lvl != actor.level){
                    AudioManager.playSe({name:'Saint5', volume:100, pitch:100});
                    $gameScreen.startFlash([255,0,0,255], 10);
                }
            }
            break;
        case "levelup":
            if (this.isInput()){
                this.refCnt++;
                if (this.refCnt < this._members.length){
                    this.drawProfile(this.refCnt);
                }else{
                    this.close();
                    this.phase = "end";
                }
            }
            break;
        }
    }

    Window_BattleResult.prototype.drawProfile = function(id){
        this.contents.clear();
        const actor = this._members[this.refCnt];
        const w = this.contents.width;
        this.drawActorFace(actor,0,0);
        this.drawActorSimpleStatus(actor,104,0,w-84);

        let i = 0;
        let y = 108;
        this.changeTextColor(this.systemColor());
        this.drawText(TextManager._battleLevelUp1,0,y-16,w);
        let status = BattleManager._rewards.oldActors[actor.actorId()][2];
        let pad = w / 2 + 4;
        let left = 4, right = 4;
        for (let j = 0; j < 8; j++){
            let x = pad * Math.floor(i % 2);
            this.changeTextColor(this.systemColor());
            this.drawText(TextManager.param(j),x,y,pad);
            this.drawTextEx(
                ("     "+status[j]).slice(-left)+
                "\\c[16]→\\c[2]"+("     "+actor.param(j)).slice(-right),
                x+32,y+9,pad
            );
            if (i++%2) {y += 16};
            if (j == 1) {
                left = 5;
                right = 3;
            };
        }
        this.changeTextColor(this.systemColor());
        this.drawText(TextManager._battleLevelUp2,0,y,w);
        this.changeTextColor(this.normalColor());
        status = BattleManager._rewards.oldActors[actor.actorId()][1];
        i = 0;
        actor.skills().forEach(function(skill){
            if (!status.contains(skill.id)){
                if (i % 2==0) { y += 16 };
                this.drawText(skill.name, pad*(i%2), y, pad);
                i++;
            }
        }, this);
    }

    Window_BattleResult.prototype.isInput = function(){
        return Input.isTriggered('ok') || TouchInput.isTriggered();
    }

    Game_Actor.prototype.shouldDisplayLevelUp = function() {
        return false;
    };

    // BattleManager
    const __makeEscapeRatio = BattleManager.makeEscapeRatio;
    BattleManager.makeEscapeRatio = function() {
        let i, mem = $gameParty.members();
        for (i=0; i < mem.length; i++){
            if (mem[i].actor().meta.escape){ break; }
        }
        if (i==mem.length){
            __makeEscapeRatio.apply(this, arguments);
        }else{
            this._escapeRatio = 1;
        }
    };
    
    BattleManager.displayRewards = function() {
        const scene = SceneManager._scene;
        scene._resultWindow = new Window_BattleResult(
            this._statusWindow.width, Graphics.height-scene._messageWindow.height-4
        );
        scene.addWindow(scene._resultWindow);
    };
    BattleManager.gainExp = function() {};

})();