/// <reference path="../runtime.d.ts" />

"use strict";

function enemys() {
    this._init();
}

////// 初始化 //////
enemys.prototype._init = function () {
    this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
    this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys;
    for (var enemyId in this.enemys) {
        this.enemys[enemyId].id = enemyId;
    }
    if (main.mode == 'play') {
        this.enemydata.hasSpecial = function (a, b) {
            return core.enemys.hasSpecial(a, b)
        };
    }
}

enemys.prototype.getEnemys = function () {
    var enemys = core.clone(this.enemys);
    var enemyInfo = core.getFlag('enemyInfo');
    if (enemyInfo) {
        for (var id in enemyInfo) {
            for (var name in enemyInfo[id]) {
                enemys[id][name] = core.clone(enemyInfo[id][name]);
            }
        }
    }
    // 将所有怪物的各项属性映射到朝下的
    for (var id in enemys) {
        if (enemys[id].faceIds) {
            var downId = enemys[id].faceIds.down;
            if (downId != null && downId != id && enemys[downId]) {
                enemys[id] = {id: id};
                for (var property in enemys[downId]) {
                    if (property != 'id' && enemys[downId].hasOwnProperty(property)) {
                        (function (id, downId, property) {
                            Object.defineProperty(enemys[id], property, {
                                get: function () { return enemys[downId][property] },
                                set: function (v) { enemys[downId][property] = v },
                                enumerable: true
                            })
                        })(id, downId, property);
                    }
                } 
            }
        }
    }
    return enemys;
}

////// 判断是否含有某特殊属性 //////
enemys.prototype.hasSpecial = function (special, test) {
    if (special == null) return false;

    if (special instanceof Array) {
        return special.indexOf(test) >= 0;
    }

    if (typeof special == 'number') {
        return special === test;
    }

    if (typeof special == 'string') {
        return this.hasSpecial(core.material.enemys[special], test);
    }

    if (special.special != null) {
        return this.hasSpecial(special.special, test);
    }

    return false;
}

enemys.prototype.getSpecials = function () {
    return this.enemydata.getSpecials();
}

////// 获得所有特殊属性的名称 //////
enemys.prototype.getSpecialText = function (enemy) {
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    if (!enemy) return [];
    var special = enemy.special;
    var text = [];

    var specials = this.getSpecials();
    if (specials) {
        for (var i = 0; i < specials.length; i++) {
            if (this.hasSpecial(special, specials[i][0]))
                text.push(this._calSpecialContent(enemy, specials[i][1]));
        }
    }
    return text;
}

////// 获得所有特殊属性的颜色 //////
enemys.prototype.getSpecialColor = function (enemy) {
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    if (!enemy) return [];
    var special = enemy.special;
    var colors = [];

    var specials = this.getSpecials();
    if (specials) {
        for (var i = 0; i < specials.length; i++) {
            if (this.hasSpecial(special, specials[i][0]))
                colors.push(specials[i][3] || null);
        }
    }
    return colors;

}

////// 获得所有特殊属性的额外标记 //////
enemys.prototype.getSpecialFlag = function (enemy) {
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    if (!enemy) return [];
    var special = enemy.special;
    var flag = 0;

    var specials = this.getSpecials();
    if (specials) {
        for (var i = 0; i < specials.length; i++) {
            if (this.hasSpecial(special, specials[i][0]))
                flag |= (specials[i][4] || 0);
        }
    }
    return flag;
}

////// 获得每个特殊属性的说明 //////
enemys.prototype.getSpecialHint = function (enemy, special) {
    var specials = this.getSpecials();

    if (special == null) {
        if (specials == null) return [];
        var hints = [];
        for (var i = 0; i < specials.length; i++) {
            if (this.hasSpecial(enemy, specials[i][0]))
                hints.push("\r[" + core.arrayToRGBA(specials[i][3] || "#FF6A6A") + "]\\d" + this._calSpecialContent(enemy, specials[i][1]) +
                    "：\\d\r[]" + this._calSpecialContent(enemy, specials[i][2]));
        }
        return hints;
    }

    if (specials == null) return "";
    for (var i = 0; i < specials.length; i++) {
        if (special == specials[i][0])
            return "\r[#FF6A6A]\\d"+this._calSpecialContent(enemy, specials[i][1]) + "：\\d\r[]" + this._calSpecialContent(enemy, specials[i][2]);
    }
    return "";
}

