From 1c34dd8db4d70c91ad1a73372a0a96689e2601bb Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 26 Feb 2019 12:28:16 +0100
Subject: [PATCH] =?UTF-8?q?Impl=C3=A9mentation=20de=20la=20d=C3=A9s=C3=A9r?=
 =?UTF-8?q?ialisation=20des=20Structures=20en=20parall=C3=A8le?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/nub.ts                          |  56 ++++++++++-
 src/session.ts                      | 144 ++++++++++------------------
 src/structure/parallel_structure.ts |  32 ++++++-
 src/structure/structure.ts          |   2 +-
 4 files changed, 131 insertions(+), 103 deletions(-)

diff --git a/src/nub.ts b/src/nub.ts
index 9d4846ab..d941aa75 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -1,4 +1,4 @@
-import { ParamDefinition } from ".";
+import { ParamDefinition, Session } from ".";
 import { ComputeNode } from "./compute-node";
 import { Dichotomie } from "./dichotomie";
 import { INamedIterableValues, INumberIterator, IterableValues } from "./param/param-value-iterator";
@@ -334,6 +334,60 @@ export abstract class Nub extends ComputeNode implements IReferencedNub {
         return ret;
     }
 
+    /**
+     * Fills the current Nub with parameter values, provided an object representation
+     * @param obj object representation of a Nub content (parameters)
+     */
+    public loadObjectRepresentation(obj: any) {
+        // set parameter modes and values
+        if (obj.parameters && Array.isArray(obj.parameters)) {
+            for (const p of obj.parameters) {
+                const param = this.getParameter(p.symbol);
+                if (! param) {
+                    throw new Error(`session file : cannot find parameter ${p.symbol} in target Nub`);
+                }
+                // set mode
+                const mode: ParamValueMode = (ParamValueMode as any)[p.mode]; // get enum index for string value @WTF
+                param.valueMode = mode;
+                // set value(s)
+                switch (mode) {
+                    case ParamValueMode.SINGLE:
+                        param.setValue(p.value);
+                        break;
+
+                    case ParamValueMode.MINMAX:
+                        param.paramValues.min = p.min;
+                        param.paramValues.max = p.max;
+                        param.paramValues.step = p.step;
+                        break;
+
+                    case ParamValueMode.LISTE:
+                        param.paramValues.valueList = p.values;
+                        break;
+
+                    case ParamValueMode.CALCUL:
+                        // nothing to do
+                        break;
+
+                    case ParamValueMode.LINK:
+                        // formulaire dont le Nub est la cible du lien
+                        const destNub = Session.getInstance().findNubByUid(p.targetNub);
+                        if (destNub) {
+                            param.defineReference(destNub, p.targetParam);
+                        } else {
+                            // @TODO et si la cible du lien n'existe pas ??
+                            // cf FormulaireService.updateParamsLinks()
+                            console.log("LA CIBLE DU LIEN N'EXISTE PAS !!");
+                        }
+                        break;
+
+                    default:
+                        throw new Error(`session file : invalid value mode '${p.mode}' in param object`);
+                }
+            }
+        }
+    }
+
     /**
      * Returns inner properties dataset associated to this Nub
      */
