import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material";
import { Inject, Component, OnInit } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { I18nService } from "../../services/internationalisation/internationalisation.service";
import { NgParameter } from "../../formulaire/ngparam";
import { ParamValueMode } from "jalhyd";
import { sprintf } from "sprintf-js";

@Component({
    selector: "dialog-edit-param-values",
    templateUrl: "dialog-edit-param-values.component.html",
    styleUrls: ["dialog-edit-param-values.component.scss"]
})
export class DialogEditParamValuesComponent implements OnInit {

    /** the related parameter to change the "variable" value of */
    public param: NgParameter;

    /** available value modes (min / max, list) */
    public valueModes: { value: ParamValueMode; label: string; }[];

    /** available decimal separators */
    public decimalSeparators: { label: string; value: string; }[];

    /** current decimal separator */
    public decimalSeparator: string;

    public valuesListForm: FormGroup;

    constructor(
        public dialogRef: MatDialogRef<DialogEditParamValuesComponent>,
        private intlService: I18nService,
        private fb: FormBuilder,
        @Inject(MAT_DIALOG_DATA) public data: any
    ) {
        this.param = data.param;

        // an explicit ReactiveForm is required for file input component
        this.valuesListForm = this.fb.group({
            file: [""],
            valuesList: [this.valuesList, [
                Validators.required,
                Validators.pattern(new RegExp(this.valuesListPattern))
            ]]
        });

        this.valueModes = [
            {
                value: ParamValueMode.MINMAX,
                label: this.intlService.localizeText("INFO_PARAMMODE_MINMAX")
            },
            {
                value: ParamValueMode.LISTE,
                label: this.intlService.localizeText("INFO_PARAMMODE_LIST")
            }
        ];
        this.decimalSeparators = [
            {
                label: this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_SEPARATEUR_POINT"),
                value: "."
            },
            {
                label: this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_SEPARATEUR_VIRGULE"),
                value: ","
            }
        ];
        this.decimalSeparator = this.decimalSeparators[0].value;
    }

    /**
     * regular expression pattern for values list validation (depends on decimal separator)
     */
    public get valuesListPattern() {
        // standard pattern for decimal separator "." : ^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$
        const escapedDecimalSeparator = (this.decimalSeparator === "." ? "\\." : this.decimalSeparator);
        const numberSubPattern = `^-?([0-9]*${escapedDecimalSeparator})?([0-9]+[Ee]-?)?[0-9]+$`;
        const re = numberSubPattern + "(" + this.separatorPattern + numberSubPattern + ")*";
        return re;
    }

    /**
     * accepted separator: everything but [numbers, E, +, -, decimal separator], any length
     */
    public get separatorPattern() {
        return "[^0-9-+Ee" + this.decimalSeparator  + "]+";
    }

    public get selectedValueMode() {
        return this.param.valueMode;
    }

    public set selectedValueMode(v) {
        this.param.valueMode = v;
    }

    public get uiTextModeSelection() {
        return this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_MODE");
    }

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

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

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

    public get uitextClose() {
        return this.intlService.localizeText("INFO_OPTION_CLOSE");
    }

    public get uitextEditParamVariableValues() {
        return this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_TITLE");
    }

    public get uitextListeValeurs() {
        return this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_VALUES_FORMAT");
    }

    public get uitextMustBeANumber(): string {
        return this.intlService.localizeText("ERROR_PARAM_MUST_BE_A_NUMBER");
    }

    public get uitextMustBeListOfNumbers() {
        return sprintf(this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_VALUES_FORMAT_ERROR"), this.separatorPattern);
    }

    public get uitextDecimalSeparator() {
        return this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_SEPARATEUR_DECIMAL");
    }

    public get uitextImportFile() {
        return this.intlService.localizeText("INFO_PARAMFIELD_PARAMVARIER_IMPORT_FICHIER");
    }

    public get isMinMax() {
        return this.param.valueMode === ParamValueMode.MINMAX;
    }

    public get isListe() {
        return this.param.valueMode === ParamValueMode.LISTE;
    }

    /**
     * renders model's numbers list as text values list (semicolon separated)
     */
    public get valuesList() {
        let baseValue;
        if (this.param.valueMode === ParamValueMode.LISTE) {
            // otherwise JalHyd model complains when reading this.param.valueList
            baseValue = this.param.valueList;
        }
        const ret = (baseValue || []).join(";");
        return ret;
    }

    /**
     * injects text values list into model's numbers list
     */
    public set valuesList(list: string) {
        const vals = [];
        const separatorRE = new RegExp(this.separatorPattern);
        const parts = list.trim().split(separatorRE);
        parts.forEach((e) => {
            if (e.length > 0) {
                // ensure decimal separator is "." for Number()
                if (this.decimalSeparator !== ".") {
                    const re = new RegExp(this.decimalSeparator, "g");
                    e = e.replace(re, ".");
                }
                vals.push(Number(e));
            }
        });
        this.param.valueList = vals;
    }

    public onFileSelected(event: any) {
        if (event.target.files && event.target.files.length) {
            const fr = new FileReader();
            fr.onload = () => {
                this.valuesList = String(fr.result);
            };
            fr.onerror = () => {
                fr.abort();
                throw new Error("Erreur de lecture du fichier");
            };
            fr.readAsText(event.target.files[0]);
        }
    }

    public onValueModeChange(event) {
        this.initVariableValues();
    }

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

    private initVariableValues() {
        // init min / max / step
        if (this.isMinMax) {
            if (this.param.minValue === undefined) {
                this.param.minValue = this.param.getValue() / 2;
            }
            if (this.param.maxValue === undefined) {
                this.param.maxValue = this.param.getValue() * 2;
            }
            let step = this.param.stepValue;
            if (step === undefined) {
                step = (this.param.maxValue - this.param.minValue) / 20;
            }
            this.param.stepValue = step;
        }
        // init values list
        if (this.isListe) {
            if (this.param.valueList === undefined) {
                if (this.param.isDefined) {
                    this.param.valueList = [ this.param.getValue() ];
                } else {
                    this.param.valueList = [];
                }
            }
        }
    }


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

      if (this.param === undefined) {
          msg = "internal error, model undefined";
      } else {
          if (!this.param.checkMin(v)) {
              msg = "La valeur n'est pas dans [" + this.param.domain.minValue + " , " + this.param.maxValue + "[";
          } else {
              valid = true;
          }
      }

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

      if (this.param === undefined) {
          msg = "internal error, model undefined";
      } else {
          if (!this.param.checkMax(v)) {
              msg = "La valeur n'est pas dans ]" + this.param.minValue + " , " + this.param.domain.maxValue + "]";
          } else {
              valid = true;
          }
      }

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

      if (! this.param) {
          msg = "internal error, model undefined";
      } else {
          if (this.param.isMinMaxValid) {
              if (!this.param.checkStep(v)) {
                  msg = "La valeur n'est pas dans " + this.param.stepRefValue.toString();
              } else {
                  valid = v > 0;
                  if (!valid) {
                      msg = "La valeur ne peut pas ĂȘtre <= 0";
                  }
              }
          } else {
              msg = "Veuillez corriger le min/max";
          }
      }

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