import { Component, ViewChild, ElementRef } from '@angular/core';
import { GHCIService } from '../../../shared/services/ghci.service';
import * as functionPlot from 'function-plot';
import { Animation, Setting, toJSON, triggerDownload } from './graph2D.helper';
import { TranslateService } from '@ngx-translate/core';

export interface Bounding {
    width: any;
    height: any;
}

export class MateFunGraph2D {
    private target: string = '#graph2D-container';
    private bounding: Bounding;

    // Chart Instance
    private instance: any;

    // Settings
    public settings: Setting = {
        axis: true,
        grid: true,
        tip: true
    }

    private funciones= [];
    private id = 0;
    private valores = [];
    private conjunto= [];

    // Animation state
    public animation: Animation = {
        data: [],
        init: false,
        currentFrame: 0,
        fps: 10,
        playing: false,
        timeout: null,
        animationFrame: null,
        speedX: 10,
        boton: true,
        zoo: 2000
    };

    public constructor(target:string, bounding:Bounding) {
        this.target = target; 
        this.bounding = bounding;
    }

    public easeInOutCubic = function(fps) {
        var t = fps < 6 ? 6 : fps;
        var k = t/60;
        var animation = k<.5 ? 60*(4*k*k*k) : 60*((k-1)*(2*k-2)*(2*k-2)+1);
        console.log(animation);
        return animation;
    }

    public setZoom = () => {
        this.animation.zoo = this.animation.zoo ;  
    }
    public multiGraf = () => { 
        this.animation.boton = !this.animation.boton;
    }

    private renderCanvas(canvas:any) {
        var shapesData = JSON.parse(canvas.resultado);
        var shapesDataNormalized = this.normalizeShapesData(shapesData);
        this.cleanPlot();
        this.instance = this.createPlotInstance(shapesDataNormalized);
    }

    private renderAnimation(canvas:any) {
        this.cleanPlot();                  
        var animationData = canvas.resultado.map(res => JSON.parse(res));
        for (var frame of animationData) {
            this.animation.data.push(this.normalizeShapesData(frame));
        }
        this.runAnimation();
        this.animation.init = true;
    }