enemys.prototype._calSpecialContent = function (enemy, content) {
    if (typeof content == 'string') return content;
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    if (content instanceof Function) {
        return content(enemy);
    }
    return "";
}

////// 获得某个点上某个怪物的某项属性 //////
enemys.prototype.getEnemyValue = function (enemy, name, x, y, floorId) {
    floorId = floorId || core.status.floorId;
    if ((((flags.enemyOnPoint||{})[floorId]||{})[x+","+y]||{})[name] != null) {
        return flags.enemyOnPoint[floorId][x+","+y][name];
    }
    if (enemy == null) {
        var block = core.getBlock(x, y, floorId);
        if (block == null) return null;
        enemy = core.material.enemys[block.event.id];
    }
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    if (enemy == null) return null;
    return enemy[name];
}

////// 能否获胜 //////
enemys.prototype.canBattle = function (enemy, x, y, floorId) {
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    var damage = this.getDamage(enemy, x, y, floorId);
    return damage != null && damage < core.status.hero.hp;
}

enemys.prototype.getDamageString = function (enemy, x, y, floorId) {
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    var damage = this.getDamage(enemy, x, y, floorId);

    var color = '#000000';
    
    if (damage == null) {
        damage = "???";
        color = '#FF2222';
    }
    else {
        if (damage <= 0) color = '#11FF11';
        else if (damage < core.status.hero.hp / 3) color = '#FFFFFF';
        else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00';
        else if (damage < core.status.hero.hp) color = '#FF9933';
        else color = '#FF2222';

        damage = core.formatBigNumber(damage, true);
        if (core.enemys.hasSpecial(enemy, 19))
            damage += "+";
        if (core.enemys.hasSpecial(enemy, 21))
            damage += "-";
        if (core.enemys.hasSpecial(enemy, 11))
            damage += "^";
    }

    return {
        "damage": damage,
        "color": color
    };
}

