import { Component, Input, Output, EventEmitter, ViewChild, AfterViewChecked, OnChanges } from "@angular/core";

import { ParamValueMode } from "jalhyd";

import { InternationalisationService } from "../../services/internationalisation/internationalisation.service";
import { NgParameter } from "../../formulaire/ngparam";
import { NgParamMinComponent } from "./ngparam-min.component";
import { NgParamMaxComponent } from "./ngparam-max.component";
import { NgParamStepComponent } from "./ngparam-step.component";
import { BaseComponent } from "../base/base.component";
import { ValueListComponent } from "./value-list.component";

@Component({
    selector: "param-values",
    templateUrl: "./param-values.component.html",
    styles: [
        `.btn-on {
            color:#505050;
            border: 3px solid #505050;
            background-color:white;
            text-transform: uppercase;
            font-size: 0.8em;
        }`,
        `.btn-off {
            color:white;
            border: 3px solid #505050;
            background-color:#505050;
            text-transform: uppercase;
            font-size: 0.8em;
        }`
    ]
})
export class ParamValuesComponent extends BaseComponent implements AfterViewChecked, OnChanges {
    @Input()
    private param: NgParameter;

    private _valueModes = [];

    /**
     * true quand les champs du composant et de ses enfants sont initialisés
     */
    private _initCompleted = false;

    /**
     * true si la valeur min est valide
     */
    private _validMin = false;

    /**
     * true si la valeur max est valide
     */
    private _validMax = false;

    /**
     * true si la valeur du pas est valide
     */
    private _validStep = false;

    /**
     * true si la liste de valeurs est valide
     */
    private _validList = false;

    /**
     * flag signalant qu'il faut initialiser le composant ValueListComponent (par ex quand on a sélectionné le mode "liste")
     */
    private _doInitList = false;

    /**
     * flag signalant qu'il faut initialiser les composants min/max/pas
     */
    private _doInitMinmax = false;

    /**
     * composant de saisie du minimum
     */
    @ViewChild(NgParamMinComponent)
    private _minComponent: NgParamMinComponent;

    /**
     * composant de saisie du maximum
     */
    @ViewChild(NgParamMaxComponent)
    private _maxComponent: NgParamMaxComponent;

    /**
     * composant de saisie du pas de variation
     */
    @ViewChild(NgParamStepComponent)
    private _stepComponent: NgParamStepComponent;

    /**
     * composant de saisie d'une liste de valeurs
     */
    @ViewChild(ValueListComponent)
    private _listComponent: ValueListComponent;

    @Output()
    private valid: EventEmitter<boolean>;

    constructor(private intlService: InternationalisationService) {
        super();
        this._valueModes.push({ "value": ParamValueMode.MINMAX, "label": "Min/max" });
        this._valueModes.push({ "value": ParamValueMode.LISTE, "label": "Liste" });
        this.valid = new EventEmitter();
    }

    /**
     * init des champs min/max/pas
     */
    private initMinMaxStep() {
        if (this.isMinMax && this._doInitMinmax) {
            this._doInitMinmax = false;

            // valeur pour min : celle déjà définie ou celle déduite de la valeur saisie
            let min: number = this.param.minValue;
            if (min === undefined) {
                min = this.param.getValue() / 2;
            }

            // valeur pour max : celle déjà définie ou celle déduite de la valeur saisie
            let max: number = this.param.maxValue;
            if (max === undefined) {
                max = this.param.getValue() * 2;
            }

            this.param.minValue = min;
            this._minComponent.model = this.param;

            this.param.maxValue = max;
            this._maxComponent.model = this.param;

            // valeur du pas
            let step = this.param.stepValue;
            if (step === undefined) {
                step = (max - min) / 20;
            }
            this.param.stepValue = step;
            this._stepComponent.model = this.param;

            this.validateAll();

            this._validMin = this._minComponent.isValid;
            this._validMax = this._maxComponent.isValid;
            this._validStep = this._stepComponent.isValid;
            this.emitValidity();

            this._initCompleted = true;
        }
    }

    /**
     * initialisation de la liste de valeurs avec celle du paramètre géré
     */
    private initList() {
        if (this._doInitList && this._listComponent !== undefined) {
            this._doInitList = false;
            let l = this.param.valueList;
            if (l === undefined) {
                if (this.param.isDefined) {
                    l = [this.param.getValue()];
                } else {
                    l = [];
                }
            }

            this.param.valueList = l;
            this._listComponent.model = this.param;
        }
    }

