import {
    Component, OnInit, Input, NgModule, forwardRef, Output, EventEmitter, ViewEncapsulation,
    ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, AfterViewInit, OnDestroy
} from '@angular/core';
import { CommonModule, DatePipe, formatDate } from '@angular/common';
import { FilterMetadata, SelectItem } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { TableModule, Table } from 'primeng/table';
import { OverlayPanelModule } from 'primeng/overlaypanel';
import { CheckboxModule } from 'primeng/checkbox';
import { SharedModule } from 'primeng/components/common/shared';
import { InputTextModule } from 'primeng/inputtext';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { EtableColumn } from 'ekangularbase/src/interface/EtableColumn';
import { CurrencyMaskModule } from 'ng2-currency-mask';
import * as xlsx from 'xlsx';

// Angular-Slickgrid start
import {
    AngularGridInstance,
    Aggregators,
    Column,
    DelimiterType,
    FieldType,
    FileType,
    Filters,
    Formatters,
    GridOption,
    Grouping,
    GroupTotalFormatters,
    SortDirectionNumber,
    Sorters,
    OnEventArgs,
    AngularSlickgridModule,
    Formatter,
    Editors,
    GridService,
    AngularUtilService,
    GridOdataService,
    OdataOption,
    GroupingGetterFunction,
} from 'angular-slickgrid';
import { AuditTrailListModule, AuditTrailListComponent } from 'ekangularbase/src/audit-trail-list/audit-trail-list.component';
import { DropdownModule } from 'primeng/dropdown';
import { MultiSelectModule } from 'primeng/multiselect';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
import { EntityStatus } from 'ekangularbase/src/interface/entity-status';
import { BlockUIModule } from 'primeng/blockui';
import { PanelModule } from 'primeng/panel';
import * as $ from 'jquery';
import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';
import { ekThousandSeparatorFormatter, numberWithCommas } from 'ekangularbase/src/ek-components/etable/formatter/ekThousandSeparatorFormatter';
import { EtableFunction } from 'ekangularbase/src/interface/EtableFunction';
import { ListboxModule } from 'primeng/primeng';

// Angular-Slickgrid end


// export const Etable_VALUE_ACCESSOR: any = {
//   provide: NG_VALUE_ACCESSOR,
//   useExisting: forwardRef(() => EtableComponent),
//   multi: true
// };

