Newer
Older
francois.grand
committed
import { Injectable } from "@angular/core";
import { Response } from "@angular/http";
import { Observable as rxObservable } from "rxjs";
francois.grand
committed
import { decode } from "he";
import { saveAs } from "file-saver";
francois.grand
committed
import { CalculatorType, EnumEx, Observable, ParamDefinition, ParamValueMode } from "jalhyd";
francois.grand
committed
import { ServiceFactory } from "../service-factory";
francois.grand
committed
import { HttpService } from "../../services/http/http.service";
import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
francois.grand
committed
import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
francois.grand
committed
import { FormulaireElement } from "../../formulaire/formulaire-element";
import { InputField } from "../../formulaire/input-field";
francois.grand
committed
import { SelectField } from "../../formulaire/select-field";
import { CheckField } from "../../formulaire/check-field";
import { StringMap } from "../../stringmap";
francois.grand
committed
import { FormulaireConduiteDistributrice } from "../../formulaire/definition/concrete/form-cond-distri";
import { FormulaireLechaptCalmon } from "../../formulaire/definition/concrete/form-lechapt-calmon";
import { FormulaireSectionParametree } from "../../formulaire/definition/concrete/form-section-parametree";
import { FormulaireCourbeRemous } from "../../formulaire/definition/concrete/form-courbe-remous";
import { FormulaireRegimeUniforme } from "../../formulaire/definition/concrete/form-regime-uniforme";
import { FormulairePasseBassinDimensions } from "../../formulaire/definition/concrete/form-passe-bassin-dim";
import { FormulairePasseBassinPuissance } from "../../formulaire/definition/concrete/form-passe-bassin-puissance";
import { FormulaireParallelStructure } from "../../formulaire/definition/concrete/form-parallel-structures";
francois.grand
committed
import { NgParameter } from "../../formulaire/ngparam";
export class FormulaireService extends Observable {
private _formulaires: FormulaireDefinition[];
private _currentFormId = -1;
francois.grand
committed
constructor() {
francois.grand
committed
private get _intlService(): InternationalisationService {
return ServiceFactory.instance.internationalisationService;
}
private get _httpService(): HttpService {
return ServiceFactory.instance.httpService;
}
public get formulaires(): FormulaireDefinition[] {
return this._formulaires;
}
private loadLocalisation(calc: CalculatorType): Promise<any> {
const f: string = this.getConfigPathPrefix(calc) + this._intlService.currentLanguage.tag + ".json";
const prom = this._httpService.httpGetRequestPromise(undefined, undefined, undefined, f);
}
/**
* met à jour la langue du formulaire
* @param formId id unique du formulaire
* @param localisation ensemble id-message traduit
*/
private updateFormulaireLocalisation(formId: number, localisation: StringMap) {
f.updateLocalisation(localisation);
break;
}
}
/**
* charge la localisation et met à jour la langue du formulaire
*/
private loadUpdateFormulaireLocalisation(f: FormulaireDefinition): Promise<FormulaireDefinition> {
return this.loadLocalisation(f.calculatorType)
.then(localisation => {
this.updateFormulaireLocalisation(f.uid, localisation);
return f;
});
}
public updateLocalisation() {
for (const c of EnumEx.getValues(CalculatorType)) {
const prom: Promise<StringMap> = this.loadLocalisation(c);
prom.then(loc => {
for (const f of this._formulaires) {
if (f.calculatorType === c) {
this.updateFormulaireLocalisation(f.uid, loc);
public getLocalisedTitleFromCalculatorType(type: CalculatorType) {
const sCalculator: string = CalculatorType[type].toUpperCase();
return this._intlService.localizeText(`INFO_${sCalculator}_TITRE`);
}
public loadConfig(ct: CalculatorType): Promise<any> {
const f: string = this.getConfigPathPrefix(ct) + "config.json";
return this._httpService.httpGetRequestPromise(undefined, undefined, undefined, f);
private newFormulaire(ct: CalculatorType, jsonState?: {}): FormulaireDefinition {
francois.grand
committed
let f: FormulaireDefinition;
switch (ct) {
case CalculatorType.ConduiteDistributrice:
francois.grand
committed
f = new FormulaireConduiteDistributrice();
francois.grand
committed
break;
case CalculatorType.LechaptCalmon:
francois.grand
committed
f = new FormulaireLechaptCalmon();
francois.grand
committed
break;
case CalculatorType.SectionParametree:
francois.grand
committed
f = new FormulaireSectionParametree();
francois.grand
committed
break;
case CalculatorType.RegimeUniforme:
francois.grand
committed
f = new FormulaireRegimeUniforme();
francois.grand
committed
break;
case CalculatorType.CourbeRemous:
francois.grand
committed
f = new FormulaireCourbeRemous();
francois.grand
committed
break;
case CalculatorType.PabDimensions:
francois.grand
committed
f = new FormulairePasseBassinDimensions();
francois.grand
committed
break;
case CalculatorType.PabPuissance:
francois.grand
committed
f = new FormulairePasseBassinPuissance();
francois.grand
committed
break;
case CalculatorType.ParallelStructure:
case CalculatorType.Cloisons:
f = new FormulaireParallelStructure();
francois.grand
committed
default:
throw new Error(`FormulaireService.newFormulaire() : type de calculette ${CalculatorType[ct]} non pris en charge`);
francois.grand
committed
}
f.defaultProperties["calcType"] = ct;
return f;
}
/**
* crée un formulaire d'un type donné
* @param ct type de formulaire
*/
public createFormulaire(ct: CalculatorType, jsonState?: {}): Promise<FormulaireDefinition> {
const f: FormulaireDefinition = this.newFormulaire(ct);
return prom.then(s => {
f.preparseConfig(JSON.parse(s));
return f;
}).then(f => {
if (jsonState === undefined) {
f.calculatorName = decode(this.getLocalisedTitleFromCalculatorType(ct) + " (" + f.uid + ")");
}
f.initSessionNub();
return f;
}).then(f => {
f.parseConfig(undefined);
if (jsonState !== undefined) {
f.deserialiseJSON(jsonState);
const props = jsonState["props"];
}
// la méthode loadUpdateFormulaireLocalisation retourne une Promise; le fait de retourner une Promise dans un then
// fait que le then suivant est exécuté juste après.
return this.loadUpdateFormulaireLocalisation(f);
}).then(f => {
f.applyDependencies();
return f;
}).then(f => {
this.notifyObservers(
{
"form": f
});
public getFormulaireFromId(uid: number): FormulaireDefinition {
for (const f of this._formulaires) {
if (f.uid === uid) {
francois.grand
committed
return undefined;
public getInputField(formId: number, elemId: string): InputField {
const s = this.getFormulaireElementById(formId, elemId);
if (!(s instanceof InputField)) {
throw new Error("Form element with id '" + elemId + "' is not an input");
}
public getCheckField(formId: number, elemId: string): CheckField {
const s = this.getFormulaireElementById(formId, elemId);
throw new Error("Form element with id '" + elemId + "' is not a checkbox");
public getSelectField(formId: number, elemId: string): SelectField {
const s = this.getFormulaireElementById(formId, elemId);
throw new Error("Form element with id '" + elemId + "' is not a select");
private getFormulaireElementById(formId: number, elemId: string): FormulaireElement {
const s = f.getFormulaireNodeById(elemId);
francois.grand
committed
return s as FormulaireElement;
francois.grand
committed
public getParamdefParentForm(prm: ParamDefinition): FormulaireDefinition {
for (const f of this._formulaires) {
for (const p of f.allFormElements) {
if (p instanceof NgParameter) {
if (p.paramDefinition.uid === prm.uid) {
francois.grand
committed
return f;
francois.grand
committed
return undefined;
}
public getConfigPathPrefix(ct: CalculatorType): string {
if (ct === undefined) {
throw new Error("FormulaireService.getConfigPathPrefix() : invalid undefined CalculatorType");
}
switch (ct) {
case CalculatorType.ConduiteDistributrice:
return "app/calculators/cond_distri/cond_distri.";
case CalculatorType.LechaptCalmon:
return "app/calculators/lechapt-calmon/lechapt-calmon.";
case CalculatorType.SectionParametree:
return "app/calculators/section-param/section-param.";
case CalculatorType.RegimeUniforme:
return "app/calculators/regime-uniforme/regime-uniforme.";
francois.grand
committed
case CalculatorType.CourbeRemous:
return "app/calculators/remous/remous.";
case CalculatorType.PabDimensions:
return "app/calculators/pab-dimensions/pab-dimensions.";
case CalculatorType.PabPuissance:
return "app/calculators/pab-puissance/pab-puissance.";
case CalculatorType.Structure:
return "app/calculators/ouvrages/ouvrages.";
case CalculatorType.ParallelStructure:
return "app/calculators/parallel-structures/parallel-structures.";
case CalculatorType.Dever:
return "app/calculators/dever/dever.";
case CalculatorType.Cloisons:
return "app/calculators/cloisons/cloisons.";
throw new Error("FormulaireService.getConfigPathPrefix() : valeur de CalculatorType " + ct + " non implémentée");
public requestCloseForm(uid: number) {
const form = this.getFormulaireFromId(uid);
this._formulaires = this._formulaires.filter(f => f.uid !== uid);
this.notifyObservers({
"form": form
});
}
}
public get currentFormId() {
return this._currentFormId;
}
public setCurrentForm(formId: number) {
const form = this.getFormulaireFromId(formId);
this._currentFormId = -1;
this.notifyObservers({
"action": "invalidFormId",
"formId": formId
});
this._currentFormId = formId;
this.notifyObservers({
"action": "currentFormChanged",
"formId": formId
francois.grand
committed
private get currentForm(): FormulaireDefinition {
return this.getFormulaireFromId(this._currentFormId);
}
public get currentFormHasResults(): boolean {
const form = this.currentForm;
francois.grand
committed
return form.hasResults;
francois.grand
committed
return false;
}
francois.grand
committed
private readSingleFile(file: File): Promise<any> {
return new Promise<any>((resolve, reject) => {
fr.onload = () => {
resolve(fr.result);
};
fr.onerror = () => {
fr.abort();
reject(new Error(`Erreur de lecture du fichier ${file.name}`));
};
fr.readAsText(file);
});
}
francois.grand
committed
/**
* charge une session en tenant compte des calculettes sélectionnées
* @param f fichier session
* @param formInfos infos sur les calculettes @see LoadCalculatorComponent._calculators
*/
public loadSession(f: File, formInfos: any[]) {
this.readSingleFile(f).then(s => {
const session = JSON.parse(s);
switch (k) {
case "session":
francois.grand
committed
this.deserialiseSession(session[k], formInfos);
break;
default:
throw new Error(`session file : invalid key '${k}'`);
}
}).catch(err => {
throw err;
});
public saveSession(session: {}, filename?: string) {
francois.grand
committed
const blob = new Blob([JSON.stringify(session)], { type: "text/plain;charset=utf-8" });
saveAs(blob, filename);
francois.grand
committed
}
francois.grand
committed
/**
* obtient des infos (nom, uid des calculettes) d'un fichier session
* @param f fichier session
*/
public calculatorInfosFromSessionFile(f: File): Promise<any[]> {
return this.readSingleFile(f).then(s => {
const res: any[] = [];
const session = JSON.parse(s);
// liste des noms de calculettes
francois.grand
committed
switch (k) {
case "session":
const sess = session[k];
const elems = sess["elements"];
francois.grand
committed
if (k === "form") {
const form = e[k];
res.push({ "uid": form["uid"], "title": form["id"] });
}
francois.grand
committed
break;
default:
throw new Error(`session file : invalid key '${k}'`);
}
francois.grand
committed
return res;
});
}
francois.grand
committed
public saveForm(f: FormulaireDefinition) {
this.notifyObservers({
"action": "saveForm",
"form": f
});
}
private deserialiseForm(elements: {}) {
const props = elements["props"];
const ct: CalculatorType = props["calcType"];
this.createFormulaire(ct, elements);
}
francois.grand
committed
private deserialiseSessionElement(element: {}, formInfos: any[]) {
const keys = Object.keys(element);
throw new Error(`session file : invalid session object '${element}'`);
switch (keys[0]) {
case "form":
francois.grand
committed
const form = element[keys[0]];
for (const i of formInfos) {
if (i["uid"] === form["uid"] && i["selected"]) {
francois.grand
committed
this.deserialiseForm(form);
break;
default:
throw new Error(`session file : invalid key '${keys[0]}' in session object`);
}
}
francois.grand
committed
private deserialiseSession(elements: {}, formInfos: any[]) {
switch (ks) {
case "elements":
francois.grand
committed
this.deserialiseSessionElement(e, formInfos);
break;
default:
throw new Error(`session file : invalid key '${ks}' in session object`);
}
francois.grand
committed
/**
francois.grand
committed
* @returns liste des valeurs liables à un paramètre sous la forme d'un tableau d'objets
francois.grand
committed
* {"param":<paramètre lié>, "nub":<Nub d'origine du paramètre lié>, "formTitle":<nom de la calculette liée au nub>}
francois.grand
committed
* @param p paramètre qui sert de clé de recherche des paramètres liables
francois.grand
committed
*/
francois.grand
committed
public getLinkableValues(p: NgParameter): any[] {
francois.grand
committed
francois.grand
committed
for (const f of this._formulaires) {
francois.grand
committed
// nub associé au formulaire
francois.grand
committed
const sn = f.currentSessionNub;
francois.grand
committed
francois.grand
committed
try {
// on vérifie que le paramètre en entrée appartient au nub
const np = sn.nub.getParameter(p.symbol);
francois.grand
committed
// si oui, on demande à exclure des valeurs retournées le résultat du même nom que le paramètre
François
committed
const exclude = np !== undefined ? p.paramDefinition.uid === np.uid : false;
// valeurs liables
const ps = sn.getLinkableValues(p.paramDefinition, exclude);
for (const np of ps) {
np["formTitle"] = f.calculatorName;
res.push(np);
}
francois.grand
committed
// p.symbol n'existe pas dans le nub testé
}
francois.grand
committed
}
francois.grand
committed
return res;
}
francois.grand
committed
/**
* filtre les valeurs liables à un paramètre :
* - supprime les valeurs non affichées dans leur parent (ce n'est pas le cas par ex pour Q, Z1, Z2 dans les ouvrages enfants des ouvrages //)
* @param values valeurs liables (modifié par la méthode)
*/
public filterLinkableValues(values: any[]): any[] {
// suppression des paramètres non affichés
for (let i = values.length - 1; i >= 0; i--) {
const v = values[i].value;
if (v instanceof ParamDefinition) {
// pour chaque paramètre...
const prm: ParamDefinition = v;
const parentForm: FormulaireDefinition = this.getParamdefParentForm(prm);
// ... on cherche s'il est affiché dans son parent
if (parentForm !== undefined) {
for (const fe of parentForm.allFormElements) {
if (fe instanceof NgParameter) {
francois.grand
committed
if (fe.paramDefinition.uid === prm.uid) {
found = true;
break;
}
francois.grand
committed
francois.grand
committed
values.splice(i, 1);
francois.grand
committed
}
}
return values;
}