diff --git a/src/session.ts b/src/session.ts
index b695b580..a4b581d4 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -52,10 +52,9 @@ export class Session {
     /**
      * crée un Nub et l'ajoute à la session
      * @param props propriétés du Nub (computeType, nodeType...)
-     * @param parentNub Nub parent, lorsqu'on crée une Structure, pour vérifier les lois admissibles
      */
-    public createSessionNub(p: Props, parentNub?: ParallelStructure, dbg: boolean = false): Nub {
-        const res = this.createNub(p, parentNub, dbg);
+    public createSessionNub(p: Props, dbg: boolean = false): Nub {
+        const res = this.createNub(p, undefined, dbg);
         this._nubs.push(res);
         return res;
     }
@@ -65,14 +64,13 @@ export class Session {
      * les Nub de types parallèle)
      * @param sn Nub à remplacer
      * @param params propriété du nouveau Nub
-     * @param parentNub Nub parent, lorsqu'on crée une Structure, pour vérifier les lois admissibles
      */
-    public replaceNub(sn: Nub, params: Props, parentNub?: ParallelStructure): Nub {
+    public replaceNub(sn: Nub, params: Props): Nub {
         let i = 0;
         const olduid: string = sn.uid;
         for (const n of this._nubs) {
             if (n.uid === olduid) {
-                const newNub = this.createNub(params, parentNub);
+                const newNub = this.createNub(params);
                 newNub.setUid(olduid); // should never lead to any collision
                 this._nubs[i] = newNub;
                 // move structure inside parent
@@ -97,6 +95,8 @@ export class Session {
      * @param sn the Nub to remove
      */
     public deleteNub(sn: Nub) {
+        // @TODO deepn Nubs iterator for Parallel Structures
+        // console.log("Session: current nubs", this._nubs.length, this._nubs);
         let i = 0;
         for (const n of this._nubs) {
             if (n.uid === sn.uid) {
@@ -136,7 +136,6 @@ export class Session {
         const data = JSON.parse(serialised);
         if (data.session && Array.isArray(data.session)) {
             // for each Nub representation, create the corresponding Nub in the session
-            // @TODO children Nubs in Parallel Structures
             data.session.forEach((e: any) => {
                 if (! uids || uids.length === 0 || uids.includes(e.uid)) {
                     const nubPointer = this.createNubFromObjectRepresentation(e);
@@ -152,99 +151,14 @@ export class Session {
      * a pointer to the Nub and its JSON metadata
      * @param serialised JSON representation of a single Nub
      */
-    public unserialiseSingleNub(serialised: string, parentNub?: ParallelStructure): { nub: Nub, meta: any } {
-        return this.createNubFromObjectRepresentation(JSON.parse(serialised), parentNub);
-    }
-
-    /**
-     * Creates a Nub from an object representation and adds it tot he current session; returns
-     * a pointer to the Nub and its JSON metadata
-     * @param obj object representation of a single Nub
-     * @param parentNub when building a sub-Nub of a parallel structure, for checking admissible laws
-     */
-    private createNubFromObjectRepresentation(obj: any, parentNub?: ParallelStructure): { nub: Nub, meta: any } {
-        const nubPointer: any = {};
-        // create the Nub
-        const newNub = this.createSessionNub(new Props(obj.props), parentNub);
-        // try to keep the original ID
-        if (! this.uidAlreadyUsed(obj.uid)) {
-            newNub.setUid(obj.uid);
-        }
-        // set parameter modes and values
-        if (obj.parameters && Array.isArray(obj.parameters)) {
-            for (const p of obj.parameters) {
-                const param = newNub.getParameter(p.symbol);
-                if (! param) {
-                    throw new Error(`session file : cannot find parameter ${p.symbol} in target Nub`);
-                }
-                // set mode
-                const mode: ParamValueMode = (ParamValueMode as any)[p.mode]; // get enum index for string value @WTF
-                param.valueMode = mode;
-                // set value(s)
-                switch (mode) {
-                    case ParamValueMode.SINGLE:
-                        param.setValue(p.value);
-                        break;
-
-                    case ParamValueMode.MINMAX:
-                        param.paramValues.min = p.min;
-                        param.paramValues.max = p.max;
-                        param.paramValues.step = p.step;
-                        break;
-
-                    case ParamValueMode.LISTE:
-                        param.paramValues.valueList = p.values;
-                        break;
-
-                    case ParamValueMode.CALCUL:
-                        // nothing to do
-                        break;
-
-                    case ParamValueMode.LINK:
-                        // formulaire dont le Nub est la cible du lien
-                        const destNub = this.findNubByUid(p.targetNub);
-                        if (destNub) {
-                            param.defineReference(destNub, p.targetParam);
-                        } else {
-                            // @TODO et si la cible du lien n'existe pas ??
-                            // cf FormulaireService.updateParamsLinks()
-                            console.log("LA CIBLE DU LIEN N'EXISTE PAS !!");
-                        }
-                        break;
-
-                    default:
-                        throw new Error(`session file : invalid value mode '${p.mode}' in param object`);
-                }
-            }
-        }
-
-        nubPointer.nub = newNub;
-        // add metadata (used by GUI, for ex.)
-        if (obj.meta) {
-            nubPointer.meta = obj.meta;
-        }
-        return nubPointer;
-    }
-
-    /**
-     * Returns true if given uid is already used by a Nub in this session
-     */
-    private uidAlreadyUsed(uid: string): boolean {
-        let alreadyUsed = false;
-        outerLoop:
-        for (const n of this._nubs) {
-            if (n.uid === uid) {
-                alreadyUsed = true;
-                break outerLoop;
-            }
-        }
-        return alreadyUsed;
+    public unserialiseSingleNub(serialised: string): { nub: Nub, meta: any } {
+        return this.createNubFromObjectRepresentation(JSON.parse(serialised));
     }
 
     /**
      * Returns the Nub identified by uid if any
      */
-    private findNubByUid(uid: string): Nub {
+    public findNubByUid(uid: string): Nub {
         let foundNub: Nub;
         outerLoop:
         for (const n of this._nubs) {
@@ -262,7 +176,7 @@ export class Session {
      *        - nodeType: sous type de Nub
      * @param dbg activer débogage
      */
-    private createNub(params: Props, parentNub?: ParallelStructure, dbg: boolean = false): Nub {
+    public createNub(params: Props, parentNub?: ParallelStructure, dbg: boolean = false): Nub {
         const calcType: CalculatorType = params.getPropValue("calcType");
         const nodeType: ComputeNodeType = params.getPropValue("nodeType");
 
@@ -425,6 +339,44 @@ export class Session {
         return nub;
     }
 
+    /**
+     * Returns true if given uid is already used by a Nub in this session
+     * @TODO deep iterator on sub-nubs
+     */
+    public uidAlreadyUsed(uid: string): boolean {
+        let alreadyUsed = false;
+        outerLoop:
+        for (const n of this._nubs) {
+            if (n.uid === uid) {
+                alreadyUsed = true;
+                break outerLoop;
+            }
+        }
+        return alreadyUsed;
+    }
+
+    /**
+     * Creates a Nub from an object representation and adds it tot he current session; returns
+     * a pointer to the Nub and its JSON metadata
+     * @param obj object representation of a single Nub
+     */
+    private createNubFromObjectRepresentation(obj: any): { nub: Nub, meta: any } {
+        const nubPointer: any = {};
+        // create the Nub
+        const newNub = this.createSessionNub(new Props(obj.props));
+        // try to keep the original ID
+        if (! this.uidAlreadyUsed(obj.uid)) {
+            newNub.setUid(obj.uid);
+        }
+        newNub.loadObjectRepresentation(obj);
+        nubPointer.nub = newNub;
+        // add metadata (used by GUI, for ex.)
+        if (obj.meta) {
+            nubPointer.meta = obj.meta;
+        }
+        return nubPointer;
+    }
+
     /**
      * Crée un Nub de type Section
      * @param nt ComputeNodeType
diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts
index d482d7a0..4e2cebfd 100644
--- a/src/structure/parallel_structure.ts
+++ b/src/structure/parallel_structure.ts
@@ -9,6 +9,8 @@ import { INamedIterableValues } from "../param/param-value-iterator";
 import { ParamValues } from "../param/param-values";
 import { IParamDefinitionIterator, ParamsEquation, ParamsEquationArrayIterator } from "../param/params-equation";
 
+import { Props } from "../props";
+import { Session } from "../session";
 import { loiAdmissiblesOuvrages, LoiDebit } from "./structure_props";
 
 export { ParallelStructureParams };
@@ -184,11 +186,7 @@ export class ParallelStructure extends Nub {
      */
     public deleteStructure(index: number) {
         if (index > -1) {
-            const removedStructures = this._structures.splice(index, 1);
-            if (removedStructures && removedStructures.length === 1) {
-                // remove reference to parent collection (this)
-                removedStructures[0].parent = undefined;
-            }
+            this._structures.splice(index, 1);
         } else {
             throw new Error("ParallelStructure.deleteStructure invalid index=" + index);
         }
@@ -367,6 +365,30 @@ export class ParallelStructure extends Nub {
         return ret;
     }
 
+    /**
+     * Fills the current Nub with parameter values, provided an object representation
+     * @param obj object representation of a Nub content (parameters, structures)
+     */
+    public loadObjectRepresentation(obj: any) {
+        // load regular Nub contents (parameters)
+        super.loadObjectRepresentation(obj);
+
+        // iterate over structures if any
+        if (obj.structures && Array.isArray(obj.structures)) {
+            for (const s of obj.structures) {
+                // create the Nub
+                const subNub = Session.getInstance().createNub(new Props(s.props), this);
+                // try to keep the original ID
+                if (! Session.getInstance().uidAlreadyUsed(s.uid)) {
+                    subNub.setUid(s.uid);
+                }
+                subNub.loadObjectRepresentation(s);
+                // add Structure to parent
+                this.addStructure(subNub as Structure);
+            }
+        }
+    }
+
     /**
      * paramétrage de la calculabilité des paramètres
      */
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
index 5988f370..9059ccf6 100644
--- a/src/structure/structure.ts
+++ b/src/structure/structure.ts
@@ -96,7 +96,7 @@ export abstract class Structure extends Nub {
     public abstract calcA(): number;
 
     /**
-     * Calcul d'une équation quelque soit l'inconnue à calculer.
+     * Calcul d'une équation quelle que soit l'inconnue à calculer.
      * Gestion du débit nul et de l'inversion de débit
      * @param sVarCalc nom de la variable à calculer
      * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie
-- 
GitLab