/**
 * 配置文件对象。
 * @create   2004-10-29 source0
 * @author   source0 source0@hotmail.com
 * @copyright 版权所有（C） 2004  source0
 *                这一程序是自由软件，你可以遵照自由软件基金会出版的GNU通用
 *            公共许可证条款来修改和重新发布这一程序。或者用许可证的第二版，
 *            或者（根据你的选择）用任何更新的版本。
 *                发布这一程序的目的是希望它有用，但没有任何担保。甚至没有
 *            适合特定目的的隐含的担保。更详细的情况请参阅GNU通用公共许可证。
 *                你应该已经和程序一起收到一份GNU通用公共许可证的副本。如果
 *            还没有，写信给：
 *                The Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 *                MA02139, USA
 */
var ROLE_FOR_PROFILE = null;
var CURRENT_PROFILE = new CProfile();

/**
 * 配置文件对象。
 * @param profileString 配置数据的字符串。格式为：
 *          1、以管道符开头(|)，每一段以管道符分隔；
 *          2、第一段为职业ID；
 *          3、第二段为数据文件地址；
 *          4、以后1～3段为各个天赋系的数据。
 *          5、数据格式为：天赋系ID:加点信息。冒号及以后可以省略，视为未加点。否则必须是28个0～5的数字，且总和不大于51。
 * @create 2004-10-29 source0
 */
function CProfile(profileString)
{
    this.dataFile = "";
    this.roleId = "";
    this.talentClasses = new Array();//CTalentClassForProfile 数组，在载入数据的时候进行初始化。

    if ( null != profileString )
    {
        this.decodeFromString(profileString);
    }

    /**
     * 从字符串中解析出天赋加点数据。并与数据文件进行合法性检查。
     * 此方法会自动加载数据文件，因此无需再次调用加载数据文件的相关方法。
     * @param str 字符串。
     * @return 如果字符串格式合法，返回 true，否则返回 false 。
     * @create 2004-10-30 source0
     */
    this.decodeFromString = function(str)
    {
        str = unescape(str);
        str = str.replace(/%2C/g, ",");
        str = str.replace(/%3A/g, ":");

//以下代码不能正常工作
//        var pointsRegStr = "^[A-Za-z_]+(:[0-5]{" + MAX_TIER * MAX_COLUMN + "})?$";//某个天赋系加点情况的正则表达式。
//        var regStr = new RegExp("^([a-zA-Z_]+)\|[^\S\|]+\|(" + pointsRegStr+"){1,3}$");//字符串格式的正则表达式。
//        if ( !regStr.test(str) )
//        {
//            alert ("数据格式错误，请检查您的数据：\n" + str);
//            return false;
//        }

        var info = str.split(",");

        /* 至少需要包含职业ID、文件地址、一个天赋系ID*/
        if ( info.length < 3 )
        {
            alert ("数据格式错误，至少需要包含职业ID、文件地址、一个天赋系ID。请检查您的数据：\n" + str);
            return false;
        }

        /* 检查职业ID 。*/
        if ( !/^\w+$/.test(info[0]) )
        {
            alert ("数据格式错误，职业ID的格式不正确。请检查您的数据：\n" + info[0]);
            return false;
        }

        /* 检查各个数据段。 */
        for ( var i = 2; i < info.length; i++ )
        {
            /* 必须有ID 。*/
            if ( info[i].indexOf(":") == 0 )
            {
                alert ("数据格式错误，必须包含天赋系ID。请检查您的数据：\n" + info[i]);
                return false;
            }
            /* 如果仅有ID，需要检查ID 。*/
            else if ( info[i].indexOf(":") < 0 )
            {
                if ( !/^\w+$/.test(info[i]) )
                {
                alert ("数据格式错误，天赋系ID的格式不正确。请检查您的数据：\n" + info[i]);
                return false;
                }
            }
            /* ID:数据 的格式。*/
            else
            {
                if ( !/^\w+:[0-5\-]{28}$/.test(info[i]) )
                {
                    alert ("数据格式错误，加点数据不正确。请检查您的数据：\n" + info[i]);
                    return false;
                }
            }

        }

		document.getElementById("CURRENT_CHAR_ID").value = info[0];
        this.roleId = info[0];
        this.dataFile = info[1];
        loadXML(this.dataFile, "loadRoleForProfile");

        if ( ROLE_FOR_PROFILE.id != this.roleId ){
            alert ("数据文件与配置数据不匹配：\n数据文件职业ID：" + ROLE_FOR_PROFILE.id + "\n配置数据职业ID：" + this.roleId);
            return false;
        }
        for ( var i = 2; i < info.length; i++ )
        {
            var tc = decodeDataString(info[i]);
            if ( null != tc )
            {
                this.talentClasses[this.talentClasses.length] = tc;
            }
        }

        var totalPoints = 0;
        for ( var i = 0; i < this.talentClasses.length; i++ )
        {
            var pts = this.talentClasses[i].getTalents();
            for ( var key in pts )
            {
				if(parseInt(pts[key] == "-"))
					continue;
                totalPoints += parseInt(pts[key]);
            }

        }
        if ( totalPoints > 51 )
        {
            alert ("数据格式错误，加点数据超过了最大值。请检查您的数据：\n" + str);
            return false;
        }
        return true;
    }

    /**
     * 将指定的职业加点信息压缩到一个字符串中。
     * @param role CRole对象实例，职业实例。
     * @param dataFile 数据文件地址。
     * @create 2004-10-30 source0
     */
    this.encodeToString = function(role, dataFile)
    {
        var ret = role.id + "," + dataFile;
        for ( var t = 0; t < role.talentClasses.length; t++ )
        {
            ret += ",";
            ret += role.talentClasses[t].id;
            if ( role.talentClasses[t].getAmount() <= 0 )
            {
                continue;
            }

            var data = new Array();
            /* 初始化一个空数组，使用天赋加点数据填充该数组后，将每个元素逐个附加到结果字符串后面即可。 */
            for ( var i = 0; i < MAX_TIER * MAX_COLUMN; i++ )
            {
                data[i] = "-";
            }

            var tvs = role.talentClasses[t].getTalentViews();
            for ( var key in tvs )
            {
                var tv = tvs[key];
                data[4 * tv.model.tier + parseInt(tv.column)] = "" + tv.getRank();
            }


            ret += ":";
            for ( var i = 0; i < MAX_TIER * MAX_COLUMN; i++ )
            {
                ret += data[i];
            }

        }
        return escape(ret);
    }
    /**
     * 从字符串中解析出天赋加点数据。
     * @param str 字符串。为28字节长的数字并且总和小于51。
     * @return 如果字符串格式合法，返回 CTalentClassForProfile 实例，否则返回 null 。
     * @create 2004-10-30 source0
     */
    function decodeDataString(str)
    {
        var reg = new RegExp("[(a-z)(A-Z)_]+:[0-5\-]{" + MAX_TIER * MAX_COLUMN + "}");
        if ( !reg.test(str) )
        {
            return null;
        }

        var tc = new CTalentClassForProfile();
        tc.id = str.substring(0, str.indexOf(":"));
        tc.talents = new Array();
        var data = str.substring(parseInt(str.indexOf(":")) + 1, str.length);

        /* 计算点数是否正确，如不正确，返回 null。 */
        var count = 0;
        for ( var i = 0; i < MAX_TIER * MAX_COLUMN; i++ )
        {
			if(data.charAt(i) == "-")
				continue;
            count += parseInt(data.charAt(i));
        }
        if ( count > 51 )
        {
            return null;
        }

        /* 查找天赋系，如果没找到，说明是非法数据。 */
        var talentClassModel = null;
        for ( var i = 0; i < 3; i++ )
        {
            if ( ROLE_FOR_PROFILE.talentClasses[i].id == tc.id )
            {
                talentClassModel = ROLE_FOR_PROFILE.talentClasses[i];
                break;
            }
        }
        if ( null == talentClassModel )
        {
            return null;
        }

        /* 使用加点信息初始化。 */
        var tvs = talentClassModel.getTalentViews();
        for ( var key in tvs )
        {
            var tv = tvs[key];
            var rank = data.charAt(4 * tv.model.tier + parseInt(tv.column));
            if ( rank > 0 )
            {
                tc.add(tv.model.id, rank);
            }
        }

        return tc;
    }

    this.toString = function()
    {
        var ret = new String();
        ret += 'CProfile[';
        ret += '数据文件="' + this.dataFile + '"';
        ret += ', 职业ID="' + this.roleId + '"';
        ret += ', 配置数据=[';
        for ( var key in this.talentClasses )
        {
            ret += '[' + this.talentClasses[key] + '] ';
        }
        ret += "]]";
        return ret;
    }
}

