import { Component, Input, Output, EventEmitter, QueryList, ViewChildren, DoCheck, AfterViewInit } from "@angular/core";

import { FieldsetContainer } from "../../formulaire/fieldset-container";
import { FieldSetComponent } from "../field-set/field-set.component";
import { FieldSet } from "../../formulaire/fieldset";
import { FormulaireDefinition } from "../../formulaire/definition/form-definition";

@Component({
    selector: "fieldset-container",
    templateUrl: "./fieldset-container.component.html",
    styleUrls: [
        "./fieldset-container.component.scss"
    ]
})
export class FieldsetContainerComponent implements DoCheck, AfterViewInit {

    public get title(): string {
        if (this._container) {
            return this._container.label;
        }
    }

    public get fieldsets() {
        return this._container.fieldsets;
    }

    public get isValid() {
        return this._isValid;
    }
    @Input()
    private _container: FieldsetContainer;

    /**
     * liste des composants FieldSet enfants
     */
    @ViewChildren(FieldSetComponent)
    private _fieldsetComponents: QueryList<FieldSetComponent>;

    /**
     * flag de validité des FieldSet enfants
     */
    private _isValid = false;

    /**
     * événément de changement d'état d'un radio
     */
    // tslint:disable-next-line:no-output-on-prefix
    @Output()
    private radio = new EventEmitter<any>();

    /**
     * événément de changement de validité
     */
    @Output()
    private validChange = new EventEmitter();

    /**
     * événément de changement de valeur d'un input
     */
    @Output()
    private inputChange = new EventEmitter();

    /** événement signalant un appui sur TAB ou SHIFT+TAB */
    @Output()
    protected tabPressed = new EventEmitter<any>();

    private addStructure(after?: FieldSet) {
        if (after) {
            this._container.addFromTemplate(0, after.indexAsKid());
        } else {
            this._container.addFromTemplate(0);
        }
    }

    private onFieldsetListChange() {
        // affichage des boutons ajouter, supprimer, monter, descendre
        this._fieldsetComponents.forEach(fs => fs.showButtons = true);

        // désactivation du bouton supprimer s'il n'en reste qu'un
        if (this._fieldsetComponents.length === 1) {
            const fs = this._fieldsetComponents.last as FieldSetComponent;
            fs.enableRemoveButton = false;
        } else {
            this._fieldsetComponents.forEach(fs => fs.enableRemoveButton = true);
        }

        // désactivation du bouton monter pour le 1er
        this._fieldsetComponents.forEach(fs => {
            fs.enableUpButton = true;
            fs.enableDownButton = true;
        });
        this._fieldsetComponents.first.enableUpButton = false;

        // désactivation du bouton monter pour le dernier
        this._fieldsetComponents.last.enableDownButton = false;

        // renumérotation
        let n = 1;
        this._fieldsetComponents.forEach(fsc => {
            fsc.fieldsetNumber = n;
            n++;
        }
        );
    }

    public ngAfterViewInit() {
        this.onFieldsetListChange();
        this._fieldsetComponents.changes.subscribe(_ => this.onFieldsetListChange());
    }

    /*
     * gestion des événements clic sur les radios :
     * réception d'un message du composant enfant (field-set)
     * cf. https://angular.io/guide/component-interaction#parent-listens-for-child-event
     */
    private onRadioClick(info: any) {
        // on renvoie l'info au parent
        this.radio.emit(info);
    }

    public ngDoCheck() {
        this.updateValidity();
    }

    /**
    * calcul de la validité de tous les FieldSet de la vue
    */
    private updateValidity() {
        this._isValid = false;

        if (this._fieldsetComponents !== undefined) {
            this._isValid = this._fieldsetComponents.reduce(
                // callback
                (
                    // accumulator (valeur précédente du résultat)
                    acc,
                    // currentValue (élément courant dans le tableau)
                    fieldset,
                    // currentIndex (indice courant dans le tableau)
                    currIndex,
                    // array (tableau parcouru)
                    array
                ) => {
                    return acc && fieldset.isValid;
                }
                // valeur initiale
                , this._fieldsetComponents.length > 0);
        }

        this.validChange.emit();
    }

    /**
     * réception d'un événement de validité de FieldSet
     */
    private onFieldsetValid() {
        this.updateValidity();
    }

    /**
    * réception d'un événement de changement de valeur d'un input
    */
    private onInputChange(event: boolean) {
        this.inputChange.emit();
    }

    /**
     * relit les valeurs dans l'interface et met à jour les NgParameter
     */
    public updateParametersFromUI() {
        this._fieldsetComponents.forEach(fsc => fsc.updateParametersFromUI());
    }

    /**
     * met à jour les paramètres liés
     */
    public updateLinkedParameters() {
        this._fieldsetComponents.forEach(fsc => fsc.updateLinkedParameters());
    }

    /**
    * réception d'un événement de demande d'ajout d'un FieldSet
    */
    private onAddFieldset(fs: FieldSet) {
        this.addStructure(fs);
    }

    /**
    * réception d'un événement de demande de suppression d'un FieldSet
    */
    private onRemoveFieldset(fs: FieldSet) {
        const form = this._container.parent as FormulaireDefinition;
        form.removeFieldset(fs);
    }

    /**
    * réception d'un événement de demande de remontée d'un FieldSet
    */
    private onMoveFieldsetUp(fs: FieldSet) {
        const form = this._container.parent as FormulaireDefinition;
        form.moveFieldsetUp(fs);
    }

    /**
    * réception d'un événement de demande de descente d'un FieldSet
    */
    private onMoveFieldsetDown(fs: FieldSet) {
        const form = this._container.parent as FormulaireDefinition;
        form.moveFieldsetDown(fs);
    }

    /**
     * Renvoie l'événement au composant du dessus
     */
    public onTabPressed(event) {
        this.tabPressed.emit(event);
    }
}