/* Copyright CloudLinux Zug GmbH 2010-2017 All Rights Reserved
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 */

import { FieldProperties, fieldValueType, FormatedValue, TypeOfElement } from './types';
import { TranslateClass } from './pipes/translate';
import { EventEmitter } from '@angular/core';
import { Tool } from '../model/tool';


export class Row {
    rowId: number;
    hidden: boolean = false;
    editing: boolean = false;
    tooltip: string = '';
    cells: {[id: string]: Cell};
    expand: boolean = false;
    wasExpand: boolean = false;
    hasEdit: boolean = false;
    hasError: boolean = false;
    hasStar: boolean = false;
    hasHistory: boolean = false;
    hasDeleteButton: boolean = false;
    hasMakeDefaultButton: boolean = false;
    hasDefaultLabel: boolean = false;
    hasChangeButton: boolean = false;
    hasListButton: boolean = false;
    hasInstallButton: boolean = false;
    checkedUpdated = new EventEmitter();
    isEmpty: boolean = false;
    tools: Tool[] = null;

    private _checked: boolean = false;

    public set checked(val: boolean) {
        this._checked = val;
        this.checkedUpdated.emit();
    }

    public get checked(): boolean {
        return this._checked;
    }

    private _loadingStage: boolean = false;
    public line: any;


    constructor() {
        this.cells = {};
    }

    public closeEditing() {
        this.editing = false;
    }

    public openEditing() {
        this.restoreCells();
        this.editing = true;
    }

    public restoreCells() {
        for (let cell in this.cells){
            for (let line in this.cells[cell].lines){
                this.cells[cell].lines[line].value = this.cells[cell].lines[line].initialValue;
            }
        }
    }

    public hasRowError() {
      for (let field in this.cells) {
        for (let line of this.cells[field].lines) {
          if (line.error) {
            return true;
          }
        }
      }
    }


    public resetError() {
        this.hasError = false;
    }

    set loadingStage(value: boolean) {
        this._loadingStage = value;
    }

    get loadingStage() {
        return this._loadingStage;
    }

    get maxLineCount(): number {
        let maxLines: number = 0;
        for (let cell in this.cells){
            maxLines = Math.max(maxLines, this.cells[cell].lines.length);
        }
      return maxLines;
    }

    public getLine(colName, lineNum) {
        if (this.cells[colName] && this.cells[colName].lines[lineNum]) {
            this.line = this.cells[colName].lines[lineNum];
            return this.line;
        }
        return null;
    }
}

export class Cell {
    constructor(public lines: Field[]){
        this.lines = lines;
    }

    get value(): string {
        return this.lines && this.lines[0] ? this.lines[0].getValue() : null;
    }

    set value(value) {
        if (this.lines && this.lines[0]) {
            this.lines[0].value = value;
        }
    }

    get initialValue() {
        return this.lines && this.lines[0] ? this.lines[0].initialValue : null;
    }

    set initialValue(value) {
        if (this.lines && this.lines[0]) {
            this.lines[0].initialValue = value;
        }
    }

    get hasChanged() {
        if (this.lines && this.lines[0]) {
            return this.lines[0].hasChanged;
        }
    }

}

export class Field implements FieldProperties {
    value: fieldValueType;
    altValue: string;
    stringValue: string;
    editing: boolean = false;
    hidden: boolean = false;
    paramName: string = null;
    error: boolean = false;
    requirements: Requirements[] = [];
    errorMessages: string[] = [];
    placeHolder: string;
    tooltipText: string;
    tooltipTextError: string = '';
    longText: boolean = false;
    type: TypeOfElement = 'text';
    label: string;
    unit: Unit;
    disabled: boolean = false;
    event: any;
    initialValue: string;

    /**
     * Field is only for admin. Reseller have no access to this field.
     * @type {boolean}
     */
    isProtected: boolean = false;

    constructor(params: FieldProperties) {
        for (let key of Object.keys(params)) {
            this[key] = params[key];
        }

        let value: string = ('object' === typeof this.value)
            ? (<FormatedValue>this.value).value : this.value;
        this.initialValue = value;

        if (!this.altValue) {
            this.altValue = (parseInt(value, 10) === 0) ?
                '-' : String(value);
        }
    }

    getValue(): string{
        return typeof this.value === 'object' ?
            (<FormatedValue>this.value).value : this.value;
    }

    setValue(value?: any, altValue: string = '') {
        this.value = String(value);
    }

    setPlaceHolder(value: string) {
        this.placeHolder = value;
        return this;
    }

    setTooltip(value: string) {
        this.tooltipText = value;
        return this;
    }

    bindWithParam(param: string): Field {
        this.paramName = param;
        return this;
    }

    bindWithEvent(event: any): Field {
        this.event = event;
        return this;
    }

    defineRequirements(requirements: Requirements[]): Field {
        this.requirements = requirements;
        return this;
    }

    defineType(type: TypeOfElement): Field {
        this.type = type;
        return this;
    }

    addError(errorMessage: string) {
        this.errorMessages.push(errorMessage);
    }

    setLongText(value: boolean): Field {
        this.longText = value;
        return this;
    }

    setLabel(label: string) {
        this.label = label;
        return this;
    }

    setUnit(unit: Unit) {
        this.unit = unit;
        return this;
    }

    resetErrors() {
        this.errorMessages = [];
        this.error = false;
        this.tooltipTextError = '';
    }

    setProtected() {
        this.isProtected = true;
        return this;
    }

    get hasChanged(){
        return this.initialValue !== (this.value.hasOwnProperty('rawValue')
            ? (<FormatedValue>this.value).value : this.value);
    }
}

export interface Requirements {
    /** Method of validation. */
    m: any;
    /** Additional params */
    p?: any[];
}

interface Unit {
    current: string;
    set?: {'val': string, title: string}[];
}
