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

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

import { Message, ParamDefinition, ParamDomain, ParamDomainValue, Observable, isNumeric } from "jalhyd";

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

export class NgBaseParam extends Observable {
    private _param: ParamDefinition;

    constructor(symb: string, d: ParamDomain | ParamDomainValue, val: number) {
        super();
        this._param = new ParamDefinition(null, symb, d, val);
    }

    public get symbol() {
        return this._param.symbol;
    }

    public get isDefined() {
        return this._param.isDefined;
    }

    public getValue() {
        return this._param.getValue();
    }

    public checkValue(val: number) {
        return this._param.checkValue(val);
    }

    public setValue(val: number) {
        this._param.setValue(val);
        this.notifyObservers(val);
    }
}

@Component({
    selector: "base-param-input",
    templateUrl: "../generic-input/generic-input.component.html",
})
export class BaseParamInputComponent extends GenericInputComponent {
    constructor(private intlService: I18nService, cdRef: ChangeDetectorRef) {
        super(cdRef);
    }

    /**
     * paramètre géré
     */
    private get _paramDef(): NgBaseParam {
        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;

    protected afterSetModel() {
        this._tmp = this._paramDef.getValue();
    }

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

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

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

        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 };
    }

    protected modelToUI(v: any): string {
        return String(v);
    }

    protected validateUIValue(ui: string): { isValid: boolean, message: string } {
        let valid = false;
        let msg: string;

        if (! isNumeric(ui)) {
            msg = "Veuillez entrer une valeur numérique";
        } else {
            valid = true;
        }

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

    protected uiToModel(ui: string) {
        return +ui;
    }
}