'use strict';

/**
 *
 *
 * @author Mai
 * @date 2018/4/27
 * @version
 */

const Service = require('egg').Service;
module.exports = app => {
    class IndexCalc extends Service {
        _initCalc (indexes, globalParams, nodeParams) {
            this.indexes = indexes;
            this.globalParams = globalParams;
            this.globalParamsIndex = {};
            for (const gp of this.globalParams) {
                this.globalParamsIndex[gp.code] = gp.calc_value;
            }
            this.nodeParams = nodeParams;
            this.nodeParamsIndex = {};
            for (const np of this.nodeParams) {
                this.nodeParamsIndex[np.code] = np.calc_value;
            }
            this.updateArr = [];
        }

        _splitByOperator(expr) {
            const exprStack = [];
            const result = [];
            for(let i = 0, len = expr.length; i < len; i++){
                const cur = expr[i];
                if(cur !== ' ' ){
                    exprStack.push(cur);
                }
            }
            let param = '', isParamBefore = false;
            while(exprStack.length > 0){
                const cur = exprStack.shift();
                if (this.ctx.helper.isOperator(cur)) {
                    if (isParamBefore) {
                        result.push(param);
                        param = '';
                    }
                    result.push(cur);
                    isParamBefore = false;
                } else {
                    param = param + cur;
                    isParamBefore = true;
                    if (exprStack.length === 0) {
                        result.push(param);
                        param = '';
                    }
                }
            }
            return result;
        }

        _getEvalRule(rule) {
            const parts = this._splitByOperator(rule);
            const evalParts = [];
            for (const p of parts) {
                if (this.ctx.helper.isOperator(p)) {
                    evalParts.push(p);
                } else if (this.globalParamsIndex[p]) {
                    evalParts.push(this.globalParamsIndex[p]);
                } else if (this.nodeParamsIndex[p]) {
                    evalParts.push(this.nodeParamsIndex[p]);
                }
            }
            return evalParts.join('');
        }

        calculate(indexes, globalParams, nodeParams) {
            this._initCalc(indexes, globalParams, nodeParams);
            for (const index of indexes) {
                const eval_rule = this._getEvalRule(index.calc_rule);
                if (eval_rule !== index.eval_rule) {
                    index.eval_rule = eval_rule;
                    const value = this.ctx.helper.calcExprStr(index.eval_rule);
                    index.value = value ? Number(value.toFixed(4)) : null;
                    this.updateArr.push(index);
                }
            }
        }
    }

    return IndexCalc;
};