/* Copyright CloudLinux Zug GmbH 2010-2017 All Rights Reserved
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 */
import {Exclude, Expose} from 'class-transformer';
import { PlainToClass } from './decorator';
import { Helper } from '../utils/helper';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';

export class NodeJSInformation {
    selector_enabled: boolean = false;
    default_version: string = '';
    /**
     * Success or string with error
     */
    result: string = '';
    cache_status: CacheStatus = 'ready';

    private _versions: {[number: string]: Version} = {};

    public set versions(value: {[number: string]: Version}) {
        for (let version in value) {
            value[version].majorNumber = version.split('.')[0];
        }
        Helper.convertDictToClass(value, Version);
        this._versions = value;
    }

    @Expose({ name: 'available_versions' })
    public get versions(): {[number: string]: Version} {
        return this._versions;
    }

    public getVersionList() {
        return Object.keys(this.versions).map(version => version);
    }

    public getFullDefaultVersion() {
        return Object.keys(this.versions).find(
            version => this.versions[version].majorNumber === this.default_version
        );
    }

    public getEnabledVersion(): string[] {
        return Object.keys(this.versions).filter((version) => {
            return this.versions[version].status === 'enabled';
        }).map(version => version);
    }

    public getDisabledVersion(): string[] {
        return Object.keys(this.versions).filter((version) => {
            return this.versions[version].status === 'disabled';
        }).map(version => version);
    }

    public getInstalledVersion(): string[] {
        return this.getEnabledVersion().concat(this.getDisabledVersion());
    }

    public getListOfVersions() {
        return Object.keys(this.versions).map(version => ({
            id: version,
            status: this.versions[version].enabled ? 'enabled' : 'disabled'
        }));
    }

    public getNotInstalledVersion() {
        return Object.keys(this.versions).filter((version) => {
            return this.versions[version].status === 'not_installed';
        }).map(version => version);
    }

    public hasVersion(versionName) {
        return this.versions.hasOwnProperty(versionName);
    }

    public hasVersions(): boolean {
        return !!Object.keys(this.versions).length;
    }

    public isCacheUpdating() {
        return this.cache_status === 'updating';
    }
}

export class Version {
    name_modifier: string = '';
    base_dir: string = '';
    enabled: boolean;
    installed: boolean;
    notInstalled: boolean;
    installing: boolean;
    removing: boolean;

    public set majorNumber(value: string) {
        this._majorNumber = value;
        for (let userKey in this.users){
            this.users[userKey].majorNodeJSVersion = value;
        }
    }

    public get majorNumber(): string {
        return this._majorNumber;
    }

    private _majorNumber: string;

    private _status: VersionStatus = 'disabled';
    private _users: {[username: string]: UserInfo} = {};

    public set users(value: {[username: string]: UserInfo}) {
        Helper.convertDictToClass(value, UserInfo);
        this._users = value;
    }

    public get users(): {[username: string]: UserInfo} {
        return this._users;
    }

    public set status(status: VersionStatus) {
        this._status = status;
        this.enabled = (status === 'enabled' || status === 'disabled')
            ? status === 'enabled' : false;
        this.installed = (status === 'enabled' || status === 'disabled');
        this.notInstalled = (status === 'not_installed');
        this.installing = (status === 'installing');
        this.removing = (status === 'removing');
    }

    public get status(): VersionStatus {
        return this._status;
    }

    get appCount(): number {
        let count = 0;
        Object.keys(this.users).forEach((user) => {
            count += this.users[user].count;
        });
        return count;
    }

    public hasUser(userName) {
        return this.users.hasOwnProperty(userName);
    }
}

export class UserInfo {
    homedir: string = '';

    private _majorNodeJSVersion: string;
    private _applications: {[path: string]: Application} = {};

    public get majorNodeJSVersion(): string{
        return this._majorNodeJSVersion;
    }

    public set majorNodeJSVersion(value: string) {
        this._majorNodeJSVersion = value;
        for (let appKey in this.applications){
            this.applications[appKey].majorNodeJSVersion = value;
        }
    }

    public set applications(value: {[path: string]: Application}) {
        Helper.convertDictToClass(value, Application);
        this._applications = value;
    }

    public get applications(): {[path: string]: Application} {
        return this._applications;
    }

    get count(): number {
        return Object.keys(this.applications).length;
    }

    public hasApplication(appName) {
        return this.applications.hasOwnProperty(appName);
    }
}

export class Application {
    get domain(): string {
        return this._domain;
    }

    set domain(value: string) {
        if (this._domain !== value) {
            this._domain = value;
            this.changeEvent.next();
        }
    }
    get env_vars(): EnvObject {
        return this._env_vars;
    }

    set env_vars(value: EnvObject) {
        if (this._env_vars !== value) {
            this._env_vars = value;
            this.changeEvent.next();
        }
    }
    get app_status(): AppStatus {
        return this._app_status;
    }

    set app_status(value: AppStatus) {
        if (this._app_status !== value) {
            this._app_status = value;
            this.changeEvent.next();
        }
    }
    get startup_file(): string {
        return this._startup_file;
    }

    set startup_file(value: string) {
        if (this._startup_file !== value) {
            this._startup_file = value;
            this.changeEvent.next();
        }
    }

    get app_mode(): AppMode {
        return this._app_mode;
    }

    set app_mode(value: AppMode) {
        if (this._app_mode !== value) {
            this._app_mode = value;
            this.changeEvent.next();
        }
    }
    get app_uri(): string {
        return this._app_uri;
    }

    set app_uri(value: string) {
        if (this._app_uri !== value) {
            this._app_uri = value;
            this.changeEvent.next();
        }
    }

    get appName(): string {
        return this._appName;
    }

    set appName(value: string) {
        if (this._appName !== value) {
            this._appName = value;
            this.changeEvent.next();
        }
    }

    @Exclude()
    public onChange: Observable<any>;
    majorNodeJSVersion: string;
    config_files: string[] = [];
    @Exclude()
    private changeEvent = new Subject<any>();
    private _version: string;
    private _appName: string = '';
    private _app_uri: string = '';
    private _app_mode: AppMode = '';
    private _startup_file: string = '';
    private _app_status: AppStatus = '';
    private _env_vars: EnvObject = {};
    private _domain: string = '';

    constructor() {
        this.onChange = this.changeEvent.asObservable();
    }

    /**
     * Major NodeJS version.
     */

    public set version(version: string) {
        this._version = version;
        if (typeof version === 'string' && version.includes('.')) {
            this.majorNodeJSVersion = version.split('.')[0];
        }
        this.changeEvent.next();
    }

    public get version(): string {
        return this._version;
    }

    public get isStarted(): boolean {
        return this._app_status === 'started';
    }

    public get appNameEncoded(): string {
        return encodeURIComponent(this._appName);
    }
}

export type EnvObject = { [name: string]: string };
export type SelectorStatus = 'enabled' | 'disabled';
export type VersionStatus = 'enabled' | 'disabled' | 'not_installed' | 'installing' | 'removing';
export type AppStatus = 'started'| 'stopped'| '';
export type AppMode = 'development' | 'production' | '';
export type ApplicationCommand = 'start' | 'stop' | 'restart' | 'create'
    | 'destroy' | 'install-modules' | 'read-config';
export type CacheStatus = 'ready' | 'updating';