    public render(canvas:any) {
        const { target, bounding } = this;
        if (this.animation.init) {
            this.stopAnimation();
        }
        switch(canvas.tipo) { 
            case 'graph': {
                console.log(canvas.resultado)
                // var jsonCanvas = JSON.parse(JSONRepair(canvas.resultado));
                var jsonCanvas = JSON.parse(canvas.resultado);
                var conjs = this.obtenerConjunto(jsonCanvas.funs[0]);
                var d = conjs + "}"; //Leo
                var obj = JSON.parse(d);

                //Para las funciones 
                if (obj.conj.sets.fdom == "function(x)") {
                    var nom = jsonCanvas.funs[0].dom;
                    var elemento1 = this.recursionfuncion(jsonCanvas.funs[0].sets, nom);
                    var funcionString = '';
                    funcionString ="var "+nom+" = function(x){\nreturn "+elemento1+"}\n"

                    funcionString += 'return ' + nom + '(x);\n'
                    
                    for (var funs of jsonCanvas.funs) {
                        funcionString = 'var ' + funs.fun + ' = function('+funs.args+'){\n return ' + this.generarExpresion(funs.bdy) + '}\n' + funcionString;
                    }
                    funcionString = '(x)=>{\n' + funcionString + '}';
                    obj.conj.sets.fdom = eval(funcionString);
                }

                if (obj.conj.sets.fcod == "function(x)") {
                   
                    var nom = jsonCanvas.funs[0].cod;
                    var elemento2 = this.recursionfuncionCod(jsonCanvas.funs[0].sets, nom);
                    console.log(elemento2)

                    obj.conj.sets.fcod = function (x) { return (eval(elemento2)) }

                    var funcionString = '';
                    funcionString ="var "+nom+" = function(x){\nreturn "+elemento2+"}\n"

                    funcionString += 'return ' + nom + '(x);\n'
                    
                    for (var funs of jsonCanvas.funs) {
                        funcionString = 'var ' + funs.fun + ' = function('+funs.args+'){\n return ' + this.generarExpresion(funs.bdy) + '}\n' + funcionString;
                    }
                    funcionString = '(x)=>{\n' + funcionString + '}';

                    obj.conj.sets.fdom = eval(funcionString);
                }

                var funcionGenerada = this.generarFuncion(jsonCanvas);

                //para Enumerados
                if (obj.conj.dom == 'Numer') {
                    var j = 0;
                    for (var f of obj.conj.sets.fdom) {
                        var expresionDom = new RegExp('( '+f+' )', 'g'); 
                        funcionGenerada = funcionGenerada.replace(expresionDom, j.toString()); 
                        j += 1;
                    }
                }

                if (obj.conj.cod == 'Numer') {
                    var j2 = 0;
                    for (var f2 of obj.conj.sets.fcod) {
                        var expresionCod = new RegExp(f2, 'g'); 
                        funcionGenerada = funcionGenerada.replace(expresionCod, j2.toString()); 
                        j2 += 1;
                    }
                }

                if (obj.conj.baseDom == 'R'){
                    obj.conj.baseCod = 'R';
                    if (obj.conj.cod != 'Func'){
                        obj.conj.cod = 'R';
                        obj.conj.fcod = 'R'; 
                    }
                }

                let fun = eval(funcionGenerada);
                var colores = ['violet', 'red', 'blue', 'orange', 'green','black']
                var num = this.getRandomArbitrary(0, 5);
                var color = colores[num];

                var tipoGraf;
                if (obj.conj.baseDom != 'R'){
                    tipoGraf = 'scatter';
                } else {
                    tipoGraf = 'polyline';
                }
                if (this.animation.boton && obj.conj.cod != 'Numer' && obj.conj.dom != 'Numer') {
                    if(this.conjunto.length == 1 && (this.conjunto[0].cod == 'Numer' || this.conjunto[0].dom == 'Numer')){
                        this.conjunto = [];
                        this.conjunto.push(obj.conj);
                        this.id = 0;
                        this.funciones = [];
                        if(obj.conj.baseDom == 'R'){
                            this.valores = [];
                            var funcionGenerada2 = this.generarFuncionDisc(jsonCanvas);
                            
                            var funcionesVer2019 =  this.createListFunction(jsonCanvas);
                            var listValores = [];
                            for (var k of this.valores){
                                listValores.push(parseInt(k))
                            }   
                            for (var i of this.valores){
                                for(var t of this.valores){
                                    var aux = parseInt(t);
                                    var aux2 = parseInt(i);
                                    var mul = aux * aux2;
                                    listValores.push(mul)
                                }
                            }
                            for (i = -999; i < 1000; i++) {                                      
                                listValores.push(i)
                            }
                            let sinRepetidos = listValores.filter((valor, indiceActual, arreglo) => arreglo.indexOf(valor) === indiceActual);

                            for (var fun2 of funcionesVer2019){
                                let fun3 = eval(fun2);
                                var insertar = false;
                                var punto1 = [];

                                if (sinRepetidos.length) {
                                    for (var p of sinRepetidos){
                                        var pn= parseInt(p) - 0.001
                                        var pp= parseInt(p) + 0.001
                                        insertar = (((fun3(pp) != undefined) ) || ((fun3(pn) != undefined)) || insertar)
                                        if((fun3(pp) != undefined)){
                                            punto1.push(pp);
                                        }else if ((fun3(pn) != undefined)){
                                            punto1.push(p);
                                        }
                                    }
                                } else {
                                    insertar = true;
                                }
                                if (insertar) {
                                    console.log("A")
                                    this.funciones.push({
                                        id: 0,
                                        sampler: 'builtIn',
                                        fn: function(scope) {
                                            return fun3(scope.x)
                                        },
                                        graphType: tipoGraf,
                                        point:punto1[0],
                                        color: color,
                                        
                                    });
                                }
                            } 
                        } else {
                            console.log("B")
                            this.funciones.push({
                                id: this.funciones.length,
                                sampler: 'builtIn',
                                fn: function(scope) {
                                    return fun(scope.x)
                                },
                                graphType: tipoGraf,
                                color: color
                            })
                        } 
                             
                    } else {
                        if(this.conjunto.length == 1){
                            this.id = 1;
                      
                            this.conjunto.unshift({radio: 2, dom:this.conjunto[0].baseDom, cod:this.conjunto[0].baseCod, baseCod:this.conjunto[0].baseCod, baseDom:this.conjunto[0].baseDom, sets:{fdom:this.conjunto[0].baseDom,fcod:this.conjunto[0].baseCod}});
                            this.funciones[0].id = this.id;
                            
                        }
                        if (this.conjunto.length != 0){ 
                            if (obj.conj.baseDom == 'R'){
                                this.conjunto[0].baseDom = 'R';
                                this.conjunto[0].dom = 'R';
                                this.conjunto[0].sets.fdom = 'R';
                            }
                            if (obj.conj.baseCod == 'R'){
                                this.conjunto[0].baseCod = 'R';
                                this.conjunto[0].cod = 'R';
                                this.conjunto[0].sets.fcod = 'R';
                            }
                        }    
                        this.conjunto.push(obj.conj);
                        var identificador=0;
                            if (this.conjunto.length > 1){
                                identificador=this.conjunto.length - 2 + this.id;
                            }
                        if(obj.conj.baseDom == 'R'){
                           this.valores = [];
                           var funcionGenerada2 = this.generarFuncionDisc(jsonCanvas);

                           var funcionesVer2019 =  this.createListFunction(jsonCanvas);
                           var listValores = [];
                           for (var k of this.valores){
                              listValores.push(parseInt(k))
                           }   
                           for (var i of this.valores){
                              for(var t of this.valores){
                                 var aux = parseInt(t);
                                 var aux2 = parseInt(i);
                                 var mul = aux * aux2;
                                 listValores.push(mul)
                               }
                            }
                            for (i = -999; i < 1000; i++) {                                      
                                listValores.push(i)
                            }
                            let sinRepetidos = listValores.filter((valor, indiceActual, arreglo) => arreglo.indexOf(valor) === indiceActual);
                            for (var fun2 of funcionesVer2019){
                                let fun3 = eval(fun2);
                                var insertar = false;
                                var punto1 = [];

                                if (sinRepetidos.length){
                                    for (var p of sinRepetidos){
                                        var pn= parseInt(p) - 0.001
                                        var pp= parseInt(p) + 0.001
                                        insertar = (((fun3(pp) != undefined) ) || ((fun3(pn) != undefined)) || insertar)
                                        if((fun3(pp) != undefined)){
                                            punto1.push(pp);
                                        }else if ((fun3(pn) != undefined)){
                                            punto1.push(p);
                                        }
                                    }
                                } else {
                                    insertar = true;
                                }
                                if (insertar){
                                    console.log(fun3)
                                    this.funciones.push({
                                        id: identificador,
                                        sampler: 'builtIn',
                                        fn: function(scope) {
                                        return fun3(scope.x)
                                        },
                                        graphType: tipoGraf,
                                        point:punto1[0],
                                        color: color,
                                       
                                    });
                                }
                            } 
                        } else {
                            console.log("D")
                            this.funciones.push({
                                id: identificador,
                                sampler: 'builtIn',
                                fn: function(scope) {
                                return fun(scope.x)
                                },
                                graphType: tipoGraf,
                                color: color
                            });
                        }
                        
                    }        
                } else { 
                    this.conjunto = [];
                    this.conjunto.push(obj.conj);
                    this.id = 0;
                    this.funciones = [];

                    if (obj.conj.baseDom == 'R') {
                        this.valores = [];
                        var funcionGenerada2 = this.generarFuncionDisc(jsonCanvas);
                        var funcionesVer2019 =  this.createListFunction(jsonCanvas);
                        var listValores = [];

                        for (var k of this.valores) {
                           listValores.push(parseInt(k))
                        }

                        for (var i of this.valores) {
                           for(var t of this.valores){
                              var aux = parseInt(t);
                              var aux2 = parseInt(i);
                              var mul = aux * aux2;
                              listValores.push(mul)
                            }
                        }

                        for (i = -999; i < 1000; i++) {                                      
                            listValores.push(i)
                        }
                        
                        let sinRepetidos = listValores.filter((valor, indiceActual, arreglo) => arreglo.indexOf(valor) === indiceActual);

                        for (var fun2 of funcionesVer2019) {
                            let fun3 = eval(fun2);
                            var insertar = false;
                            var punto1 = [];

                            if (sinRepetidos.length) {
                                for (var p of sinRepetidos) {
                                    var pn= parseInt(p) - 0.001
                                    var pp= parseInt(p) + 0.001
                                    insertar = (((fun3(pp) != undefined) ) || ((fun3(pn) != undefined)) || insertar)
                                    if ((fun3(pp) != undefined)) {
                                        punto1.push(pp);
                                    } else if ((fun3(pn) != undefined)) {
                                        punto1.push(p);
                                    }
                                }
                            } else {
                                insertar = true;
                            }

                            if (insertar) {
                                this.funciones.push({
                                    id: 0,
                                    sampler: 'builtIn',
                                    fn: function(scope) {
                                    return fun3(scope.x)
                                    },
                                    graphType: tipoGraf,
                                    point:punto1[0],
                                    color: color,
                                });
                            }
                        } 
                    } else {
                        this.funciones.push({
                            id: this.funciones.length,
                            sampler: 'builtIn',
                            fn: function(scope) {
                            return fun(scope.x)
                            },
                            graphType: tipoGraf,
                            color: color
                        });

                    }
                }
                this.instance = this.createGraficPloteInstace(this.conjunto, this.funciones, this.animation);
                break; 
            }
            case 'canvas': {
                this.renderCanvas(canvas);
                break; 
            }
            case 'animacion': {
                this.renderAnimation(canvas);
                break; 
            }
        }
    }

