import { OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Http } from '@angular/http';
// import { MessageService, Message } from "primeng/api";
import { MessageService, SelectItem } from 'node_modules/primeng/api';
import { ConfirmationService } from 'node_modules/primeng/api';
import { BaseService } from '../baseclass/BaseService';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { Observable, BehaviorSubject, Subscription } from 'rxjs';
import { AuthService } from '../auth/auth.service';
import { RequireInteractiveControl } from '../interface/Interactive Component/RequireInteractiveControl';
import { WebNotificationService } from '../auth/webNotification.service';
import { ConnectionIndicationService } from '../auth/ConnectionIndication.service';
import { RequireOcList } from '../interface/Interactive Component/RequireOc';
import { LocalContainerObject } from '../interface/Interactive Component/LocalContainerObject';
import { FormGroup } from '@angular/forms';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { formatDate, Location } from '@angular/common';
import { FieldHasAuditTrailClass } from 'ekangularbase/src/interface/field-has-audit-trial';
import { EtableColumn } from 'ekangularbase/src/interface/EtableColumn';
import { EntityStatus } from 'ekangularbase/src/interface/entity-status';
import { LookupItem } from 'ekangularbase/src/interface/lookUpItem';
import { filter } from 'rxjs/operators';
import * as moment from 'moment';
import { EtableFunction } from 'ekangularbase/src/interface/EtableFunction';
import { Dialog } from 'primeng/dialog';
import * as CryptoJS from 'crypto-js';

export class BaseComponent<T extends RequireInteractiveControl> implements OnInit, OnDestroy {

    readonly AES_SALT_KEY = 'a#}^895kmh)FGST^';
    readonly AES_IV_KEY = 'GP!kRrn7`TE9:HZ~';

    yearRange = '1900:2999';
    minimumDate: Date = new Date('1900-01-01T00:00:00');
    maximumDate: Date = new Date('2999-12-31T00:00:00');

    detectRefresSubscription: Subscription;
    detectBackSubscription: Subscription;
    totalDropdownSubscription: Subscription;

    totalDropdown: number;
    totalDropdownChange: BehaviorSubject<number>;
    listServiceDoneChange: BehaviorSubject<boolean>;

    public MAX_LENGTH_INT: string;
    public MAX_LENGTH_DEC: string;
    public MAX_LENGTH_STR: string;
    public MAX_LENGTH_SINT: string;

    @BlockUI() baseblockUI: NgBlockUI;
    userform: FormGroup;
    displayDialog: boolean;
    public mode: string;
    public baseu: string;
    public generalhttp: Http;
    public loading = false;
    public selectedObject: T;
    public objectlist: T[];
    public obvobjlist: BehaviorSubject<T[]>;
    public isnewobject: boolean;
    public classObj: any;

    public footerObjectlist: any[];
    public footerColumns: any[];
    public colHeader: any[];
    public cols: EtableColumn[] = [];
    public func: EtableFunction[] = [];

    firstLoadComplete: boolean;

    public isDataFinishLoaded = false;

    SelectedOcChangedSubscription: Subscription;
    objHasAuditField: FieldHasAuditTrailClass[];

    //   public  actionitems:string[] =["Insert","Delete","Update"];
    constructor(
        public confirmationService: ConfirmationService,
        public webNotificationservice: WebNotificationService
        , public messageService: MessageService
        , public objectservice: BaseService<T>
        , public objectname: string
        , public authService: AuthService
        , public routerNav?: Router
        , public actionitems: string[] = ['Insert', 'Delete', 'Update']
        , public blockUiControl: boolean = false
        , public SelectedOcChanged: boolean = false
        , public locationNav?: Location
        , public route?: ActivatedRoute
    ) {
        this.obvobjlist = new BehaviorSubject<T[]>([]);

        this.MAX_LENGTH_INT = '11';
        this.MAX_LENGTH_DEC = '22'; // default 2 decimal place. if 5 decimal use {{MAX_LENGTH_DEC+3}}
        this.MAX_LENGTH_STR = '200';
        this.MAX_LENGTH_SINT = '4';

        this.loading = false;
        this.isDataFinishLoaded = false;
        this.detectNavigation();

        this.totalDropdown = 0;
        this.totalDropdownChange = new BehaviorSubject(0);
    }

    detectNavigation() {
        this.routerNav.events
        .pipe(filter((rs): rs is NavigationEnd => rs instanceof NavigationEnd))
        .subscribe(event => {
        if (
            event.id === 1 &&
            event.url === event.urlAfterRedirects
        ) {
            console.log('browser Refresh');
            this.ResetFlagAndRedirectToHome();
        }
        });
    }

    ngOnInit(): void {
        const callback = (data: any, typestr: string): void => { this.OnReceiveUpdate(data); };
        this.webNotificationservice.on(callback, this.objectname);

        // ConnectionIndicationService.ConnectionStatusChanged.subscribe(online => {
        //     if (online) {
        //         this.list();
        //     }
        // });

          this.SelectedOcChangedSubscription = this.authService.SelectedOcChanged.subscribe(currentOC => {
            this.OcChangeAction(currentOC);
        });

        this.baseOnInit();

        if (!this.checkUrl()) {
            console.log('redirect to home page');
            // return;
        }

    }

    baseOnInit() {}

