import { Debug, IDebug } from "./base";
import { JalhydObject } from "./jalhyd_object";
import { ParamCalculability, ParamDefinition } from "./param/param-definition";
import { IParamDefinitionIterator, ParamsEquation } from "./param/params-equation";

/**
 * type de calculette
 */
export enum CalculatorType {
    ConduiteDistributrice,
    LechaptCalmon,
    SectionParametree,
    RegimeUniforme,
    CourbeRemous,
    PabDimensions,      // passe à bassin rectangulaire
    PabPuissance,       // passe à bassin : puissance dissipée
    Structure,          // ouvrages hydrauliques simples
    ParallelStructure,  // ouvrages hydrauliques en parallèle
    Dever,              // Outil Cassiopée Dever
    Cloisons,           // Outil Cassiopée PAB Cloisons
    MacroRugo,          // Passe à enrochement simple (Cassan et al., 2016)
    PabChute,
    PabNombre,
    Section,
    Pab                 // Passe à bassins
}

/**
 * type de noeud de calcul (sous type de calculette)
 */
export enum ComputeNodeType {
    None,
    // types de sections
    SectionTrapeze, SectionRectangle, SectionCercle, SectionPuissance,
    // types d'ouvrages hydrauliques
    StructureRectangle
}

/**
 * noeud de calcul
 */
export abstract class ComputeNode extends JalhydObject implements IDebug {
    /**
     * Set of ParamDefinition, used as input of this node
     */
    protected _prms: ParamsEquation;

    /**
     * { symbol => ParamFamily } map for ExtraResults; defines a priori which
     * future extra result can be linked to other Nub's parameters
     */
    protected _extraResultsFamilies: any;

    protected _calcType: CalculatorType;

    private _debug: Debug;

    constructor(prms: ParamsEquation, dbg: boolean = false) {
        super();
        this._debug = new Debug(dbg);
        this._prms = prms;
        this.debug("PARAMS", prms);

        // important for Param uid
        this._prms.parent = this;

        if (!this._prms.calculabilityDefined) {
            this._prms.resetParametersCalculability();
        }
        this._prms.Pr.calculability = ParamCalculability.FREE; // so that it can be set through Pr.v
        this.setParametersCalculability();
        this._prms.DefineCalculability();
        this.setExtraResultsFamilies();
    }

    public get prms(): ParamsEquation {
        return this._prms;
    }

    /**
     * Retrieves a parameter from its symbol (unique in a given Nub)
     * @WARNING also retrieves **extra results** and returns them as ParamDefinition !
     */
    public getParameter(name: string): ParamDefinition {
        for (const p of this.parameterIterator) {
            if (p.symbol === name) {
                return p;
            }
        }
        return undefined;
    }

    public getFirstAnalyticalParameter(): ParamDefinition {
        for (const p of this.parameterIterator) {
            if (
                p.isAnalytical()
                && p.symbol !== "Pr"
            ) {
                return p;
            }
        }
        return undefined;
    }

    /**
     * Returns an iterator over own parameters (this._prms)
     */
    public get parameterIterator(): IParamDefinitionIterator {
        return this._prms.iterator;
    }

    // interface IDebug
    public debug(...args: any[]) {
        this._debug.debug(...args);
    }

    public get DBG(): boolean {
        return this._debug.DBG;
    }

    /**
     * Define ParamFamily (@see ParamDefinition) for extra results
     */
    protected setExtraResultsFamilies() {
        this._extraResultsFamilies = {};
    }

    public get extraResultsFamilies()  {
        return this._extraResultsFamilies;
    }

    protected abstract setParametersCalculability(): void;

}