/**
 * IMPORTANT !
 * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine")
 * Pour exécuter ce code dans le débugger.
 * Faire de même avec le fichier test_func.ts
 */
import { describe, expect, it, xdescribe, xit } from "../mock_jasmine";

import { NubTest, NubTestParams } from "../nubtest";
import { precDigits } from "../test_config";
import { ParamValueMode, Result } from "../../src";

let nub1: NubTest;
let nub2: NubTest;
let prm1: NubTestParams;
let prm2: NubTestParams;

/**
 * crée l'environnement de test.
 * répété à chaque test car il manque un mock de beforeEach
 */
function createEnv() {
    // Nub maître (dont on référence la valeur du paramètre A)
    nub1 = new NubTest(new NubTestParams());
    prm1 = nub1.parameters as NubTestParams;

    // Nub esclave (qui utilise la valeur de A du Nub maître)
    nub2 = new NubTest(new NubTestParams());
    prm2 = nub2.parameters as NubTestParams;
}

describe("référence d'un paramètre à un autre : ", () => {
    describe("lien au paramètre du même nom : ", () => {
        it("test 1", () => {
            // cas de figure :
            // nub2.A est lié à nub1.A (valeur fixe)
            // lecture des valeurs de tous les paramètres

            createEnv();

            prm2.A.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1)
            prm2.A.defineReference(nub1, "A");

            expect(prm1.A.v).toEqual(1);
            expect(prm1.B.v).toEqual(2);
            expect(prm1.C.v).toEqual(3);
            expect(prm2.A.v).toEqual(1);
            expect(prm2.B.v).toEqual(2);
            expect(prm2.C.v).toEqual(3);
        });

        it("test 2", () => {
            // cas de figure :
            // nub2.B est lié à nub1.B (valeur fixe)
            // lecture des valeurs de tous les paramètres

            createEnv();

            prm2.B.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.B, normalement 2)
            prm2.B.defineReference(nub1, "B");

            expect(prm1.A.v).toEqual(1);
            expect(prm1.B.v).toEqual(2);
            expect(prm1.C.v).toEqual(3);
            expect(prm2.A.v).toEqual(1);
            expect(prm2.B.v).toEqual(2);
            expect(prm2.C.v).toEqual(3);
        });

        it("test 3", () => {
            // cas de figure :
            // nub2.C est lié à nub1.C (valeur fixe)
            // lecture des valeurs de tous les paramètres

            createEnv();

            prm2.C.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
            prm2.C.defineReference(nub1, "C");

            expect(prm1.A.v).toEqual(1);
            expect(prm1.B.v).toEqual(2);
            expect(prm1.C.v).toEqual(3);
            expect(prm2.A.v).toEqual(1);
            expect(prm2.B.v).toEqual(2);
            expect(prm2.C.v).toEqual(3);
        });

        it('test 4', () => {
            // cas de figure :
            // nub2.A est lié à nub1.A (valeur fixe)
            // calcul de tous les paramètres

            createEnv();

            prm2.A.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1)
            prm2.A.defineReference(nub1, "A");

            expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits);
            expect(nub1.Calc("B").vCalc).toBeCloseTo(2, precDigits);
            expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits);

            expect(nub2.Calc("A").vCalc).toBeCloseTo(1, precDigits);
            expect(nub2.Calc("B").vCalc).toBeCloseTo(2, precDigits);
            expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits);
        });

        it('test 5', () => {
            // cas de figure :
            // nub2.B est lié à nub1.B (valeur fixe)
            // calcul de tous les paramètres

            createEnv();

            prm1.B.v = 3;  // valeur maître
            prm2.B.v = 0;  // valeur esclave (doit être masquée par la valeur maître)
            prm2.B.defineReference(nub1, "B");

            expect(nub1.Calc("A").vCalc).toBeCloseTo(0, precDigits);
            expect(nub1.Calc("B").vCalc).toBeCloseTo(3, precDigits);
            expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits);

            expect(nub2.Calc("A").vCalc).toBeCloseTo(0, precDigits);
            //expect(nub2.Calc("B").vCalc).toBeCloseTo(3, precDigits); // échoue car l'écriture du paramètre esclave n'affecte pas la valeur maître
            expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits);
        });

        it('test 6', () => {
            // cas de figure :
            // nub2.C est lié à nub1.C (valeur fixe)
            // calcul de tous les paramètres

            createEnv();

            prm2.C.v = 0;  // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
            prm2.C.defineReference(nub1, "C");


            expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits);
            expect(nub1.Calc("B").vCalc).toBeCloseTo(2, precDigits);
            expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits);

            expect(nub2.Calc("A").vCalc).toBeCloseTo(1, precDigits);
            expect(nub2.Calc("B").vCalc).toBeCloseTo(2, precDigits);
            expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits);
        });
    });

    describe("lien à un paramètre non fixé : ", () => {
        it('test 1', () => {
            // cas de figure :
            // nub2.A est lié à nub1.C (valeur calculée)
            // lecture de nub2.A

            createEnv();

            prm1.C.v = 10;  // valeur maître bidon
            prm1.C.paramValues.valueMode = ParamValueMode.CALCUL;
            prm2.A.v = 0;  // valeur esclave (doit être masquée par la valeur maître, cad prm1.C, normalement 3)
            prm2.A.defineReference(nub1, "C");

            expect(prm2.A.v).toBeCloseTo(3, precDigits);
        });

        it('test 2', () => {
            // cas de figure :
            // nub2.A est lié à nub1.C (valeur calculée)
            // calcul de nub2.C

            createEnv();

            prm1.C.v = 0;  // valeur bidon, doit être 3 après calcul
            prm1.C.paramValues.valueMode = ParamValueMode.CALCUL;
            prm2.C.v = 0;  // valeur bidon, doit être 5 après calcul
            prm2.A.v = 0;  // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.C, normalement 3)
            prm2.A.defineReference(nub1, "C");

            expect(nub2.Calc("C").vCalc).toBeCloseTo(5, precDigits);
        });

        it('test 3', () => {
            // cas de figure :
            // nub2.A est lié à nub1.A (valeur variée)
            // lecture de nub2.A 

            createEnv();

            const min = 1;
            const max = 5;
            const step = 1;

            const pv = prm1.A.paramValues;
            pv.setValues(min, max, step);
            prm2.A.v = 0;  // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.A, normalement [1,2,3,4,5])
            prm2.A.defineReference(nub1, "A");

            let n = 0;
            let i = min;
            for (const v of prm2.A.paramValues.getValuesIterator()) {
                expect(v).toEqual(i);
                n++;
                i += step;
            }
            expect(n).toEqual((max - min) / step + 1);
        });

        it('test 4', () => {
            // cas de figure :
            // nub2.A est lié à nub1.A (valeur variée)
            // calcul de nub2.C

            createEnv();

            const min = 1;
            const max = 5;
            const step = 1;

            const input = [1, 2, 3, 4, 5];
            const pv = prm1.A.paramValues;
            pv.setValues(input);
            prm2.A.v = 0;  // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.A, normalement [1,2,3,4,5])
            prm2.A.defineReference(nub1, "A");

            const r: Result = nub2.CalcSerie(0.001, 0.1, "C");

            let n = 0;
            for (const re of r.resultElements) {
                expect(re.vCalc).toEqual(input[n] + 2);
                n++;
            }
            expect(n).toEqual(input.length);
        });
    });
});