/**
 * 专为配置文件对象服务的天赋系模型对象。本对象仅保存天赋系的ID和各天赋的ID、级别。
 * @create 2004-10-29 source0
 */
function CTalentClassForProfile()
{
    this.id = null
    var talents = new Array();//key = 天赋的ID, value = 天赋的级别。

    /**
     * 增加一个天赋及级别。
     * @param id 天赋的ID。
     * @param rank 天赋的级别。
     * @create 2004-10-29 source0
     */
    this.add = function(id, rank)
    {
        talents[id] = rank;
    }

    /**
     * 判断指定的天赋是否存在。
     * @param id 天赋的ID。
     * @return 如果存在，返回 true，否则返回 false。
     * @create 2004-10-29 source0
     */
    this.exist = function (id)
    {
        return null != talents[id];
    }

    /**
     * 得到所有天赋的信息。
     * @return 天赋的信息数组，key = 天赋的ID, value = 天赋的级别。
     * @create 2004-10-29 source0
     */
    this.getTalents = function()
    {
        return talents;
    }
    /**
     * 得到指定天赋的级别。
     * @param id 天赋的ID。
     * @return 如果天赋存在，返回其级别，否则返回 -1 。
     * @create 2004-10-29 source0
     */
    this.getRank = function(id)
    {
        if (null != talents[id])
        {
            return talents[id];
        }
        else
        {
            return -1;
        }
    }
    this.toString = function()
    {
        var ret = new String();
        ret += 'CTalentClassForProfile[';
        ret += '天赋系ID="' + this.id + '"';
        ret += ', 加点数据=[';
        for ( var id in talents )
        {
            ret += '[天赋ID="' + id + '", 天赋级别=' + talents[id] +']';
        }
        ret += ']';
        ret += ']';
        return ret;
    }
}

