import { Component } from '@angular/core';
import { GHCIService } from '../../../shared/services/ghci.service'; 
import  functionPlot from 'function-plot';
 
@Component({
    moduleId: module.id,
    selector: 'graph2D-component',
    templateUrl: './graph2D.component.html',
    host: {
        
    }
})
export class Graph2DComponent {
    public constructor(private ghciService: GHCIService) {
        ghciService.messages.subscribe(
            canvas=>{
                
                if (canvas.tipo == 'graph'){
                    var jsonCanvas = JSON.parse(canvas.resultado);
                    let fun = eval(this.generarFuncion(jsonCanvas));
                    

                    var conjs = this.obtenerConjunto(jsonCanvas.funs[0]);

                    var d = conjs+"}";
                    
                    var obj = JSON.parse(d);
                    //Para las funciones 
                    if (obj.conj.sets.fdom == "function(x)"){
                        var nom = jsonCanvas.funs[0].dom;
                        var elemento = this.recursionfuncion(jsonCanvas.funs[0].sets,nom);
                        obj.conj.sets.fdom = function (x) { return eval(elemento)} 
                    }
                    if (obj.conj.sets.fcod == "function(x)"){
                        var nom = jsonCanvas.funs[0].cod;
                        var elemento = this.recursionfuncion(jsonCanvas.funs[0].sets,nom);
                        obj.conj.sets.fcod = function (x) { return (eval(elemento))}  
                    }
                    //para Enumerados
                    if(obj.conj.dom == 'Numer'){
                        var cantElementos = obj.conj.sets.fdom.length;
                        var j = 0;
                        for (var fun of obj.conj.sets.fdom) {                     
                            //var newstr = nuevo2.replace(fun, j); 
                            j = j + 1;
                        }

                    }
                    if(obj.conj.cod == 'Numer'){
                        var cantElementos = obj.conj.sets.fcod.length;
                        var j = 0;
                        for (var fun of obj.conj.sets.fcod) {                     
                            //var newstr = nuevo2.replace(fun, j); 
                            j = j + 1;
                        }

                    }

                    var colores = ['pink','red','blue','orange','green']
                    var num = this.getRandomArbitrary(0,4);
                    var color = colores[num];

                    var tipoGraf;
                    if (obj.conj.baseDom != 'R'){
                        tipoGraf = 'scatter';
                    }else{
                        tipoGraf = 'polyline';
                    }
                     functionPlot({
                         target: '#graph2D-container',
                         width: 620,
                         height: 450,
                         conj:obj.conj,
                         data: [{
                             sampler: 'builtIn',
                             fn: function(scope) {
                               return fun(scope.x)
                             },
                             graphType: tipoGraf,
                             color: color
                         }]
                       })
                }
        },
        error=>{
            
        })
    }


    getRandomArbitrary= function (min, max) {
        return Math.round(Math.random() * (max - min) + min);
    }
    generarFuncion = function(graph) {
            var funcionString = '';
            var grafica;
            for (var fun of graph.funs) {
                funcionString = 'var ' + fun.fun + ' = function(' + fun.args.join() + '){\n return ' + this.generarExpresion(fun.bdy) + '}\n' + funcionString;

                if (fun.fun == graph.graph) {
                    funcionString += 'return ' + fun.fun + '(' + fun.args.join() + ');\n'
                    grafica = fun;
                }
            }
            funcionString = '(' + grafica.args.join() + ',delta,hayPunto)=>{\n' + funcionString + '}';
            
            return funcionString;
        }