////// 接下来N个临界值和临界减伤计算 //////
enemys.prototype.firstCritical = function (enemy, number, x, y, floorId) 
{
    //话说，你就不能只算一个吗？等点击的时候再算更多的临界值？
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    number = number || 1;
    //我们不用管坚固怪
    //var specialCriticals = this._nextCriticals_special(enemy, number, x, y, floorId);
    //if (specialCriticals != null) return specialCriticals;
    //计算
    var atk0=core.status.hero.atk;
    var id=enemy.id;
    var info0=core.battleInfo(id,atk0);
    var lastAtk=atk0;
    var maxAtk=core.material.enemys[id].def+core.material.enemys[id].hp;
    if(core.hasSpecial(enemy,3))
    {
        var temp=core.battlePerformer.getLevel("SW2");
        if(temp>=1)
        {
            maxAtk=Math.ceil(core.material.enemys[id].hp/core.battlePerformer.SW2VALUE[temp]);
        }
        else
        {
            return [];
        }
    }
    if(info0==null){
        //这时是铁定的没剑技、没破防。只能加攻击到破防，不然反弹也没用。
        lastAtk=core.material.enemys[id].def+1;
        info0=core.battleInfo(id,lastAtk);
        return [[lastAtk-atk0,-info0.damage]];
    }
    var lastTurnNum=info0.crit_turn;
    var damage0=info0.damage;
    var lastDamage=damage0;
    //注！我们没有什么奇奇怪怪的怪物，只要减伤就是临界！
    if(info0.per_damage>0)
    {
        if(lastDamage==0)
            return [[0,0]];
        if(lastTurnNum==0)
            return [[0,0]];//能秒掉大概是没临界了。少算一点。
        //二分搜索开始
        var leftAtk=lastAtk+1;
        var rightAtk=maxAtk;
        var midAtk;
        var info;
        while(true)
        {
            if(leftAtk>=rightAtk)
                break;
            midAtk=Math.floor((leftAtk+rightAtk)/2);
            info=core.battleInfo(id,midAtk);
            if(info.damage<lastDamage)
                rightAtk=midAtk;
            else
                leftAtk=midAtk+1;
        }
        info=core.battleInfo(id,leftAtk);
        if(info.damage<lastDamage)
            return [[leftAtk-atk0,damage0-info.damage]];
        else
            return [[0,0]];
    }
    return [[0,0]];
}
enemys.prototype.someCriticals = function (enemy, number, x, y, floorId) 
{
    //算多个临界值
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    number = number || 1;
    //先处理模仿坚固一类的。我们不需要！
    //var specialCriticals = this._nextCriticals_special(enemy, number, x, y, floorId);
    //if (specialCriticals != null) return specialCriticals;
    //计算
    var atk0=core.status.hero.atk;
    var id=enemy.id;
    var info0=core.battleInfo(id,atk0);
    var lastAtk=atk0;
    var maxAtk=core.material.enemys[id].def+core.material.enemys[id].hp;
    if(core.hasSpecial(enemy,3))
    {
        var temp=core.battlePerformer.getLevel("SW2");
        if(temp>=1)
        {
            maxAtk=Math.ceil(core.material.enemys[id].hp/core.battlePerformer.SW2VALUE[temp]);
        }
        else
        {
            return [];
        }
    }
    var rtn=[];
    if(info0==null){
        //这时是铁定的没剑技、没破防。只能加攻击到破防，不然反弹也没用。
        lastAtk=core.material.enemys[id].def+1;
        info0=core.battleInfo(id,lastAtk);
        rtn.push([lastAtk-atk0,-info0.damage]);
    }
    var lastTurnNum=info0.crit_turn;
    var damage0=info0.damage;
    var lastDamage=damage0;
    if(info0.per_damage>0)
    {
        while(rtn.length<number)
        {
            if(lastDamage==0)
                break;
            if(lastTurnNum==0)
                break;
            //二分搜索开始
            var leftAtk=lastAtk+1;
            var rightAtk=maxAtk;
            var midAtk;
            var info;
            while(true)
            {
                if(leftAtk>=rightAtk)
                    break;
                midAtk=Math.floor((leftAtk+rightAtk)/2);
                info=core.battleInfo(id,midAtk);
                if(info.damage<lastDamage)
                    rightAtk=midAtk;
                else
                    leftAtk=midAtk+1;
            }
            info=core.battleInfo(id,leftAtk);
            if(info.damage<lastDamage)
                rtn.push([leftAtk-atk0,damage0-info.damage]);
            else
                break;
            lastAtk=leftAtk;
            lastTurnNum=info.crit_turn;
            lastDamage=info.damage;
        }
    }
    if(rtn.length==0)
        rtn=[[0,0]];
    return rtn;
}
enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) {
	alert("游戏运行错误：执行了不再使用的函数");
    throw("nextCriticals函数已不再使用");
}

enemys.prototype._nextCriticals_special = function (enemy, number, x, y, floorId) {
    if (this.hasSpecial(enemy.special, 10) || this.hasSpecial(enemy.special, 3))
        return []; // 模仿or坚固临界
    return null;
}

////// N防减伤计算 //////
enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) {
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    k = k || 1;
    var nowInfo = core.battleInfo(enemy.id);
    var nextInfo = core.battleInfo(enemy.id,null,core.status.hero.def + k);
    if (nowInfo == null || nextInfo == null) return "???";
    return nowInfo.damage - nextInfo.damage;
}

enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) {
    if (enemy == null) return null;
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId)
}

////// 获得战斗伤害信息（实际伤害计算函数） //////
enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) {
    if (enemy == null) return null;
    // 移动到了脚本编辑 - getDamageInfo中
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    return this.enemydata.getDamageInfo(enemy, hero, x, y, floorId);
}

////// 获得在某个勇士属性下怪物伤害 //////
enemys.prototype.getDamage = function (enemy, x, y, floorId) {
    return this._getDamage(enemy, null, x, y, floorId);
}

enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) {
    if (enemy == null) enemy = core.getBlockId(x, y, floorId);
    if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
    if (enemy == null) return null;

    var info = this.getDamageInfo(enemy, hero, x, y, floorId);
    if (info == null) return null;
    if (typeof info == 'number') return info;
    return info.damage;
}