    /**
     * revalidation de tous les composants enfants
     */
    private validateAll() {
        if (this._minComponent !== undefined) {
            this._minComponent.validate();
        }
        if (this._maxComponent !== undefined) {
            this._maxComponent.validate();
        }
        if (this._stepComponent !== undefined) {
            this._stepComponent.validate();
        }
        if (this._listComponent !== undefined) {
            this._listComponent.validate();
        }
    }

    /**
     * envoi d'un événement de validité
     */
    private emitValidity() {
        switch (this.param.valueMode) {
            case ParamValueMode.LISTE:
                this.valid.emit(this._validList);
                break;

            case ParamValueMode.MINMAX:
                this.valid.emit(this._validMin && this._validMax && this._validStep);
                break;
        }
    }

    /**
     * réception d'un événement de NgParamMinComponent
     */
    private onMinChanged(event: any) {
        if (this._initCompleted) {
            switch (event.action) {
                case "model":
                    this.validateAll();
                    break;

                case "valid":
                    this._validMin = event.value;
                    this.emitValidity();
                    break;
            }
        }
    }

    /**
     * réception d'un événement de NgParamMaxComponent
     */
    private onMaxChanged(event: any) {
        if (this._initCompleted) {
            switch (event.action) {
                case "model":
                    this.validateAll();
                    break;

                case "valid":
                    this._validMax = event.value;
                    this.emitValidity();
                    break;
            }
        }
    }

    /**
     * réception d'un événement de NgParamStepComponent
     */
    private onStepChanged(event: any) {
        if (this._initCompleted) {
            switch (event.action) {
                case "model":
                    this.validateAll();
                    break;

                case "valid":
                    this._validStep = event.value;
                    this.emitValidity();
                    break;
            }
        }
    }

    /**
     * réception d'un événement de ValueListComponent
     */
    private onListChanged(event: any) {
        if (this._initCompleted) {
            switch (event.action) {
                case "model":
                    this.validateAll();
                    break;

                case "valid":
                    this._validList = event.value;
                    this.emitValidity();
                    break;
            }
        }
    }

    private get uitextValeurMini() {
        return this.intlService.localizeText("INFO_PARAMFIELD_VALEURMINI");
    }

    private get uitextValeurMaxi() {
        return this.intlService.localizeText("INFO_PARAMFIELD_VALEURMAXI");
    }

    private get uitextPasVariation() {
        return this.intlService.localizeText("INFO_PARAMFIELD_PASVARIATION");
    }

    /**
     * true si mode "liste de valeurs"
     */
    public get isList(): boolean {
        return this.param.valueMode === ParamValueMode.LISTE;
    }

    /**
     * true si mode "lié"
     */
    public get isLink(): boolean {
        return this.param.valueMode === ParamValueMode.LINK;
    }

    /**
     * true si mode "min/max/pas"
     */
    public get isMinMax(): boolean {
        return this.param.valueMode === ParamValueMode.MINMAX;
    }

    /**
     * valeur courante affichée dans le select min-max/list
     */
    public get currentModeSelectLabel(): string {
        return ParamValueMode[this.param.valueMode];
    }

    /**
     * réception d'un événement du menu "min/max/liste"
     */
    public onSelectValueMode(event: any) {
        const next = event.target.value;

        switch (next) {
            // on a sélectionné "min/max" ?
            case ParamValueMode.MINMAX:
                this._doInitMinmax = true;
                break;

            // on a sélectionné "liste" ?
            case ParamValueMode.LISTE:
                this._doInitList = true;
                break;

            default:
                throw new Error("valeur " + next + " de ParamValueMode non prise en charge");
        }

        this.param.valueMode = next;
    }

    public get valueModes() {
        return this._valueModes;
    }

    /**
     * appelé quand les @Input changent
     */
    ngOnChanges() {
        if (this.isMinMax) {
            this._doInitMinmax = true;
        } else {
            this._doInitList = true;
        }
    }

    ngAfterViewChecked() {
        super.ngAfterViewChecked();
        this.initMinMaxStep();
        this.initList();
    }
}