    public renderClean() {
        const { bounding } = this;
        if (!this.instance) {
            this.instance = functionPlot({
                target: this.target,
                width: bounding.width,
                height: bounding.height,
                grid: this.settings.grid,
                axis:  this.settings.axis,
                xAxis: {
                    scale: 'linear',
                    domain: {
                        initial: [-10, 10],
                        type: 'discrete'
                    }
                },
                data: []
            })
        }
    }

    public setBounding(bounding:Bounding) {
        const { instance } = this;
        this.bounding = bounding;
        if (bounding.width > 0 && instance) {
            instance.options.width = bounding.width;
            instance.options.height = bounding.height;
            instance.build();
        }
    }

    private createGraficPloteInstace = (conjunto, funciones, animation) => {
        const { bounding, target, settings } = this;
        return functionPlot({
            target: '#graph2D-container',
            grid: settings.grid,
            axis:  settings.axis,
            width: bounding.width,
            height: bounding.height,
            tip: { 
                color: 'green'
            },
            xAxis: {
                scale: 'linear',
                domain: { 
                    initial: [-4, 4],
                    type: 'discrete' 
                },
                yAxis: { domain: [-4, 4] }
            },
            conj: this.conjunto,
            data: this.funciones,
            zoom: animation ? animation.zoo : undefined,
            plugins: [
                functionPlot.plugins.zoomBox()
            ]
        })

    }

    private createPlotInstance = (data) => {
        const { bounding, settings, target } = this;
        return functionPlot({
            target: target,
            grid: settings.grid,
            axis:  settings.axis,
            width: bounding.width,
            height: bounding.height,
            xAxis: {
                label: 'x - axis',
                scale: 'linear',
                domain: {
                    initial: [-10, 10],
                    type: 'discrete'
                }
            },
            data: data,
            plugins: [
                functionPlot.plugins.zoomBox()
            ]
        });
    }

    /**
     * @name updateFrame
     * @desc update data for Function Plot and redraw the graph
     */
    public updateFrame = function() {
        var $this = this;
        var $data = $this.animation.data[$this.animation.currentFrame];
        if ($this.instance) {
            $this.instance.options.data = $data;
            $this.instance.draw();
        } else {
            $this.instance = this.createPlotInstance($data);
        }
        // Update Frame
        $this.animation.timeout = setTimeout(function() {
            $this.animation.currentFrame = ($this.animation.currentFrame + 1) % $this.animation.data.length;
            $this.animation.animationFrame = requestAnimationFrame($this.updateFrame.bind($this));
        }, 1000/ this.easeInOutCubic($this.animation.fps));
    }

    /**
     * @name runAnimation
     * @desc Run Shapes Animation
     */
    public runAnimation = function() {
        if (this.animation.playing) return;
        var $this = this;
        $this.animation.playing = true;
        $this.updateFrame();
    }

    /**
     * @name pauseAnimation
     * @desc Pause Shapes Animation
     */
    public pauseAnimation = function() {
        var $this = this;
        cancelAnimationFrame($this.animation.animationFrame);
        clearTimeout($this.animation.timeout);
        $this.animation.timeout = null;
        $this.animation.playing = false;
    }

    /**
     * @name stopAnimation
     * @desc Stop Shapes Animation
     */
    public stopAnimation = function() {
        var $this = this;
        $this.pauseAnimation();
        $this.animation.data = [];
        $this.animation.currentFrame = 0;
        $this.animation.init = false;
        this.instance.removeAllGraphs();
    }

