import {Button, MathBox, resizeContainer2D} from "../../../modules/HTMLUtils.js";

/**
 * Ejemplo del desarrollo del método de eliminación gaussiana.
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

//Matrices
const A = getAMatrix([2,4,6,18,4,5,6,24,3,1,-2,4]);
const M1 = getAMatrix([1,2,3,9,4,5,6,24,3,1,-2,4]);
const M2 = getAMatrix([1,2,3,9,0,-3,-6,-12,0,-5,-11,-23]);
const M3 = getAMatrix([1,2,3,9,0,1,2,4,0,-5,-11,-23]);
const M4 = getAMatrix([1,2,3,9,0,1,2,4,0,0,-1,-3]);
const M5 = getAMatrix([1,2,3,9,0,1,2,4,0,0,1,3]);
//Matrices activas
const M1A = getActiveAMatrix(1,[1,2,3,9,4,5,6,24,3,1,-2,4]);
const M3A = getActiveAMatrix(2,[1,2,3,9,0,1,2,4,0,-5,-11,-23]);
const M4A = getActiveAMatrix(3,[1,2,3,9,0,1,2,4,0,0,-1,-3]);
const M5A = getActiveAMatrix(3,[1,2,3,9,0,1,2,4,0,0,1,3]);
const M2A =  "\\begin{bmatrix}" +
            "\\color{#8FA39E}1 & \\color{#8FA39E}2 & \\color{#8FA39E}3 & | & \\color{#8FA39E}9\\\\" +
            "\\color{#0D8A70}0 & \\color{#0D8A70}-3 & \\color{#0D8A70}-6 & | & \\color{#0D8A70}-12\\\\" +
            "\\color{#6F8DD8}0 & \\color{#6F8DD8}-5 & \\color{#6F8DD8}-11  & | & \\color{#6F8DD8}-23" +
            "\\end{bmatrix}";
//Reglas elementales
const R1 =  getArrow("R_1", "\\frac{1}{2}R_1");
const R2 =  "\\underrightarrow{" +
            "\\begin{subarray}{l}" +
            "R_2 \\to R_2-4R_1 \\\\" +
            "R_3 \\to R_3-3R_1" +
            "\\end{subarray}" +
            "}";
const R3 =  getArrow("R_2", "-\\frac{1}{3}R_2");
const R4 =  getArrow("R_3", "R_3 + 5R_2");
const R5 =  getArrow("R_3", "-1R_3");
//Operaciones
const OPR1 =    R1 + "\\begin{cases}" +
                    "\\underline{" +
                    getEquationP("\\frac{1}{2}", "2", "4", "6", "18") + 
                    "} \\\\" +
                    "\\kern{4.2em}" +
                    getEquation("1", "2", "3", "9") + 
                "\\end{cases}";

const OPR2A =   getArrow("R_2", " R_2-4R_1") +
                "\\begin{cases}" +
                "\\kern{1.2em}" +  getEquation("4", "5", "6", "24", "black") + "\\\\" +
                "\\underline{" +
                "- \\kern{.5em}" + getEquationP("4","1", "2", "3", "9") + 
                "} \\\\" +
                "\\kern{4.2em}" + getEquation(null,"-3", "6", "- 12",null, "+", "-") + 
                "\\end{cases}";
const OPR2B =   getArrow("R_3", " R_3-3R_1") +
                "\\begin{cases}" +
                "\\kern{1.2em}" +  getEquation("3", "1", "2", "4", "black", "+", "-") + "\\\\" +
                "\\underline{" +
                "- \\kern{.5em}" + getEquationP("3","1", "2", "3", "9") + 
                "} \\\\" +
                "\\kern{4.2em}" + getEquation(null,"-5", "11", "-23", "#6F8DD8", "+", "-") + 
                "\\end{cases}";
const OPR3 = R3 +  
                "\\begin{cases}" +
                "\\underline{" +
                getEquationP("-\\frac{1}{3}", null, "-3", "-6", "-12") + 
                "} \\\\" +
                "\\kern{5.9em}" +
                getEquation(null, "1", "2", "4") + 
                "\\end{cases}";
const OPR4 = R4 + 
            "\\begin{cases}" +
            "\\kern{.5em}" +  getEquation(null,"-5", "11", "-23", "black", "+", "-") + "\\\\" +
            "\\underline{" +
            "+ \\kern{.5em}" + getEquationP("5", null, "1", "2", "4") + 
            "} \\\\" +
            "\\kern{1.2em}" + getEquation(null, null, "-1", "-3") + 
            "\\end{cases}";
const OPR5 = R5 + 
            "\\begin{cases}" +
            "\\underline{" +
            getEquationP("-1", null, null,"-1", "-3") + 
            "} \\\\" +
            "\\kern{2.8em}" + getEquation(null, null, "1", "3") + 
            "\\end{cases}";
const CASES = "\\text{Soluciones } \\\\" +
              "x_3 = {\\color{#15BB96}3} \\kern{2.9em}" +
              "x_2 = 4 - 2(x_3) \\kern{2.9em}" +
              "x_1 = 9 - 2(x_2) - 3(x_3) \\\\" +
              " \\kern{4.4em}\\to " + "x_2 = 4 - 2({\\color{#15BB96}3})" +
              " \\kern{1.9em}\\to " + "x_1 = 9 - 2({\\color{#54B6CF}-2}) - 3({\\color{#15BB96}3}) \\\\" +
              " \\kern{4.4em}\\to " + "x_2 = {\\color{#54B6CF}-2}" +
              " \\kern{4.1em}\\to " + "x_1 = {\\color{#6679D1}4}";
             
var step = 0;
const max_step = 6;
function main(){
    resizeContainer2D();
    let equations = document.getElementById("equations");
    let controls = document.getElementById("ui-container");
    controls.className = "vertical-bttns-box";
    controls.style.bottom = "-53px";

    //HTML CONTROLS
    let buttons = [ new Button(controls, upadateStep(1), "Sig"),
                    new Button(controls, upadateStep(-1), "Prev", "", true),
                    new Button(controls, reset, "Reset")
                ];
    
    //MathBoxes para escribir las matrices
    const auxPos = {top: 83, left: 5};
    const defaultPos = {top: -100, left: -100};
    let stepr1 = new MathBox(equations, {top: 5, left: 3}, A);
    let stepr2 = new MathBox(equations, {top: 25, left: 3}, M2);
    let stepr3 = new MathBox(equations, {top: 45, left: 3}, M4);
    let solutions = new MathBox(equations, {top: 70, left: 5});
    let solutionsAux = new MathBox(equations, defaultPos, OPR2B);
    
    let rows = [stepr1, stepr2, stepr3];
    var matrix = [A, M1, M2, M3, M4, M5];
    var activesMatrix = ["", M1A, M2A, M3A, M4A, M5A, ""];
    var arrows = ["", R1, R2, R3, R4, R5, ""];
    var operations = ["", OPR1, OPR2A, OPR3, OPR4, OPR5, CASES];
    //Para la animación
    var current = 0;
    var elapsed = 0;
    var lastTime = Date.now();
    let max_elapsed_wait = 700/1000;
    var complete = true;

    window.addEventListener('resize', draw);
    draw();
    
    function draw(){
        resizeContainer2D();
        if(step < 4){
            stepr3.setText("");
        }
        if(step < 2){
            stepr2.setText("");
        }
        if(step == 0){
            stepr1.setText(A);
            solutions.setText("");
            solutionsAux.setPosition(defaultPos);
            return;
        }

        if(complete)
            lastTime = Date.now();
        complete = clockWait();

        //Renglón actual
        var ri = Math.floor(step/2);
        for(var rPrev = ri -1; rPrev > -1; rPrev--)
            rows[rPrev].setText(getPrevRText(rPrev));
        if(step < 6)
            rows[ri].setText(getStepText(step, complete, step % 2 == 0));

        //Operaciones y solución
        if(step == 2)
            solutionsAux.setPosition(auxPos);
        else
            solutionsAux.setPosition(defaultPos);

        var solPos = (step == 2) ? {top: 65, left: 5} : {top: 70, left: 5};
        solutions.setText(operations[step]);
        solutions.setPosition(solPos);

        if(!complete)
            for(var i = 0; i < 3; i++)
                buttons[i].disabled(true);
        else{
            buttons[0].updateState(step, 0, max_step-1);
            buttons[1].updateState(step, 1, max_step);
            buttons[2].disabled(false);
        }
    } 
    /**
     * Devuelve el texto que corresponde al renglón i 
     * de acuerdo a si la animación está activa o no 
     * y si se trata de un paso par o impar.
     * Si se trata de par se trata de la primera 
     * matriz del renglón, en otro caso es la segunda.
     * @param {*} i el step actual
     * @param {*} complete 
     */
    function getStepText(i, complete, odd){
        if(odd)
            return (complete) ? activesMatrix[i] : "";
        var text = matrix[i-1];
        text += (complete) ? arrows[i] + activesMatrix[i] : arrows[i];
        return text;
    }
    /**
     * Obtiene las matrices y flechas del renglón dado.
     * @param {*} ri el renglón
     */
    function getPrevRText(ri){
        return matrix[2*ri] + arrows[2*ri + 1] + matrix[2*ri + 1] + arrows[2*ri + 2];
    }
    /**
     * false sigue esperando
     * true terminó la espera
     */
    function clockWait(){
        current = Date.now();
        elapsed = (current - lastTime) / 1000;
        if (elapsed > max_elapsed_wait) {
            elapsed = 0;
            lastTime = current;
            return true;
        }
        window.requestAnimationFrame(draw);
        return false;
    }
    function upadateStep(button){
        return function(){
            if (step + button < 0 || step + button > max_step)
                return;
            step += button;
            buttons[0].updateState(step, 0, max_step-1);
            buttons[1].updateState(step, 1, max_step);
            draw(); 
        }
    }
    function reset(){
        step = 0;
        buttons[0].updateState(step, 0, max_step-1);
        buttons[1].updateState(step, 1, max_step);
        draw();
    }
}
function getAMatrix(m){
    return "\\begin{bmatrix}" +
            `${m[0]} & ${m[1]} & ${m[2]} & | & ${m[3]}\\\\` +
            `${m[4]} & ${m[5]} & ${m[6]} & | & ${m[7]}\\\\` +
            `${m[8]} & ${m[9]} & ${m[10]} & | & ${m[11]}` +
            "\\end{bmatrix}";
}
function getActiveAMatrix(activeRow, m){
    let matrix = "\\begin{bmatrix}";
    matrix += (activeRow == 1) ? 
              `\\color{#0D8A70}${m[0]} & \\color{#0D8A70}${m[1]} & \\color{#0D8A70}${m[2]} & | & \\color{#0D8A70}${m[3]}\\\\` :
              `\\color{#8FA39E}${m[0]} & \\color{#8FA39E}${m[1]} & \\color{#8FA39E}${m[2]} & | & \\color{#8FA39E}${m[3]}\\\\`;
    matrix += (activeRow == 2) ? 
              `\\color{#0D8A70}${m[4]} & \\color{#0D8A70}${m[5]} & \\color{#0D8A70}${m[6]} & | & \\color{#0D8A70}${m[7]}\\\\` :
              `\\color{#8FA39E}${m[4]} & \\color{#8FA39E}${m[5]} & \\color{#8FA39E}${m[6]} & | & \\color{#8FA39E}${m[7]}\\\\`;
    matrix += (activeRow == 3) ? 
              `\\color{#0D8A70}${m[8]} & \\color{#0D8A70}${m[9]} & \\color{#0D8A70}${m[10]} & | & \\color{#0D8A70}${m[11]}` :
              `\\color{#8FA39E}${m[8]} & \\color{#8FA39E}${m[9]} & \\color{#8FA39E}${m[10]} & | & \\color{#8FA39E}${m[11]}`;
    matrix += "\\end{bmatrix}";
    return matrix;
}
function getEquationP(k, x1, x2, x3, b, color, sx1="+", sx2="+"){
    var fcolor = color || "black";
    var eq = "";
    if(x1 != null)
        eq +=  k + "({\\color{" + fcolor + "}" + x1 + "})" + "x_1 " + sx1;
    if(x2 != null)
        eq += k + "({\\color{" + fcolor + "}" + x2 + "})" + "x_2 " + sx2;
    eq += k + "({\\color{" + fcolor + "}" + x3 + "})" + "x_3" +
           "=" + k + "({\\color{" + fcolor + "}" + b + "})";
    return eq;
}
function getEquation(x1, x2, x3, b, color, sx1="+", sx2="+"){
    var fcolor = color || "#0D8A70";
    var eq = "";
    if(x1 != null)
        eq += "{\\color{" + fcolor + "}" + x1 + "} x_1 " + sx1;
    if(x2 != null)
        eq += "{\\color{" + fcolor + "}" + x2 + "} x_2 " + sx2;
    eq +=   "{\\color{" + fcolor + "}" + x3 + "} x_3"+
            "=" + "{\\color{" + fcolor + "}" + b + "}";
    return eq;
}
function getArrow(a, b){
    return "\\underrightarrow{" +
            "\\begin{subarray}{l}" +
            a + "\\to " + b +
            "\\end{subarray}" +
            "}";
}