"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnnotationsService = void 0;
const tslib_1 = require("tslib");
const InternalRedux = tslib_1.__importStar(require("../../Redux/ActionsReducers/InternalRedux"));
const ArrayExtensions_1 = tslib_1.__importDefault(require("../Extensions/ArrayExtensions"));
/**
 * This service controls the interaction between Notes & Comments
 * If there are active Notes or Comments it listens to Cell Selection and Mouse Enter events
 */
class AnnotationsService {
    api;
    adaptable;
    isListeningToEvents;
    constructor(api) {
        this.api = api;
        this.isListeningToEvents = false;
        this.adaptable = api.internalApi.getAdaptableInstance();
        this.adaptable.api.eventApi.on('AdaptableReady', () => this.checkListenToEvents());
    }
    destroy() { }
    getAdaptableState() {
        return this.api.internalApi.getAdaptableState();
    }
    dispatchAction(action) {
        this.api.internalApi.dispatchReduxAction(action);
    }
    static isSameAddress(a, b) {
        if (!a || !b) {
            return false;
        }
        if (a?.ColumnId === b?.ColumnId && a?.PrimaryKeyValue === b?.PrimaryKeyValue) {
            return true;
        }
        // Primary keys retrieved from the grid dom are always strings, so we must also consider them strings
        if ((typeof a.PrimaryKeyValue === 'number' && typeof b.PrimaryKeyValue === 'string') ||
            (typeof b.PrimaryKeyValue === 'string' && typeof a.PrimaryKeyValue === 'number')) {
            return (a.PrimaryKeyValue.toString() === b.PrimaryKeyValue.toString() && a.ColumnId === b.ColumnId);
        }
        return false;
    }
    checkListenToEvents() {
        if (!this.isListeningToEvents && this.shouldListenToEvents()) {
            this.setUpEventListeners();
            this.isListeningToEvents = true;
        }
    }
    shouldListenToEvents() {
        // Listen to events if we either have Notes in state or if Comments have been set up
        return (ArrayExtensions_1.default.IsNotNullOrEmpty(this.api.noteApi.getAllNotes()) ||
            this.api.internalApi.getModuleService().isAdapTableModulePresent('Comment'));
    }
    setUpEventListeners() {
        this.adaptable._on('MouseEnter', (event) => this.handleMouseEnter(event));
        this.api.eventApi.on('CellSelectionChanged', (params) => {
            const cells = params.selectedCellInfo.gridCells;
            if (ArrayExtensions_1.default.hasOneItem(cells)) {
                const selectedCell = cells[0];
                if (selectedCell.column?.columnId && selectedCell.primaryKeyValue) {
                    const selectedCellAddress = {
                        PrimaryKeyValue: selectedCell.primaryKeyValue,
                        ColumnId: selectedCell.column.columnId,
                    };
                    this.handleCellSelected(selectedCellAddress);
                }
            }
        });
    }
    getCellPositionFromEvent(event) {
        const target = event.target;
        if (!target?.classList?.contains?.('ag-cell')) {
            return null;
        }
        try {
            const PrimaryKeyValue = target.parentElement.getAttribute('row-id');
            return {
                PrimaryKeyValue,
                ColumnId: target.getAttribute('col-id'),
            };
        }
        catch (e) {
            return null;
        }
    }
    handleMouseEnter(event) {
        const editMode = this.getEditMode();
        if (editMode) {
            // ignore
            return;
        }
        const cellPosition = this.getCellPositionFromEvent(event);
        const openCellAddress = this.getOpenCellAddress();
        // Hovering over something that is not a cell and there is no open note
        if (!cellPosition && openCellAddress) {
            // need to close if the new cell does not have a note
            this.hidePopup();
            return;
        }
        // call only if cell address is different
        if (AnnotationsService.isSameAddress(openCellAddress, cellPosition)) {
            return;
        }
        const cellNote = this.api.noteApi.getNoteForCell(cellPosition);
        const cellComments = this.api.commentApi.getCommentThreadForCell(cellPosition);
        if (!cellNote && !cellComments) {
            return;
        }
        this.showPopup(cellPosition, false);
    }
    handleCellSelected(cellAddress) {
        // if already opened - do nothing
        const openCellAddress = this.getOpenCellAddress();
        if (AnnotationsService.isSameAddress(openCellAddress, cellAddress)) {
            return;
        }
        // if open but this has no note, close
        const cellNote = this.api.noteApi.getNoteForCell(cellAddress);
        const cellComments = this.api.commentApi.getCommentThreadForCell(cellAddress);
        const hasNotesOrComments = cellNote || cellComments;
        if (openCellAddress && !hasNotesOrComments) {
            // hide only if in edit mode
            // because if you select a cell and move the mouse fast over another cell
            // with a note, you do not want to close that note
            // the selection is debounced, so the moment goes over the new cell this event is triggered
            if (this.getEditMode()) {
                this.hidePopup();
            }
            return;
        }
        // if open but the new selection has a note open that one in edit mode (because of click)
        if (openCellAddress && hasNotesOrComments) {
            this.showPopup(cellAddress, true);
            return;
        }
    }
    getOpenCellAddress() {
        return InternalRedux.CommentsAndNotesSelector(this.getAdaptableState().Internal);
    }
    getEditMode() {
        return InternalRedux.CommentsAndNotesEditModeSelector(this.getAdaptableState().Internal);
    }
    hidePopup() {
        this.dispatchAction(InternalRedux.CellPopupHide());
    }
    showPopup(cellAddress, editMode) {
        this.dispatchAction(InternalRedux.CellPopupShow(cellAddress, editMode));
    }
    editFocusedEntity(entity) {
        this.dispatchAction(InternalRedux.CellPopupEditFocusedEntity(entity));
    }
    getNotePopupEditMode() {
        return InternalRedux.CommentsAndNotesEditModeSelector(this.getAdaptableState().Internal);
    }
}
exports.AnnotationsService = AnnotationsService;