    /**
     * @name decreaseSpeed
     * @desc Decrease Speed Animation
     */
    public decreaseSpeed = function() {
        var decrease = false;
        if (this.animation.fps > 6) {
            decrease = true;
        }
        if (decrease) {
            if (this.animation.fps > 10) {
                this.animation.fps -= 1;
                this.animation.speedX = this.animation.fps / 10;
            } else {
                this.animation.fps -= 1;
                this.animation.speedX = this.animation.fps / 10;
            }
            this.pauseAnimation();
            this.runAnimation();
        }
    }
    
    /**
     * @name restoreSpeed
     * @desc Increase Speed Animation
     */
    public restoreSpeed = function() {
        this.animation.fps = 10;
        this.animation.speedX = 1;
        this.pauseAnimation();
        this.runAnimation();
    }

    /**
     * @name increaseSpeed
     * @desc Increase Speed Animation
     */
    public increaseSpeed = function() {
        var increase = false;
        if (this.animation.fps < 60) {
            increase = true;
        }
        if (increase) {
            if (this.animation.fps >= 10) {
                this.animation.fps += 1;
                this.animation.speedX = this.animation.fps / 10;
            } else {
                this.animation.fps += 1;
                this.animation.speedX = this.animation.fps / 10;
            }
            this.pauseAnimation();
            this.runAnimation();
        }
    }


    /**
     * @name toggleGrid
     * @desc Show and Hide Grid
     */
    public toggleGrid = function () {
        this.instance.toggleGrid();
        this.settings.grid = !this.settings.grid;
    }

    /**
     * @name toggleAxis
     * @desc Show and Hide Axis
     */
    public toggleAxis = function () {
        this.instance.toggleAxis();
        this.settings.axis = !this.settings.axis;
    }

    /**
     * @name toggleTip
     * @desc Show and Hide Tip
     */
    public toggleTip = function () {
        this.instance.toggleTip();
        this.settings.tip = !this.settings.tip;
    }

    /**
     * @name zoomOut
     * @desc Zoom Out Button Control
     */
    public zoomOut = function () {
        this.instance.zoomOut();
    }
    /**
     * @name zoomIn
     * @desc Zoom In Button Control 
     */
    public zoomIn = function () {
        this.instance.zoomIn();
    }
    /**
     * @name recenterPlot
     * @desc center the plot and it returns to the initial state.
     */
    public recenterPlot = function () {
        this.instance.recenter();
    }
    /**
     * @name cleanPlot
     * @desc remove all the graph from the instance.
     */
    public cleanPlot = function () {
        if (this.animation.playing) {
            this.stopAnimation();
        } else {
            this.funciones = [];
            this.conjunto = [];
            this.id = 0;
            this.instance.removeAllGraphs();
        }
    }

    /**
     * @name exportPlot
     * @desc Download Plot as an SVG image.
     */
    //Ver bien
    public exportPlot = function() {
        // Objects
        var svg = document.querySelector(`${this.target} svg`);
        var canvas = document.createElement("canvas");

        // Set dimensions of the image
        var svgSize = svg.getBoundingClientRect();
        canvas.width = svgSize.width;
        canvas.height = svgSize.height;

        // Convert SVG DOM structure to xml
        var ctx = canvas.getContext('2d');
        var data = new XMLSerializer().serializeToString(svg);

        // URL Object used to parse, construct, normalise, and encode URLs.
        var DOMURL = window.URL || (<any>window).webkitURL || window;

        var img = new Image();
        var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
        var url = DOMURL.createObjectURL(svgBlob);

        img.onload = function () {
            ctx.drawImage(img, 0, 0);
            DOMURL.revokeObjectURL(url);

            var imgURI = canvas
                .toDataURL('image/png')
                .replace('image/png', 'image/octet-stream');

            triggerDownload(imgURI);
        };
        img.src = url;
    }


    /**
     * @name normalizeRectData
     * @desc Normalize Rectangle data for Function Plot Library 
     * @param {Object} rectData Data of Rectangle to be normalized
     * @returns {Object}
     */
    public normalizeRectData = function ($rectData) {
        var $rectNormalized:any = {};
        var $shape:any = {};
        $shape.w = $rectData.w;
        $shape.h = $rectData.h;
        $shape.x = $rectData.x;
        $shape.y = $rectData.y;
        $rectData.color && ($shape.fill = $rectData.color);
        $rectData.rot !== 'undefined' && ($shape.rotation = $rectData.rot);

        $rectNormalized.shape = $shape;
        $rectNormalized.graphType = 'shape';
        $rectNormalized.shapeType = 'rect';
    
        return $rectNormalized;
    }
    /**
     * @name normalizeCircleData
     * @desc Normalize Circle data for Function Plot Library 
     * @param {Object} circleData Data of Circle to be normalized
     * @returns {Object}
     */
    public normalizeCircleData = function ($circleData) {
        var $circleNormalized:any = {};
        var $shape:any = {};
        $shape.r = $circleData.r;
        $shape.x = $circleData.x;
        $shape.y = $circleData.y;
        $circleData.color && ($shape.fill = $circleData.color);
        $circleData.rot !== 'undefined' && ($shape.rotation = $circleData.rot);

        $circleNormalized.shape = $shape;
        $circleNormalized.graphType = 'shape';
        $circleNormalized.shapeType = 'circle';
    
        return $circleNormalized;
    }
    /**
     * @name normalizeTextData
     * @desc Normalize Text data for Function Plot Library 
     * @param {Object} textData Data of Text to be normalized
     * @returns {Object}
     */
    public normalizeTextData = function ($textData) {
        var $textNormalized:any = {};
        var $shape:any = {};
        $shape.text = $textData.text;
        $shape.size = $textData.size;
        $shape.x = $textData.x;
        $shape.y = $textData.y;
        $textData.color && ($shape.fill = $textData.color);
        $textData.rot !== 'undefined' && ($shape.rotation = $textData.rot);

        $textNormalized.shape = $shape;
        $textNormalized.graphType = 'shape';
        $textNormalized.shapeType = 'text';
    
        return $textNormalized;
    }
    /**
     * @name normalizeLineData
     * @desc Normalize Line data for Function Plot Library 
     * @param {Object} lineData Data of Line to be normalized
     * @returns {Object}
     */
    public normalizeLineData = function ($lineData) {
        var $lineNormalized:any = {};
        var $points = []
        for (var p of $lineData.pts) {
            $points.push([p[0],p[1]]);
        }
        $lineNormalized.points = $points;
        $lineNormalized.stroke = $lineData.color;
        $lineNormalized.rotation = $lineData.rot;
        $lineNormalized.fnType = 'points';
        $lineNormalized.polylineType = 'line';
        $lineNormalized.graphType = 'polyline';
    
        return $lineNormalized;
    }
    /**
     * @name normalizePolygonData
     * @desc Normalize Polygon data for Function Plot Library 
     * @param {Object} textData Data of Polygon to be normalized
     * @returns {Object}
     */
    public normalizePolygonData = function ($polygonData) {
        var $polygonNormalized:any = {};
        var $points = []
        for (var p of $polygonData.pts) {
            $points.push([p[0],p[1]]);
        }
        $polygonNormalized.points = $points;
        $polygonNormalized.fill = $polygonData.color;
        $polygonNormalized.rotation = $polygonData.rot;
        $polygonNormalized.fnType = 'points';
        $polygonNormalized.polylineType = 'polygon';
        $polygonNormalized.graphType = 'polyline';
    
        return $polygonNormalized;
    }

