Skip to content
Snippets Groups Projects
ngparam.ts 9.42 KiB
import { ParamDefinition, Pair, ParamDomain } from "jalhyd";

import { InputField } from "./input-field";
import { Dependency } from "./dependency/dependency";
import { DependencyConditionType } from "./dependency/dependency-condition";
import { ValueDependencyCondition } from "./dependency/value-dependency-condition";
import { Observable, IObservable, Observer } from "../services/observer";
import { FormulaireDefinition } from "./definition/form-definition";
import { ApplicationSetupService } from "../services/app-setup/app-setup.service";

export enum ParamRadioConfig {
    /**
     * pas de radio, paramètre modifiable à la main uniquement
     */
    FIX,

    /**
     * boutons radio "paramètre fixé" et "paramètre à varier"
     */
    VAR,

    /**
     * boutons radio "paramètre fixé", "paramètre à varier" et "paramètre à calculer"
     */
    CAL
};


/**
 * mode de génération des valeurs d'entrée lors d'un calcul avec plusieurs valeurs
 */
export enum ParamValueMode {
    /**
     * min, max, pas
     */
    MINMAX,

    /**
     * liste de valeurs discrètes
     */
    LISTE
}

/**
 * classe englobante de ParamDefinition (champs supplémentaires pour l'affichage, radio boutons, ...)
 */
export class NgParameter extends InputField { // implements IObservable {
    public unit: string;
    public radioConfig: ParamRadioConfig;
    public radioState: ParamRadioConfig;
    public isDefault: boolean = false; // archi bug du langage ! si on relit cette propriété sans l'avoir modifiée entre-temps, elle vaut undefined !

    /**
     * mode de génération des valeurs : min/max, liste, ...
     */
    private _valueMode: ParamValueMode = ParamValueMode.MINMAX;

    /**
     * valeur min dans le cas ParamRadioConfig.VAR && ParamValueMode.MINMAX
     */
    private _minValue: number = undefined;

    /**
     * valeur max dans le cas ParamRadioConfig.VAR && ParamValueMode.MINMAX
     */
    private _maxValue: number = undefined;

    /**
     * pas de progression dans le cas ParamRadioConfig.VAR && ParamValueMode.MINMAX
     */
    private _stepValue: number = undefined;

    /**
     * liste de valeurs dans le cas ParamRadioConfig.VAR && ParamValueMode.LISTE
     */
    private _valueList: number[];

    /**
     * implémentation par délégation de IObservable
     */
    private _observable: Observable;

    constructor(private _paramDef: ParamDefinition, isTmpl = false) {
        super(isTmpl);
        this._observable = new Observable();
    }

    get symbol(): string {
        return this._paramDef.symbol;
    }

    get domain(): ParamDomain {
        return this._paramDef.getDomain();
    }

    public getValue() {
        return this._paramDef.v;
    }

    public setValue(val: number) {
        this._paramDef.v = val;
        // this.notifyObservers(
        //     {
        //         "action": "value",
        //         "value": val
        //     }
        // )
    }

    get isDefined(): boolean {
        return this._paramDef.isDefined;
    }

    public checkValue(val: number) {
        this._paramDef.checkValue(val);
    }

    public checkList(l: number[]) {
        for (let e of l)
            this.checkValue(e);
    }

    public get valueMode() {
        return this._valueMode;
    }

    public set valueMode(m: ParamValueMode) {
        // undefined si on clique en dehors du select après l'avoir ouvert (cad sans avoir fait de sélection)
        // et au même niveau, cad à côté du bouton et non à côté du menu déroulant
        if (m != undefined)
            this._valueMode = m;
    }

    /**
     * vérifie si un min/max est valide par rapport au domaine de définition
     */
    private isMinMaxDomainValid(v: number): boolean {
        if (v == undefined)
            return false;
        if (this._valueMode == ParamValueMode.MINMAX)
            try {
                this.checkValue(v);
            }
            catch (e) {
                return false;
            }

        return true;
    }

    private checkMinMax(min: number, max: number): boolean {
        return this.isMinMaxDomainValid(min) && this.isMinMaxDomainValid(max) && (min < max);
    }

    public checkMin(min: number): boolean {
        return this.isMinMaxDomainValid(min) && (min < this._maxValue);
    }

    public checkMax(max: number): boolean {
        return this.isMinMaxDomainValid(max) && (this._minValue < max);
    }

    public get isMinMaxValid(): boolean {
        return this.checkMinMax(this._minValue, this._maxValue);
    }

    public get minValue() {
        return this._minValue;
    }