    checkUrl(): boolean {
        console.log('routerNav');
        console.log(this.routerNav.url);
        console.log(this.authService.currentSidebarMenu);
        if (this.authService.currentSidebarMenu && this.authService.currentSidebarMenu.length > 0
            && this.routerNav.url && this.routerNav.url !== '/') {
                const indexSlash = this.routerNav.url.indexOf('/', 1);

                let curUrl = this.routerNav.url;

                if (indexSlash !== -1) { curUrl = curUrl.substr(0, indexSlash); }

                const i = curUrl.indexOf('?');
                if (i === -1) {
                    const m = this.authService.currentSidebarMenu.find(s => s.routerLink === curUrl);

                    if (!m) {
                        console.log('url not found');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    }
                } else {
                    const preUrl = curUrl.substr(0, i);

                    const menus = this.authService.currentSidebarMenu.filter(s => s.routerLink === preUrl);
                    console.log(menus);

                    if (!menus || menus.length === 0) {
                        console.log('url not found');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    }

                    let found = false;

                    const queryParams = curUrl.substr(i + 1, curUrl.length - i - 1);

                    const queryParam = queryParams.split(',');

                    // queryParam.forEach(q => {
                    //     q = '\"' + q.replace('=', '\":\"') + '\"';
                    // });

                    menus.forEach(menu => {
                        queryParam.forEach(q => {
                            menu.queryParams = menu.queryParams.replace(/:/g, '=');
                            menu.queryParams = menu.queryParams.replace(/"/g, '');

                            const iq = menu.queryParams.indexOf(q);

                            if (iq !== -1) {
                                found = true;
                            }
                        });
                    });

                    if (!found) {
                        console.log('url not found');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    }

                }
        }

        return true;
    }

    ResetFlagAndRedirectToHome() {
        if (this.authService.isRedirect === true) {
            console.log('redirect ResetFlagAndRedirectToHome cancel', this.routerNav.url);
            this.authService.isRedirect = false;
            return;
        }
        // const indexSlash = this.routerNav.url.indexOf('?type=excep&');
        // if (indexSlash !== -1) {
        //     console.log('redirect ResetFlagAndRedirectToHome cancel excep', this.routerNav.url);
        //     // this.authService.isRedirect = false;
        //     return;
        // }
        console.log('ResetFlagAndRedirectToHome', this.routerNav.url);
        this.authService.ResetFlag();
        this.routerNav.navigate(['']);
    }

    OcChangeAction(currentOC) {
        if (this.authService.previousOC == null) {
            this.authService.previousOC = currentOC;
            this.ResetFlagAndRedirectToHome();
            return;
        } else if ((this.authService.previousOC !== currentOC)) {
            this.authService.previousOC = currentOC;
            this.ResetFlagAndRedirectToHome();
            return;
        }

        if (this.authService.getById) { // input page
            this.baseblockUI.start('Loading...');
            this.objectservice.GetById(this.objectservice.data['id']).subscribe(res => {
               this.authService.getById = false;
                if (res == null) {
                    this.messageService.add({ severity: 'Info', summary: 'Info',
                    detail: 'Object not found' });
                    this.ResetFlagAndRedirectToHome();
                }

                this.selectedObject = res;
                this.baseblockUI.stop();
                this.ngOnInitLocal();
            });
        } else { // listing page
            if (this.authService.previousOC !== currentOC) { // change oc
                if (this.authService.pageName === 'Input') {
                    this.authService.ResetFlag();
                    this.authService.pageName = 'List';
                    this.routerNav.navigate(['']);
                } else {
                    this.authService.previousOC = currentOC;
                    this.ngOnInitLocal();
                    this.GetList();
                }
            } else {
                if (this.authService.isEstimateEntryLoaded) {
                    this.validateEstimateEntryId();
                } else {
                    this.ngOnInitLocal();
                    if (this.authService.pageName !== 'Input') {
                        this.GetList();
                    }
                }
            }
        }
    }

    ngOnDestroy() {
        if (this.SelectedOcChangedSubscription !== undefined) {
            this.SelectedOcChangedSubscription.unsubscribe();
        }
        this.webNotificationservice.off();
        if (this.blockUiControl) {
            this.baseblockUI.stop();
        }
        this.objectlist = [];
    }

      ngOnInitLocal() { }

    validateEstimateEntryId() {
        this.ngOnInitLocal();
    }
    GetList() {
        this.list();
    }

    list() {
        if (this.blockUiControl) {
            this.baseblockUI.start('Loading List...');
        }

        this.loading = true;
        this.objectservice.Get().subscribe(obj => {
            console.log(obj);
            this.objectlist = obj;
            this.obvobjlist.next(obj);
            this.baseblockUI.stop();
            this.loading = false;
            if (this.blockUiControl) {
                this.baseblockUI.stop();
            }
            this.cols.forEach(s => {
                if (s.isSubObject) { s.sortFeild = s.field + '.' + s.subField; }
            });
            // console.log(this.cols);

            this.isDataFinishLoaded = true;
            this.dataFinishLoaded();
        }, error => {
            console.error(error);
            this.loading = false;
        }
        );
    }

    dataFinishLoaded() {
        const event = {};
        event['selectAllCheckBox'] = false;
        console.log('dataFinishLoaded v2', event);
        this.detectChanges(event);
    }

    detectChanges(event = null) {}

    checkPermission(claim: string): boolean {
        return this.authService.hasPermissions(claim);
    }

    instanceOfRequireOcList(object: any): object is RequireOcList {
        return 'ocStrList' in object;
    }
    OnReceiveUpdate(lco: LocalContainerObject) {
        console.log(lco);
        // this.messageService.add({severity:'Info', summary:'Info', detail:lco.objectUniqueId});
        if (lco.ocList != null && lco.ocList.length > 0) {
            if (!lco.ocList.some(s => s == this.authService.getSelectedOc())) {
                return;
            }
        }
        if (this.selectedObject != null && lco.objectUniqueId == this.selectedObject.id) {
            // var actionitems:string[] =["Insert","Delete","Update"];
            if (this.actionitems.includes(lco.action)) {
                this.messageService.add({ severity: 'Info', summary: 'Info', detail: 'The list will updated, please close dialog' });
                this.list();
                this.selectedObject.isLocked = true;
            }
        } else {
            // var actionitems:string[] =["Insert","Delete","Update"];
            if (this.actionitems.includes(lco.action)) {
                this.messageService.add({ severity: 'Info', summary: 'Info', detail: 'The list is updated, system will now refresh' });
                this.list();
            }

        }
    }




    onRowClickEtable(event) {
        // console.log(event);
        this.onRowSelect(event.row, event.field);
    }

    onRowSelect(event: any, field: string) {

        switch (field) {
            case 'onRowSelect': { // for user management
                this.edit(event);
                break;
            }
            case 'deleteRecord': { // for user management
                this.deleteRecord(event);
                break;
            }
            case 'onEdit': {
                this.onRowEdit(event);
                break;
            }
            case 'onDelete': {
                this.onRowDelete(event);
                break;
            }
            case 'onRestore': {
                this.onRowRestore(event);
                break;
            }
            case 'onActivate': {
                this.onActivate(event);
                break;
            }
            default: {
                console.log('Invalid choice');
                break;
            }
        }

    }

    onActivate(row: T) {
        let status = '';

        if (row['entityStatus'] === EntityStatus.Active) { status = 'Deactivate';
        } else { status = 'Activate'; }

        this.confirmationService.confirm({
            message: 'Do you want to ' + status + ' selected record?',
            header: 'Confirmation',
            icon: 'pi pi-info-circle',
            accept: () => {
                this.onActivationExe(status, row);
            },
            reject: () => {
            }
        });
    }

    onActivationExe(status: string, row: T) {
        this.baseblockUI.start(status + ' List...');
        this.loading = true;

        let entityStatus = '';

        if (status === 'Activate') { entityStatus = EntityStatus.Active;
        } else { entityStatus = EntityStatus.InActive; }

        this.objectservice.ActivateContent(entityStatus, row.id).subscribe(res => {
            this.baseblockUI.stop();
            this.loading = false;
            // this.selectAllIsChecked = false;
            this.list();

            if (res.synced) {
                this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Row are ' + status });
            } else {
                this.messageService.add({ severity: 'Info', summary: 'Info', detail: 'Some Row are not ' + status });
            }
        });
    }

    onRowRestore(row: T) {}

    onRowAdd() {
        this.onRowAddUpdateObject();
        this.objectservice.isAdd = true;
        this.routerNav.navigate(['input'], { relativeTo: this.route });
    }

    onRowAddUpdateObject() {
    }

    onRowEditUpdateObject(row: T) {
    }

    onRowEdit(row: T) {
        this.onRowEditUpdateObject(row);
        this.objectservice.data = row;
        this.objectservice.isAdd = false;
        this.authService.getById = true;
        this.routerNav.navigate(['input'], { relativeTo: this.route });
    }

    getErrorSubMessage() {
        return { columnName: '', messageText: '' };
    }

    onRowDelete(row): void {
        this.selectedObject = row;
        const event = {};
        event['name'] = 'onDelete';
        event['data'] = row;
        this.detectChanges(event);
        this.confirmationService.confirm({
            message: 'Do you want to delete this record?' +
            this.subMessage(this.getErrorSubMessage().columnName, this.getErrorSubMessage().messageText),
            header: 'Delete Confirmation',
            icon: 'pi pi-info-circle',
            accept: () => {
                this.exeDeleteAction();
            }
        });
    }

    subMessage(columnName: string, messageText: string): string {
        try {
            if (!columnName || columnName === '') { return ''; }
            const msg = messageText.substring(0, 50);
            const ellipsis = messageText.length > msg.length ? '...' : '';
            return '<br /><pre class="delete-msg-pre">Selected Record : ' + columnName + '<br /><span class="text-uppercase">(' +
            msg + ellipsis + ')</span></pre>';
        } catch (error) {
            console.log(error);
            return '';
        }
    }

    delRecord(row) {
        if (row == null) {
            this.messageService.add({ severity: 'error', summary: 'Error', detail: 'No record selected' });
            return;
        }
        this.baseblockUI.start('Deleting...');
        this.objectservice.Delete(row)
            .subscribe(res => {
                this.baseblockUI.stop();
                if (res == null) {
                    return;
                }
                this.messageService.add({ severity: 'success', summary: 'success', detail: 'Record Deleted' });
                this.list();
                row = null;
            });
    }

    cloneObj(c: any): void { }

    getAllDropdownList() { }

    edit(event) {
        this.baseblockUI.start('Loading...');
        this.getAllDropdownList();
        this.objectservice.GetById(event.id).subscribe(res => {
            try {
                if (res != null) {
                    console.log(res);
                    this.isnewobject = false;
                    this.selectedObject = res;
                    this.cloneObj(res);
                    this.displayDialog = true;

                } else {
                    this.messageService.add({
                        severity: 'error', sticky: true, summary: 'Error',
                        detail: 'Object not found'
                    });
                    this.messageService.add({
                        severity: 'error', sticky: true, summary: 'Error',
                        detail: 'Object not found', key: 'fixtop'
                    });
                    return;
                }
            } catch (error) {
                this.messageService.add({
                    severity: 'error', sticky: true, summary: 'Error',
                    detail: error
                });
                this.messageService.add({
                    severity: 'error', sticky: true, summary: 'Error',
                    detail: error, key: 'fixtop'
                });
            }
            this.baseblockUI.stop();
        });
    }

    submitObject(editObject: T): T {

        return editObject;
    }

    exeSubmit(value: string) {
        console.log(this.userform.value);
        let editObject: T = this.userform.value;

        editObject = this.submitObject(editObject);

        if (this.isnewobject) {
            this.baseblockUI.start('Loading...');
            this.objectservice.Create(editObject)
                .subscribe(res => {
                    this.saved(res);
                    this.baseblockUI.stop();
                });
        } else {
            if (!this.selectedObject.isLocked) {
                this.baseblockUI.start('Loading...');
                this.objectservice.Update(editObject)
                    .subscribe(res => {
                        this.saved(res);
                        this.baseblockUI.stop();
                    });
            } else {
                this.messageService.add({
                    severity: 'Info', summary: 'Info',
                    detail: 'The object is updated, pelase refresh the page.'
                });
                return;
            }
        }
    }

    onSubmit(value: string) {
        if (this.isnewobject) {
            this.exeSubmit('');
            return;
        }
        // this.displayDialog = false;
        this.confirmationService.confirm({
            message: 'Do you want to save and resync this record?',
            header: 'Confirmation',
            icon: 'pi pi-info-circle',
            accept: () => {
                this.exeSubmit('');
            },
            reject: () => {
                this.messageService.add({
                    severity: 'info', summary: 'Rejected',
                    detail: 'You have rejected'
                });
            }
        });
    }

    saved(resp: any) {
        console.log('saved');
        console.log(resp);
        if (resp == null) { return; }
        if (!resp.synced) {
            this.messageService.add({ key: 'errorDialog', sticky: true, severity: 'error',
            summary: 'Error',
            detail: resp.errorMessage });
            // this.messageService.add({
            //     severity: 'error', sticky: true, summary: 'Error',
            //     detail: resp.errorMessage, key: 'fixtop'
            // });
            return;
        }

        // let objs = [...this.objectlist];

        this.selectedObject = null;
        this.displayDialog = false;

        if (this.isnewobject) {
            try {
                this.isnewobject = false;
                this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Record Saved' });
                // objs.push(resp);
            } catch (error) {
                console.log('error: ' + error);
                return;
            }
        } else {
            try {
                this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Record Updated' });
                // objs[this.objectlist.indexOf(this.selectedObject)] = resp;
            } catch (error) {
                console.log('error: ' + error);
                return;
            }
        }

        this.list();
        // this.objectlist = objs;
    }

    exeDeleteAction() {
        if (this.selectedObject == null) {
            this.messageService.add({ severity: 'error', sticky: true, summary: 'Error', detail: 'No record seleted' });
            // this.messageService.add({ severity: 'error', sticky: true, summary: 'Error', detail: 'No record seleted', key: 'fixtop' });
            return;
        }
        if (this.selectedObject.isLocked) {
            this.messageService.add({
                severity: 'Info', summary: 'Info',
                detail: 'The object is updated, pelase refresh the page.'
            });
            return;
        }
        this.deleteServices();
    }

    deleteServices() {
        this.baseblockUI.start('Deleting...');
        this.objectservice.Delete(this.selectedObject)
            .subscribe(res => {
                this.baseblockUI.stop();
                if (res == null || res['synced'] !== true) {
                    this.messageService.add({ severity: 'error', sticky: true, key: 'errorDialog', summary: 'Error',
                    detail: res['errorMessage'] ? res['errorMessage'] : '' });
                    return;
                }

                // this.removeList(res)
                this.list();

                this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Record Deleted' });
            });
    }

    removeList(resp: any) {
        // console.log(resp);
        if (resp == null) { return; }

        this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Record Deleted' });
        const index = this.objectlist.indexOf(this.selectedObject);
        this.objectlist = this.objectlist.filter((val, i) => i != index);
        this.selectedObject = null;
        this.displayDialog = false;
    }

    confirmDeleteTittle(): string {
        return '';
    }

    confirmDelete() {
        this.displayDialog = false;
        const Seleted = this.confirmDeleteTittle(); //  this.selectedObject.string1? this.selectedObject.string1 : '';
        this.confirmationService.confirm({
            message: 'Do you want to delete this record?'
                + ' (Selected record: ' + Seleted + ')',
            header: 'Delete Confirmation',
            icon: 'pi pi-info-circle',
            accept: () => {
                this.exeDeleteAction();
            },
            reject: () => {
                this.messageService.add({
                    severity: 'info', summary: 'Rejected',
                    detail: 'You have rejected'
                });
            }
        });
    }

    deleteRecord(row): void {
        const Seleted = this.confirmDeleteTittle(); // row.string1? row.string1 : '';
        this.confirmationService.confirm({
            message: 'Do you want to delete this record?'
                + ' (Selected record: ' + Seleted + ')',
            header: 'Delete Confirmation',
            icon: 'pi pi-info-circle',
            accept: () => {
                this.selectedObject = row;
                this.exeDeleteAction();
            },
            reject: () => {
                this.messageService.add({
                    severity: 'info', summary: 'Rejected',
                    detail: 'You have rejected'
                });
            }
        });
    }

     // Etable functions start//
    countHeaderRows(name: string, row: number, cols = this.cols): number {
        let i = 0;
        cols.forEach(s => {
            if (s.visible && s.colHeader[row] === name) { i = i + 1; }
        });
        return i;
    }

    onMenuClick(colHeader = this.colHeader, footerObjectlist = this.footerObjectlist, cols = this.cols) {
        let i = 0;
        colHeader.forEach(a => {
            a.forEach(s => {
                s.colspan = this.countHeaderRows(s.name, i, cols);
            });
            i = i + 1;
        });

        let j = 0;
        footerObjectlist.forEach(a => {
         console.log(a);
            a.config.forEach(s => {
                s.colspan = this.countFooterColSpan(s.name, j, cols);
            });
            j = j + 1;
        });
    }

    countFooterColSpan(name: string, row: number, cols = this.cols): number {
        let i = 0;
        cols.forEach(s => {
            if (s.visible && s.colFooter[row] === name) { i = i + 1; }
        });
        return i;
     }

    funcCondition(event): boolean {
        // if (event.row != null && event.row.objective == '2') return false;
        return true;
    }

    checkBoxCondition(event): boolean {
        // if (event.row != null && event.row.createBy == 'IPMS') return false;
        return true;
    }

    textBoxCondition(event): boolean {
        return true;
    }

    classChange(event): string {
        let clas = '';
        if (event && event.func) {
            if (event.func.class) { clas += event.func.class + ' '; }
            if (event.func.function === 'onEdit' || event.func.function === 'onDelete') {
                clas += 'ui-button-default-etable';
            }
         }
        return clas;
    }

    iconChange(event): string {
        return event.func.icon;
    }
    // Etable functions end//

    starVisibility(strColumnName: string): boolean {
        let isVisible = false;
        if (this.objHasAuditField === undefined || this.objHasAuditField === null) {
            isVisible = false;
        } else {

            const resultList: any[] = this.objHasAuditField.filter(f => f.fieldName.toLocaleLowerCase() === strColumnName.toLocaleLowerCase());
            if (resultList.length > 0) {
                isVisible = resultList[0].hasChanges;
            }
        }
        return isVisible;
    }

    exportCSV(objectlist: T[], exportFilename = 'ExportData') {
        const csvSeparator = ',';
        // const exportFilename = 'ExportData';
        let csv = '';
        const csvHeaders = new Map();

        const cols = this.cols.filter(s => s.visible);

        for (const record of objectlist) {
        // objectlist.forEach((record, i) => {
            for (let i = 0; i < cols.length; i++) {
                const column = cols[i];
                if (column.exportable !== false && column.field) {
                    if (column.isSubObject) {
                        // const fields = column.field.split('.');
                        const fields: string[] = [];
                        fields.push(column.field);
                        fields.push(column.subField);
                        const detailField = column.subField; // fields[fields.length - 1];
                        // record[fields[0]].forEach((detailRecord, j) => {
                            const csvHeader = '"' + (column.header || column.field) + '"';
                            const detailFieldId = detailField + i;
                            if (!csvHeaders.has(detailFieldId)) {
                                csvHeaders.set(detailFieldId, csvHeader);
                            }
                            let detailCellData = record[fields[0]] == null ? null :
                                                 record[fields[0]][detailField]; // detailRecord[detailField];
                            if (detailCellData != null && detailCellData !== '') {
                                if (column.dataType === 'DateTime' && detailCellData.length >= 10) {
                                    detailCellData = String(detailCellData).substring(0, 10);
                                } else if (column.dataType === 'DateTime_ToLocal_General' && detailCellData.length > 10) {
                                    const x = new Date(detailCellData.toString() + 'Z').toLocaleString();
                                    detailCellData = formatDate(new Date(x), 'yyyy-MM-dd HH:mm:ss', 'en_US');
                                } else if (column.dataType === 'Date_ToLocal_General' && detailCellData.length > 10) {
                                    const x = new Date(detailCellData.toString() + 'Z').toLocaleString();
                                    detailCellData = formatDate(new Date(x), 'yyyy-MM-dd', 'en_US');
                                } else {
                                    detailCellData = String(detailCellData).replace(/"/g, '""');
                                }
                            } else {
                                detailCellData = '';
                            }
                            csv += '"' + detailCellData + '"';

                            if (i < (cols.length - 1)) {
                                csv += csvSeparator;
                            }
                        // });
                    } else {
                        const csvHeader = '"' + (column.header || column.field) + '"';
                        if (!csvHeaders.has(column.field)) {
                            csvHeaders.set(column.field, csvHeader);
                        }
                        let cellData = record[column.field];
                        if (cellData != null && cellData !== '') {
                            if (column.dataType === 'DateTime' && cellData.length >= 10) {
                                cellData = String(cellData).substring(0, 10);
                            } else if (column.dataType === 'DateTime_ToLocal_General' && cellData.length > 10) {
                                const x = new Date(cellData.toString() + 'Z').toLocaleString();
                                cellData = formatDate(new Date(x), 'yyyy-MM-dd HH:mm:ss', 'en_US');
                            } else if (column.dataType === 'Date_ToLocal_General' && cellData.length > 10) {
                                const x = new Date(cellData.toString() + 'Z').toLocaleString();
                                cellData = formatDate(new Date(x), 'yyyy-MM-dd', 'en_US');
                            } else {
                                cellData = String(cellData).replace(/"/g, '""');
                            }
                        } else {
                            cellData = '';
                        }
                        csv += '"' + cellData + '"';

                        if (i < (cols.length - 1)) {
                            csv += csvSeparator;
                        }
                    }
                }
            }
            csv += '\n';
        // });
        }

        let csvF = '';

        if (this.footerObjectlist && this.footerObjectlist.length > 0) {

            this.footerObjectlist.forEach(o => {
                for (let index = 0; index < o.config.length; index++) {
                    const colspan = o.config[index].colspan;
                    for (let i = 1; i < colspan; i++) {
                        csvF += '""' + csvSeparator;
                    }

                    const field = o.config[index].field;
                    const data = o.data[field];

                    if (data) { csvF += data + csvSeparator;
                    } else { csvF += '""' + csvSeparator; }
                }
            });

            csvF += '\n';
        }

        csv = Array.from(csvHeaders.values()).join(csvSeparator) + '\n' + csv + csvF;
        const blob = new Blob([csv], {
            type: 'text/csv;charset=utf-8;'
        });

        if (window.navigator.msSaveOrOpenBlob) {
            navigator.msSaveOrOpenBlob(blob, exportFilename + '.csv');
        } else {
            const link = document.createElement('a');
            link.style.display = 'none';
            document.body.appendChild(link);
            if (link.download !== undefined) {
                link.setAttribute('href', URL.createObjectURL(blob));
                link.setAttribute('download', exportFilename + '.csv');
                link.click();
            } else {
                csv = 'data:text/csv;charset=utf-8,' + csv;
                window.open(encodeURI(csv));
            }
            document.body.removeChild(link);
        }
    }

    mandatoryChecking(): boolean {
        return true;
      }

    onRowInsert() {
        if (!this.mandatoryChecking()) {
            return;
        }

        this.baseblockUI.start('Loading...');
        // for (const field in this.userform.controls) {
        //     this.selectedObject[field] = this.userform.get(field).value;
        //   }

        Object.keys(this.userform.controls).forEach(key => {
            this.selectedObject[key] = this.userform.get(key).value;
        });

          this.setItemBeforeSave();

        if (this.objectservice.isAdd) {
            this.selectedObject['id'] = '00000000-0000-0000-0000-000000000000';
            this.selectedObject['ocCode'] = this.authService.getSelectedOc();
            console.log(this.selectedObject);
            this.objectservice.Create(this.selectedObject)
                .subscribe(res => {
                    this.saveResponse(res);
                });
        } else {
            console.log(this.selectedObject);
            if (!this.selectedObject.isLocked) {
                //  rowObject.empID = this.overtimeForm.get("empID").value;
                //  rowObject.transDate = this.overtimeForm.get("transDate").value;
                this.objectservice.Update(this.selectedObject)
                    .subscribe(res => {
                        this.saveResponse(res);
                    });
            } else {
                this.baseblockUI.stop();
                this.messageService.add({ severity: 'Info', summary: 'Info',
                detail: 'The object is updated, pelase refresh the page.' });
                return;
            }
        }

    }

    setItemBeforeSave() {
    }

    saveResponse(response: any) {
        this.baseblockUI.stop();

        if (response == null) { return; }
        if (!response.synced) {
            this.messageService.add({ key: 'errorDialog', sticky: true, severity: 'error',
            summary: 'Error',
            detail: response.errorMessage });
            // this.messageService.add({
            //     severity: 'error', sticky: true, summary: 'Error',
            //     detail: resp.errorMessage, key: 'fixtop'
            // });
            return;
        }
        let saveMessage;
        if (this.objectservice.isAdd) {
            this.isnewobject = false;
            saveMessage = 'Record Saved';
        } else {
            saveMessage = 'Record Updated';
        }
        try {
            this.messageService.add({ severity: 'success', summary: 'Success', detail: saveMessage });
        } catch (error) {
            console.log('error: ' + error);
            return;
        }
        this.selectedObject = null;
        this.displayDialog = false;
        this.onBackButtonClick();
    }

    onBackButtonClick() {
        this.locationNav.back();
        // this.overtimeService.data = <OverTimeClass>{};
        // this.overtimeService.data = OverTimeFunc.empty();
    }

    toSelectItemList(lookupItemOptions: LookupItem[]): SelectItem[] {
        const options: SelectItem[] = [];
        lookupItemOptions.forEach(s => {
            options.push({ label: s.displayValue, value: s.id,
              disabled: s.entityStatus === EntityStatus.Active ? false : true});
          });
        return options;
    }

    onInputDate(event, name, maxDate = this.maximumDate, minDate = this.minimumDate, form: FormGroup = this.userform): void {
        let cursorPosition = event.target.selectionEnd;

        if (event.inputType === 'deleteContentBackward' && (cursorPosition === 4 || cursorPosition === 7)) {
            event.target.value = event.target.value.substring(0, cursorPosition - 1) + event.target.value.substring(cursorPosition);
            cursorPosition --;
        }
        if (event.inputType === 'insertText' && (event.target.value.length > 10)) {
            event.target.value = event.target.value.substring(0, event.target.value.length - 1);
        }

        let dateMask = event.target.value.toString();
        dateMask = dateMask.replace(/\D/g, '');

        let mask = '';
        for (let i = 0; i < dateMask.length; i++) {
            mask += dateMask[i];
            if (i === 3 || i === 5) {
                mask += '-';
                if (cursorPosition === 4 || cursorPosition === 7) { cursorPosition++; }
            }
        }

        const placeholder = 'yyyy-mm-dd';

        if (mask.length >= 10) {
            event.target.value = mask;
            event.target.selectionStart = cursorPosition;
            event.target.selectionEnd = cursorPosition;
            try {
                const dt = new Date(event.target.value);
                if (dt != null && dt.getTime() === dt.getTime()) {
                    if (maxDate !== null) {
                        const md = new Date(maxDate);
                        if (md != null && md.getTime() === md.getTime() && dt <= md) {
                            if (minDate !== null) {
                                const mnd = new Date(minDate);
                                if (mnd != null && mnd.getTime() === mnd.getTime() && dt >= mnd) {
                                    form.get(name).setErrors(null);
                                    form.get(name).setValue(event.target.value);
                                } else {
                                    form.get(name).setErrors({ 'InvalidDateRange' : true });
                                }
                            } else {
                                form.get(name).setErrors(null);
                                form.get(name).setValue(event.target.value);
                            }
                        } else {
                            form.get(name).setErrors({ 'InvalidDateRange' : true });
                        }
                    } else {
                        form.get(name).setErrors(null);
                        form.get(name).setValue(event.target.value);
                    }
                } else {
                    form.get(name).setErrors({ 'InvalidDate' : true });
                }
            } catch (error) {
                form.get(name).setErrors(null);
                form.get(name).setValue(null);
                event.target.value = '';
            }
        } else {
            try {
                event.target.value = mask +
                placeholder.substr(mask.length, placeholder.length - mask.length);
                event.target.selectionStart = cursorPosition;
                event.target.selectionEnd = cursorPosition;
            } catch (error) {
                form.get(name).setErrors(null);
                event.target.value = '';
            }
        }
    }

    onInputBlur(event, name, maxDate = this.maximumDate, minDate = this.minimumDate, form: FormGroup = this.userform) {
        try {
            let existingValue = form.get(name).value;

            if (existingValue === null) {
                existingValue = '';
            }

            if (existingValue === event.target.value) {
                return;
            }

            if (!event.target.value) {
                form.get(name).setValue(null);
                return;
            }

            if (event.target.value.length === 10 && event.target.value.substr(9, 1) === 'd' && event.target.value.substr(8, 1) !== 'd') {
                event.target.value = event.target.value.substr(0, 8) + '0' +
                event.target.value.substr(8, 1);
            }

            form.get(name).setValue(event.target.value);
            const dt = new Date(event.target.value);
            if (dt != null && dt.getTime() === dt.getTime()) {
                if (maxDate !== null) {
                    const md = new Date(maxDate);
                    if (md != null && md.getTime() === md.getTime() && dt <= md) {
                        if (minDate !== null) {
                            const mnd = new Date(minDate);
                            if (mnd != null && mnd.getTime() === mnd.getTime() && dt >= mnd) {
                                // form.get(name).setErrors(null);
                            } else {
                                form.get(name).setErrors({ 'InvalidDateRange' : true });
                            }
                        } else {
                            form.get(name).setErrors(null);
                        }
                    } else {
                        form.get(name).setErrors({ 'InvalidDateRange' : true });
                    }
                } else {
                    form.get(name).setErrors(null);
                }
            } else {
                console.log('onInputBlur error date');
                event.target.value = null;
                form.get(name).setValue(null);
                form.get(name).setErrors({ 'InvalidDate' : true });
            }
        } catch (error) {
            console.log('onInputBlur error', error);
            event.target.value = null;
            form.get(name).setValue(null);
            form.get(name).setErrors({ 'InvalidDate' : true });
        }
    }

    onInputMonthYear(event, name): void {
        let cursorPosition = event.target.selectionEnd;

        if (event.inputType === 'deleteContentBackward' && (cursorPosition === 4)) {
            event.target.value = event.target.value.substring(0, cursorPosition - 1) + event.target.value.substring(cursorPosition);
            cursorPosition --;
        }
        if (event.inputType === 'insertText' && (event.target.value.length > 7)) {
            event.target.value = event.target.value.substring(0, event.target.value.length - 1);
        }

        let dateMask = event.target.value.toString();
        dateMask = dateMask.replace(/\D/g, '');

        let mask = '';
        for (let i = 0; i < dateMask.length; i++) {
            mask += dateMask[i];
            if (i === 3) {
                mask += '-';
                if (cursorPosition === 4) { cursorPosition++; }
            }
        }

        const placeholder = 'yyyy-mm';

        if (mask.length >= 7) {
            event.target.value = mask;
            event.target.selectionStart = cursorPosition;
            event.target.selectionEnd = cursorPosition;
            try {
                const dt = new Date(event.target.value);
                const validYear = new Date('1900-12');

                if (dt < validYear) {
                    this.userform.get(name).setValue(null);
                    return;
                }
                if (dt != null && dt.getTime() === dt.getTime()) {
                    this.userform.get(name).setValue(dt);
                } else {
                    this.userform.get(name).setValue(null);
                    event.target.value = '';
                }
            } catch (error) {
                this.userform.get(name).setValue(null);
                event.target.value = '';
            }
        } else {
            try {
                this.userform.get(name).setValue(null);
                event.target.value = mask +
                placeholder.substr(mask.length, placeholder.length - mask.length);
                event.target.selectionStart = cursorPosition;
                event.target.selectionEnd = cursorPosition;
            } catch (error) {
                event.target.value = '';
            }
        }
    }

    dateBinding(name: string) {
        try {
            if (this.selectedObject[name] && this.selectedObject[name] !== null) {
                const date = this.selectedObject[name].toString();
                const newDate = date.split('T')[0];
                if (moment(newDate, 'YYYY-MM-DD', true).isValid()) {
                    const dateToAssign: Date =  new Date(newDate);
                    this.selectedObject[name] = dateToAssign.getFullYear() + '-' + ('00' + (dateToAssign.getMonth() + 1)).slice(-2) + '-' + ('00' + dateToAssign.getDate()).slice(-2);
                    return;
                }
            }
        } catch (error) {
        }
        this.selectedObject[name] = null;
    }

    onDownloadCSV(csv: string, exportFilename: string) {
        const blob = new Blob([csv], {
            type: 'text/csv;charset=utf-8;'
        });

        if (window.navigator.msSaveOrOpenBlob) {
            navigator.msSaveOrOpenBlob(blob, exportFilename + '.csv');
        } else {
            const link = document.createElement('a');
            link.style.display = 'none';
            document.body.appendChild(link);
            if (link.download !== undefined) {
                link.setAttribute('href', URL.createObjectURL(blob));
                link.setAttribute('download', exportFilename + '.csv');
                link.click();
            } else {
                csv = 'data:text/csv;charset=utf-8,' + csv;
                window.open(encodeURI(csv));
            }
            document.body.removeChild(link);
        }
    }

    // example: (onShow)="showDialogMaximized($event,dialPermission)" #dialPermission
    // use in p-dialog
    showDialogMaximized(event, dialog: Dialog) {
        dialog.maximized = false;
        dialog.toggleMaximize(event);
    }

    startBlockUiGeneral() {
        this.baseblockUI.start('Loading...');
        this.totalDropdown = 0;
        this.totalDropdownSubscription = this.totalDropdownChange.subscribe(totalDropdown => {
            this.onTotalDropdownChange(totalDropdown);
        });
    }

    onTotalDropdownChange(totalDropdown: number) {
        if (totalDropdown === 0) {
            this.stopBlockUI();
        }
    }

    stopBlockUI() {
        this.baseblockUI.stop();
        this.totalDropdown = 0;
        this.totalDropdownChange = new BehaviorSubject(0);
        if (this.totalDropdownSubscription !== undefined) {
            this.totalDropdownSubscription.unsubscribe();
        }
    }

    onTotalDropdownIncrease() {
        this.totalDropdown += 1;
        this.totalDropdownChange.next(this.totalDropdown);
    }

    // aesEncrpt(text: string): string {
    //     return CryptoJS.AES.encrypt(text.trim(), this.AES_SALT_KEY).toString();
    // }

    // aesDecrpt(text: string): string {
    //     return CryptoJS.AES.decrypt(text.trim(), this.AES_SALT_KEY).toString(CryptoJS.enc.Utf8);
    // }

    aesEncrpt(text: string): string {
        const key = CryptoJS.enc.Utf8.parse(this.AES_SALT_KEY);
        const iv = CryptoJS.enc.Utf8.parse(this.AES_IV_KEY);
        const encrypted = CryptoJS.AES.encrypt(text, key, { iv: iv,
            padding: CryptoJS.pad.Pkcs7,
            mode: CryptoJS.mode.CBC }).toString();
        return this.base64ToHex(encrypted);
    }

    aesDecrpt(text: string): string {
        const key = CryptoJS.enc.Utf8.parse(this.AES_SALT_KEY);
        const iv = CryptoJS.enc.Utf8.parse(this.AES_IV_KEY);
        const encrypted = this.hexToBase64(text);

        return CryptoJS.AES.decrypt(encrypted, key, { iv: iv,
            padding: CryptoJS.pad.Pkcs7,
            mode: CryptoJS.mode.CBC }).toString(CryptoJS.enc.Utf8);
    }

    base64ToHex(str: string): string {
        const raw = atob(str);
        let result = '';
        for (let i = 0; i < raw.length; i++) {
          const hex = raw.charCodeAt(i).toString(16);
          result += (hex.length === 2 ? hex : '0' + hex);
        }
        return result.toUpperCase();
    }

    hexToBase64(str: string): string {
        return btoa(String.fromCharCode.apply(null,
          str.replace(/\r|\n/g, '').replace(/([\da-fA-F]{2}) ?/g, '0x$1 ').replace(/ +$/, '').split(' '))
        );
      }

    objectIsNull(object: any): boolean {
        if (!object || object === null) { return true;
        } else { return false; }
    }

    arrayOfObjectIsNull(object: any[]): boolean {
        if (!object || object === null || !Array.isArray(object) || object.length === 0) { return true;
        } else { return false; }
    }

    stringIsNull(object: string): boolean {
        if (!object || object === null || object.trim() === '') { return true;
        } else { return false; }
    }

    setMultiSelectToolTips(eventValue: string[], optionList: SelectItem[]): string {
        console.log('eventValue', eventValue);
        console.log('optionList', optionList);
        let ToolTips = '';

        if (this.arrayOfObjectIsNull(eventValue) || this.arrayOfObjectIsNull(optionList)) { return ''; }

        let resultList: string[] = [];

        eventValue.forEach(e => {
            const r = optionList.find(o => o.value === e);
            if (!this.objectIsNull(r)) { resultList.push(r.label); }
        });

        resultList = resultList.sort();
        resultList.forEach(e => {
            ToolTips += e + ', ';
        });

        if (ToolTips !== '') {
            ToolTips = ToolTips.substr(0, ToolTips.length - 2);
        }
        return ToolTips;
    }

    orderSelectItemByStatus(optionList: SelectItem[]): SelectItem[] {
        if (this.arrayOfObjectIsNull(optionList)) { return []; }
        return optionList.sort((a, b) => (a.disabled > b.disabled) ? 1 : -1);
    }

}
