Skip to content
Snippets Groups Projects
calculator-list.component.ts 12.87 KiB
import { Component, OnInit, Inject, forwardRef, ElementRef, ViewChild } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";

import { CalculatorType, EnumEx, Session } from "jalhyd";

import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
import { ServiceFactory } from "../../services/service-factory";
import { I18nService } from "../../services/internationalisation.service";
import { FormulaireParallelStructure } from "../../formulaire/definition/form-parallel-structures";
import { FieldsetContainer } from "../../formulaire/elements/fieldset-container";
import { FormulairePab } from "../../formulaire/definition/form-pab";
import { HttpService } from "../../services/http.service";
import { AppComponent } from "../../app.component";
import { FormulaireMacrorugoCompound } from "../../formulaire/definition/form-macrorugo-compound";
import { FormulaireSPP } from "../../formulaire/definition/form-spp";
import { ApplicationSetupService } from "../../services/app-setup.service";


@Component({
    selector: "list",
    templateUrl: "./calculator-list.component.html",
    styleUrls: ["./calculator-list.component.scss"]
})
export class CalculatorListComponent implements OnInit {

    private _items: any[];

    public filteredItems: any[];

    /** enable search only if /list/search route was called */
    public enableSearch = false;

    /** what is typed into the search field in the nav bar */
    public searchTerms: string;

    @ViewChild("searchField")
    private searchField: ElementRef;

    constructor(
        @Inject(forwardRef(() => AppComponent)) private appComponent: AppComponent,
        private router: Router,
        private httpService: HttpService,
        private intlService: I18nService,
        private appSetupService: ApplicationSetupService,
        public route: ActivatedRoute
    ) {
        ServiceFactory.i18nService.addObserver(this);
        ServiceFactory.applicationSetupService.addObserver(this);

        this.searchTerms = "";

        this.route.url.subscribe(params => {
            if (params.length > 1 && params[1].path === "search") {
                this.enableSearch = true;
                // focus the new Field
                setTimeout(() => {
                    this.searchField.nativeElement.focus();
                }, 0);
            }
        });
    }

    /** triggered on init */
    private loadCalculatorsThemes() {
        this._items = [];
        const unusedCalculators = EnumEx.getValues(CalculatorType);
        const themes = ServiceFactory.applicationSetupService.themes;
        if (themes) {
            // group by themes
            for (const theme of themes) {
                if (theme.name) {
                    // get theme details from config
                    const themeTitleKey = "INFO_THEME_" + theme.name + "_TITRE";
                    const themeDescriptionKey = "INFO_THEME_" + theme.name + "_DESCRIPTION";
                    const credits = ServiceFactory.i18nService.localizeText("INFO_THEME_CREDITS");
                    const item = {
                        title: ServiceFactory.i18nService.localizeText(themeTitleKey),
                        description: ServiceFactory.i18nService.localizeText(themeDescriptionKey),
                        image: {
                            path: "assets/images/themes/" + theme.image.path,
                            credits: credits + " : " + theme.image.credits
                        },
                        calculators: []
                    };
                    // get calculators for this theme
                    for (const calcType of theme.calculators) {
                        item.calculators.push({
                            type: calcType,
                            label: ServiceFactory.formulaireService.getLocalisedTitleFromCalculatorType(calcType),
                            shortLabel: ServiceFactory.formulaireService.getLocalisedShortTitleFromCalculatorType(calcType),
                            description: ServiceFactory.formulaireService.getLocalisedDescriptionFromCalculatorType(calcType),
                            buttonId: "create-calc-" + calcType
                        });
                        // mark as used
                        const index = unusedCalculators.indexOf(calcType);
                        if (index > -1) {
                            unusedCalculators.splice(index, 1);
                        }
                    }
                    this._items.push(item);
                }
                // else special theme for unused calculators
            }
            // extra card for unused calculators
            if (unusedCalculators.length > 0) {
                const unusedThemeConfig = themes.find(i => i.name === undefined);
                const unusedTheme: any = {};
                unusedTheme.calculators = [];
                unusedTheme.title = ServiceFactory.i18nService.localizeText("INFO_THEME_MODULES_INUTILISES_TITRE");
                unusedTheme.description = ServiceFactory.i18nService.localizeText("INFO_THEME_MODULES_INUTILISES_DESCRIPTION");
                unusedTheme.image = {
                    path: "assets/images/themes/" + unusedThemeConfig.image.path
                };

                for (const t of unusedCalculators) {
                    if ( // those sub-Nub types cannot be built outside a parent
                        ! [
                            CalculatorType.Structure,
                            CalculatorType.Section,
                            CalculatorType.CloisonAval,
                            CalculatorType.YAXN,
                            CalculatorType.PbBassin,
                            CalculatorType.PbCloison,
                            CalculatorType.LechaptCalmon,
                            CalculatorType.PressureLossLaw
                        ].includes(t)
                    ) {
                        unusedTheme.calculators.push({
                            type: t,
                            label: ServiceFactory.formulaireService.getLocalisedTitleFromCalculatorType(t),
                            shortLabel: ServiceFactory.formulaireService.getLocalisedShortTitleFromCalculatorType(t),
                            description: ServiceFactory.formulaireService.getLocalisedDescriptionFromCalculatorType(t),
                            buttonId: "create-calc-" + t
                        });
                    }
                }
                if (unusedTheme.calculators.length > 0) {
                    this._items.push(unusedTheme);
                } // else the only remaining calculator was "Structure", the one we don't want
            }
        }

        // at first there is no filter, initialize anyway
        this.filterItems();
    }