    public set minValue(v: number) {
        this._minValue = v;
    }

    public get maxValue() {
        return this._maxValue;
    }

    public set maxValue(v: number) {
        this._maxValue = v;
    }

    public checkStep(step: number): boolean {
        return this.isMinMaxValid && this.stepRefValue.intervalHasValue(step);
    }

    public get stepRefValue(): Pair {
        return new Pair(1e-9, this._maxValue - this._minValue);
    }

    public get stepValue() {
        return this._stepValue;
    }

    public set stepValue(v: number) {
        this._stepValue = v;
    }

    public get valueList() {
        return this._valueList;
    }

    public set valueList(l: number[]) {
        this._valueList = l;
    }

    private get isListValid(): boolean {
        if (this._valueList == undefined)
            return false;

        for (let v of this._valueList)
            try {
                this.checkValue(v);
            }
            catch (e) {
                return false;
            }
        return true;
    }

    private get isRangeValid(): boolean {
        switch (this._valueMode) {
            case ParamValueMode.LISTE:
                return this.isListValid;

            case ParamValueMode.MINMAX:
                return this.checkStep(this._stepValue);
        }

        throw "NgParameter.isRangeValid() : valeur " + this._valueMode + " de ParamValueMode non prise en compte";
    }

    private get isValueValid(): boolean {
        try {
            const v = this._paramDef.getValue();
            this._paramDef.checkValue(v);
            return true;
        }
        catch (e) {
            return false;
        }
    }

    public get isValid() {
        switch (this.radioState) {
            case ParamRadioConfig.FIX:
                return this.isValueValid;

            case ParamRadioConfig.VAR:
                return this.isRangeValid;

            case ParamRadioConfig.CAL:
                return true;
        }

        throw "NgParameter.isValid() : valeur de ParamRadioConfig non prise en compte";
    }

    private static getRadioConfig(s: string) {
        if (s == "fix")
            return ParamRadioConfig.FIX;

        if (s == "var")
            return ParamRadioConfig.VAR;

        if (s == "cal")
            return ParamRadioConfig.CAL;

        throw "invalid parameter radio configuration " + s;
    }

    public parseConfig(json: {}, data?: {}) {
        const appSetupService: ApplicationSetupService = data["appSetupService"];
        const radioConfig: string = data["radioConfig"];

        this._confId = json["id"];
        this.unit = json["unit"];
        if (this.symbol == "Pr")
            var val = appSetupService.computePrecision;
        else
            val = json["value"];
        if (val != undefined)
            this.setValue(+val);
        this.radioConfig = NgParameter.getRadioConfig(radioConfig);
        this.radioState = ParamRadioConfig.FIX;
        this.isDefault = false; // malgré le fait qu'il soit initialisé dans la déclaration de la classe NgParam à false, quand on relit sa valeur, il vaut undefined (merci Microsoft)
    }

    protected verifyDependency(d: Dependency): boolean {
        switch (d.masterCondition.type) {
            case DependencyConditionType.HasValue:
                {
                    let mc: ValueDependencyCondition = <ValueDependencyCondition>d.masterCondition;
                    return this.getValue() === mc.value;
                }

            case DependencyConditionType.IsVariable:
                return this.radioState == ParamRadioConfig.VAR;

            default:
                throw "NgParameter.verifyDependency() : type de condition '" + DependencyConditionType[d.masterCondition.type] + "' non pris en charge";
        }
    }

    /**
     * copie des membres
     */
    protected copyMembers(n: NgParameter) {
        super.copyMembers(n);
        n.unit = this.unit;
        n.radioConfig = this.radioConfig;
        n.radioState = this.radioState;
        n.isDefault = this.isDefault;
        n._valueMode = this.valueMode;
        n._minValue = this._minValue;
        n._maxValue = this._maxValue;
        n._stepValue = this._stepValue;
        if (this._valueList != undefined)
            n._valueList = this._valueList.slice(0); // copie
    }

    /**
     * crée une nouvelle instance
     */
    protected clone(): NgParameter {
        return new NgParameter(this._paramDef.clone());
    }

    // // interface IObservable

    // /**
    //  * ajoute un observateur à la liste
    //  */
    // public addObserver(o: Observer) {
    //     this._observable.addObserver(o);
    // }

    // /**
    //  * supprime un observateur de la liste
    //  */
    // public removeObserver(o: Observer) {
    //     this._observable.removeObserver(o);
    // }

    // /**
    //  * notifie un événement aux observateurs
    //  */
    // public notifyObservers(data: any) {
    //     this._observable.notifyObservers(data, this);
    // }
}