    generarExpresion = function(exp) {
        var expresion = '';
        if (exp.kind == 'cnd') {
        expresion = ' (' + this.generarExpresion(exp.cond) + '?' + this.generarExpresion(exp.exp1) + ':' + this.generarExpresion(exp.exp2) + ') ';
        } else if (exp.kind == 'bop') {
        if (exp.op == '==') {
            expresion = ' Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) < delta && hayPunto() ';
        } else if (exp.op == '/=') {
            expresion = ' Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) > delta ||  Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) < delta && !hayPunto()  ';
        } else if (exp.op == '^') {
            expresion = ' Math.pow(' + this.generarExpresion(exp.exp1) + ',' + this.generarExpresion(exp.exp2) + ') ';
        } else {
            expresion = ' (' + this.generarExpresion(exp.exp1) + ')' + exp.op + '(' + this.generarExpresion(exp.exp2) + ') ';
        }
        } else if (exp.kind == 'uop') {
        expresion = ' ' + exp.op + ' ' + this.generarExpresion(exp.exp) + ' ';
        } else if (exp.kind == 'app') {
        if (exp.fun == 'cos') {
            exp.fun = 'Math.cos'
        } else if (exp.fun == 'sin') {
            exp.fun = 'Math.sin'
        } else if (exp.fun == 'round') {
            exp.fun = 'Math.round'
        }
        expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
        } else if (exp.kind == 'tup') {
        expresion = ' (' + exp.exps.map(e => this.generarExpresion(e)).join() + ') ';
        } else if (exp.kind == 'lit') {
        expresion = ' ' + exp.val + ' ';
        } else if (exp.kind == 'var') {
        expresion = ' ' + exp.var+' ';
        } else {
        expresion = ' undefined ';
        }
    
        return expresion;
    }
    
     //Nuevo 20-07-2018


     obtenerConjunto= function(grf){

        var setf = '\"sets\": {';
        var dominio = '{\"conj\": {'; 
        if (grf.dom == 'R'){
            dominio += "\"radio\": 0.3, \"baseDom\": \"R\", \"dom\": \"R\"";
            setf += "\"fdom\": \"R\",";
        }else if(grf.dom == 'Z'){
            dominio += "\"radio\": 2, \"baseDom\": \"Z\", \"dom\": \"Z\"";
            setf += "\"fdom\": \"Z\",";
        }else if(grf.dom == 'N'){
            dominio += "\"radio\":2, \"baseDom\": \"N\", \"dom\": \"N\"";
            setf += "\"fdom\": \"N\",";
        }else{
            var nom = grf.dom;
            if (Array.isArray(grf.sets[0][nom])){
                var arreglo = grf.sets[0][nom];
                var arreglo2 = [];
                for (var item of arreglo){
                    arreglo2.push("\""+item+"\"");
                }
                dominio += "\"radio\":2, \"baseDom\": \"N\", \"dom\": \"Numer\"";
                setf += "\"fdom\": [" + arreglo2 + "], ";
            }else{
                
                dominio += this.recursivoDom(grf.sets,nom);
                setf += "\"fdom\":\"function(x)\",";
            }     
        }
        dominio += ", "; 
        if (grf.cod == 'R'){
            dominio += "\"baseCod\": \"R\", \"cod\": \"R\" ,";
            setf += "\"fcod\": \"R\"";
        }else if(grf.cod == 'Z'){
            dominio += "\"baseCod\": \"Z\", \"cod\": \"Z\" ,";
            setf += "\"fcod\": \"Z\"";
        }else if(grf.cod == 'N'){
            dominio += "\"baseCod\": \"N\", \"cod\": \"N\" ,";
            setf += "\"fcod\": \"N\"";
        }else{
            var nom = grf.cod;
            if (Array.isArray(grf.sets[0][nom])){
                var arreglo = grf.sets[0][nom];
                var arreglo2 = [];
                for (var item of arreglo){
                    arreglo2.push("\""+item+"\"");
                }
                dominio += "\"baseCod\": \"N\", \"cod\": \"Numer\" ,";
                setf += '\"fcod\":[' + arreglo2+']';
            }else{
                dominio += this.recursivoCod(grf.sets,nom);
                setf += "\"fcod\": \"function(x)\"";
            }     
        }
        return dominio + setf + "}}";
    }

    recursionfuncion = function(func,nombre){
        var fun = func[0][nombre].set;
        var resul = "";
        if (fun == 'R' || fun == 'Z' || fun == 'N'){
             resul += this.generarF(func[0][nombre].cond);
        }else {
             resul += this.generarF(func[0][nombre].cond) + " && " + this.recursionfuncion(func,fun);
             
        }
        return resul;
    }

