// cf. https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html

import { Component, ChangeDetectorRef, OnDestroy } from "@angular/core";

import { Message, Observer } from "jalhyd";

import { I18nService } from "../../services/internationalisation/internationalisation.service";
import { NgParameter } from "../../formulaire/ngparam";
import { GenericInputComponent } from "../generic-input/generic-input.component";

@Component({
    selector: "ngparam-input",
    templateUrl: "../generic-input/generic-input.component.html",
    styleUrls: [
        "./ngparam-input.component.scss"
    ]
})
export class NgParamInputComponent extends GenericInputComponent implements Observer, OnDestroy {
    /**
     * paramètre géré
     */
    private get _paramDef(): NgParameter {
        return this.model;
    }

    /**
     * valeur intermédiaire nécessitée par le fait que toutes les valeurs numériques ne sont pas légales
     * pour NgParameter (l'affecter peut provoquer une exception) et qui permet de faire fonctionner la validation du modèle
     */
    private _tmp: number;

    constructor(intlService: I18nService, cdRef: ChangeDetectorRef) {
        super(cdRef, intlService);
    }

    /**
     * appelé avant le changement de modèle
     */
    protected beforeSetModel() {
        if (this._paramDef) {
            this._paramDef.removeObserver(this);
        }
    }

    /**
     * appelé après le changement de modèle
     */
    protected afterSetModel() {
        if (this._paramDef) {
            if (this._paramDef.isDefined) {
                this._tmp = this._paramDef.getValue();
            }
            this._paramDef.addObserver(this);
        }
    }

    protected getModelValue(): any {
        return this._tmp;
    }

    protected setModelValue(sender: any, v: any) {
        this._tmp = v;
        try {
            this._paramDef.setValue(sender, v);
        } catch (e) {
            // géré par validateModelValue()
        }
    }

    protected validateModelValue(v: any): { isValid: boolean, message: string } {
        let msg: string;
        let valid = false;

        if (! this._paramDef) {
            msg = "internal error, model undefined";
        } else {
            try {
                this._paramDef.checkValue(v);
                valid = true;
            } catch (e) {
                if (e instanceof Message) {
                    msg = this.intlService.localizeMessage(e);
                } else {
                    msg = "invalid value";
                }
            }
        }

        return { isValid: valid, message: msg };
    }

    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();
                }
                break;

            // changement de valueMode du paramètre ou de valeur à laquelle il est lié
            case "valueModeChange":
            case "valueLinkChange":
                if (this._tmp !== data["value"]) {
                    this._tmp = data["value"];
                    this.updateAndValidateUI();
                }
                break;
        }
    }

    public ngOnDestroy() {
        this._paramDef.removeObserver(this);
    }
}