@Component({
    selector: 'e-table',
    templateUrl: './etable.component.html',
    encapsulation: ViewEncapsulation.None,
    styleUrls: ['./etable.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class EtableComponent implements OnInit, AfterViewInit, OnDestroy {

    selectAll = false;
    boolHeaderOption: SelectItem[];
    lazyLoadingChangesSubscription: Subscription;
    lazyLoadingChanges: BehaviorSubject<string>;
    selectedCols: any[];

    constructor(private cd: ChangeDetectorRef,
        private angularUtilService: AngularUtilService,
        public datepipe: DatePipe) {
        this.loadSlickGrid = false;
        this.loading = false;
        this.lazyLoadingChanges = new BehaviorSubject('');

        this.boolHeaderOption = [
            { value: null, label: 'All' },
            { value: true, label: 'Yes' },
            { value: false, label: 'No' },
        ];

    }

    // Angular-Slickgrid start
    gridRowCountFilter = 0;

    private _commandQueue = [];
    angularGrid: AngularGridInstance;
    columnDefinitions: Column[];
    columnDefinitionsVisible: Column[];
    // dataset: any[];
    dataviewObj: any;
    draggableGroupingPlugin: any;
    durationOrderByCount = false;
    gridObj: any;
    gridOptions: GridOption;
    processing = false;
    selectedGroupingFields: Array<string | GroupingGetterFunction> = ['', '', ''];
    gridService: GridService;

    // Angular-Slickgrid end

    @ViewChild('dt', { static: false }) dt: Table;

    @Input() strTableName = '';
    @Input() tableType = '';

    @Input() columns: EtableColumn[];
    @Input() func: EtableFunction[];
    @Input() value: any[];
    @Input() colHeader: any[];
    @Input() footerColumns: any[];
    @Input() footerObjectlist: any[];

    @Input() paginator: boolean;

    @Input() scrollHeight = '400px';

    @Input() rows: number;

    // @Input() first: number = 0;

    @Input() pageLinks = 5;

    @Input() rowsPerPageOptions: number[];

    @Input() sortMode = 'single';

    // @Input() resetPageOnSort: boolean = true;

    @Input() selectionMode: string;

    @Input() scrollable: boolean;

    @Input() responsive: boolean;

    // @Input() contextMenu: any;

    @Input() resizableColumns: boolean;

    @Input() columnResizeMode = 'fit';

    // @Input() reorderableColumns: boolean;

    @Input() loading = false;

    @Input() allowGrouping = false;

    @Input() allowExportToExcel = false;
    @Input() showTotalRecord = true;
    @Input() slickMinHeight = 480;
    @Input() slickMaxHeight = 1024;
    @Input() slickBottomPadding = 30;
    @Input() logColumnList: string[] = [];
    @Input() gridId = 'grid19';
    @Input() selection: any;
    @Input() hideDeletedButton = true;
    @Input() isDataFinishLoaded = false;
    @Input() allowLazyLoading = false;
    @Input() inActiveStatusList: string[] = [EntityStatus.InActive, EntityStatus.Deleted, EntityStatus.Retired];

    @Input() updateCssIdList: string[];
    @Input() updateCssClass: string;

    @Input() defaultHideFilter = true;

    timerInterval: any;
    loadSlickGrid = false;
    filteredValueCount = 0;
    headerCount = 0;

    @Output() listEvent = new EventEmitter();

    @Output() onRowClickEvent = new EventEmitter();

    @Input() funcConditionEvent: (value: any) => boolean;

    @Input() checkBoxConditionEvent: (value: any) => boolean;

    @Input() classChangeEvent: (value: any) => string;

    @Input() iconChangeEvent: (value: any) => string;

    @Output() lazyLoadingApiCallEvent = new EventEmitter();

    @Output() onMenuClickEvent = new EventEmitter();

    @Output() onCellClickedEvent = new EventEmitter();

    @Output() onCellChangedEvent = new EventEmitter();

    @Output() onCellFocusEvent = new EventEmitter();

    @Output() onCellKeyPressEvent = new EventEmitter();

    @Input() textBoxConditionEvent: (value: any) => boolean;

    ngOnInit() {
        if (this.tableType === 'SlickGrid') {
            this.loading = false;
            this.timerInterval = setInterval(() => {
                if (this.isDataFinishLoaded && this.isDataFinishLoaded === true) {
                    clearInterval(this.timerInterval);

                    this.defineGrid();
                    this.defineGridOption();
                    this.loadSlickGrid = true;
                    this.detectChanges();
                }
            }, 100);
        }
    }

    ngAfterViewInit() {
        if (this.tableType === 'SlickGrid' && this.allowLazyLoading === false) {
            this.loading = true;
        }
    }

    detectChanges(event = null) {
        console.log('detectChanges', event);
        try {
            if (this.tableType === 'SlickGrid') {
                if (event !== null) {
                    if (event['name'] && event['name'] === 'onDelete') {
                        this.selectRow(event);
                    }
                    if (event['selectAllCheckBox'] !== undefined) {
                        this.updateSelectAllCheckBox(event);
                    }
                    if (event['lazyLoadingChanges']) {
                        this.lazyLoadingChanges.next(event['lazyLoadingChanges']);
                    }
                }
                this.cd.detectChanges();
                // this.checkNoData();
                // this.resetSlickGrid();
                this.render();
            } else if (this.tableType === '') {
                if (event !== null) {
                    if (event['selectAllCheckBox'] !== undefined) {
                        this.bindingSelectedCols();
                    }
                }
                setTimeout(() => {
                    console.log('gridId', this.gridId);
                    console.log('this.value.length', this.value);
                    this.filteredValueCount = this.value ? this.value.length : 0;

                    const totalFuncs = this.func.filter(s => s.visible === true);
                    const totalCols = this.columns.filter(s => s.visible === true);
                    this.headerCount = totalFuncs.length + totalCols.length;

                    this.cd.detectChanges();
                }, 200);
            }
        } catch (error) {
            console.log(error);
        }
    }

    bindingSelectedCols() {
        console.log('bindingSelectedCols', this.columns);
        this.selectedCols = [];
        if (this.arrayOfObjectIsNull(this.columns)) { return; }
        this.columns.forEach(c => {
            if (c.visible === true) { this.selectedCols.push(c); }
        });
        this.cd.detectChanges();
    }

    updateSelectAllCheckBox(event) {
        try {
            console.log('updateSelectAllCheckBox', event);
            console.log('this.func', this.func);
            const cb = this.func.find(s => s.funcType === 'checkbox');
            if (!cb || cb === null) { return; }

            if (this.angularGrid) {
                const allColumns = this.angularGrid.gridService.getAllColumnDefinitions();
                console.log('allColumns', allColumns);
                allColumns[0].header.buttons[0]['cssClass'] = 'fa fa-square header-checkbox';

                // this.columnDefinitions = this.columnDefinitions.slice();
            }
            // this.resetSlickGrid();
        } catch (error) {
            console.log(error);
        }
    }

    selectRow(event) {
        this.dt._selection = event.data;
        this.dt.tableService.onSelectionChange();
        if (this.dt.isStateful()) {
            this.dt.saveState();
        }
    }

    seachTextChange(event: any) {
        setTimeout(() => {
            this.cd.detectChanges();
        }, 1000);
    }

    exportCSV() {
        this.dt.exportCSV();
    }

    emitList(args) {
        this.columns.forEach(c => c.searchText = null);
        if (this.tableType === '') {
            this.dt.reset();
        } else if (this.tableType === 'SlickGrid') {
            // try {
            //     const cb = this.func.find(s => s.funcType === 'checkbox');
            //     if (cb && cb !== null) {
            //         args.allColumns[0].header.buttons[0].cssClass = 'fa fa-square header-checkbox';
            //     }
            // } catch (error) {
            //     console.log(error);
            // }
        }
        this.listEvent.emit();
        this.cd.detectChanges();
    }

    resetTable() {
        if (this.tableType === 'SlickGrid') {
            this.resetSlickGrid();
        } else { this.resetPtable(); }
    }

    resetPtable() {
        this.dt.reset();
        this.cd.detectChanges();
    }

    resetSlickGrid() {
        if (this.angularGrid) {
            this.defineGrid();
            // this.defineGridOption();
            this.angularGrid.slickGrid.setColumns(this.columnDefinitions);
        }
    }

    toDecimal(input: number | string, minDecimal?: number, maxDecimal?: number, isRounding = true): string {
        if (input === undefined || input === null || input === '') { input = 0; }
        if (isNaN(+input)) {
            return 'NaN';
        }
        const valStr = String(input);
        const parts = valStr.split('.');

        let parts1 = parts[0];
        let parts2 = '';
        if (parts.length === 2) {
            parts2 = parts[1];
        }

        if (minDecimal && minDecimal > parts2.length) {
            while (minDecimal > parts2.length) { parts2 += '0'; }
        }

        if (maxDecimal && maxDecimal > 0 && maxDecimal < parts2.length) {
            const lastDigit = parseInt(parts2[maxDecimal], 10);
            let last2ndDigit = parseInt(parts2[maxDecimal - 1], 10);

            if (isRounding && lastDigit >= 5) { last2ndDigit += 1; }

            parts2 = parts2.substr(0, maxDecimal - 1) + last2ndDigit.toString();
        }

        if (maxDecimal === 0 && parts2.length > 0) {
            const lastDigit = parseInt(parts2[0], 10);
            let last2ndDigit = parseInt(parts1[parts1.length - 1], 10);

            if (isRounding && lastDigit >= 5) { last2ndDigit += 1; }

            parts1 = parts1.substr(0, parts1.length - 1) + last2ndDigit.toString();
            parts2 = '';
        }

        let result = parts2 === '' ? '' : '.' + parts2;
        result = parts1 + result;

        return result;
    }

    exportObjList(): any[][] {
        const result: any[][] = [];
        const cols = this.columns.filter(s => s.visible);

        const headerRow: any[] = [];
        for (let i = 0; i < cols.length; i++) {
            const column = cols[i];
            headerRow.push(column.header);
        }
        result.push(headerRow);

        for (const record of this.value) {
            const row: any[] = [];
            for (let i = 0; i < cols.length; i++) {
                const column = cols[i];
                if (column.exportable !== false && column.field) {
                    if (column.isSubObject) {
                        const fields: string[] = [];
                        fields.push(column.field);
                        fields.push(column.subField);
                        const detailField = column.subField;
                        let detailCellData = record[fields[0]] == null ? null :
                            record[fields[0]][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 if (column.dataType === 'amount_General') {
                                detailCellData = this.toDecimal(detailCellData, 2, 2);
                            } else {
                                detailCellData = String(detailCellData).replace(/"/g, '""');
                            }
                        } else {
                            if (column.dataType === 'amount_General') {
                                detailCellData = this.toDecimal(detailCellData, 2, 2);
                            } else {
                                detailCellData = '';
                            }
                        }
                        row.push(detailCellData);
                    } else {
                        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 if (column.dataType === 'amount_General') {
                                cellData = this.toDecimal(cellData, 2, 2);
                            } else {
                                cellData = String(cellData).replace(/"/g, '""');
                            }
                        } else {
                            if (column.dataType === 'amount_General') {
                                cellData = this.toDecimal(cellData, 2, 2);
                            } else {
                                cellData = '';
                            }
                        }
                        row.push(cellData);
                    }
                }
            }
            result.push(row);
        }

        if (this.footerObjectlist && this.footerObjectlist.length > 0) {
            this.footerObjectlist.forEach(o => {
                const row: any[] = [];
                let x = -1;
                for (let index = 0; index < o.config.length; index++) {
                    const colspan = o.config[index].colspan;
                    x += 1;
                    for (let i = 1; i < colspan; i++) {
                        row.push('');
                        x += 1;
                    }

                    const field = o.config[index].field;
                    const data = o.data[field];

                    if (data) {
                        if (o.config[index].dataType === 'amount_General') {
                            row.push(this.toDecimal(data, 2, 2));
                        } else { row.push(data); }
                    } else { row.push(''); }
                }
                result.push(row);
            });
        }

        console.log('exportObjList', result);
        return result;
    }

    exportToExcelPtable() {
        const ws: xlsx.WorkSheet =
            xlsx.utils.aoa_to_sheet(this.exportObjList());
        const wb: xlsx.WorkBook = xlsx.utils.book_new();
        xlsx.utils.book_append_sheet(wb, ws, 'Sheet1');
        xlsx.writeFile(wb, 'ExportData.xlsx');
    }

    onHideFilter() {
        this.defaultHideFilter = !this.defaultHideFilter;
    }
    emitonSelectAllClickClick(func, field: string) {
        func.args = this.selectAll;
        this.emitOnRowClick(func, field);
    }
    emitOnRowClick(row, field: string) {
        this.onRowClickEvent.emit({ row, field });
    }
    emitFuncCondition(row, func): boolean {
        try {
            return this.funcConditionEvent({ row, func });
        } catch (error) {
            return true;
        }
    }
    emitCheckBoxCondition(row, func): boolean {
        try {
            return this.checkBoxConditionEvent({ row, func });
        } catch (error) {
            return true;
        }
    }
    emitClassChange(row, func) {
        try {
            return this.classChangeEvent({ row, func });
        } catch (error) {
            return '';
        }
    }
    emitIconChange(row, func) {
        try {
            return this.iconChangeEvent({ row, func });
        } catch (error) {
            return true;
        }
    }
    emitOnMenuClick() {
        this.onMenuClickEvent.emit();
        this.cd.detectChanges();
    }

    selectedColsChange() {
        console.log('selectedCols', this.selectedCols);
        if (!this.arrayOfObjectIsNull(this.columns)) {
            this.columns.forEach(c => {
                c.visible = false;
                if (!this.arrayOfObjectIsNull(this.selectedCols)) {
                    const se = this.selectedCols.find(s => s.field === c.field);
                    if (se) { c.visible = true; }
                }
            });
        }
        this.emitOnMenuClick();
    }

    emitOnCellClicked(event, args) {
        this.onCellClickedEvent.emit({ event, args });
    }
    emitOnCellChanged(event, args, field) {
        this.onCellChangedEvent.emit({ event, args, field });
    }
    emitOnCellFocus(event, args, field) {
        this.onCellFocusEvent.emit({ event, args, field });
    }
    emitOnCellKeyPress(event, args, field) {
        this.onCellKeyPressEvent.emit({ event, args, field });
    }
    emitTextBoxCondition(row, column, value): boolean {
        try {
            return this.textBoxConditionEvent({ row, column, value });
        } catch (error) {
            return true;
        }
    }

    onFilter(event) {
        console.log('onFilter', event);
        this.filteredValueCount = event.filteredValue.length;
        this.cd.detectChanges();
    }

    // Angular-Slickgrid start

    angularGridReady(angularGrid: AngularGridInstance) {
        this.angularGrid = angularGrid;
        this.gridObj = angularGrid.slickGrid; // grid object
        this.dataviewObj = angularGrid.dataView;
        this.gridService = angularGrid.gridService;

        this.checkNoData();

        // this.dataviewObj.getItemMetadata = this.updateItemMetadataForDurationOver50(this.dataviewObj.getItemMetadata);
        this.dataviewObj.getItemMetadata = this.metadata(this.dataviewObj.getItemMetadata,
            this.inActiveStatusList);
        this.gridObj.invalidate();
        this.gridObj.render();
        this.updateRowCssWithId();

        if (this.allowGrouping === true) {
            console.log('setPreHeaderPanelVisibility');
            this.gridObj.setPreHeaderPanelVisibility(!this.gridObj.getOptions().showPreHeaderPanel);
        }

        if (this.defaultHideFilter === true) {
            console.log('setHeaderRowVisibility');
            this.gridObj.setHeaderRowVisibility(!this.defaultHideFilter);
        }

        this.gridRowCountFilter = this.gridObj.getDataLength();
        this.getGridRowCountFilter().subscribe((r) => {
            console.log('getGridRowCountFilter subscribe', r);
            this.gridRowCountFilter = r;
            this.checkNoData();
            this.cd.detectChanges();
        });
    }

    checkNoData() {
        try {
            if (!this.value || this.value === null || !Array.isArray(this.value) ||
                this.value.length === 0) {
                // const gridBody: HTMLCollectionOf<Element> =
                // <HTMLCollectionOf<Element>> document.getElementsByClassName('grid-canvas');
                const elementById: HTMLLinkElement =
                    <HTMLLinkElement>document.getElementById('slick-container-' + this.gridId);
                const gridBody: HTMLCollectionOf<Element> =
                    <HTMLCollectionOf<Element>>elementById.getElementsByClassName('grid-canvas');
                if (gridBody && gridBody !== null && gridBody.length > 0) {
                    console.log('gridBody', gridBody);
                    gridBody.item(0).innerHTML =
                        '<div class="slick-no-data-main"><div class="eslic-no-data">"No Data Found"</div><div class="eslic-no-data">"No Data Found"</div></div>';
                }
            } else {
                const el = document.querySelector('.slick-no-data-main');
                if (el) {
                    el.className += ' slickgrid-hide-nodata';
                }
            }
        } catch (error) {
            console.error(error);
        }
    }

    getGridRowCountFilter(): Observable<number> {
        let totalQuestions: number;
        const subject = new Subject<number>();
        this.dataviewObj.onRowCountChanged
            .subscribe(function (e, args) {
                console.log('getGridRowCountFilter', args);
                totalQuestions = args.current;
                subject.next(totalQuestions);
            }
            );
        return subject.asObservable();
    }

    getFormatters(field, func, dataContext): any {
        switch (field) {
            case 'onRowSelect':
            case 'onEdit': {
                return `<i class="pi pi-external-link pointer edit-icon" aria-hidden="true"></i>`;
            }
            case 'onDelete': {
                return `<i class="fa fa-trash pointer delete-icon" aria-hidden="true"></i>`;
            }
            case 'onAdopterSelect': {
                if (dataContext && dataContext['polisyCreated'] === true) {
                    return `<i class="pi pi-tag pointer delete-icon" aria-hidden="true"></i>`;
                } else {
                    return `<i class="fa fa-plus pointer delete-icon" aria-hidden="true"></i>`;
                }
            }
            case 'onActivate': {
                if (dataContext && dataContext['entityStatus'] === 'Active') {
                    return `<i class="pi pi-check-circle pointer" aria-hidden="true"></i>`;
                } else {
                    return `<i class="pi pi-times-circle pointer" aria-hidden="true"></i>`;
                }
            }
            default: {
                // console.log('Invalid Formatters: ' + field);
                return `<i class="${func.icon} pointer edit-icon" aria-hidden="true"></i>`;
            }
        }
    }

    getFieldType(cd, columns): any {
        switch (columns.dataType) {
            case 'number_General': {
                cd.filter = { model: Filters.compoundInput };
                cd.type = FieldType.number;
                cd.formatter = ekThousandSeparatorFormatter;
                cd.params = { minDecimalPlaces: 1, maxDecimalPlaces: 5 };
                cd.cssClass = 'etable-number-general ' + columns.class;
                break;
            }
            case 'amount_General': {
                cd.filter = { model: Filters.compoundInput };
                cd.type = FieldType.number;
                cd.formatter = ekThousandSeparatorFormatter;
                cd.params = { minDecimalPlaces: 2, maxDecimalPlaces: 2 };
                cd.cssClass = 'etable-amount-general ' + columns.class;
                break;
            }
            case 'int_General': {
                cd.filter = { model: Filters.compoundInput };
                cd.type = FieldType.number;
                cd.formatter = ekThousandSeparatorFormatter;
                cd.params = { minDecimalPlaces: 0, maxDecimalPlaces: 0 };
                cd.cssClass = 'etable-number-general ' + columns.class;
                break;
            }
            case 'Date_General': {
                cd.filter = { model: Filters.compoundDate };
                cd.type = FieldType.date;
                cd.formatter = Formatters.dateIso;
                cd.cssClass = columns.class;
                break;
            }
            case 'DateTime': {
                cd.filter = { model: Filters.compoundDate };
                cd.type = FieldType.date;
                cd.formatter = Formatters.dateTimeIso;
                cd.cssClass = columns.class;
                break;
            }
            case 'time': {
                cd.filter = { model: Filters.compoundInputText };
                // cd.type = FieldType.dateTimeIso;
                cd.formatter = this.myTimeFormatter;
                cd.cssClass = columns.class;
                break;
            }
            case 'Date_ToLocal_General': {
                cd.filter = { model: Filters.compoundInputText };
                // cd.type = FieldType.dateTimeIso;
                cd.formatter = this.myDateToLocalFormatter;
                cd.cssClass = columns.class;
                break;
            }
            case 'DateTime_ToLocal_General': {
                cd.filter = { model: Filters.compoundInputText };
                // cd.type = FieldType.dateTimeIso;
                cd.formatter = this.myDateTimeToLocalFormatter;
                cd.cssClass = columns.class;
                break;
            }
            case 'DateTime_MonthName': {
                cd.filter = { model: Filters.compoundInputText };
                cd.formatter = this.myDateToMonthNameFormatter;
                cd.cssClass = columns.class;
                break;
            }
            case 'number': {
                cd.filter = { model: Filters.compoundInput };
                cd.type = FieldType.number;
                cd.cssClass = columns.class;
                break;
            }
            case 'currency': {
                cd.filter = { model: Filters.compoundInput };
                cd.type = FieldType.number;
                cd.cssClass = columns.class;
                break;
            }
            case 'uppercase': {
                cd.filter = { model: Filters.compoundInputText };
                cd.formatter = Formatters.uppercase;
                cd.cssClass = columns.class;
                break;
            }
            case 'lowercase': {
                cd.filter = { model: Filters.compoundInputText };
                cd.formatter = Formatters.lowercase;
                cd.cssClass = columns.class;
                break;
            }
            case 'boolean': {
                cd.filterable = true;
                cd.type = FieldType.boolean;
                cd.filter = {
                    model: Filters.singleSelect,
                    collection: [{ value: '', label: 'All' }, { value: true, label: 'Yes' },
                    { value: false, label: 'No' }],
                };
                cd.formatter = this.checkmarkFormatter;
                cd.cssClass = columns.class;
                break;
            }
            case 'hyperlink': {
                cd.filter = { model: Filters.compoundInputText };
                cd.formatter = Formatters.hyperlink;
                cd.params = { hyperlinkText: 'Company Website', hyperlinkUrl: 'http://www.somewhere.com' };
                cd.cssClass = columns.class;
                break;
            }
            case 'textBox': {
                cd.filter = { model: Filters.compoundInputText };
                cd.formatter = this.myCustomTextBoxFormatter;
                // cd.cssClasses = 'form-control';
                cd.cssClass = columns.class;
                cd.type = FieldType.string;
                cd.editor = {
                    model: Editors.text,
                    // required: true,
                    // minValue: 0,
                    // elementOptions: {
                    //     onClick: (event, args) => {
                    //         // here i want to write some code which can trigger to grid to start update
                    //         console.log(event);
                    //         console.log(args);
                    //       }
                    // }
                };
                break;
            }
            default: {
                // console.log("Invalid FieldType");
                cd.filter = { model: Filters.compoundInputText };
                cd.type = FieldType.string;
                cd.cssClass = columns.class;
                break;
            }
        }
        return cd;
    }

    onCellClicked(event, args) {
        console.log(event);
        console.log(args);
        // const fadingDelay = 2000; // in milliseconds

        // // you can pass an optional fading delay (1500ms by default)
        // this.gridService.highlightRow(args.row, fadingDelay);
        this.emitOnCellClicked(event, args);
    }

    onCellChanged(event, args) {
        console.log(event);
        console.log(args);
        this.emitOnCellChanged(event, args, '');
    }

    onCellFocus(event, args) {
        this.emitOnCellFocus(event, args, '');
    }

    onCellKeyPress(event, args) {
        this.emitOnCellKeyPress(event, args, '');
    }

    toggleCompletedProperty(item) {
        // toggle property
        if (typeof item === 'object') {
            //   item.completed = !item.completed;

            // simulate a backend http call and refresh the grid row after delay
            setTimeout(() => {
                this.angularGrid.gridService.updateItemById(item.id, item, { highlightRow: false });
            }, 250);
        }
    }

    customEnableButtonFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column,
        dataContext: any, grid: any) => {
        try {
            const c = this.func.find((v, i, o) => v.function === columnDef.field);
            // console.log(c);
            if (!this.emitCheckBoxCondition(dataContext, c)) { return ''; }

            let field = 'isSelected';
            if (c.field) { field = c.field; }

            return `<span>
                <i class="fa ${dataContext[field] === true ? 'fa-check-square' : 'fa-square'} fa-lg pointer" style="color:
                ${dataContext[field] === true ? 'black' : 'lavender'}"></i>
            </span>`;
        } catch (error) {
            console.log('customEnableButtonFormatter', error);
            return '';
        }
    }

    customImgFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column,
        dataContext: any, grid: any) => {
        const c = this.func.find((v, i, o) => v.function === columnDef.field);
        if (!(dataContext[c.function] && dataContext[c.function] !== '')) {
            return `<span class="${c.class}">
                <img src="assets/images/emp.png" />
            </span>`;
        }

        const d = dataContext[c.function];
        const empImgSrc = c.url + d;

        return `<span class="${c.class}">
            <img src="${empImgSrc}" />
        </span>`;
    }

    customAuditLogListFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column,
        dataContext: any, grid: any) => {
        const h = dataContext['hasChanges'];
        const v = dataContext['hasChanges'] === true;
        if (v) {
            return `<span>
                <a href="javascript:void(0)" (click)="showAuditTrailEvent($event,auditPanel)"  title="show audit trail">
                    <span><b> <i class="pi pi-circle-on audit-trail-popup-icon"></i></b></span>
                </a>
                </span>`;
        } else {
            return '';
        }
    }

    myCustomFuncFormatter: Formatter = (row, cell, value, columnDef: Column, dataContext) => {
        // you can return a string of a object (of type FormatterResultObject), the 2 types are shown below
        const c = this.func.find((v, i, o) => v.function === columnDef.field);
        // console.log(c);
        if (!this.emitFuncCondition(dataContext, c)) { return ''; }

        if (this.hideDeletedButton && c.function === 'onDelete'
            && dataContext['entityStatus'] === EntityStatus.Deleted) {
            return '';
        }

        // return Formatters.editIcon;

        // return { text: editIconFormatter};

        // return { text: editIconFormatter, addClasses: 'lightblue', toolTip: 'Freezing' };

        // return `<i class="fa fa-pencil pointer edit-icon" aria-hidden="true"></i>`;

        // return { text: '<i class="fa fa-snowflake-o" aria-hidden="true"></i>', addClasses: 'lightblue', toolTip: 'Freezing' };

        return this.getFormatters(columnDef.field, c, dataContext);
    }

    render() {
        console.log('render()');
        if (this.gridObj) {
            console.log('this.gridObj.getOptions().gridMenu.hideTogglePreHeaderCommand', this.gridObj.getOptions().gridMenu.hideTogglePreHeaderCommand);
            console.log('this.gridObj.getOptions().showPreHeaderPanel', this.gridObj.getOptions().showPreHeaderPanel);
            this.gridObj.invalidate();
            this.gridObj.render();
        }
    }

    insertSlickGrid(item) {
        this.dataviewObj.addItem(item);
        // this.angularGrid.gridService.addItem(item);
    }

    myCustomTextBoxFormatter: Formatter = (row, cell, value, columnDef: Column, dataContext) => {
        // return '<input type="text" value="' + dataContext[columnDef.field] +
        // '" style="width: 100%;" id="' + columnDef.field + '_' + row +
        // '" class="' + columnDef.cssClass + '">';
        // return '<input type="text" [(ngModel)]="value[' + row + ']' + '[' + columnDef.field + ']" style="width: 100%;">';
        value = '<span class=\'dataType-textBox form-control\'>' + value + '</span>';
        return value;
    }

    myTimeFormatter: Formatter = (row, cell, value, columnDef: Column, dataContext) => {
        if (!value) { return ''; }
        try {
            const x = value.toString().substring(0, 5);
            return x;
        } catch (error) {
            return value;
        }
    }

    myDateTimeToLocalFormatter: Formatter = (row, cell, value, columnDef: Column, dataContext) => {
        if (!value) { return ''; }
        try {
            const x = new Date(value.toString() + 'Z');
            const y = this.datepipe.transform(x, 'yyyy-MM-dd HH:mm:ss');
            return y;
        } catch (error) {
            return value;
        }
    }

    myDateToMonthNameFormatter: Formatter = (row, cell, value, columnDef: Column, dataContext) => {
        if (!value) { return ''; }
        try {
            const x = new Date(value.toString() + 'Z');
            const y = this.datepipe.transform(x, 'MMM y');
            return y.toUpperCase();
        } catch (error) {
            return value;
        }
    }

    myDateToLocalFormatter: Formatter = (row, cell, value, columnDef: Column, dataContext) => {
        if (!value) { return ''; }
        try {
            const x = new Date(value.toString() + 'Z');
            const y = this.datepipe.transform(x, 'yyyy-MM-dd');
            return y;
        } catch (error) {
            return value;
        }
    }

    checkmarkFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
        return this.parseBoolean(value) ? `<i class="fa fa-check checkmark-icon" aria-hidden="true"></i>` :
            '';
    }

    parseBoolean(input: any): boolean {
        return /(true|1)/i.test(input + '');
    }

    metadata(old_metadata, inActiveStatusList: string[]) {
        return function (row) {
            const item = this.getItem(row);
            const meta = old_metadata(row) || {};

            if (item) {
                // Make sure the "cssClasses" property exists
                meta.cssClasses = meta.cssClasses || '';

                const inActive = inActiveStatusList.includes(item.entityStatus);
                if (inActive === true) {
                    meta.cssClasses += ' slickgrid-inactive-tr';
                }

                // if (item.qty < 1) {                   // If the quantity (qty) for this item less than 1
                //     meta.cssClasses += ' out-of-stock'; // add a class of "out-of-stock" to the row element.
                // }

                /* Here is just a random example that will add an HTML class to the row element
                   that is the value of your row's "rowClass" property. Be careful with this as
                   you may run into issues if the "rowClass" property isn't a string or isn't a
                   valid class name. */
                // if (item.rowClass) {
                //     const myClass = ' ' + item.rowClass;
                //     meta.cssClasses += myClass;
                // }
            }

            return meta;
        };
    }

    updateRowCssWithId() {
        console.log('updateCssIdList', this.updateCssIdList);
        if (this.arrayOfObjectIsNull(this.updateCssIdList)) { return; }
        this.dataviewObj.getItemMetadata = this.exeUpdateRowCssWithId(this.dataviewObj.getItemMetadata,
            this.updateCssClass, this.updateCssIdList);
        this.gridObj.invalidate();
        this.gridObj.render();
    }

    exeUpdateRowCssWithId(previousItemMetadata: any, newCssClass: string, ids: string[]) {
        return (rowNumber: number) => {
            const item = this.dataviewObj.getItem(rowNumber);
            let meta = {
                cssClasses: ''
            };
            if (typeof previousItemMetadata === 'object') {
                meta = previousItemMetadata(rowNumber);
            }

            if (meta && item) {
                const found = ids.find(id => id === item.id);
                if (found && found !== null) {
                    meta.cssClasses = (meta.cssClasses || '') + ' ' + newCssClass;
                }
            }

            return meta;
        };
    }

    UpdateAllTotals(args) {
        // this.gridOptions.createFooterRow = true;
        // this.gridOptions.showFooterRow = true;
        // this.gridOptions.footerRowHeight = 21;

        // this.render();

        let columnIdx = this.gridObj.getColumns().length;
        while (columnIdx--) {
            if (args.allColumns[columnIdx].type && args.allColumns[columnIdx].type === 5) {
                this.UpdateTotal(columnIdx, args.allColumns[columnIdx].field);
            }
        }
    }

    UpdateTotal(cell, field) {
        try {
            const col = this.columns.find(c => c.field === field);
            if (this.objectIsNull(col)) { return; }

            const columnId = this.gridObj.getColumns()[cell].id;
            const columnFeild = this.gridObj.getColumns()[cell].field;

            let total = 0;
            let i = this.value.length;
            while (i--) {
                total += (+this.value[i][columnFeild] || 0);
            }

            let strTotal = '';

            switch (col.dataType) {
                case 'number_General': {
                    strTotal = numberWithCommas(total, 1, 5);
                    break;
                }
                case 'amount_General': {
                    strTotal = numberWithCommas(total, 2, 2);
                    break;
                }
                case 'int_General': {
                    strTotal = numberWithCommas(total, 0, 0);
                    break;
                }
                default: {
                    strTotal = total.toString();
                    break;
                }
            }

            const columnElement = this.gridObj.getFooterRowColumn(columnId);
            columnElement.innerHTML = '<span>' + strTotal + '</span>';
        } catch (error) {
            console.log(error);
        }
    }

    bindFooter() {
        if (!this.footerObjectlist || this.footerObjectlist[0].config.length === 0) { return; }

        let cell = 0;
        const i = this.gridObj.getColumns().length;
        while (cell < i) {
            try {
                const columnId = this.gridObj.getColumns()[cell].id;
                // const columnFeild = this.gridObj.getColumns()[cell].field;

                const col = this.columns.find(s => s.id === columnId);

                const fotterConfig = this.footerObjectlist[0].config.find(s => s.name === col.colFooter[0]);
                const fotterData = this.footerObjectlist[0].data[fotterConfig.field];

                const columnElement = this.gridObj.getFooterRowColumn(columnId);
                columnElement.innerHTML = '<span>' + fotterData + '</span>';
            } catch (error) {
                console.log(error);
            }
            cell++;
        }
    }

    getHeader(colHeader: string[]): string {
        if (this.allowGrouping) { return null; }

        if (!this.colHeader || this.colHeader.length === 0) {
            return null;
        }

        const h = this.colHeader[0].find(s => s.name === colHeader[0]);

        return h.display;
    }

    /* Define grid Options and Columns */
    defineGrid() {
        let i = 0;
        this.columnDefinitions = [];
        this.columnDefinitionsVisible = [];
        if (this.func !== undefined) {
            this.func.forEach(s => {
                if (s.visible) {
                    if (s.funcType === 'checkbox') {
                        s.id = 'func_' + i.toString();
                        let field = 'isSelected';
                        if (s.field) { field = s.field; }
                        const cd = {
                            id: s.id,
                            field: s.function,
                            name: s.header || '',
                            columnGroup: '',
                            excludeFromHeaderMenu: true,
                            formatter: this.customEnableButtonFormatter,
                            minWidth: s.minWidth ? s.minWidth : 30,
                            maxWidth: s.maxWidth ? s.maxWidth : 30,
                            headerCssClass: (s.headerCssClass && s.headerCssClass !== '') ?
                                s.headerCssClass : 'vertical-text-header-checkbox',
                            header: s.showSelectAll !== false ? {
                                buttons: [
                                    {
                                        cssClass: 'fa fa-square header-checkbox',
                                        command: 'toggle-checkbox',
                                        tooltip: 'Select All',
                                        //   showOnHover: true,
                                    }
                                ]
                            } : null,
                            // use onCellClick OR grid.onClick.subscribe which you can see down below
                            onCellClick: (e: Event, args: OnEventArgs) => {
                                try {
                                    if (args.dataContext[field]) {
                                        args.dataContext[field] = false;
                                    } else {
                                        args.dataContext[field] = true;
                                    }
                                    this.toggleCompletedProperty(args && args.dataContext);
                                    console.log(args);
                                    if (this.emitCheckBoxCondition(args.dataContext, s)) {
                                        this.emitOnRowClick(args.dataContext, s.function);
                                    }
                                } catch (error) {
                                    console.log(error);
                                }
                            }
                        };
                        this.columnDefinitions.push(cd);
                        this.columnDefinitionsVisible.push(cd);
                        i++;
                    } else if (s.funcType === 'img') {
                        s.id = 'func_' + i.toString();
                        const cd = {
                            id: s.id,
                            field: s.function,
                            name: s.header || '',
                            columnGroup: '',
                            excludeFromHeaderMenu: true,
                            formatter: this.customImgFormatter,
                            minWidth: s.maxWidth,
                            maxWidth: s.maxWidth,
                            headerCssClass: s.class,
                        };
                        this.columnDefinitions.push(cd);
                        this.columnDefinitionsVisible.push(cd);
                        i++;
                    } else if (s.funcType === 'hasChanges') {
                        s.id = 'func_' + i.toString();
                        const cd = {
                            id: s.id,
                            field: s.function,
                            name: s.header || '',
                            columnGroup: '',
                            excludeFromHeaderMenu: true,
                            // formatter: this.customAuditLogListFormatter,
                            minWidth: 30,
                            maxWidth: 30,
                            headerCssClass: 'vertical-text-header-span',

                            // filter: {},
                            //   queryFieldFilter: 'assignee.id',
                            //   queryFieldSorter: 'assignee.name',
                            formatter: () => '',
                            asyncPostRender: this.renderAngularComponent.bind(this),
                            params: {
                                component: AuditTrailListComponent,
                                angularUtilService: this.angularUtilService,
                                complexFieldLabel: 'hasChanges', // for the exportCustomFormatter
                            },
                            exportCustomFormatter: Formatters.complexObject,
                        };
                        this.columnDefinitions.push(cd);
                        this.columnDefinitionsVisible.push(cd);
                        i++;
                    } else {
                        s.id = 'func_' + i.toString();
                        if (s.function === 'onRowSelect' || s.function === 'onEdit') {
                            s.header = 'Detail';
                        }
                        const cd = {
                            id: s.id,
                            field: s.function,
                            name: s.header || '',
                            columnGroup: '',
                            excludeFromHeaderMenu: true,
                            formatter: this.myCustomFuncFormatter,
                            minWidth: 30,
                            maxWidth: 30,
                            headerCssClass: 'vertical-text-header-span',
                            cssClass: 'slickgrid-col-cell-func',
                            // use onCellClick OR grid.onClick.subscribe which you can see down below
                            onCellClick: (e: Event, args: OnEventArgs) => {
                                console.log(args);
                                //   if (confirm('Are you sure edit ' + args.dataContext.title + '?')) {
                                //     this.angularGrid.gridService.deleteDataGridItemById(args.dataContext.id);
                                //   }
                                //   this.onRowEdit(args.dataContext);
                                if (this.emitFuncCondition(args.dataContext, s)) {
                                    // this.angularGrid.gridService.highlightRow(args.row, 1500);
                                    // this.angularGrid.gridService.setSelectedRow(args.row);
                                    this.emitOnRowClick(args.dataContext, s.function);
                                }
                            }
                        };
                        this.columnDefinitions.push(cd);
                        this.columnDefinitionsVisible.push(cd);
                        i++;
                    }
                }
            });
        } else {
            this.func = [];
        }


        if (this.columns !== undefined) {
            const sumCols = this.columns.filter(s => s.sumInGrouping === true);
            const aggregators = [];
            sumCols.forEach(s => {
                aggregators.push(new Aggregators.Sum(s.field));
            });
            this.columns.forEach(s => {
                s.id = 'colm_' + i.toString();
                let cd = {
                    id: s.id,
                    name: s.header || '',
                    field: s.field,
                    columnGroup: this.getHeader(s.colHeader),
                    minWidth: +s.width || 0,
                    maxWidth: +s.width * 2,
                    headerCssClass: 'eslick-header-span ' + s.headerClass,
                    // cssClass: s.class || '',
                    filterable: true,
                    sortable: true,
                    // type: this.getFieldType(s.dataType),
                    groupTotalsFormatter: null,
                    params: {},
                    grouping: {},
                };
                if (s.isSubObject === true) {
                    cd.field = s.field + '.' + s.subField;
                }
                if (this.allowGrouping) {
                    // if need to display sum
                    if (sumCols.length > 0) {
                        const sumCol = sumCols.find(c => c.id === s.id);
                        if (!sumCol) {
                            cd.grouping = {
                                getter: s.field,
                                formatter: (g) => s.header + `: ${g.value}  <span style="color:green">(${g.count} items)</span>`,
                                aggregators: aggregators,
                                aggregateCollapsed: false,
                                collapsed: false
                            };
                        } else {
                            cd.groupTotalsFormatter = GroupTotalFormatters.sumTotals;
                            cd.params = { groupFormatterPrefix: '<b>T</b>: ' /*, groupFormatterSuffix: ' USD'*/ };
                            cd.grouping = {
                                getter: s.field,
                                formatter: (g) => s.header + `: ${g.value}  <span style="color:green">(${g.count} items)</span>`,
                                aggregators: aggregators,
                                aggregateCollapsed: false,
                                collapsed: false
                            };
                        }
                    } else {
                        cd.grouping = {
                            getter: s.field,
                            formatter: (g) => s.header + `: ${g.value}  <span style="color:green">(${g.count} items)</span>`,
                            //   aggregators: [
                            //     new Aggregators.Sum('ha')
                            //   ],
                            aggregateCollapsed: false,
                            collapsed: false
                        };
                    }
                }
                cd = this.getFieldType(cd, s);
                this.columnDefinitions.push(cd);
                i++;
                if (s.visible) {
                    this.columnDefinitionsVisible.push(cd);
                }
            });
        } else {
            this.columns = [];
        }
    }

    renderAngularComponent(cellNode: HTMLElement, row: number, dataContext: any, colDef: Column) {
        if (colDef.params.component && dataContext['hasChanges'] === true) {
            const componentOutput = this.angularUtilService.createAngularComponent(colDef.params.component);
            Object.assign(componentOutput.componentRef.instance, {
                //   item: dataContext
                entityName: this.strTableName,
                columns: this.columns,
                columnList: this.logColumnList,
                rowID: dataContext['id'],
            });

            // use a delay to make sure Angular ran at least a full cycle and make sure it finished rendering the Component
            setTimeout(() => $(cellNode).empty().html(componentOutput.domElement));

            //   let themeLink: HTMLLinkElement = <HTMLLinkElement> document.getElementById(cellNode.id);
            //   setTimeout(() => themeLink = componentOutput.domElement);
        }
    }

    defineGridOption() {
        const mappedColumnDefinitions = this.columnDefinitionsVisible.map((col) => {
            return {
                columnId: col.id.toString(), cssClass: col.cssClass,
                headerCssClass: col.headerCssClass, width: col.minWidth
            };
        });

        this.gridOptions = {
            presets: {
                columns: mappedColumnDefinitions
            },
            autoResize: {
                containerId: 'slick-container-' + this.gridId,
                sidePadding: 10,
                bottomPadding: this.slickBottomPadding,
                minHeight: this.slickMinHeight,
                maxHeight: this.slickMaxHeight,
            },
            rowHeight: 24,
            formatterOptions: {
                dateSeparator: '-'
            },
            enableRowSelection: true,
            rowSelectionOptions: {
                // True (Single Selection), False (Multiple Selections)
                selectActiveRow: true
            },

            autoEdit: true,
            editable: true,
            enableCellNavigation: true,
            enableColumnPicker: true,
            // enableExcelCopyBuffer: true,
            editCommandHandler: (item, column, editCommand) => {
                this._commandQueue.push(editCommand);
                editCommand.execute();
            },

            createFooterRow: true,
            showFooterRow: true,
            footerRowHeight: 21,

            // enableDraggableGrouping: true,
            // createPreHeaderPanel: true,
            // showPreHeaderPanel: true,
            // preHeaderPanelHeight: 40,

            showHeaderRow: true, // !this.defaultHideFilter,
            enableFiltering: true,
            enableSorting: true,
            enableColumnReorder: true,
            enableExcelExport: false,
            exportOptions: {
                sanitizeDataExport: true
            },
            gridMenu: {
                //   iconCssClass: 'fa fa-ellipsis-v',
                customItems: [
                    {
                        iconCssClass: 'fa fa-refresh',
                        disabled: false,
                        command: 'refresh',
                        positionOrder: 99,
                        title: 'Refresh',
                        tooltip: 'Refresh List'
                    },
                    // {
                    //     iconCssClass: 'fa fa-retweet',
                    //     disabled: false,
                    //     command: 'render',
                    //     positionOrder: 99,
                    //     title: 'Render',
                    //     tooltip: 'Render List'
                    // },
                    {
                        iconCssClass: 'fa fa-plus',
                        disabled: false,
                        command: 'total',
                        positionOrder: 99,
                        title: 'Total',
                        tooltip: 'Total of each column'
                    }
                ],
                onCommand: (e, args) => {
                    if (args.command === 'toggle-preheader') {
                        // in addition to the grid menu pre-header toggling (internally), we will also clear grouping
                        //   this.clearGrouping();
                    } else if (args.command === 'refresh') {
                        console.log('refresh args', args);
                        this.emitList(args);
                    } else if (args.command === 'render') {
                        this.render();
                    } else if (args.command === 'total') {
                        console.log('UpdateAllTotals args', args);
                        this.UpdateAllTotals(args);
                    }
                },
            },
            // draggableGrouping: {
            //   dropPlaceHolderText: 'Drop a column header here to group by the column',
            //   // groupIconCssClass: 'fa fa-outdent',
            //   deleteIconCssClass: 'fa fa-times',
            //   onGroupChanged: (e, args) => this.onGroupChanged(args),
            //   onExtensionRegistered: (extension) => this.draggableGroupingPlugin = extension,
            // }
            dataItemColumnValueExtractor: function (item, columnDef) {
                const names = columnDef.field.split('.');
                let val = item[names[0]];

                for (let i = 1; i < names.length; i++) {
                    if (val && typeof val === 'object' && names[i] in val) {
                        val = val[names[i]];
                    } else {
                        val = '';
                    }
                }

                return val;
            }
        };

        if (this.colHeader && this.colHeader.length > 0) {
            this.gridOptions.createPreHeaderPanel = true;
            this.gridOptions.showPreHeaderPanel = true;
            this.gridOptions.preHeaderPanelHeight = 40;
            this.gridOptions.gridMenu.hideTogglePreHeaderCommand = false;
        }

        if (this.allowGrouping) {
            this.gridOptions.enableDraggableGrouping = true;
            this.gridOptions.createPreHeaderPanel = true;
            this.gridOptions.showPreHeaderPanel = true;
            this.gridOptions.preHeaderPanelHeight = 40;
            this.gridOptions.gridMenu.hideTogglePreHeaderCommand = false;

            this.gridOptions.draggableGrouping = {
                dropPlaceHolderText: 'Drop a column header here to group by the column',
                // groupIconCssClass: 'fa fa-outdent',
                deleteIconCssClass: 'fa fa-times',
                onGroupChanged: (e, args) => this.onGroupChanged(args),
                onExtensionRegistered: (extension) => this.draggableGroupingPlugin = extension,
            };
        }

        const cb = this.func.find(s => s.funcType === 'checkbox');
        console.log('cb');
        console.log(cb);
        if (cb) {
            console.log('cb yes');
            this.gridOptions.enableHeaderButton = true;
            this.gridOptions.enableHeaderMenu = false;
            this.gridOptions.headerButton = {
                onCommand: (e, args) => {
                    console.log(args);
                    const column = args.column;
                    const button = args.button;
                    const command = args.command;
                    // let columnsWithHighlightingById = {};
                    // if (!columnsWithHighlightingById) {
                    //   columnsWithHighlightingById = {};
                    // }

                    if (command === 'toggle-checkbox') {
                        if (button.cssClass === 'fa fa-square header-checkbox') {
                            // delete columnsWithHighlightingById[column.id];
                            button.cssClass = 'fa fa-check-square header-checkbox-check';
                            // button.tooltip = 'Highlight negative numbers.';
                            this.onSelectAllClick(true);
                            cb.args = true;
                            this.emitOnRowClick(cb, 'onSelectAllClick');
                        } else {
                            // columnsWithHighlightingById[column.id] = true;
                            button.cssClass = 'fa fa-square header-checkbox';
                            // button.tooltip = 'Remove highlight.';
                            this.onSelectAllClick(false);
                            cb.args = false;
                            this.emitOnRowClick(cb, 'onSelectAllClick');
                        }

                        //   this.gridObj.invalidate();
                    }
                }
            };
        }

        const hc = this.func.find(s => s.funcType === 'hasChanges');
        if (hc) {
            this.gridOptions.enableAsyncPostRender = true; // for the Angular PostRenderer, don't forget to enable it
            this.gridOptions.asyncPostRenderDelay = 0; // also make sure to remove any delay to render it
            this.gridOptions.params = {
                angularUtilService: this.angularUtilService // provide the service to all at once (Editor, Filter, AsyncPostRender)
            };
        }

        const img = this.func.find(s => s.funcType === 'img');
        if (img) {
            this.gridOptions.rowHeight = img.rowHeight;
        }

        if (this.allowLazyLoading === true) {
            this.gridOptions.multiColumnSort = true;
            this.gridOptions.pagination = {
                pageSizes: [5, 10, 20, 50, 100, 500, 1000],
                pageSize: 20,
                totalItems: 0
            };
            this.gridOptions.presets = {
                // // you can also type operator as string, e.g.: operator: 'EQ'
                // filters: [
                //     { columnId: 'gender', searchTerms: ['male'], operator: OperatorType.equal },
                // ],
                // sorters: [
                //     // direction can be written as 'asc' (uppercase or lowercase) and/or use the SortDirection type
                //     { columnId: 'name', direction: 'asc' }
                // ],
                pagination: { pageNumber: 1, pageSize: 20 }
            };
            this.gridOptions.backendServiceApi = {
                service: new GridOdataService(),
                options: {
                    enableCount: true, // add the count in the OData query, which will return a property named
                    // "odata.count" (v2) or "@odata.count" (v4)
                    version: 4        // defaults to 2, the query string is slightly different between OData 2 and 4
                } as OdataOption,
                preProcess: () => this.slickLazyLoadingPreProcess(),
                process: (query) => this.getLazyLoadingApiCall(query),
                postProcess: (response) => {
                    //   this.metrics = response.metrics;
                    this.getLazyLoadingCallback(response);
                }
            };
        }
    }

    getLazyLoadingApiCall(query) {
        console.log('query: ', query);
        return new Promise((resolve, reject) => {
            try {
                this.lazyLoadingApiCallEvent.emit({ query: query });
                this.lazyLoadingChangesSubscription = this.lazyLoadingChanges.subscribe(l => {
                    if (l === query) {
                        resolve('');
                    }
                });
            } catch (error) {
                console.error(error);
                this.loading = false;
                resolve('');
            }
        });
    }

    getLazyLoadingCallback(datas) {
        const res = (!this.value || this.value === null) ? [] : this.value;
        const data = { totalRecordCount: res.length, items: res };
        this.loading = false;
        // totalItems property needs to be filled for pagination to work correctly
        // however we need to force Angular to do a dirty check, doing a clone object will do just that
        const countPropName = 'totalRecordCount'; // you can use "totalRecordCount" or any name or "odata.count" when "enableCount" is set
        // if (this.isCountEnabled) {
        //   countPropName = 'odata.count';
        // }
        this.gridOptions.pagination.totalItems = data[countPropName];
        // if (this.metrics) {
        //   this.metrics.totalItemCount = data[countPropName];
        // }
        this.gridOptions = Object.assign({}, this.gridOptions);

        // once pagination totalItems is filled, we can update the dataset
        this.value = data['items'];
        // this.odataQuery = data['query'];
        this.cd.detectChanges();
    }

    slickLazyLoadingPreProcess() {
        this.loading = true;
        this.cd.detectChanges();
    }

    onSelectAllClick(event: boolean) {
        this.value.forEach(v => {
            v.isSelected = event;
        });
        this.render();
        console.log(this.value);
    }

    clearGroupsAndSelects() {
        this.clearGroupingSelects();
        this.clearGrouping();
    }

    clearGrouping() {
        if (this.draggableGroupingPlugin && this.draggableGroupingPlugin.setDroppedGroups) {
            this.draggableGroupingPlugin.clearDroppedGroups();
        }
    }

    clearGroupingSelects() {
        this.selectedGroupingFields.forEach((g, i) => this.selectedGroupingFields[i] = '');
    }

    collapseAllGroups() {
        this.dataviewObj.collapseAllGroups();
    }

    expandAllGroups() {
        this.dataviewObj.expandAllGroups();
    }

    exportToExcel() {
        this.angularGrid.excelExportService.exportToExcel({
            filename: 'Export',
            format: FileType.xlsx
        });
    }

    exportToCsv(type = 'csv') {
        this.angularGrid.exportService.exportToFile({
            delimiter: (type === 'csv') ? DelimiterType.comma : DelimiterType.tab,
            filename: 'myExport',
            format: (type === 'csv') ? FileType.csv : FileType.txt
        });
    }

    groupByDuration() {
        this.clearGrouping();
        if (this.draggableGroupingPlugin && this.draggableGroupingPlugin.setDroppedGroups) {
            this.showPreHeader();
            this.draggableGroupingPlugin.setDroppedGroups('duration');
            this.gridObj.invalidate();
            this.gridObj.render();
        }
    }

    groupByDurationOrderByCount(isOrderingByCount = false) {
        this.durationOrderByCount = isOrderingByCount;
        this.clearGrouping();
        this.groupByDuration();
    }

    groupByDurationEffortDriven() {
        this.clearGrouping();
        if (this.draggableGroupingPlugin && this.draggableGroupingPlugin.setDroppedGroups) {
            this.showPreHeader();
            this.draggableGroupingPlugin.setDroppedGroups(['duration', 'effortDriven']);
            this.gridObj.invalidate();
            this.gridObj.render();
        }
    }

    groupByFieldName(fieldName, index) {
        this.clearGrouping();
        if (this.draggableGroupingPlugin && this.draggableGroupingPlugin.setDroppedGroups) {
            // get the field names from Group By select(s) dropdown, but filter out any empty fields
            const groupedFields = this.selectedGroupingFields.filter((g) => g !== '');

            this.showPreHeader();
            this.draggableGroupingPlugin.setDroppedGroups(groupedFields);
            this.gridObj.invalidate();
            this.gridObj.render();
        }
    }

    onGroupChanged(change: { caller?: string; groupColumns: Grouping[] }) {
        // the "caller" property might not be in the SlickGrid core lib yet, reference PR https://github.com/6pac/SlickGrid/pull/303
        const caller = change && change.caller || [];
        const groups = change && change.groupColumns || [];

        if (Array.isArray(this.selectedGroupingFields) && Array.isArray(groups) && groups.length > 0) {
            // update all Group By select dropdown
            this.selectedGroupingFields.forEach((g, i) => this.selectedGroupingFields[i] = groups[i] && groups[i].getter || '');
        } else if (groups.length === 0 && caller === 'remove-group') {
            this.clearGroupingSelects();
        }
    }

    showPreHeader() {
        this.gridObj.setPreHeaderPanelVisibility(true);
    }

    selectTrackByFn(index, item) {
        return index;
    }

    toggleDraggableGroupingRow() {
        this.clearGrouping();
        this.gridObj.setPreHeaderPanelVisibility(!this.gridObj.getOptions().showPreHeaderPanel);
    }
    // Angular-Slickgrid end

    ngOnDestroy() {
        if (this.lazyLoadingChangesSubscription !== undefined) {
            this.lazyLoadingChangesSubscription.unsubscribe();
        }
    }

    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; }
    }

}

@NgModule({
    imports: [CommonModule, ButtonModule, TableModule, OverlayPanelModule, CheckboxModule,
        InputTextModule, FormsModule, AuditTrailListModule, DropdownModule, MultiSelectModule,
        CurrencyMaskModule, BlockUIModule, PanelModule, ProgressSpinnerModule, ListboxModule,
        AngularSlickgridModule
            .forRoot({
                // add any Global Grid Options/Config you might want
                // to avoid passing the same options over and over in each grids of your App
                // enableAutoResize: true,
                // autoResize: {
                //   containerId: 'slick-container',
                //   sidePadding: 15
                // }
            })
    ],
    entryComponents: [AuditTrailListComponent],
    exports: [EtableComponent],
    declarations: [EtableComponent]
})
export class ETableModule { }
