From 5d99177ce52a48e471c394b3adf8a2d0beb89c2d Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Wed, 14 Mar 2018 16:43:52 +0100
Subject: [PATCH] =?UTF-8?q?=20#27=20:=20NgParameter=20:=20ajout=20de=20la?=
 =?UTF-8?q?=20notion=20de=20contexte=20pour=20la=20valeur=20du=20param?=
 =?UTF-8?q?=C3=A8tre=20-=20calculettes=20ouvrages=20//=20:=20affichage=20d?=
 =?UTF-8?q?es=20valeurs=20par=20d=C3=A9faut=20issues=20de=20la=20factory?=
 =?UTF-8?q?=20JalHyd=20-=20NgParamInputComponent=20:=20modif=20de=20la=20c?=
 =?UTF-8?q?orrection=20du=20bug=20emp=C3=AAchant=20de=20saisir=20un=20'.'?=
 =?UTF-8?q?=20(en=20utilisant=20l'exp=C3=A9diteur=20('sender')=20des=20not?=
 =?UTF-8?q?ifications=20(cf=20IObservable))?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../calculator.component.ts                   |  15 +-
 .../generic-input/generic-input.component.ts  |  12 +-
 .../ngparam-input/ngparam-input.component.ts  |  34 +++--
 .../concrete/form-parallel-structures.ts      | 114 ++++++++++-----
 .../form-compute-parallel-structures.ts       |  36 ++---
 .../form-def-parallel-structures.ts           |  66 +++++++++
 .../formulaire/definition/form-def-section.ts |   2 +-
 src/app/formulaire/field.ts                   |   2 +-
 src/app/formulaire/formulaire-element.ts      |   4 +-
 src/app/formulaire/input-field.ts             |   2 +-
 src/app/formulaire/ngparam.ts                 | 131 ++++++++++++++++--
 src/app/services/observer.ts                  |   2 +-
 12 files changed, 326 insertions(+), 94 deletions(-)
 create mode 100644 src/app/formulaire/definition/form-def-parallel-structures.ts

diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 752e911dd..4121ce7bc 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -194,10 +194,13 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
     /**
      * met à jour l'interface
      */
