import { ComputeNodeType, CalculatorType } from "./compute-node"
import { ParamsEquation } from "./param/params-equation";
import { ParamDefinition } from "./param/param-definition";
import { ConduiteDistribParams, ConduiteDistrib } from "./cond_distri";
import { LechaptCalmonParams, LechaptCalmon } from "./lechaptcalmon";
import { acSection } from "./section/section_type";
import { ParamsSectionTrapez, cSnTrapez } from "./section/section_trapez";
import { ParamsSectionRectang, cSnRectang } from "./section/section_rectang";
import { ParamsSectionCirc, cSnCirc } from "./section/section_circulaire";
import { ParamsSectionPuiss, cSnPuiss } from "./section/section_puissance";
import { RegimeUniforme } from "./regime_uniforme";
import { CourbeRemous, CourbeRemousParams } from "./remous";
import { PabDimensionParams, PabDimension } from "./pab/pab_dimension";
import { PabPuissanceParams, PabPuissance } from "./pab/pab_puissance";
import { HashTable } from "./util/hashtable";
import { ParallelStructureParams } from "./structure/parallel_structure_params";
import { ParallelStructure } from "./structure/parallel_structure";
import { RectangularStructureParams } from "./structure/rectangular_structure_params";
import { StructureCem88d } from "./structure/structure_cem88d";
import { StructureKiviParams } from "./structure/structure_kivi_params";
import { StructureKivi } from "./structure/structure_kivi";


export class ComputeNodeParameters {
    private static _instance: ComputeNodeParameters;

    private _nodes: HashTable;

    private constructor() {
        this._nodes = new HashTable();
    }

    public static getInstance() {
        if (ComputeNodeParameters._instance == undefined)
            ComputeNodeParameters._instance = new ComputeNodeParameters();
        return ComputeNodeParameters._instance;
    }

    private createSection(nt: ComputeNodeType): acSection {
        switch (nt) {
            case ComputeNodeType.None: // pour les paramètres communs, n'importe quelle section convient
            case ComputeNodeType.SectionTrapeze:
                {
                    let cn = new ParamsSectionTrapez(1, 0.5, undefined, undefined,
                        1, undefined, 0.1, 1);
                    let n = new cSnTrapez(cn); // pour initialiser la calculabilité des paramètres
                    return n;
                }

            case ComputeNodeType.SectionRectangle:
                {
                    let cn = new ParamsSectionRectang(undefined, 1, undefined, 1,
                        undefined, 0.1, 1);
                    let n = new cSnRectang(cn); // pour initialiser la calculabilité des paramètres
                    return n;
                }

            case ComputeNodeType.SectionCercle:
                {
                    let cn = new ParamsSectionCirc(1, undefined, undefined, 1,
                        undefined, 0.1, 1);
                    let n = new cSnCirc(cn); // pour initialiser la calculabilité des paramètres
                    return n;
                }

            case ComputeNodeType.SectionPuissance:
                {
                    let cn = new ParamsSectionPuiss(0.5, undefined, 1, undefined,
                        1, undefined, 0.1, 1);
                    let n = new cSnPuiss(cn); // pour initialiser la calculabilité des paramètres
                    return n;
                }

            default:
                throw new Error(`type de section ${ComputeNodeType[nt]} non pris en charge`);
        }
    }

    private createComputeNodeParameters(calcType: CalculatorType, nodeType: ComputeNodeType): ParamsEquation {
        switch (calcType) {
            case CalculatorType.ConduiteDistributrice:
                {
                    const cn = new ConduiteDistribParams(undefined, undefined, undefined, undefined, undefined);
                    const n = new ConduiteDistrib(cn); // pour initialiser la calculabilité des paramètres
                    return cn;
                }

            case CalculatorType.LechaptCalmon:
                {
                    const cn = new LechaptCalmonParams(undefined, undefined, undefined, undefined, undefined, undefined, undefined);
                    const n = new LechaptCalmon(cn); // pour initialiser la calculabilité des paramètres
                    return cn;
                }

            case CalculatorType.SectionParametree:
                {
                    const sect: acSection = this.createSection(nodeType);
                    return sect.prms;
                }

            case CalculatorType.RegimeUniforme:
                const sect: acSection = this.createSection(nodeType);
                const ru = new RegimeUniforme(sect); // pour initialiser la calculabilité des paramètres
                return sect.prms;


            case CalculatorType.CourbeRemous:
                {
                    const sect: acSection = this.createSection(nodeType);
                    const crp = new CourbeRemousParams(sect, undefined, undefined, undefined, undefined, undefined);
                    const ru = new CourbeRemous(crp); // pour initialiser la calculabilité des paramètres
                    return crp;
                }

            case CalculatorType.PabDimensions:
                {
                    let cn = new PabDimensionParams(undefined, undefined, undefined);
                    let n = new PabDimension(cn); // pour initialiser la calculabilité des paramètres
                    return cn;
                }

            case CalculatorType.PabPuissance:
                {
                    let cn = new PabPuissanceParams(undefined, undefined, undefined);
                    let n = new PabPuissance(cn); // pour initialiser la calculabilité des paramètres
                    return cn;
                }

            case CalculatorType.Structure:
                switch (nodeType) {
                    case ComputeNodeType.None: // pour les paramètres communs, n'importe quelle structure convient
                    case ComputeNodeType.StructureRectangle:
                        let cn = new RectangularStructureParams(undefined, 0.5, 2, 1, undefined, undefined);
                        let n = new StructureCem88d(cn);
                        return cn;

                    case ComputeNodeType.StructureKIVI:
                        {
                            let cn = new StructureKiviParams(undefined, 1, 2, 1, undefined, undefined, undefined, undefined);
                            let n = new StructureKivi(cn);
                            return cn;
                        }

                    default:
                        throw new Error(`ComputeNodeParameters.createComputeNodeParameters() : calculatrice '${CalculatorType[calcType]}' / noeud de calcul '${ComputeNodeType[nodeType]}' non pris en charge`);
                }

            case CalculatorType.ParallelStructure:
                {
                    let cn = new ParallelStructureParams(undefined, undefined, undefined);
                    let n = new ParallelStructure(cn);
                    return cn;
                }

            default:
                throw new Error(`ComputeNodeParameters.createComputeNodeParameters() : calculatrice '${CalculatorType[calcType]}' / noeud de calcul '${ComputeNodeType[nodeType]}' non pris en charge`);
        }
    }

    public getComputeNodeParameter(calcType: CalculatorType, nodeType: ComputeNodeType, symbol: string): ParamDefinition {
        const key = { calcType, nodeType };
        let params = this._nodes.get(key);
        if (params == undefined) {
            params = this.createComputeNodeParameters(calcType, nodeType);
            this._nodes.put(key, params);
        }

        return params.map[symbol];
    }
}