    /**
     * @name normalizeShapesData
     * @desc Normalize Shapes data for Function Plot Library 
     * @param {Array} shapesData Data of Shapes to be normalized 
     * @returns {Array}
     */
    public normalizeShapesData = function (shapesData) {
        var normalized:Array<Object> = [];
        for (var shape of shapesData) {
            switch(shape.kind) { 
                case 'rect': { 
                    normalized.push(this.normalizeRectData(shape)); 
                    break; 
                } 
                case 'circle': { 
                    normalized.push(this.normalizeCircleData(shape)); 
                    break; 
                } 
                case 'text': { 
                    normalized.push(this.normalizeTextData(shape)); 
                    break; 
                }
                case 'line': { 
                    normalized.push(this.normalizeLineData(shape)); 
                    break; 
                }
                case 'poly': { 
                    normalized.push(this.normalizePolygonData(shape)); 
                    break; 
                } 
            } 
        }
        return normalized;
    }

    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() + ')=>{\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) + ')) == 0 ';
            } else if (exp.op == '/=') {
                expresion = ' Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) != 0';
            } 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'
			}else if (exp.fun == 'sqrt'){
                exp.fun = 'Math.sqrt'
            }
			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;
    }



    // nueva
    createListFunction = function (graph) {
        var funcionString = '';
        var grafica;
        var funciones = [];
        var j = 0;
        while (graph.funs[j].fun != graph.graph) {
            j += 1;
        }

        var fun1 = graph.funs[j];
        var arrayFunction = [];
        var nameFun = [];
        nameFun.push(fun1.fun);
        funciones = this.armarFuncion(fun1.bdy,graph,nameFun);
        for (var funs of funciones){
            for (var fun of graph.funs){
                if (fun.fun != fun1.fun){
                    funcionString = 'var ' + fun.fun + ' = function(' + fun.args.join() + '){\n return ' + this.generarExpresion(fun.bdy) + '}\n' + funcionString;
                }
            }

            funcionString = 'var ' + fun1.fun + ' = function(' + fun1.args.join() + '){\n return ' + funs + '}\n' + funcionString;
            funcionString += ';return ' + fun1.fun + '(' + fun1.args.join() + ');\n'
            grafica = fun1;
            funcionString = '(' + grafica.args.join() + ')=>{\n' + funcionString + '}';
            
            arrayFunction.push(funcionString);   
            var funcionString = '';
        }
        return arrayFunction;
    }

    armarFuncion = function (exp,graph,nameFun){
        var lisArm = this.generateFunctionAndExp(exp,graph,nameFun);
        var lisFun = [];
        for(var lis of lisArm){
            var aux = '';
            if(lis[0] == 'N'){
                aux = lis[1];
            }else{
                aux = '('+lis[0]+' ? '+lis[1]+' : undefined )';
            }
            lisFun.push(aux);
        }
        return lisFun
    }


    generateFunctionAndExp = function (exp,graph,namefun6) {
        var myList = [];
        // devuelvo lista con tupla (cond,funcion)
        if (exp.kind == 'cnd') {
            var lisA = this.generateFunctionAndExp(exp.exp1,graph,namefun6);
            var lisB = this.generateFunctionAndExp(exp.exp2,graph,namefun6);
            var cond = this.createListExp(exp.cond);
            var g = this.createListExp(exp.cond);
            
            var cond2 = g.splice(1);
            var union = g[0]


            for (var a of cond2) {
                union = '('+union+' && '+a+')';
            }
            for (var fun1 of lisA) {
                var aux121 = [];
                if (fun1[0] == 'N') {
                    if (cond.length == 0) {
                        aux121[0]='N';
                    }else{
                        aux121[0]=union;
                    }
                }else{ 
                    aux121[0]= '('+fun1[0]+' && '+union+ ')';
                }
                aux121[1] = fun1[1];
                myList.push(aux121);
            }
            for (var fun2 of lisB) {
                if (cond.length != 0) {
                    for (var condi of cond) {
                        var aux123 = [];
                        aux123[1]=fun2[1];
                        if (fun2[0] == 'N') {
                            aux123[0]='!('+condi+')';
                        } else {
                            aux123[0] = '('+fun2[0]+' && !('+condi+'))';
                        }
                        myList.push(aux123);
                    }
                } else {
                    myList.push(fun2);
                }
            }
        } else if (exp.kind == 'bop') {
            if (exp.op == '^') {
                var lisA1 = this.generateFunctionAndExp(exp.exp1,graph,namefun6);
                var lisB1 = this.generateFunctionAndExp(exp.exp2,graph,namefun6);
                var aux1 = [];
                for (var f1 of lisA1){
                    for (var f2 of lisB1){
                        var aux11 = 'Math.pow('+f1[1]+' , '+f2[1]+')';
                        var aux21;
                        if ((f2[0] == 'N') && (f1[0] == 'N')){
                            aux21 = 'N'
                        }else if(f2[0] == 'N'){
                            aux21=f1[0]
                        }else if(f1[0] == 'N'){
                            aux21=f2[0]
                        }else{
                            aux21= '('+f1[0]+' && '+f2[0]+')';
                        }
                        aux1[0]= aux21;
                        aux1[1] = aux11;
                        myList.push(aux1);
                    }
                }
            } else {
                var lisA2 = this.generateFunctionAndExp(exp.exp1,graph,namefun6);
                var lisB2 = this.generateFunctionAndExp(exp.exp2,graph,namefun6);
                var aux2 = [];
                for (var f1 of lisA2){
                    for (var f2 of lisB2){
                        var aux12 = '(('+f1[1]+')'+exp.op+'('+f2[1]+'))';
                        var aux22
                        if ((f2[0] == 'N') && (f1[0] == 'N')) {
                            aux22 = 'N'
                        } else if (f2[0] == 'N') {
                            aux22 =f1[0]
                        } else if (f1[0] == 'N') {
                            aux22 =f2[0]
                        } else { 
                            aux22= '('+f1[0]+' && '+f2[0]+')';
                        }
                        aux2[0]= aux22;
                        aux2[1] = aux12;
                        myList.push(aux2);
                    }
                }
            }
        } else if (exp.kind == 'uop') {
            var lisA3 = this.generateFunctionAndExp(exp.exp,graph,namefun6);
            var aux3 = [];
            for (var f1 of lisA3) {
                var aux13 = ' '+exp.op+' '+f1[1]+' ';               
                aux3[0]= f1[0];
                aux3[1] = aux13;
                myList.push(aux3);
            }
        } else if (exp.kind == 'app') {       
            if ((exp.fun == 'Math.cos') || (exp.fun == 'cos')) {
                var aux4 = [];
                var aux14 = 'Math.cos('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux24 = 'N'
                aux4[0]= aux24;
                aux4[1] = aux14;
                myList.push(aux4);           
            } else if ((exp.fun == 'Math.sin') || (exp.fun == 'sin')) {
                var aux5 = [];
                var aux15 = 'Math.sin('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux25 = 'N'
                aux5[0]= aux25;
                aux5[1] = aux15;
                myList.push(aux5);
            } else if ((exp.fun == 'Math.round') || (exp.fun == 'round')) {
                var aux6 = [];
                var aux16 = 'Math.round('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux26 = 'N'
                aux6[0]= aux26;
                aux6[1] = aux16;
                myList.push(aux6);
            } else if ((exp.fun == 'Math.sqrt') || (exp.fun == 'sqrt')) {
                var aux7 = [];
                var aux17 = 'Math.sqrt('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux27 = 'N'
                aux7[0]= aux27;
                aux7[1] = aux17;
                myList.push(aux7);
            /*
            } else if (exp.args[0].kind == 'app') {
                var aux101 = [];
                var aux1101 = exp.fun+'('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux2101 = 'N'
                aux101[0]= aux2101;
                aux101[1] = aux1101;
                myList.push(aux101);
            } else if(((exp.args[0].kind == 'cnd' || exp.args[0].kind == 'bop') && (exp.args[0].exp1.kind == 'app' || exp.args[0].exp2.kind == 'app' )) || (exp.args[0].kind == 'uop' && exp.args[0].exp.kind == 'app') ){
                var aux102 = [];
                var aux1102 = exp.fun+'('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux2102 = 'N'
                aux102[0]= aux2102;
                aux102[1] = aux1102;
                myList.push(aux102);
            */
            } else if(JSON.stringify(exp.args[0]).indexOf("app") != -1) { 
                console.log("Entro");
                exp.args[0] = this.recorrerArgumentos(exp.args[0]);
                var aux102 = [];
                var aux1102 = exp.fun+'('+ exp.args.map(e => this.generarExpresion(e)).join() +')';
                var aux2102 = 'N'
                aux102[0]= aux2102;
                aux102[1] = aux1102;
                myList.push(aux102);        
            } else { 
                var nomFun = exp.fun+exp.args.map(e => this.generarExpresion(e)).join()
                if (!namefun6.includes(nomFun)) {
                    var ListnameFNew = namefun6;
                    ListnameFNew.push(nomFun);

                    for (var fun5 of graph.funs) {
                        if (fun5.fun == exp.fun) {
                            myList = this.generateFunctionAndExp(fun5.bdy,graph,ListnameFNew);
                            for(var iter of myList){
                                iter[1] = iter[1].replace(/x/g,exp.args.map(e => this.generarExpresion(e)).join())
                            }
                        }
                    }
                } else {
                    var aux76 = [];
                    aux76[0] = 'N';
                    aux76[1] = exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ')';
                    myList.push(aux76);
                }
            }
            
        } else if (exp.kind == 'tup') {
            var lisA7 = this.generateFunctionAndExp(exp.exps,graph,namefun6);
            for (var f of lisA7){
                var aux65 = [];
                aux65[1] = '('+f[1]+')';
                aux65[0] = f[0];
                myList.push(aux65);
            }
        //Es esto o las combinaciones
        // expresion = ' (' + exp.exps.map(e => this.generarExpresion(e)).join() + ') ';
        } else if (exp.kind == 'lit') {
            var aux8 = [];
            aux8[0] = 'N';
            aux8[1] = ' ' + exp.val + ' ';
            myList.push(aux8);
        } else if (exp.kind == 'var') {

            var aux9 = [];
            aux9[0] = 'N';
            aux9[1] = ' ' + exp.var + ' ';
            myList.push(aux9);
        } else {
            var aux54 = [];
            aux54[0]= 'N';
            aux54[1]='undefined';
            myList.push(aux54);
        }

        return myList;
    }

    recorrerArgumentos = function(argumento) {
        if (argumento.kind == 'app') {
            if ((argumento.fun == 'Math.cos') || (argumento.fun == 'cos')) {
                argumento.fun = 'Math.cos';
            } else if((argumento.fun == 'Math.sin') || (argumento.fun == 'sin')) {
                argumento.fun = 'Math.sin';
            } else if((argumento.fun == 'Math.round') || (argumento.fun == 'round')) {
                argumento.fun = 'Math.round';
            } else if((argumento.fun == 'Math.sqrt') || (argumento.fun == 'sqrt')) {
                argumento.fun = 'Math.sqrt';
            }
        } else if(argumento.kind == 'cnd') {
            this.recorrerArgumentos(argumento.exp1)
            this.recorrerArgumentos(argumento.exp2)
        } else if(argumento.kind == 'bop') {
            this.recorrerArgumentos(argumento.exp1)
            this.recorrerArgumentos(argumento.exp2)
        } else if(argumento.kind == 'uop') {
            this.recorrerArgumentos(argumento.exp1)
        }
        return argumento;
    }

    createListExp = function (exp) {
        var expresion = '';
        var funcione = [];
        if (exp.kind == 'cnd') {
                funcione = this.createListExp(exp.cond);
        } else if (exp.kind == 'bop') {
            if (exp.op == '==') {
                expresion = ' Math.abs((' + this.createListExp(exp.exp1)[0] + ') - (' + this.createListExp(exp.exp2)[0] + ')) == 0 ';
                if (exp.exp1.kind == 'lit') {
                    this.valores.push(exp.exp1.val)
                }
                if (exp.exp2.kind == 'lit') {
                    this.valores.push(exp.exp2.val)
                }
                funcione.push(expresion)

            } else if (exp.op == '/=') {
                expresion = ' Math.abs((' + this.createListExp(exp.exp1) + ') - (' + this.createListExp(exp.exp2) + ')) != 0';
                funcione.push(expresion)

            } else if (exp.op == '^') {
                expresion = ' Math.pow(' + this.createListExp(exp.exp1) + ',' + this.createListExp(exp.exp2) + ') ';
                funcione.push(expresion)

            } else if (exp.op == '&&') {
                for (var atr of this.createListExp(exp.exp1)){
                    funcione.push(atr)
                }
                for (var atr2 of this.createListExp(exp.exp2)){
                    funcione.push(atr2)
                }
            }else if (exp.op == 'or'){
                funcione.push('!'+this.createListExp(exp.exp1))
                funcione.push('!'+this.createListExp(exp.exp2))
            }else{
                var lis1 = this.createListExp(exp.exp1)
                var lis2 = this.createListExp(exp.exp2)
                for(var expes1 of lis1){
                    for (var expes2 of lis2){
                        expresion = ' ((' + expes1 + ')' + exp.op + '(' + expes2 + ') )';
                        funcione.push(expresion)
                    }
                }
            }
        } else if (exp.kind == 'uop') {
            expresion = ' ' + exp.op + ' ' + this.createListExp(exp.exp) + ' ';
            funcione.push(expresion)

        } else if (exp.kind == 'app') {

            if (exp.fun == 'Math.cos') {
                exp.fun = 'Math.cos'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
                funcione.push(expresion)

            } else if (exp.fun == 'Math.sin') {
                exp.fun = 'Math.sin'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
                funcione.push(expresion)

            } else if (exp.fun == 'Math.round') {
                exp.fun = 'Math.round'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
                funcione.push(expresion)

            } else if (exp.fun == 'Math.sqrt') {
                exp.fun = 'Math.sqrt'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
                funcione.push(expresion)

            }else{
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
                funcione.push(expresion)
            }

        } else if (exp.kind == 'tup') {
            expresion = ' (' + exp.exps.map(e => this.generarExpresion(e)).join() + ') ';
            funcione.push(expresion)

        } else if (exp.kind == 'lit') {
            expresion = ' ' + exp.val + ' ';
            this.valores.push(exp.val)
            funcione.push(expresion)

        } else if (exp.kind == 'var') {

            expresion = ' ' + exp.var + ' ';
            funcione.push(expresion)

        } else {
            expresion = 'undefined ';
            funcione.push(expresion)

        }
        return funcione;
    }
    ///////////////////// fin de nuevo

     // Prueba 2019
     generarFuncionDisc = function (graph) {
        var funcionString = '';
        var grafica;
        var arrayFunction = [];
        var fun = graph.funs[0];
        var ListnameF = [];
        ListnameF.push(fun.fun);
        var funciones = this.generarExpresionDisc(fun.bdy,graph,ListnameF)
        for (var funs of funciones){
            funcionString = 'var ' + fun.fun + ' = function(' + fun.args.join() + '){\n return ' + funs + '}\n' + funcionString;

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


        var arrayFunction1 = [arrayFunction[0]]
        return arrayFunction;
    }

    generarExpresionDisc = function (exp,grap,ListnameF) {
        var expresion = '';
        var funcione = [];
        if (exp.kind == 'cnd') {
            var con1 = this.generarExpresionDisc(exp.cond,grap,ListnameF);
            var con11 = '';
            
            for (var condi of con1){
                if (con11 == ''){
                    con11 = condi;
                }else{
                    con11 = '('+con11 +' && '+ condi +')';
                }
                
            }
            for (var funs of this.generarExpresionDisc(exp.exp1,grap,ListnameF)){ 
                funcione.push('('+con11+' ? '+ funs +' : undefined)');      
            }
            for (var funs2 of this.generarExpresionDisc(exp.exp2,grap,ListnameF)){ 
                for (var condi2 of con1){
                    funcione.push('(!('+condi2+') ? '+ funs2 +' : undefined)');

                }   
            }
        } else if (exp.kind == 'bop') {
            if (exp.op == '==') {
                expresion = ' Math.abs((' + this.generarExpresionDisc(exp.exp1,grap,ListnameF) + ') - (' + this.generarExpresionDisc(exp.exp2,grap,ListnameF) + ')) == 0 ';
                if (exp.exp1.kind == 'lit') {
                    this.valores.push(exp.exp1.val)
                }
                if (exp.exp2.kind == 'lit') {
                    this.valores.push(exp.exp2.val)
                }
                funcione.push(expresion)

            } else if (exp.op == '/=') {
                expresion = ' Math.abs((' + this.generarExpresionDisc(exp.exp1,grap,ListnameF) + ') - (' + this.generarExpresionDisc(exp.exp2,grap,ListnameF) + ')) != 0';
                funcione.push(expresion)

            } else if (exp.op == '^') {
                expresion = ' Math.pow(' + this.generarExpresionDisc(exp.exp1,grap,ListnameF) + ',' + this.generarExpresionDisc(exp.exp2,grap,ListnameF) + ') ';
                funcione.push(expresion)

            } else if (exp.op == '&&') {
                for (var atr of this.generarExpresionDisc(exp.exp1,grap,ListnameF)){
                    funcione.push(atr)
                }
                for (var atr2 of this.generarExpresionDisc(exp.exp2,grap,ListnameF)){
                    funcione.push(atr2)
                }
            } else if (exp.op == 'or') {
                funcione.push('!'+this.generarExpresionDisc(exp.exp1,grap,ListnameF))
                funcione.push('!'+this.generarExpresionDisc(exp.exp2,grap,ListnameF))
            } else {
                var lis1 = this.generarExpresionDisc(exp.exp1,grap,ListnameF)
                var lis2 = this.generarExpresionDisc(exp.exp2,grap,ListnameF)
                for(var expes1 of lis1){
                    for (var expes2 of lis2){
                        expresion = ' ((' + expes1 + ')' + exp.op + '(' + expes2 + ') )';
                        funcione.push(expresion)
                    }
                }
            }
        } else if (exp.kind == 'uop') {
            expresion = ' ' + exp.op + ' ' + this.generarExpresionDisc(exp.exp,grap,ListnameF) + ' ';
            funcione.push(expresion)

        } else if (exp.kind == 'app') {

			if (exp.fun == 'Math.cos') {
                exp.fun = 'Math.cos'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresionDisc(e,grap,ListnameF)).join() + ') ';
                funcione.push(expresion)

			} else if (exp.fun == 'Math.sin') {
                exp.fun = 'Math.sin'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresionDisc(e,grap,ListnameF)).join() + ') ';
                funcione.push(expresion)

			} else if (exp.fun == 'Math.round') {
                exp.fun = 'Math.round'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresionDisc(e,grap,ListnameF)).join() + ') ';
                funcione.push(expresion)

            } else if (exp.fun == 'Math.sqrt') {
                exp.fun = 'Math.sqrt'
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresionDisc(e,grap,ListnameF)).join() + ') ';
                funcione.push(expresion)
    
            } else {

                if (!ListnameF.includes(exp.fun)) {
                    var ListnameFNew = ListnameF;
                    ListnameFNew.push(exp.fun);
                    for (var fun5 of grap.funs){
                        if(fun5.fun == exp.fun){
                            var funresul = this.generarExpresionDisc(fun5.bdy,grap,ListnameFNew);
                            for (var subfunciones of funresul){
                                funcione.push(subfunciones);
                            }
                        }
                    }
                } else {
                    funcione.push(exp.fun);
                }
                
            }

        } else if (exp.kind == 'tup') {
            expresion = ' (' + exp.exps.map(e => this.generarExpresionDisc(e,grap,ListnameF)).join() + ') ';
            funcione.push(expresion)

        } else if (exp.kind == 'lit') {
            expresion = ' ' + exp.val + ' ';
            this.valores.push(exp.val)
            funcione.push(expresion)

        } else if (exp.kind == 'var') {

            expresion = ' ' + exp.var + ' ';
            funcione.push(expresion)

        } else {
            expresion = ' undefined ';
            funcione.push(expresion)

        }
        return funcione;
    }

    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 nom1 = grf.cod;

            if (Array.isArray(grf.sets[0][nom1])) {
                var arreglo3 = grf.sets[0][nom1];
                var arreglo4 = [];
                for (var item of arreglo3) {
                    arreglo4.push("\"" + item + "\"");
                }
                dominio += "\"baseCod\": \"N\", \"cod\": \"Numer\" ,";
                setf += '\"fcod\":[' + arreglo4 + ']';
            } else {
                dominio += this.recursivoCod(grf.sets, nom1);
                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;
    }


    recursionfuncionCod = function (func, nombre) {
        //ACA CAMBIE
        var fun = func[0][nombre].set;
        var resul = "";
        if (fun == 'R' || fun == 'Z' || fun == 'N') {
            //ACA TAMBIEN
            resul += this.generarF(func[0][nombre].cond);
        } else {
            //ACA TAMBIEN
            resul += this.generarF(func[0][nombre].cond) + " && " + this.recursionfuncionCod(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 ';
            } 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'
            }else if (exp.fun == 'sqrt'){
                exp.fun = 'Math.sqrt'
            }
            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;
    }
}