From 61ecf51417ccf9de613949ff139e4958eaf06ae3 Mon Sep 17 00:00:00 2001
From: "francois.grand" <francois.grand@irstea.fr>
Date: Mon, 19 Feb 2018 09:50:19 +0100
Subject: [PATCH] =?UTF-8?q?=20#27=20:=20d=C3=A9but=20d'int=C3=A9gration=20?=
 =?UTF-8?q?du=20composant=20FieldsetContainerComponent?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../parallel-structures.fr.json               |   1 +
 .../fieldset-container.component.html         |   7 +-
 .../fieldset-container.component.ts           |  10 +-
 .../calculator.component.html                 |   8 +-
 .../calculator.component.ts                   |  20 +-
 src/app/formulaire/fieldset-container.ts      |   2 +
 src/app/formulaire/formulaire-definition.ts   | 263 +++++++++++++++---
 7 files changed, 261 insertions(+), 50 deletions(-)

diff --git a/src/app/calculators/parallel-structures/parallel-structures.fr.json b/src/app/calculators/parallel-structures/parallel-structures.fr.json
index 4c1d1697f..e18459573 100644
--- a/src/app/calculators/parallel-structures/parallel-structures.fr.json
+++ b/src/app/calculators/parallel-structures/parallel-structures.fr.json
@@ -8,6 +8,7 @@
     "L": "Largeur du déversoir",
     "Cd": "Coefficient de débit",
     "fs_struct_cem88v": "Cem88v",
+    "struct_container": "Ouvrages",
     "fs_param_calc": "Paramètres de calcul",
     "Pr": "Précision de calcul"
 }
\ No newline at end of file
diff --git a/src/app/components/fieldset-container/fieldset-container.component.html b/src/app/components/fieldset-container/fieldset-container.component.html
index f2ccd2f72..d29466053 100644
--- a/src/app/components/fieldset-container/fieldset-container.component.html
+++ b/src/app/components/fieldset-container/fieldset-container.component.html
@@ -1,2 +1,7 @@
+<div class="container-fluid" style="border-style:solid; border-color: lightgray">
+    <div class="row">
+        <h4>{{title}}</h4>
+    </div>
+</div>
 <field-set *ngFor="let fs of fieldsets" [fieldSet]=fs>
