/**
 * Created by Tony on 2017/6/21.
 */
let calcBaseCodeCollection = ["定额基价人工费", "定额基价材料费", "定额基价机械费"
    , "定额基价人工费(调整后)", "定额基价材料费(调整后)", "定额基价机械费(调整后)"
    , "市场价格人工费", "市场价格材料费", "市场价格机械费"
    , "定额基价机上人工费", "主材费", "设备费"
];
let dummyCalcBaseCodeTypeCollection = [[2], [6], [64]
    , [], [], []
    , [], [], []
    , [], [], []
];

let executeObj = {
    currentTpl : null,
    currentRationItem: null,
    currentFeeRateFile: null,
    at: function(code) {
        let me = executeObj,
            rst = 0;
        rst = me.currentTpl.compileAssistantObj[code].execRst;
        return rst;
    },
    base: function(calcBaseCode) {
        let me = executeObj, rst = 0,
            idx = calcBaseCodeCollection.indexOf(calcBaseCode);
        if (idx >= 0) {
            if (dummyCalcBaseCodeTypeCollection[idx].length > 0) {
                let tmpSum = 0;
                for (let glj of me.currentRationItem.rationGljList) {
                    if (dummyCalcBaseCodeTypeCollection[idx].indexOf(glj["glj"]["gljType"]) >= 0) {
                        tmpSum += glj["glj"]["basePrice"] * glj["consumeAmt"];
                    }
                }
                rst = tmpSum;
            } else {
                //rst = 10 + idx; //随便给个数
            }
        }
        //rst = idx; //暂时返回值，测试用
        return rst;
    },
    fee: function(feeID) {
        let me = executeObj, rst = 0;
        /*
        for (let fee of me.currentFeeRateFile) {
            if (fee.ID == feeID) {
                rst = fee.rate;
                break;
            }
        }
        /*/
        if (me.compiledFeeRateFile["fee_" + feeID]) rst = me.compiledFeeRateFile["fee_" + feeID].rate;
        //*/
        return rst;
    },
    factor: function(factorCode) {
        let me = executeObj;
        let rst = 0.89; //暂时固定输出，测试用
        return rst;
    }
};

class calculation {
    init(calcTpl, calFee){
        let me = this;
        me.calcTpl = calcTpl;
        me.calFee = calFee;
        me.hasCompiled = false;
    };

    compile(){
        let me = this;
        me.hasCompiled = false;
        me.errs = [];
        let private_extract_code = function(str, idx){
            let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
            for (let i = idx; i < str.length; i++) {
                if (str[i] === '(') {
                    lBracket++;
                    if (lBracket == 1) firstIdx = i + 1;
                }
                if (str[i] === ')') {
                    rBracket++;
                    if (lBracket == rBracket) {
                        lastIdx = i - 1;
                        if (lastIdx > firstIdx) {
                            if (str[firstIdx] === "'") firstIdx++;
                            if (str[lastIdx] !== "'") lastIdx++;
                            if (lastIdx > firstIdx) {
                                rst = str.slice(firstIdx, lastIdx);
                            }
                        }
                        break;
                    }
                }
            }
            return rst;
        };
        let private_parse_ref = function(item, itemIdx){
            let expr = item.expression.split('at(').join('@(');
            item.expression = expr;
            //console.log('expression： ' + expr);
            let idx = expr.indexOf('@(', 0);
            while (idx >= 0) {
                let code = private_extract_code(expr, idx);
                //console.log('提取code： ' + code);
                if (code.length > 0) {
                    let subItem = me.compileAssistantObj[code];
                    if (subItem) {
                        if (subItem.code !== item.code) {
                            private_parse_ref(subItem, me.compileAssistantObj[code + "_idx"]);
                        } else {
                            me.errs.push("There exists the self refer code: " + code);
                        }
                    } else {
                        me.errs.push("There exists the invalid code by which could not find the item: " + code);
                        console.log('invalid code： ' + code);
                    }
                }
                idx = expr.indexOf('@(', idx + code.length + 3);
            }
            if (me.calcTpl.compiledSeq.indexOf(itemIdx) < 0) {
                //console.log('the code ready to push： ' + item.code);
                me.calcTpl.compiledSeq.push(itemIdx);
            }
        };
        let private_setup_seq = function(item, itemIdx){
            if (me.calcTpl.compiledSeq.indexOf(itemIdx) < 0) {
                private_parse_ref(item, itemIdx);
            }
        };
        let private_compile_items = function() {
            for (let idx of me.calcTpl.compiledSeq) {
                let item = me.calcTpl.calcItems[idx];
                item.compiledExpr = item.expression.split('@(').join('$CE.at(');
                item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
                item.compiledExpr = item.compiledExpr.split('fee(').join('$CE.fee(');
                item.compiledExpr = item.compiledExpr.split('factor(').join('$CE.factor(');
                //console.log(item.compiledExpr);
            }
        };
        let private_comile_feeFile = function() {
            if (me.calFee) {
                me.compiledFee = {};
                for (let fee of me.calFee) {
                    me.compiledFee["fee_" + fee.ID] = fee;
                }
            }
        };

        if (me.calcTpl && me.calcTpl.calcItems && me.calcTpl.calcItems.length > 0) {
            me.calcTpl.compiledSeq = [];
            me.compileAssistantObj = {};
            //1. first round -> prepare
            private_comile_feeFile();
            for (let i = 0; i < me.calcTpl.calcItems.length; i++) {
                let item = me.calcTpl.calcItems[i];
                me.compileAssistantObj[item.code] = item;
                me.compileAssistantObj[item.code + "_idx"] = i;
            }
            //2. second round -> go!
            for (let i = 0; i < me.calcTpl.calcItems.length; i++) {
                private_setup_seq(me.calcTpl.calcItems[i], i);
            }
            if (me.errs.length == 0) {
                private_compile_items();
                if (me.errs.length == 0) me.hasCompiled = true;
            } else {
                console.log('errors: ' + me.errs.toString());
            }
        }
        //console.log(me.compileAssistantObj);
        //console.log(me.calcTpl.compiledSeq);
    };
    calculate( $RATION){
        let me = this;
        if ($RATION && me.hasCompiled) {
            let $CE = executeObj;
            $CE.currentRationItem = $RATION;
            $CE.currentTpl = me;
            $CE.currentFeeRateFile = me.calFee;
            $CE.compiledFeeRateFile = me.compiledFee;
            for (let idx of me.calcTpl.compiledSeq) {
                let item = me.calcTpl.calcItems[idx];
                item.execRst = eval(item.compiledExpr);
            }
        }
    }
}

module.exports = new calculation();