"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataService = void 0;
const tslib_1 = require("tslib");
const Emitter_1 = tslib_1.__importDefault(require("../../Utilities/Emitter"));
const rxjs_1 = require("rxjs");
const Helper_1 = tslib_1.__importDefault(require("../Helpers/Helper"));
// ~ 8 hours
const MAX_TIMEFRAME_SIZE = 86400000;
class DataService {
    constructor(adaptable) {
        this.adaptable = adaptable;
        this.on = (eventName, callback) => this.emitter.on(eventName, callback);
        this.emit = (eventName, data) => this.emitter.emit(eventName, data);
        this.adaptable = adaptable;
        this.emitter = new Emitter_1.default();
        this.dataChangeLogSubject$ = new rxjs_1.Subject();
        this.dataChangeLog$ = this.dataChangeLogSubject$.asObservable();
        this.gridChangeLogSubject$ = new rxjs_1.Subject();
        this.gridChangeLog$ = this.gridChangeLogSubject$.asObservable();
        this.undoChangeLog = new Map();
        this.undoChangeTimers = new Map();
    }
    destroy() {
        this.emitter.destroy();
        this.emitter = null;
        this.dataChangeLogSubject$.complete();
        this.dataChangeLogSubject$ = null;
        this.dataChangeLog$ = null;
        this.gridChangeLogSubject$.complete();
        this.gridChangeLogSubject$ = null;
        this.gridChangeLog$ = null;
        this.undoChangeLog.clear();
        this.undoChangeLog = null;
        this.undoChangeTimers.clear();
        this.undoChangeTimers = null;
    }
    CreateDataChangedEvent(cellDataChangedInfo) {
        if (cellDataChangedInfo.newValue != cellDataChangedInfo.oldValue) {
            this.emitter.emitSync('CellDataChanged', cellDataChangedInfo);
            this.adaptable.api.gridApi.internalApi.fireCellChangedEvent(cellDataChangedInfo);
            const dataChangeLogEntry = this.extractDataChangeLogEntry(cellDataChangedInfo);
            this.dataChangeLogSubject$.next(dataChangeLogEntry);
        }
    }
    CreateGridChangedEvent(gridDataChangedInfo) {
        this.gridChangeLogSubject$.next(gridDataChangedInfo);
    }
    // we need this temporary "shared memory" because the value change and the AG Grid cellChanged event are asynchronous
    // in the first phase we keep the undone change
    logUndoChange(change) {
        const { primaryKeyValue, column, oldValue, newValue } = change;
        const undoChangeKey = this.getUndoChangeKey(primaryKeyValue, column.columnId, oldValue, newValue);
        this.undoChangeLog.set(undoChangeKey, change);
        // normally the extractUndoChange() should be executed right after this method
        // just to be sure that no 'zombie' undo change remains here (if something goes wrong with the undo value change)
        // we manually extract the change after a 2 seconds
        // why 2 and not 3 or 1? no good reason, only seems like a reasonable waiting time :)
        const UNDO_WAIT = 2000;
        const timeoutId = setTimeout(() => {
            this.adaptable.logger.warn(`Undo change was NOT handled, this should NOT happen: PK(${change.primaryKeyValue}) Col(${change.column}) RevertedValue(${change.newValue}) NewValue(${change.oldValue})`);
            this.extractUndoChange(change);
        }, UNDO_WAIT);
        this.undoChangeTimers.set(undoChangeKey, timeoutId);
    }
    // in the second phase, when AG-Grid triggers the cellChange event, we check if it corresponds to an undone change
    extractUndoChange(change) {
        const { primaryKeyValue, column, oldValue, newValue } = change;
        // this is post-undo, so we have to swap the new& old values
        const undoChangeKey = this.getUndoChangeKey(primaryKeyValue, column.columnId, newValue, oldValue);
        const result = this.undoChangeLog.get(undoChangeKey);
        this.undoChangeLog.delete(undoChangeKey);
        const timeoutId = this.undoChangeTimers.get(undoChangeKey);
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
        return result;
    }
    getUndoChangeKey(primaryKeyValue, columnId, previousValue, newValue) {
        return JSON.stringify({
            primaryKeyValue,
            columnId,
            previousValue,
            newValue,
        });
    }
    extractDataChangeLogEntry(cellDataChangedInfo) {
        // create rowData snapshot
        const rowData = cellDataChangedInfo.rowData
            ? Helper_1.default.cloneObject(cellDataChangedInfo.rowData)
            : null;
        // strip down rowNode properties as it is pretty "heavy" on the memory
        const rowNode = rowData ? { data: rowData } : null;
        return Object.assign(Object.assign({}, cellDataChangedInfo), { rowNode,
            rowData });
    }
}
exports.DataService = DataService;