-</field-set>
\ No newline at end of file
+</field-set>
diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts
index 8740d3a37..4cf663b58 100644
--- a/src/app/components/fieldset-container/fieldset-container.component.ts
+++ b/src/app/components/fieldset-container/fieldset-container.component.ts
@@ -1,4 +1,5 @@
-import { Component } from "@angular/core";
+import { Component, Input } from "@angular/core";
+
 import { FieldsetContainer } from "../../formulaire/fieldset-container";
 
 @Component({
@@ -6,8 +7,15 @@ import { FieldsetContainer } from "../../formulaire/fieldset-container";
     templateUrl: "./fieldset-container.component.html"
 })
 export class FieldsetContainerComponent {
+    @Input("container")
     private _container: FieldsetContainer;
 
+    private get title(): string {
+        if (this._container == undefined)
+            return undefined;
+        return this._container.label;
+    }
+
     private get fielsets() {
         return this._container.fieldsets;
     }
diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index 8c7d3b1c4..6d01899d8 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -22,8 +22,12 @@
     <div [ngClass]="(hasResults) ? 'col-12 col-lg-6' : 'col-12'">
         <div class="container-fluid">
             <!-- chapitres -->
-            <field-set *ngFor="let fs of fieldSets" [style.display]="getFieldsetStyleDisplay(fs.id)" [fieldSet]=fs (onRadio)=onRadioClick($event)
-                (onSelectChange)=onSelectChanged($event) (onValid)=OnFieldsetValid()></field-set>
+            <ng-template ngFor let-fe [ngForOf]="formElements">
+                <field-set *ngIf="isFieldset(fe)" [style.display]="getFieldsetStyleDisplay(fe.id)" [fieldSet]=fe (onRadio)=onRadioClick($event)
+                    (onSelectChange)=onSelectChanged($event) (onValid)=OnFieldsetValid()></field-set>
+
+                <fieldset-container *ngIf="isFieldsetContainer(fe)" [container]=fe></fieldset-container>
+            </ng-template>
         </div>
 
         <!-- bouton calculer -->
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 74042da79..2076dfa17 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -12,6 +12,8 @@ import { FieldSetComponent } from "../field-set/field-set.component";
 import { BaseComponent } from "../base/base.component";
 import { CalculatorNameComponent } from "./calc-name.component";
 import { SelectEntry } from "../../formulaire/select-entry";
+import { FormulaireElement } from "../../formulaire/formulaire-element";
+import { FieldsetContainer } from "../../formulaire/fieldset-container";
 
 @Component({
     selector: 'hydrocalc',
@@ -84,10 +86,24 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
         super();
     }
 
-    private get fieldSets(): FieldSet[] {
+    private get formElements(): FormulaireElement[] {
         if (this._formulaire == undefined)
             return [];
-        return this._formulaire.getFieldSets();
+        return this._formulaire.formElements;
+    }
+
+    /**
+     * détermine si un FormulaireElement est du type FieldSet
+     */
+    private isFieldset(fe): boolean {
+        return fe instanceof FieldSet && !fe.isTemplate;
+    }
+
+    /**
+     * détermine si un FormulaireElement est du type FieldsetContainer
+     */
+    private isFieldsetContainer(fe): boolean {
+        return fe instanceof FieldsetContainer;
     }
 
     private get hasForm() {
diff --git a/src/app/formulaire/fieldset-container.ts b/src/app/formulaire/fieldset-container.ts
index 95ed4452f..975027008 100644
--- a/src/app/formulaire/fieldset-container.ts
+++ b/src/app/formulaire/fieldset-container.ts
@@ -9,6 +9,8 @@ export class FieldsetContainer extends FormulaireElement {
 
     private _fieldsets: FieldSet[];
 
+    public title: string
+
     constructor(id: string, formId: number) {
         super(ComputeNodeType.None, id, formId);
         this._fieldsets = [];
diff --git a/src/app/formulaire/formulaire-definition.ts b/src/app/formulaire/formulaire-definition.ts
index f0afd4b77..976974f6d 100644
--- a/src/app/formulaire/formulaire-definition.ts
+++ b/src/app/formulaire/formulaire-definition.ts
@@ -27,8 +27,192 @@ import { RemousResults } from "../results/remous-results";
 import { StringMap } from "../stringmap";
 import { Observable, Observer, IObservable } from "../services/observer";
 
+// /** 
+//  * itérateur qui extrait les FieldSet de 1er niveau dans un tableau de FormulaireElement
+//  */
+// class TopFieldsetIterator2 implements IterableIterator<FieldSet> {
+//     private _array: FormulaireElement[];
+
+//     private _index: number = 0;
+
+//     constructor(fes: FormulaireElement[]) {
+//         this._array = fes;
+//     }
+
+//     public next(): IteratorResult<FieldSet> {
+//         while (this._index < this._array.length) {
+//             const i = this._index;
+//             const fe: FormulaireElement = this._array[this._index];
+//             this._index = i + 1;
+//             if (fe instanceof FieldSet) {
+//                 const res = {
+//                     done: false,
+//                     value: fe as FieldSet
+//                 };
+//                 return res;
+//             }
+//         }
+//         return {
+//             done: true,
+//             value: undefined
+//         };
+//     }
+
+//     // interface IterableIterator
+
+//     [Symbol.iterator](): IterableIterator<FieldSet> {
+//         return this;
+//     }
+// }
+
+/** 
+ * itérateur qui parcourt un arbre de FormulaireElement
+ */
+class AbstractFormulaireElementIterator<T extends FormulaireElement> {
+    private _array: T[] = [];
+
+    private _index: number = 0;
+
+    constructor(fes: FormulaireElement[]) {
+        this.flatten(fes, this._array);
+    }
+
+    private flatten(input: FormulaireElement[], out: FormulaireElement[]) {
+        for (let fe of input) {
+            if (this.isIterable(fe))
+                out.push(fe);
+            if (this.isDeepIterator())
+                if (fe instanceof FieldSet) {
+                    const fs: FieldSet = fe as FieldSet;
+                    this.flatten(fs.fields, out);
+                }
+                else if (fe instanceof FieldsetContainer) {
+                    const fsc: FieldsetContainer = fe as FieldsetContainer;
+                    this.flatten(fsc.fieldsets, out);
+                }
+        }
+    }
+
+    protected isIterable(fe: FormulaireElement): boolean {
+        return true;
+    }
+
+    protected isDeepIterator(): boolean {
+        return true;
+    }
+
+    public next(): IteratorResult<T> {
+        const i = this._index;
+        if (this._index < this._array.length) {
+            this._index = i + 1;
+            return {
+                done: false,
+                value: this._array[i]
+            };
+        } else {
+            return {
+                done: true,
+                value: undefined
+            };
+        }
+    }
+}
+
+/** 
+ * itérateur qui extrait récursivement les FormulaireElement dans un tableau de FormulaireElement
+ * (qui peut contenir des FieldsetContainer)
+ */
+class FormulaireElementIterator extends AbstractFormulaireElementIterator<FormulaireElement> implements IterableIterator<FormulaireElement> {
+    // interface IterableIterator
+
+    [Symbol.iterator](): IterableIterator<FormulaireElement> {
+        return this;
+    }
+}
+
+/** 
+ * itérateur qui extrait les FieldSet de 1er niveau dans un tableau de FormulaireElement
+ * (qui peut contenir des FieldsetContainer)
+ */
+class TopFieldsetIterator extends AbstractFormulaireElementIterator<FieldSet> implements IterableIterator<FieldSet> {
+    protected isIterable(fe: FormulaireElement): boolean {
+        return fe instanceof FieldSet;
+    }
+
+    protected isDeepIterator(): boolean {
+        return false;
+    }
+
+    // interface IterableIterator
+
+    [Symbol.iterator](): IterableIterator<FieldSet> {
+        return this;
+    }
+}
+
+/** 
+ * itérateur qui extrait récursivement les FieldSet dans un tableau de FormulaireElement
+ * (qui peut contenir des FieldsetContainer)
+ */
+class DeepFieldsetIterator extends AbstractFormulaireElementIterator<FieldSet> implements IterableIterator<FieldSet> {
+    protected isIterable(fe: FormulaireElement) {
+        return fe instanceof FieldSet;
+    }
+
+    // interface IterableIterator
+
+    [Symbol.iterator](): IterableIterator<FieldSet> {
+        return this;
+    }
+}
 
-export class FormulaireDefinition extends Observable implements Observer {
+// /** 
+//  * itérateur qui extrait les FieldSet récursivement dans un tableau de FormulaireElement
+//  */
+// export class DeepFieldsetIterator2 implements IterableIterator<FieldSet> {
+//     private _array: FieldSet[] = [];
+
+//     private _index: number = 0;
+
+//     constructor(fes: FormulaireElement[]) {
+//         this.flatten(fes, this._array);
+//     }
+
+//     private flatten(input: FormulaireElement[], out: FieldSet[]) {
+//         for (let fe of input) {
+//             if (fe instanceof FieldSet)
+//                 out.push(fe);
+//             else if (fe instanceof FieldsetContainer) {
+//                 const fsc: FieldsetContainer = fe as FieldsetContainer;
+//                 this.flatten(fsc.fieldsets, out);
+//             }
+//         }
+//     }
+
+//     public next(): IteratorResult<FieldSet> {
+//         const i = this._index;
+//         if (this._index < this._array.length) {
+//             this._index = i + 1;
+//             return {
+//                 done: false,
+//                 value: this._array[i]
+//             };
+//         } else {
+//             return {
+//                 done: true,
+//                 value: undefined
+//             };
+//         }
+//     }
+
+//     // interface IterableIterator
+
+//     [Symbol.iterator](): IterableIterator<FieldSet> {
+//         return this;
+//     }
+// }
+
+export class FormulaireDefinition extends Observable implements Observer { //, Iterable<FieldSet> {
     /**
      * objet JSON chargé depuis le fichier de configuration de la calculette
      */
@@ -39,9 +223,7 @@ export class FormulaireDefinition extends Observable implements Observer {
      */
     private _defaultCalculatedParam: string;
 
-    private _fieldSets: FieldSet[] = [];
-
-    private _fieldsetContainer: FieldsetContainer;
+    private _formElements: FormulaireElement[] = [];
 
     private _dependencies: Dependency[] = [];
 
@@ -126,29 +308,16 @@ export class FormulaireDefinition extends Observable implements Observer {
         return this._remousResults;
     }
 
-    public getFieldSets(): FieldSet[] {
-        let res: FieldSet[] = [];
-
-        for (let fs of this._fieldSets) {
-            const ok = !fs.isTemplate && (
-                !this.hasSectionNodeTypeSelect ||
-                fs.computeNodeType == this._sectionNodeType ||
-                fs.computeNodeType == ComputeNodeType.None
-            );
-            if (ok)
-                res.push(fs);
-
-        }
-
-        return res;
+    public get formElements(): FormulaireElement[] {
+        return this._formElements;
     }
 
     public get dependencies(): Dependency[] {
         return this._dependencies;
     }
 
-    private getFieldSet(id: string) {
-        for (let fs of this._fieldSets) {
+    private getFieldSet(id: string): FieldSet {
+        for (let fs of this.allFieldsets) {
             if (fs.id == id)
                 return fs;
         }
@@ -156,7 +325,7 @@ export class FormulaireDefinition extends Observable implements Observer {
     }
 
     private hasParameter(symbol: string): boolean {
-        for (let fs of this._fieldSets) {
+        for (let fs of this.topFieldsets) {
             for (let p of fs.fields) {
                 if (p instanceof NgParameter)
                     if (p.symbol === symbol)
@@ -167,7 +336,7 @@ export class FormulaireDefinition extends Observable implements Observer {
     }
 
     public getParamFromSymbol(symbol: string): NgParameter {
-        for (let fs of this._fieldSets) {
+        for (let fs of this.topFieldsets) {
             for (let p of fs.fields) {
                 if (p instanceof NgParameter)
                     if (p.symbol === symbol)
@@ -178,7 +347,7 @@ export class FormulaireDefinition extends Observable implements Observer {
     }
 
     public getParamFromState(st: ParamRadioConfig): NgParameter {
-        for (let fs of this._fieldSets) {
+        for (let fs of this.topFieldsets) {
             for (let p of fs.fields) {
                 if (p instanceof NgParameter)
                     if (p.radioState == st)
@@ -237,7 +406,7 @@ export class FormulaireDefinition extends Observable implements Observer {
      * remet les radios de tous les paramètres à FIX sauf "me" et ceux (celui) à l'état "except"
      */
     private resetOtherRadio(me: NgParameter, except: ParamRadioConfig) {
-        for (let fs of this._fieldSets) {
+        for (let fs of this.topFieldsets) {
             for (let p of fs.fields) {
                 if (p instanceof NgParameter)
                     if (p != me && p.radioState != except && p.radioConfig != ParamRadioConfig.FIX)
@@ -297,7 +466,7 @@ export class FormulaireDefinition extends Observable implements Observer {
         if (this.getParamFromState(ParamRadioConfig.CAL) == undefined) {
             let newCal: NgParameter = undefined;
 
-            for (let fs of this._fieldSets) {
+            for (let fs of this.topFieldsets) {
                 for (let p of fs.fields) {
                     if (p instanceof NgParameter)
                         if (p.radioConfig == ParamRadioConfig.CAL && p.radioState == ParamRadioConfig.FIX && p != sourceParam) {
@@ -333,7 +502,7 @@ export class FormulaireDefinition extends Observable implements Observer {
 
     private getInputParameters(): NgParameter[] {
         let res = [];
-        for (let fs of this._fieldSets)
+        for (let fs of this.allFieldsets)
             for (let p of fs.fields)
                 if (p instanceof NgParameter)
                     res.push(p);
@@ -342,7 +511,7 @@ export class FormulaireDefinition extends Observable implements Observer {
 
     private getDisplayedInputParameters(): NgParameter[] {
         let res = [];
-        for (let fs of this._fieldSets)
+        for (let fs of this.allFieldsets)
             if (fs.isDisplayed)
                 for (let p of fs.fields)
                     if (p instanceof NgParameter && p.isDisplayed)
@@ -351,7 +520,7 @@ export class FormulaireDefinition extends Observable implements Observer {
     }
 
     private getNodeParameterValue(nodeType: ComputeNodeType, symbol: string): number {
-        for (let fs of this._fieldSets) {
+        for (let fs of this.allFieldsets) {
             for (let p of fs.fields) {
                 if (p instanceof NgParameter)
                     // if (p.computeNodeType == nodeType && (p.symbol === symbol || p.alias == symbol)) {
@@ -389,7 +558,7 @@ export class FormulaireDefinition extends Observable implements Observer {
     }
 
     public getFormulaireElementById(id: string): FormulaireElement {
-        for (let fs of this._fieldSets) {
+        for (let fs of this.allFieldsets) {
             if (fs.id == id)
                 return fs;
 
@@ -525,7 +694,7 @@ export class FormulaireDefinition extends Observable implements Observer {
         let node_type: ComputeNodeType = nt == undefined ? ComputeNodeType.None : ComputeNodeType[nt];
 
         const res: FieldSet = new FieldSet(node_type, fs_id, this._uid, json["type"] == "fieldset_template");
-        this._fieldSets.push(res);
+        this._formElements.push(res);
 
         const fields = json["fields"];
         for (const field_index in fields) {
@@ -549,10 +718,12 @@ export class FormulaireDefinition extends Observable implements Observer {
     private parse_template_container(json: {}) {
         const fsc_id: string = json["id"];
 
-        this._fieldsetContainer = new FieldsetContainer(fsc_id, this._uid);
+        const fsc: FieldsetContainer = new FieldsetContainer(fsc_id, this._uid);
+
         const templs: string[] = json["templates"];
         for (const t of templs)
-            this._fieldsetContainer.addTemplate(this.getFieldSet(t));
+            fsc.addTemplate(this.getFieldSet(t));
+        this.formElements.push(fsc);
     }
 
     private getOption(option: string): string {
@@ -1171,16 +1342,8 @@ export class FormulaireDefinition extends Observable implements Observer {
     }
 
     public updateLocalisation(localisation: StringMap) {
-        for (let loc_id in localisation) {
-            for (let fs of this._fieldSets) {
-                if (fs.id == loc_id)
-                    fs.updateLocalisation(localisation);
-
-                for (let p of fs.fields)
-                    if (p.id === loc_id)
-                        p.updateLocalisation(localisation);
-            }
-        }
+        for (let fe of this.allFormElements)
+            fe.updateLocalisation(localisation);
 
         if (this.hasResults)
             this.doCompute(); // pour mettre à jour la langue
@@ -1188,7 +1351,7 @@ export class FormulaireDefinition extends Observable implements Observer {
 
     public get isValid(): boolean {
         let res: boolean = true;
-        for (let fs of this._fieldSets)
+        for (let fs of this.allFieldsets)
             res = res && fs.isValid;
         return res;
     }
@@ -1212,4 +1375,16 @@ export class FormulaireDefinition extends Observable implements Observer {
             this.updateSectionNodeType();
         }
     }
+
+    private get topFieldsets(): IterableIterator<FieldSet> {
+        return new TopFieldsetIterator(this._formElements);
+    }
+
+    private get allFieldsets(): IterableIterator<FieldSet> {
+        return new DeepFieldsetIterator(this._formElements);
+    }
+
+    private get allFormElements(): IterableIterator<FormulaireElement> {
+        return new FormulaireElementIterator(this._formElements);
+    }
 }
-- 
GitLab