    public async create(t: CalculatorType) {
        const f: FormulaireDefinition = await ServiceFactory.formulaireService.createFormulaire(t);
        await this.router.navigate(["/calculator", f.uid]);
        // on ajoute un ouvrage après l'ouverture du module de calcul "ouvrages parallèles"
        if (f instanceof FormulaireParallelStructure) {
            for (const e of f.allFormElements) {
                if (e instanceof FieldsetContainer) {
                    e.addFromTemplate();
                    break;
                }
            }
        }
        // on ajoute un ouvrage après l'ouverture du module de calcul "passe à bassins"
        if (f instanceof FormulairePab) {
            for (const e of f.allFormElements) {
                if (e instanceof FieldsetContainer) {
                    e.addFromTemplate();
                    break;
                }
            }
        }
        // adding GUI for default apron, in MacroRugoCompound
        if (f instanceof FormulaireMacrorugoCompound) {
            for (const e of f.allFormElements) {
                if (e instanceof FieldsetContainer) {
                    e.addFromTemplate(0, f.currentNub.getChildren()[0]);
                    break;
                }
            }
        }
        // on ajoute un YAXN après l'ouverture du module de calcul "somme / produit de puissances"
        if (f instanceof FormulaireSPP) {
            for (const e of f.allFormElements) {
                if (e instanceof FieldsetContainer) {
                    e.addFromTemplate();
                    break;
                }
            }
        }
    }

    public get nbOpenCalculators() {
        return Session.getInstance().getNumberOfNubs();
    }

    public resetSearch() {
        this.searchTerms = "";
        this.filterItems();
    }

    /**
     * Returns calculators grouped by themes, filtered by the search
     * terms entered in the navbar's search field in AppComponent
     */
    public filterItems() {
        if (this.searchTerms === "") {
            this.filteredItems = this._items;
        } else {
            this.filteredItems = JSON.parse(JSON.stringify(this._items));
            // filter items based on parent component's search field
            for (const i of this.filteredItems) {
                i.calculators = i.calculators.filter((c) => {
                    return this.searchMatches(c.label) || this.searchMatches(c.shortLabel) || this.searchMatches(c.description);
                });
            }
            this.filteredItems = this.filteredItems.filter((i) => {
                return (i.calculators.length > 0);
            });
        }
    }

    /**
     * Returns true if given str matches this.searchTerms: all terms (separated
     * by " ") must match, in any order
     */
    private searchMatches(str: string): boolean {
        let ok = false;
        let terms = this.searchTerms.split(" ");
        terms = terms.filter(
            (item, index) => item !== "" && terms.indexOf(item) === index // deduplicate and remove ""
        );
        if (terms.length > 1) {
            // all terms must match
            ok = terms.every((t) => {
                return str.toLowerCase().includes(t.toLowerCase());
            });
        } else if (terms.length > 0) {
            ok = (str.toLowerCase().includes(terms[0].toLowerCase()));
        } else {
            ok = true;
        }
        return ok;
    }

    /**
     * IMPORTANT: keep in sync with app/examples folder contents
     */
    public get exampleFiles() {
        return [
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_PAB_COMPLETE"),
                path: "pab-complete-chain.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_CHANNEL_FLOW"),
                path: "solveur-channel-flow.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_WEIR_JET_LENGTH"),
                path: "weir-jet-length.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_PENTE_CRITIQUE_CANAL"),
                path: "pente-critique-canal.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_PAB_ECH_TRIANG"),
                path: "pab-ech-triang.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_PERR"),
                path: "perr.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_PB"),
                path: "prebarrage.json"
            },
            {
                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_RANGEES_PERIOD"),
                path: "passe_rangees_periodiques.json"
            }
        ];
    }
    public async loadExample(path: string) {
        const realPath = "app/examples/" + path;
        try {
            const d = await this.httpService.httpGetBlobRequestPromise(realPath);
            const f: any = new Blob([d], { type: "application/json" });
            this.appComponent.loadSessionFile(f);
        } catch (e) {
            console.error("could not load session file", e);
        }
    }

    public get uitextWelcomeTitle() {
        return "Cassiopée";
    }

    public get uitextWelcomeSubtitle() {
        return ServiceFactory.i18nService.localizeText("INFO_WELCOME_SUBTITLE");
    }

    public get uitextWelcomeContent() {
        return ServiceFactory.i18nService.localizeText("INFO_WELCOME_CONTENT");
    }

    public get uitextExamplesTitle() {
        return ServiceFactory.i18nService.localizeText("INFO_EXAMPLES_TITLE");
    }

    public get uitextExamplesSubtitle() {
        return ServiceFactory.i18nService.localizeText("INFO_EXAMPLES_SUBTITLE");
    }

    public get uitextSearchNoResult() {
        return ServiceFactory.i18nService.localizeText("INFO_SEARCH_NO_RESULT");
    }

    // interface Observer

    public update(sender: any, data: any): void {
        if (sender instanceof I18nService) {
            // reload themes if language changed
            this.loadCalculatorsThemes();
        }
    }

    public ngOnInit() {
        this.loadCalculatorsThemes();
    }
}