/**
 * 专供载入配置文件时，给xml解析器调用的方法。
 * @param xmlDoc 由xml解析器获得的xml文档对象。
 * @create 2004-10-29 source0
 */
function loadRoleForProfile(xmlDoc)
{
    ROLE_FOR_PROFILE = decodeRole(xmlDoc);
}



/**
 * 解析配置文件，读出自定义配置。
 * @param xmlDoc 保存有指定角色配置数据的xml文档实例。
 * @create 2004-10-14 source0
 */
function loadProfile(xmlDoc){
    var roleDoc = xmlDoc.getElementsByTagName("role")[0];
    var roleId = roleDoc.getAttribute("id");
    var dataFile = roleDoc.getAttribute("dataFile");
    var talentClasses = new Array();
    CURRENT_PROFILE = new CProfile();
    CURRENT_PROFILE.dataFile = dataFile;
    CURRENT_PROFILE.roleId = roleId;
    CURRENT_PROFILE.talentClasses = talentClasses;
    var classDocs = roleDoc.getElementsByTagName("class");
    for(var c = 0; c < classDocs.length; c++) {
        talentClasses[c] = new CTalentClassForProfile();

        talentClasses[c].id = classDocs[c].getAttribute("id");
        var talents = classDocs[c].getElementsByTagName("talent");
        for( var i = 0; i < talents.length; i++ ){
            var id = talents[i].getAttribute("id");
            var rank = talents[i].getAttribute("rank");
            talentClasses[c].add(id, rank);
        }
    }
}


/**
 * 解析配置文件，读出自定义配置。
 * @param xmlDoc 保存有指定角色配置数据的xml文档实例。
 * @create 2004-10-14 source0
 */
function decodeProfile(xmlDoc){
    var roleDoc = xmlDoc.getElementsByTagName("role")[0];
    var roleId = roleDoc.getAttribute("id");
    var dataFile = roleDoc.getAttribute("dataFile");
    if ( CURRENT_ROLE.id != roleId ){
        alert("数据文件与配置文件不匹配：\n数据文件职业ID：" + CURRENT_ROLE.id + "\n配置文件职业ID：" + roleId);
        return;
    }
    var classDocs = roleDoc.getElementsByTagName("class");
    var talentClass = null;
    for(var c = 0; c < classDocs.length; c++) {
        talentClass = CURRENT_ROLE.getTalentClassById(classDocs[c].getAttribute("id"));
        if ( null == talentClass ){
            alert("数据文件与配置文件不匹配：\n职业ID：" + CURRENT_ROLE.id + "\n配置文件天赋系ID：" + classDocs[c].getAttribute("id") + "\n在数据文件中不存在");
            return;
        }
        talentClass.reset();
        var talents = classDocs[c].getElementsByTagName("talent");
        var talent = null;
        for( var i = 0; i < talents.length; i++ ){
            var id = talents[i].getAttribute("id");
            var rank = talents[i].getAttribute("rank");
            talent = talentClass.getTalentView(id);
            if ( null == talent ){
                alert("数据文件与配置文件不匹配：\n职业ID：" + CURRENT_ROLE.id + "\n天赋系ID：" + classDocs[c].getAttribute("id") + "\n天赋ID：" + id + "\n在数据文件中不存在");
                return;
            }
            talent.init(rank);
        }
    }
}

/**
 * 编码配置文件。
 * @param role 职业对象。
 * @param dataFile 数据文件。
 * @create 2004-10-14 source0
 */
function encodeProfile(role, dataFile){

    var attrs = null;
    var degree = 0;
    var indents = new Array('');
    var rt = new String();

    rt += '<' + '?xml version="1.0" encoding="GBK"?' + '>\n';
    start('role id="' + role.id + '" dataFile="' + dataFile + '"');

    for ( var key in role.talentClasses ){
        encodeTalentClass(role.talentClasses[key]);
    }

    end('role');

    return rt;

    function getIndent(degree){
        while ( degree >= indents.length ){
            indents[indents.length] = indents[indents.length - 1] + '  ';
        }
        return indents[degree];
    }
    function start(s){
        rt += getIndent(degree) + '<' + s + '>\n';
        degree ++;
    }
    function end(s){
        degree--;
        rt += getIndent(degree) + '<' + '/' + s + '>\n';
    }
    function node(s){
        rt += getIndent(degree) + '<' + s + '/' + '>\n';
    }
    function encodeTalentClass(talentClass){
        start('class id="' + talentClass.id + '"');

        var tvs = talentClass.getTalentViews();
        for( var key in tvs ){
            encodeTalent(tvs[key]);
        }
        end('class');
    }
    function encodeTalent(talentView){
        var model = talentView.model;
        if ( talentView.getRank() > 0 ){
            node('talent id="' + model.id + '" rank="' + talentView.getRank() + '"');
        }
    }

}

