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

import {
    Component, AfterViewInit, DoCheck, ChangeDetectorRef,
    ViewChildren, QueryList
} from '@angular/core';
import { Cell } from './utils/row';
import { XHR } from './utils/xhr';
import { ConfigRepo } from './repository/config_repo';
import { Config, OptionResponse } from './model/config';
import { Validator } from './utils/validator';
import { BaseComponent } from './utils/base_component';
import { NotificationsService } from './services/notifiaction_service';
import { AppState } from './app.service';
import { UiSelectOption } from './utils/ui-elements/ui-select/ui-select';
import { FeText } from './utils/ui-elements/form-elements/fe-text/fe-text';
import { UiAccordionGroup } from './utils/ui-elements/ui-accordion-group/ui-accordion-group';
import { LoaderSelector } from './utils/loader';

declare const panelName: any;

@Component({
    selector: '.options_block',
    template: require('./../templates/options.component.html'),
    styles: [
        require('../styles/options.component.less'),
    ],
    providers: [XHR, ConfigRepo]
})
export class OptionsComponent extends BaseComponent implements AfterViewInit, DoCheck {
    @ViewChildren(UiAccordionGroup) uiAccordionComponents: QueryList<UiAccordionGroup>;
    get filterField(): string {
        return this._filterField;
    }

    set filterField(value: string) {
        value = String(value);
        this._filterField = value;
        this.filterPanelsByText(value);
        this.appState.set('options.highlightPhrase', value);
    }

    public rows: OptionRow[];
    public hasError: boolean = false;
    public panel: string = panelName;
    public disabledByOperationOff: boolean = false;
    public disabledByModePeriod: boolean = false;
    public disabledByModeLimit: boolean = false;
    public isReseller = this.appState.get('isReseller');
    public isAdmin = this.appState.get('isAdmin');
    public isElementsForValidationDetected: boolean = false;
    public optionsIsHidden: boolean = false;

    @ViewChildren(FeText) feTextList: QueryList<FeText>;

    private _filterField: string = '';

    private _config: OptionResponse = null;

    private defaultConfig: OptionResponse = {
        "faultsNotification": {
            "faultsToInclude": {
                "concurrentConnections": false,
                "cpu": true,
                "mem": true,
                "nproc": false
            },
            "minimumNumberOfFaultsToNotify": {
                "customer": 1,
                "reseller": 1
            },
            "notify": {
                "customer": {
                    "period": 12,
                    "unitOfTime": "hours"
                },
                "reseller": {
                    "period": 12,
                    "unitOfTime": "hours"
                }
            },
            "notifyCustomers": false,
            "notifyReseller": true,
            "notifyResellerOnCustomers": true
        }
    };

    public get config(): OptionResponse {
        // return this._config;
        return (this._config === null) ? this.defaultConfig : this._config;
    }
    public set config(value: OptionResponse) {
        if (this.appState.get('isReseller') && Object.keys(value).length === 0) {
            this._config = this.defaultConfig;
        } else {
            this._config = value;
        }
    }
   public faultsToIncludeList = [
      ['cpu', 'SPEED'],
      ['io', 'IO'],
      ['iops', 'IOPS'],
      ['mem', 'Memory'],
      ['concurrentConnections', 'Concurrent connections'],
      ['nproc', 'NPROC']
    ];

    public logFormatList: UiSelectOption[] = [
      {'id': 'SHORT', 'caption': 'Short'},
      {'id': 'MEDIUM', 'caption': 'Medium'},
      {'id': 'LONG', 'caption': 'Long'},
      {'id': 'VERY LONG', 'caption': 'Very Long'}
    ];

    public errorLogLevelList: UiSelectOption[] = [
      {'id': 'ERROR', 'caption': 'Error'},
      {'id': 'DEBUG', 'caption': 'Debug'}
    ];

    constructor(
        private configRepo: ConfigRepo,
        private notifictions: NotificationsService,
        private chRef: ChangeDetectorRef,
        public appState: AppState
    ) {
      super();
      this.loaderSelector = new LoaderSelector('.options_component');
    }

    filterPanelsByText(text: string = '') {
        let panels = this.uiAccordionComponents.toArray();
        this.optionsIsHidden = true;
        panels.forEach(panel => {
            if (!!text && text.length >= 3) {
                panel.hidden = !panel.filterByText(text.toLowerCase());
            } else {
                panel.hidden = !panel.filterByText('');
            }
            this.optionsIsHidden = this.optionsIsHidden && panel.hidden;
        });
    }

    ngAfterViewInit() {
        this.load();
        this.feTextList.changes.subscribe(() => {
            if (this.feTextList.length > 0) {
                this.isElementsForValidationDetected = true;
            }
        });
    }

    async load() {
        this.loading = true;
        try {
            this.config = (await this.configRepo.getConfig()).options;
            this.processGovernorSettings();
        } catch (e) {
            this.config = null;
            this.chRef.detectChanges();
        } finally {
            this.loading = false;
        }
    }

    save() {
    this.loading = true;
    let options = JSON.stringify({'options': this.config});
    this.configRepo.saveConfig(options).then(() => {
      this.loading = false;
      this.configRepo.getConfig().then((data: Config) => {
        this.config = data.options;
        this.processGovernorSettings();
        this.notifictions.success('Success', 'Options successfully saved!');
      });
    });
    }

    /**
     * @todo: remove if it will not used until next release
     * @deprecated
     */
    controlNotifyCustomers() {
      if (this.hasConfig('faultsNotification.notifyResellerCustomers'))
        this.config.faultsNotification.notifyResellerCustomers = false;
    }

    elementEvent(event: any) {
        event.call();
    }

    resetInodeLimits() {
        let self = this;
        this.configRepo.resetInodesLimit().then((data: any) => {
          self.notifictions.success('Success', 'Inode limits was reset successfully!');
        });
    }

    public processGovernorSettings() {
        if (!this.config.hasOwnProperty('mySQLGovSettings')) return;

        if (['off', 'all'].includes(this.config['mySQLGovSettings']['modeOfOperation'])) {
            this.disabledByOperationOff = true;
        } else {
            this.disabledByOperationOff = false;
            this.disabledByModePeriod =
                (this.config['mySQLGovSettings']['restrictType']['mode'] === 'period');
            this.disabledByModeLimit = !this.disabledByModePeriod;
        }
    }

    public ngDoCheck() {
        if (this.isElementsForValidationDetected) {
            this.hasError = this.detectFormError();
        }
    }

    private detectFormError(): boolean {
        return this.feTextList.some((item) => {
            let validator: Validator = item.innerUiText.validator;
            return validator.error;
        });
    }

    private hasConfig(key) {
        let keys = key.split('.');
        let checkObj = this.config;
        while (checkObj.hasOwnProperty(keys[0])) {
            checkObj = checkObj[keys[0]];
            keys.shift();
            if (keys.length === 0) return true;
        }
        return false;
    }

}

class OptionRow {
    constructor(public title: Cell, public value?: Cell) { }
}