////// 获得当前楼层的怪物列表 //////
enemys.prototype.getCurrentEnemys = function (floorId) {
    floorId = floorId || core.status.floorId;
    var enemys = [], used = {};
    core.extractBlocks(floorId);
    core.status.maps[floorId].blocks.forEach(function (block) {
        if (!block.disable && block.event.cls.indexOf('enemy') == 0) {
            this._getCurrentEnemys_addEnemy(block.event.id, enemys, used, block.x, block.y, floorId);
        }
    }, this);
    return this._getCurrentEnemys_sort(enemys);
}

enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) {
    var enemy = core.material.enemys[enemyId];
    if (!enemy) return null;

    // 检查朝向；displayIdInBook
    return core.material.enemys[enemy.displayIdInBook] || core.material.enemys[(enemy.faceIds || {}).down] ||  enemy;
}

enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, x, y, floorId) {
    var enemy = this._getCurrentEnemys_getEnemy(enemyId);
    if (enemy == null) return;

    var id = enemy.id;

    var enemyInfo = this.getEnemyInfo(enemy, null, null, null, floorId);
    var locEnemyInfo = this.getEnemyInfo(enemy, null, x, y, floorId);

    if (!core.flags.enableEnemyPoint ||
        (locEnemyInfo.atk == enemyInfo.atk && locEnemyInfo.def == enemyInfo.def && locEnemyInfo.hp == enemyInfo.hp)) {
        x = null;
        y = null;
    } else {
        // 检查enemys里面是否使用了存在的内容
        for (var i = 0; i < enemys.length; ++i) {
            var one = enemys[i];
            if (id == one.id && one.locs != null &&
                locEnemyInfo.atk == one.atk && locEnemyInfo.def == one.def && locEnemyInfo.hp == one.hp) {
                one.locs.push([x, y]);
                return;
            }
        }
        enemyInfo = locEnemyInfo;
    }
    var id = enemy.id + ":" + x + ":" + y;
    if (used[id]) return;
    used[id] = true;

    var specialText = core.enemys.getSpecialText(enemy);
    var specialColor = core.enemys.getSpecialColor(enemy);

    var critical = this.firstCritical(enemy, 1, x, y, floorId);
    if (critical.length > 0) critical = critical[0];

    var e = core.clone(enemy);
    for (var v in enemyInfo) {
        e[v] = enemyInfo[v];
    }
    if (x != null && y != null) {
        e.locs = [[x, y]];
    }
    e.name = core.getEnemyValue(enemy, 'name', x, y, floorId);
    e.specialText = specialText;
    e.specialColor = specialColor;
    e.damage = this.getDamage(enemy, x, y, floorId);
    e.critical = critical[0];
    e.criticalDamage = critical[1];
    e.defDamage = this._getCurrentEnemys_addEnemy_defDamage(enemy, x, y, floorId);
    enemys.push(e);
}

enemys.prototype._getCurrentEnemys_addEnemy_defDamage = function (enemy, x, y, floorId) {
    var ratio = core.status.maps[floorId || core.status.floorId].ratio || 1;
    return this.getDefDamage(enemy, 1, x, y, floorId);
    //注：我只想要1防的结果。不要加防。
}

enemys.prototype._getCurrentEnemys_sort = function (enemys) {
    return enemys.sort(function (a, b) {
        if (a.damage == b.damage) {
            return a.money - b.money;
        }
        if (a.damage == null) {
            return 1;
        }
        if (b.damage == null) {
            return -1;
        }
        return a.damage - b.damage;
    });
}

enemys.prototype.hasEnemyLeft = function (enemyId, floorId) {
    if (floorId == null) floorId = core.status.floorId;
    if (!(floorId instanceof Array)) floorId = [floorId];
    var enemyMap = {};
    if (enemyId instanceof Array) enemyId.forEach(function(v) { enemyMap[v] = true;});
    else if (enemyId) enemyMap[enemyId] = true;
    else enemyMap = null;
    for (var i = 0; i < floorId.length; i++) {
        core.extractBlocks(floorId[i]);
        var mapBlocks = core.status.maps[floorId[i]].blocks;
        for (var b = 0; b < mapBlocks.length; b++) {
            if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') === 0) {
                if (enemyMap === null || enemyMap[core.getFaceDownId(mapBlocks[b])]) return true;
            }
        }
    }
    return false;
}