-    //    private updateUI() {
-    // this.appRef.tick();
-    // this.changeDetectorRef.detectChanges();  // provoque une détection des changements dans les contrôles
-    //}
+    // private updateUI() {
+    //     // this.appRef.tick();
+    //     // this.changeDetectorRef.detectChanges();  // provoque une détection des changements dans les contrôles
+    //     // if (!this.changeDetectorRef['destroyed']) // pour éviter l'erreur "Attempt to use a destroyed view: detectChanges"
+    //     //     this.changeDetectorRef.detectChanges();
+    //     this.changeDetectorRef.markForCheck();
+    // }
 
     private doCompute() {
         this._formulaire.doCompute();
@@ -248,6 +251,10 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
         }
         else if (sender instanceof FormulaireDefinition) {
             switch (data["action"]) {
+                // case "reset": // réinitialisation du formulaire
+                //     this.updateUI();
+                //     break;
+
                 case "resultsUpdated":
                     const f = sender as FormulaireDefinition;
                     if (this._formulaire.uid == f.uid)
diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts
index 578ab729d..ed55114a0 100644
--- a/src/app/components/generic-input/generic-input.component.ts
+++ b/src/app/components/generic-input/generic-input.component.ts
@@ -99,7 +99,9 @@ export abstract class GenericInputComponent extends BaseComponent {
      */
     protected detectChanges() {
         if (this.cdRef != undefined)
-            this.cdRef.detectChanges();
+            // if (!this.cdRef['destroyed']) // pour éviter l'erreur "Attempt to use a destroyed view: detectChanges"
+            //     this.cdRef.detectChanges();
+            this.cdRef.markForCheck();
     }
 
     /**
@@ -164,8 +166,8 @@ export abstract class GenericInputComponent extends BaseComponent {
         this.onChange.emit({ "action": "model", "value": this.getModelValue() });
     }
 
-    private setAndValidateModel(v: any) {
-        this.setModelValue(v);
+    private setAndValidateModel(sender: any, v: any) {
+        this.setModelValue(sender, v);
         this.emitModelChanged();
 
         this.validateModel();
@@ -198,7 +200,7 @@ export abstract class GenericInputComponent extends BaseComponent {
     private set uiValue(ui: any) {
         this._uiValue = ui;
         if (this.validateUI())
-            this.setAndValidateModel(this.uiToModel(ui));
+            this.setAndValidateModel(this, this.uiToModel(ui));
     }
 
     private updateAll() {
@@ -231,7 +233,7 @@ export abstract class GenericInputComponent extends BaseComponent {
     /**
      * affecte la valeur du modèle
      */
-    protected abstract setModelValue(v: any);
+    protected abstract setModelValue(sender: any, v: any);
 
     /**
      * valide une valeur de modèle : est ce une valeur acceptable ? (par ex, nombre dans un intervalle, valeur dans une liste, ...)
diff --git a/src/app/components/ngparam-input/ngparam-input.component.ts b/src/app/components/ngparam-input/ngparam-input.component.ts
index b7c3bcbf0..10e33c675 100644
--- a/src/app/components/ngparam-input/ngparam-input.component.ts
+++ b/src/app/components/ngparam-input/ngparam-input.component.ts
@@ -8,12 +8,13 @@ import { NumericalString, Message } from "jalhyd";
 import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
 import { NgParameter } from "../../formulaire/ngparam";
 import { GenericInputComponent } from "../generic-input/generic-input.component";
+import { Observer } from "../../services/observer";
 
 @Component({
     selector: "ngparam-input",
     templateUrl: "../generic-input/generic-input.component.html"
 })
-export class NgParamInputComponent extends GenericInputComponent { // implements Observer {
+export class NgParamInputComponent extends GenericInputComponent implements Observer {
     /**
      * paramètre géré
      */
@@ -34,10 +35,10 @@ export class NgParamInputComponent extends GenericInputComponent { // implements
     /**
      * appelé avant le changement de modèle
      */
-    // protected beforeSetModel() {
-    //     if (this._paramDef != undefined)
-    //         this._paramDef.removeObserver(this);
-    // }
+    protected beforeSetModel() {
+        if (this._paramDef != undefined)
+            this._paramDef.removeObserver(this);
+    }
 
     /**
      * appelé après le changement de modèle
@@ -46,7 +47,7 @@ export class NgParamInputComponent extends GenericInputComponent { // implements
         if (this._paramDef != undefined) {
             if (this._paramDef.isDefined)
                 this._tmp = this._paramDef.getValue();
-            // this._paramDef.addObserver(this);
+            this._paramDef.addObserver(this);
         }
     }
 
@@ -54,10 +55,10 @@ export class NgParamInputComponent extends GenericInputComponent { // implements
         return this._tmp;
     }
 
-    protected setModelValue(v: any) {
+    protected setModelValue(sender: any, v: any) {
         this._tmp = v;
         try {
-            this._paramDef.setValue(v);
+            this._paramDef.setValue(sender, v);
         }
         catch (e) {
             // géré par validateModelValue()
@@ -106,10 +107,15 @@ export class NgParamInputComponent extends GenericInputComponent { // implements
         return +ui;
     }
 
-    // public update(sender: IObservable, data: any): void {
-    //     if (data["action"] == "value") {
-    //         this._tmp = data["value"];
-    //         this.updateAndValidateUI();
-    //     }
-    // }
+    public update(sender: any, data: any): void {
+        switch (data["action"]) {
+            case "ngparamAfterValue":
+                // on ne fait rien au cas où la modif vient de l'interface (on ne remet pas à jour _uiValue ce qui permet
+                // de garder par ex le '.' si on supprime le '2' de '1.2')
+                if (sender !== this) {
+                    this._tmp = data["value"];
+                    this.updateAndValidateUI();
+                }
+        }
+    }
 }
diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
index c195885cd..af41d8efb 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
@@ -1,19 +1,23 @@
 import { FormulaireDefinition } from "../form-definition";
 import { CalculatorResults } from "../../../results/calculator-results";
-import { CalculatorType } from "jalhyd";
+import { CalculatorType, CreateStructure, StructureType, LoiDebit } from "jalhyd";
 import { ParamService } from "../../../services/param/param.service";
 import { ApplicationSetupService } from "../../../services/app-setup/app-setup.service";
 import { FormDefParamToCalculate } from "../form-def-paramcalc";
 import { FormDefFixedVar } from "../form-def-fixedvar";
+import { FormDefParallelStructures } from "../form-def-parallel-structures";
 import { FormComputeParallelStructures } from "../form-compute-parallel-structures";
 import { FormResultFixedVar } from "../form-result-fixedvar";
 import { FieldsetContainer } from "../../fieldset-container";
 import { FieldSet } from "../../fieldset";
 import { SelectField } from "../../select-field";
+import { NgParameter } from "../../ngparam";
 
 export class FormulaireParallelStructure extends FormulaireDefinition {
     private _formFixedVar: FormDefFixedVar;
 
+    private _formParallelStruct: FormDefParallelStructures;
+
     private _formParamCalc: FormDefParamToCalculate;
 
     private _formCompute: FormComputeParallelStructures;
@@ -25,7 +29,8 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         this._formFixedVar = new FormDefFixedVar(this);
         this._formParamCalc = new FormDefParamToCalculate(this);
         this._formResult = new FormResultFixedVar(this, false);
-        this._formCompute = new FormComputeParallelStructures(this, this._formResult);
+        this._formParallelStruct = new FormDefParallelStructures();
+        this._formCompute = new FormComputeParallelStructures(this, this._formParallelStruct, this._formResult);
     }
 
     protected initParse() {
@@ -37,36 +42,6 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
     }
 
     protected completeParse() {
-        // récupération des valeurs par défaut pour les affecter au template
-
-        // for (const n of this.allFormElements)
-        //     if (n instanceof FieldsetContainer) {
-        //         var fsc: FieldsetContainer = n;
-        //         break;
-        //     }
-
-        // if (fsc == undefined)
-        //     console.log("warning : pas de valeurs par défaut trouvées pour les ouvrages en parallèle")
-        // else {
-        //     const st = CreateStructure(StructureType.Cem88d);
-        //     for (const i in st.prms.map) {
-        //         const param = st.prms.map[i];
-
-        //         let found = false;
-        //         for (const tmpl of fsc.templates) {
-        //             for (const n of tmpl.allFormElements)
-        //                 if (n.id === param.symbol) {
-        //                     // if (n.id === param.symbol) {
-        //                     const ng = n as NgParameter;
-        //                     ng.setValue(param.v);
-        //                     found = true;
-        //                     break;
-        //                 }
-        //             if (found) break;
-        //         }
-        //     }
-        // }
-
         this.subscribeFieldsetContainer();
     }
 
@@ -77,6 +52,55 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         this._formParamCalc.onRadioClick(info);
     }
 
+    /**
+     * @return une chaîne représentant le "contexte" courant (ici, combinaison type d'ouvrage-loi de débit)
+     * @param fs FieldSet contenant les listes déroulantes type d'ouvrage et loi de débit
+     */
+    private getContext(fs: FieldSet): string {
+        // type d'ouvrage courant
+        const fsStructType = this._formParallelStruct.getStructureType(fs);
+
+        // loi de débit courante
+        const loiDebit = this._formParallelStruct.getLoiDebit(fs);
+
+        return `${StructureType[fsStructType]}-${LoiDebit[loiDebit]}`
+    }
+
+    /**
+     * réinitialisation du formulaire.
+     * en plus de du comportement par défaut, on remet les valeurs des champs en fonction du contexte
+     * (type de structure, loi de débit)
+     */
+    public reset() {
+        super.reset();
+
+        for (const e of this.allFormElements) {
+            if (e instanceof FieldSet) {
+                const fs = e as FieldSet;
+                if (!fs.isTemplate && fs.calculatorType === CalculatorType.Structure) {
+                    const fsStructType: StructureType = this._formParallelStruct.getStructureType(fs);
+                    const loiDebit: LoiDebit = this._formParallelStruct.getLoiDebit(fs);
+                    const st = CreateStructure(fsStructType, loiDebit);
+
+                    for (const p of fs.allFormElements)
+                        if (p instanceof NgParameter) {
+                            const defaultParam = st.prms.map[p.symbol];
+                            p.resetValue(this, this.getContext(fs), defaultParam.v);
+                        }
+                }
+            }
+        }
+
+        // prévenir les composants qu'il faut détecter les changements
+        // this.notifyReset();
+    }
+
+    // private notifyReset() {
+    //     this.notifyObservers({
+    //         "action": "reset"
+    //     }, this);
+    // }
+
     public resetResults() {
         this._formResult.resetResults();
     }
@@ -104,6 +128,14 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         fsc.addObserver(this);
     }
 
+    /**
+     * abonnement en tant qu'observateur des NgParameter des FieldSet contenus dans le FieldsetContainer
+     */
+    private subscribeStructureInputFields(fs: FieldSet) {
+        for (const n of fs.allFormElements)
+            if (n instanceof NgParameter)
+                n.addObserver(this);
+    }
     /**
      * abonnement en tant qu'observateur du SelectField des FieldSet contenus dans le FieldsetContainer
      */
@@ -113,16 +145,32 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
                 n.addObserver(this);
     }
 
+    // interface Observer
+
     public update(sender: any, data: any) {
         if (sender instanceof FieldsetContainer)
-            switch (data["action"]) {
+            switch (data.action) {
                 case "newFieldset":
                     this.reset();
+                    this.subscribeStructureInputFields(data["fieldset"]);
                     this.subscribeStructureSelectFields(data["fieldset"]);
             }
         else if (sender instanceof SelectField) {
             // la valeur d'un des select (type d'ouvrage, loi de débit) a changé
             this.reset();
         }
+        // else if (sender instanceof NgParameter) {
+        else {
+            switch (data.action) {
+                case "ngparamBeforeValue":  // la valeur d'un NgParameter est sur le point d'être modifiée
+                    const param: NgParameter = data.param;
+
+                    // FieldSet parent    
+                    const parentFieldset = param.getDirectParent(this) as FieldSet;
+
+                    // contexte dans lequel la valeur du paramètre est fixée manuellement
+                    param.currentContextId = this.getContext(parentFieldset);
+            }
+        }
     }
 }
diff --git a/src/app/formulaire/definition/form-compute-parallel-structures.ts b/src/app/formulaire/definition/form-compute-parallel-structures.ts
index 02cd70390..572bc88a1 100644
--- a/src/app/formulaire/definition/form-compute-parallel-structures.ts
+++ b/src/app/formulaire/definition/form-compute-parallel-structures.ts
@@ -1,4 +1,7 @@
-import { ComputeNode, ParamsEquation, ParallelStructure, ParallelStructureParams, CalculatorType, StructureParams, Structure, CreateStructure, StructureType, ComputeNodeType } from "jalhyd";
+import {
+    ComputeNode, ParamsEquation, ParallelStructure, ParallelStructureParams, CalculatorType, StructureParams,
+    Structure, CreateStructure, StructureType, ComputeNodeType, LoiDebit
+} from "jalhyd";
 
 import { FormComputeFixedVar } from "./form-compute-fixedvar";
 import { FormResultFixedVar } from "./form-result-fixedvar";
@@ -9,22 +12,14 @@ import { NgParameter } from "../ngparam";
 import { FormulaireNode } from "../formulaire-node";
 import { FieldSet } from "../fieldset";
 import { FieldsetContainer } from "../fieldset-container";
+import { FormDefParallelStructures } from "./form-def-parallel-structures";
 
 export class FormComputeParallelStructures extends FormComputeFixedVar {
-    constructor(formBase: FormulaireDefinition, formResult: FormResultFixedVar) {
-        super(formBase, formResult);
-    }
+    private _formParallelStruct: FormDefParallelStructures;
 
-    /**
-     * dictionnaire des StructureType indexés par les valeurs de liste déroulante (loi de débit)
-     */
-    private static tsMap = {
-        "cem88d": StructureType.Cem88d,
-        "cem88v": StructureType.Cem88d,
-        "cunge80": StructureType.Cunge80,
-        "seuildenoye": StructureType.WeirFree,
-        "vannenoye": StructureType.OrificeSubmerged,
-        "vannedenoye": StructureType.OrificeFree
+    constructor(formBase: FormulaireDefinition, formParallelStruct: FormDefParallelStructures, formResult: FormResultFixedVar) {
+        super(formBase, formResult);
+        this._formParallelStruct = formParallelStruct;
     }
 
     /**
@@ -82,15 +77,8 @@ export class FormComputeParallelStructures extends FormComputeFixedVar {
 
         for (const fs of this._formBase.allFieldsets)
             if (fs.calculatorType == CalculatorType.Structure) {
-                let loiDebit: string = fs.getSelectedValue("select_loidebit1");
-                if (loiDebit == undefined)
-                    loiDebit = fs.getSelectedValue("select_loidebit2");
-                if (loiDebit == undefined)
-                    throw new Error(`FormComputeParallelStructures.getNubAndParameters() : aucune loi de débit trouvée`);
-
-                const ts: StructureType = FormComputeParallelStructures.tsMap[loiDebit];
-                if (ts == undefined)
-                    throw new Error(`FormComputeParallelStructures.getNubAndParameters() :loi de débit ${loiDebit} non prise en charge`);
+                const ts: StructureType = this._formParallelStruct.getStructureType(fs);
+                const ld: LoiDebit = this._formParallelStruct.getLoiDebit(fs);
 
                 // cote de radier
                 const ZDV = fs.getNodeParameterValue("ZDV");
@@ -102,7 +90,7 @@ export class FormComputeParallelStructures extends FormComputeFixedVar {
                 }
 
                 // création de l'ouvrage
-                const ouvr = CreateStructure(ts);
+                const ouvr = CreateStructure(ts, ld);
 
                 // affectation des valeurs (en prenant garde de ne pas écraser les valeurs par défaut dans le cas d'un paramètre à calculer)
                 if (Z1 != undefined)
diff --git a/src/app/formulaire/definition/form-def-parallel-structures.ts b/src/app/formulaire/definition/form-def-parallel-structures.ts
new file mode 100644
index 000000000..75a5aa89c
--- /dev/null
+++ b/src/app/formulaire/definition/form-def-parallel-structures.ts
@@ -0,0 +1,66 @@
+import { CalculatorType, StructureType, LoiDebit } from "jalhyd";
+
+import { FieldSet } from "../fieldset";
+
+/**
+ * gestion des formulaires "ouvrages parallèles"
+ */
+export class FormDefParallelStructures {
+    /**
+     * dictionnaire des types d'ouvrages indexés par les valeurs de liste déroulante
+     * la clé est la chaîne utilisée dans le fichier de configuration de la calculette pour les valeurs de la liste déroulante
+     */
+    private static tsMap = {
+        "vanne_rect": StructureType.VanneRectangulaire,
+        "seuil_rect": StructureType.SeuilRectangulaire
+    }
+
+    /**
+     * dictionnaire des LoiDebit indexés par les valeurs de liste déroulante
+     * la clé est la chaîne utilisée dans le fichier de configuration de la calculette pour les valeurs de la liste déroulante
+     */
+    private static ldMap = {
+        "cem88d": LoiDebit.Cem88d,
+        "cem88v": LoiDebit.Cem88d,
+        "cunge80": LoiDebit.Cunge80,
+        "seuildenoye": LoiDebit.WeirFree,
+        "vannenoye": LoiDebit.OrificeSubmerged,
+        "vannedenoye": LoiDebit.OrificeFree
+    }
+
+    /**
+     * @return type d'ouvrage courant du FieldSet donné
+     */
+    public getStructureType(fs: FieldSet): StructureType {
+        if (fs.calculatorType !== CalculatorType.Structure)
+            throw new Error(`FormDefParallelStructures.getStructureType() : le FieldSet n'est pas du type Structure`);
+
+        let structType: string = fs.getSelectedValue("select_ouvrage");
+        if (structType == undefined)
+            throw new Error(`FormDefParallelStructures.getStructureType() : aucun ouvrage trouvé dans le FieldSet`);
+
+        const res = FormDefParallelStructures.tsMap[structType];
+        if (res == undefined)
+            throw new Error(`FormDefParallelStructures.getStructureType() : type d'ouvrage ${StructureType[structType]} non pris en charge`);
+        return res;
+    }
+
+    /**
+     * @return type d'ouvrage courant du FieldSet donné
+     */
+    public getLoiDebit(fs: FieldSet): LoiDebit {
+        if (fs.calculatorType !== CalculatorType.Structure)
+            throw new Error(`FormDefParallelStructures.getLoiDebit() : le FieldSet n'est pas du type Structure`);
+
+        let loiDebit: string = fs.getSelectedValue("select_loidebit1");
+        if (loiDebit == undefined)
+            loiDebit = fs.getSelectedValue("select_loidebit2");
+        if (loiDebit == undefined)
+            throw new Error(`FormDefParallelStructures.getStructureType() : aucune loi de débit trouvée dans le FieldSet`);
+
+        const res = FormDefParallelStructures.ldMap[loiDebit];
+        if (res == undefined)
+            throw new Error(`FormDefParallelStructures.getStructureType() : loi de débit ${LoiDebit[loiDebit]} non prise en charge`);
+        return res;
+    }
+}
diff --git a/src/app/formulaire/definition/form-def-section.ts b/src/app/formulaire/definition/form-def-section.ts
index 556e58edd..9a3a49503 100644
--- a/src/app/formulaire/definition/form-def-section.ts
+++ b/src/app/formulaire/definition/form-def-section.ts
@@ -156,7 +156,7 @@ export class FormDefSection implements Observer {
 
     // interface Observer 
 
-    update(sender: IObservable, data: any): void {
+    update(sender: any, data: any): void {
         if (sender instanceof SelectField) {
             this.updateSectionNodeType();
         }
diff --git a/src/app/formulaire/field.ts b/src/app/formulaire/field.ts
index 9ebb45e53..34411775b 100644
--- a/src/app/formulaire/field.ts
+++ b/src/app/formulaire/field.ts
@@ -10,7 +10,7 @@ export abstract class Field extends FormulaireElement {
     public abstract get isValid();
 
     public abstract getValue(): any;
-    public abstract setValue(val: any): void;
+    public abstract setValue(sender: any, val: any): void;
 
     private parse_value_dependencies(json: {}, parentForm: FormulaireDefinition) {
         for (let di in json) {
diff --git a/src/app/formulaire/formulaire-element.ts b/src/app/formulaire/formulaire-element.ts
index c86c2e306..318eb5b67 100644
--- a/src/app/formulaire/formulaire-element.ts
+++ b/src/app/formulaire/formulaire-element.ts
@@ -142,9 +142,9 @@ export abstract class FormulaireElement extends FormulaireNode {
                 if (master.verifiesDependency(d)) {
                     let slave = parentForm.getFieldById(this.id);
                     if (this.isNumber(vd.slaveValue))
-                        slave.setValue(+vd.slaveValue);
+                        slave.setValue(this, +vd.slaveValue);
                     else
-                        slave.setValue(vd.slaveValue);
+                        slave.setValue(this, vd.slaveValue);
                 }
             }
         }
diff --git a/src/app/formulaire/input-field.ts b/src/app/formulaire/input-field.ts
index f569de08c..fa0110d52 100644
--- a/src/app/formulaire/input-field.ts
+++ b/src/app/formulaire/input-field.ts
@@ -13,7 +13,7 @@ export abstract class InputField extends Field {
         return this._value;
     }
 
-    public setValue(val: any) {
+    public setValue(sender: any, val: any) {
         this._value = val;
     }
 }
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 6cd0bd3a1..f495294f0 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -40,6 +40,14 @@ export enum ParamValueMode {
     LISTE
 }
 
+/**
+ * infos sur le contexte, les valeurs par défaut et saisie manuellement
+ */
+class Context {
+    public default: number;
+    public current: number;
+}
+
 /**
  * classe englobante de ParamDefinition (champs supplémentaires pour l'affichage, radio boutons, ...)
  */
@@ -47,6 +55,10 @@ export class NgParameter extends InputField {
     public unit: string;
     public radioConfig: ParamRadioConfig;
     public radioState: ParamRadioConfig;
+
+    /**
+     * true si ce paramètre est celui par défaut dans un formulaire (cf. fichier de conf des calculettes, objet "options", champ "idCal")
+     */
     public isDefault: boolean = false; // archi bug du langage ! si on relit cette propriété sans l'avoir modifiée entre-temps, elle vaut undefined !
 
     /**
@@ -74,6 +86,18 @@ export class NgParameter extends InputField {
      */
     private _valueList: number[];
 
+    /**
+     * dictionnaire indiquant la valeur du paramètre dans différents contextes
+     * clé : contexte représenté par une chaîne
+     * valeur : instance de Context
+     */
+    private _contexts: { [key: string]: Context } = {};
+
+    /**
+     * id du contexte courant
+     */
+    public currentContextId: string;
+
     constructor(private _paramDef: ParamDefinition, isTmpl = false) {
         super(isTmpl);
     }
@@ -90,14 +114,105 @@ export class NgParameter extends InputField {
         return this._paramDef.v;
     }
 
-    public setValue(val: number) {
+    /**
+     * notification envoyée après la modification de la valeur du paramètre
+     */
+    private notifyValueModified(sender: any) {
+        this.notifyObservers(
+            {
+                "action": "ngparamAfterValue",
+                "param": this,
+                "value": this._paramDef.v
+            }, sender
+        );
+    }
+
+    /**
+     * @return true si la valeur du paramètre a été modifiée manuellement dans un contexte donné
+     * @param contextId id du contexte
+     */
+    private isOverriden(contextId: string) {
+        const cnt = this._contexts[contextId];
+        if (cnt == undefined)
+            return false;
+        return cnt.current != undefined;
+    }
+
+    /**
+     * fixe la valeur du paramètre dans un contexte donné
+     * @param contextId id du contexte (par ex dans les ouvrages //, valeur de StructureType+LoiDebit)
+     * @param defaultValue valeur par défaut si la valeur du paramètre n'a pas été modifiée par setValue() depuis la création de l'objet
+     */
+    public resetValue(sender: any, contextId: string, defaultValue: number) {
+        if (!this.isOverriden(contextId)) {
+            this._paramDef.v = defaultValue;
+            this.setContextValue(contextId, defaultValue, false);
+        }
+        else
+            this._paramDef.v = this.getContextValue(contextId);
+        this.notifyValueModified(sender);
+    }
+
+    /**
+     * @return la valeur du paramètre dans un contexte donné
+     * @param contextId id du contexte
+     */
+    private getContextValue(contextId: string): number {
+        if (contextId == undefined)
+            return this._paramDef.v;
+
+        const cnt = this._contexts[contextId];
+        if (cnt == undefined)
+            return this._paramDef.v;
+
+        if (cnt.current != undefined)
+            return cnt.current;
+
+        return cnt.default;
+    }
+
+    /**
+     * fixe la valeur du paramètre dans un contexte donné
+     * @param contextId id du contexte
+     * @param val valeur du paramètre
+     * @param currentOrDefault true si on fixe la valeur modifiée à la main, false si valeur par défaut
+     */
+    private setContextValue(contextId: string, val: number, currentOrDefault: boolean) {
+        if (contextId != undefined) {
+            var cnt = this._contexts[contextId];
+
+            if (cnt == undefined)
+                cnt = new Context();
+
+            if (currentOrDefault)
+                cnt.current = val;
+            else
+                cnt.default = val;
+
+            this._contexts[contextId] = cnt;
+        }
+    }
+
+    /**
+     * fixe la valeur du paramètre.
+     * une notification préalable est envoyée pour laisser l'occasion aux objets liés de préciser le contexte
+     * dans lequel cette valeur existe
+     * @param sender 
+     * @param val 
+     */
+    public setValue(sender: any, val: number) {
+        // on laisse l'occasion de préciser le contexte
+        this.notifyObservers(
+            {
+                "action": "ngparamBeforeValue",
+                "param": this,
+                "value": val
+            }, sender
+        )
+
         this._paramDef.v = val;
-        // this.notifyObservers(
-        //     {
-        //         "action": "value",
-        //         "value": val
-        //     }
-        // )
+        this.setContextValue(this.currentContextId, val, true);
+        this.notifyValueModified(sender);
     }
 
     get isDefined(): boolean {
@@ -274,7 +389,7 @@ export class NgParameter extends InputField {
         else
             val = json["value"];
         if (val != undefined)
-            this.setValue(+val);
+            this.setValue(this, +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)
diff --git a/src/app/services/observer.ts b/src/app/services/observer.ts
index e33135c05..6a1e85b46 100644
--- a/src/app/services/observer.ts
+++ b/src/app/services/observer.ts
@@ -1,5 +1,5 @@
 export interface Observer {
-    update(sender: IObservable, data: any): void;
+    update(sender: any, data: any): void;
 }
 
 export interface IObservable {
-- 
GitLab