/**
 * Created by shadeeka on 7/9/18.
 */
importScripts('https://unpkg.com/mathjs@5.0.2/dist/math.min.js');

// create a parser
const parser = self.math.parser();

self.addEventListener('message', function (event) {
    const request = JSON.parse(event.data);
    var result = null;
    var err = null;
    // build a response
    const response = {
        id: request.id,
        result: result,
        err: err
    };
    try {
        //{'cmd': 'stop', 'msg': 'Bye'}
        switch (request.cmd) {
            case 'evaluate':
                response.result = evaluate(request.expr,request.scope);
                break;
            case 'prepare':
                response.result = prepareRows(request.dataSet,request.exprs);
                colCalc(response.result,null,request.exprs);
                break;
            case 'calcin':
                console.log(request);
                response.result = colCalc(request.dataSet,request.lastRow,request.exprs);
                break;
            case 'stop':
                self.postMessage('WORKER STOPPED: ' + request.msg +
                    '. (buttons will no longer work)');
                self.close(); // Terminates the worker.
                break;
            default:
                self.postMessage('Unknown command: ' + request.msg);
        };
    } catch (e) {
        // return the error
        response.err = e;
    }



    // send the response back
    self.postMessage(JSON.stringify(response))
}, false);


function evaluate(equation,scope) {
    try{
        //console.log(equation);
        //console.log(scope);
        const h = self.math.parse(equation);
        const code2 = h.compile();
        return code2.eval(scope);
    }catch(e){
        console.log(e);
    }

    //console.log(code2.eval({x: 3,y:4})); // '7'
}

function prepareRows(data,formulaCols) {
    var rows = [];

    for(var i=0;i<data.length;i++){
        var node = data[i];
        var rowNode = {};
        for(var j=0; j<formulaCols.length;j++){
            var val = null;
            if(formulaCols[j].calc_type == 'abs') {
                val = node[formulaCols[j].prop];
            }else if(formulaCols[j].calc_type == 'formula') {
                //console.log(formulaCols[j]);
                //console.log(node);
                 val = evaluate(formulaCols[j].formula,node);
                 var roundby = (formulaCols[j].roundBy) ? formulaCols[j].roundBy:2;
                 val = val.toFixed(roundby);
                 val = parseFloat(val);
            }
            rowNode[formulaCols[j].prop] = val;
        }
      rows.push(rowNode);
    }
    //console.log(rows);
    return rows;
}

function colCalc(data,lastRow,formulaCols){
    // add last row before the new rows;
    var i = 0;
    if(lastRow){
        data.splice(0, 0, lastRow);
        i=1;
    }
    for(i;i<data.length;i++){
        var DataRow = data[i];
        var PrevRow = data[i-1];
        //console.log('inline----------->');
        //console.log(data[i]);
        for(var j=0; j<formulaCols.length;j++){
            var colConfig = formulaCols[j];

            if(colConfig.calc_type === 'inline'){
                const nodeTree = self.math.parse(colConfig.formula);
                var evalScope ={};
                //console.log(colConfig);
                var transformed = nodeTree.transform(function (node, path, parent) {
                    //console.log('transform----------->'+node.name);
                    //console.log(DataRow);
                    if (node.isSymbolNode && DataRow.hasOwnProperty(node.name)) {
                        //return new math.expression.node.ConstantNode(3);
                       // console.log('inline node----------->');
                        evalScope[node.name] = DataRow[node.name];
                        return node;
                    }
                    else if(node.isSymbolNode && node.name.indexOf('last_')>-1){
                       // console.log('inline node----------->'+node.name);
                        if(i==0){
                            evalScope[node.name] = 0;
                        }else {
                            var props = node.name.split('last_');
                            evalScope[node.name] = PrevRow[props[1]];
                        }
                        return node;
                    }else{
                        //console.log(node);
                        return node;
                    }
                });
                //evaluate formula
                val = evaluate(colConfig.formula,evalScope);
                DataRow[colConfig.prop] = val;

            }
        }
    }
    return data[data.length -1]; //return only last
}