    recursivoDom = function (sets,nom){
        var domin = "";
        if (sets[0][nom].set == 'R'){
            domin += "\"radio\": 0.3, \"baseDom\": \"R\", \"dom\": \"Func\"";
        }else if(sets[0][nom].set == 'Z'){
            domin += "\"radio\": 2, \"baseDom\": \"Z\", \"dom\": \"Func\"";
        }else if(sets[0][nom].set == 'N'){
            domin += "\"radio\": 2, \"baseDom\": \"N\", \"dom\": \"Func\"";
        }else{
            var nombre = sets[0][nom].set;
            domin = this.recursivoDom(sets,nombre);
        }
        return domin;
    }

 
    recursivoCod = function (sets,nom){
        var coodo = "";
        if (sets[0][nom].set == 'R'){
            coodo += "\"baseCod\": \"R\", \"cod\": \"Func\",";
        }else if(sets[0][nom].set == 'Z'){
            coodo += "\"baseCod\": \"Z\", \"cod\": \"Func\",";
        }else if(sets[0][nom].set == 'N'){
            coodo += "\"baseCod\": \"N\", \"cod\": \"Func\",";
        }else{
            var nombre = sets[0][nom].set;
            coodo += this.recursivoDom(sets,nombre);
        }
        return coodo;
    }
    
    generarF = function(exp) {
        var expresion = '';
        if (exp.kind == 'cond') {
           expresion = ' (' + this.generarF(exp.cond) + '?' + this.generarF(exp.exp1) + ':' + this.generarF(exp.exp2) + ') ';
        } else if (exp.kind == 'bop') {
            if (exp.op == '==') {
                expresion = ' Math.abs((' + this.generarF(exp.exp1) + ') - (' + this.generarF(exp.exp2) + ')) == 0 ';
            } else if (exp.op == '/=') {
                expresion = ' Math.abs((' + this.generarF(exp.exp1) + ') - (' + this.generarF(exp.exp2) + ')) == 0 ||  Math.abs((' + this.generarF(exp.exp1) + ') - (' + this.generarF(exp.exp2) + ')) == 0  ';
            } else if (exp.op == '^') {
                expresion = ' Math.pow(' + this.generarF(exp.exp1) + ',' + this.generarF(exp.exp2) + ') ';
            } else {
                expresion = ' (' + this.generarF(exp.exp1) + ')' + exp.op + '(' + this.generarF(exp.exp2) + ') ';
            }
        } else if (exp.kind == 'uop') {
            expresion = ' ' + exp.op + ' ' + this.generarF(exp.exp) + ' ';
        } else if (exp.kind == 'app') {
            if (exp.fun == 'cos') {
                exp.fun = 'Math.cos'
            } else if (exp.fun == 'sin') {
                exp.fun = 'Math.sin'
            } else if (exp.fun == 'round') {
                exp.fun = 'Math.round'
            }
            expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarF(e)).join() + ') ';
        } else if (exp.kind == 'tup') {
            expresion = ' (' + exp.exps.map(e => this.generarF(e)).join() + ') ';
        } else if (exp.kind == 'lit') {
            expresion = ' ' + exp.val + ' ';
        } else if (exp.kind == 'var') {
            expresion = ' ' + exp.var+' ';
        } else {
           expresion = ' undefined ';
        }
    
        return expresion;
    }

    generarFun = function(graph) {
        var funcionString = '';
        var grafica;
        for (var fun of graph.funs) {
            funcionString = 'var ' + fun.fun + ' = function(' + fun.args.join() + '){\n return ' + this.generarF(fun.bdy) + '}\n' + funcionString;

            if (fun.fun == graph.graph) {
                funcionString += 'return ' + fun.fun + '(' + fun.args.join() + ');\n'
                grafica = fun;
            }
        }
        funcionString = '(' + grafica.args.join() + ')=>{\n' + funcionString + '}';            

        return funcionString;
    }
  
}