import { h } from "@stencil/core";
import { EditCell } from './edit-cell';
import { BatchEditingController } from './controllers/batch-editing.controller';
import { NoopEditingController } from './controllers/noop-editing.controller';
import { RowEditingController } from './controllers/row-editing.controller';
import Tunnel from '../../locale/i18n.provider';
var Translations;
(function (Translations) {
    Translations["SAVE_ALL"] = "Save All";
    Translations["UNDO"] = "Undo";
    Translations["CREATE_NEW"] = "Create New";
})(Translations || (Translations = {}));
export class Editing {
    constructor() {
        this.rowsWillChangeListener = () => this.onRowsWillChange();
        this.rowsDidChangeListener = () => this.onRowsDidChange();
        this.history = [];
        /**
         * Renderer to use for cell content when the selected cell conditions are met
         */
        this.cell = (props) => h(EditCell, Object.assign({}, props));
        /**
         * If true, the user cannot create records
         */
        this.createDisabled = false;
        /**
         * Can the user add a row? Defaults to false.
         */
        this.creating = false;
        /**
         * If true, the user cannot delete records
         */
        this.deleteDisabled = false;
        /**
         * Can the user delete a row? Defaults to false.
         */
        this.deleting = false;
        /**
         * The mode of editing
         * Possible values are: `"batch"`, `"row"`, and `"noop"`. Defaults to "noop"
         */
        this.mode = 'noop';
        /**
         * If true, will emit a cancelable event to signal the table to update the underlying data
         */
        this.saving = false;
        /**
         * Can the user undo, defaults to true
         */
        this.undo = false;
        /**
         * Can the user edit? Defaults to false.
         */
        this.updating = false;
        /**
         * Rules to use for using this as a renderer
         */
        this.when = this.useAsRenderer.bind(this);
    }
    componentWillLoad() {
        this.table = this.element.closest('anj-table');
    }
    componentDidLoad() {
        this.anjCellControlDidLoad.emit();
        this.table.addEventListener('anjRowsWillLoad', this.rowsWillChangeListener);
        this.table.addEventListener('anjRowsDidLoad', this.rowsDidChangeListener);
        this.table.addEventListener('anjPage', this.rowsWillChangeListener);
        this.controller = this.initController();
    }
    componentDidUnload() {
        this.table.removeEventListener('anjRowsWillLoad', this.rowsWillChangeListener);
        this.table.removeEventListener('anjRowsDidLoad', this.rowsDidChangeListener);
        this.table.removeEventListener('anjPage', this.rowsWillChangeListener);
    }
    initController() {
        switch (this.mode) {
            case 'batch':
                return new BatchEditingController(this.element, this.table);
            case 'row':
                return new RowEditingController(this.element, this.table);
            default:
                return new NoopEditingController(this.element, this.table);
        }
    }
    useAsRenderer(column, rowIndex) {
        return (column.editable && (this.mode === 'batch' || rowIndex === this.table.activeRowIndex));
    }
    onRowsWillChange() {
        this.table.activeRowIndex = undefined;
    }
    async onRowsDidChange() {
        return new Promise(resolve => {
            window.setTimeout(() => {
                resolve(this.controller.validate(this.table.querySelector('.anj-table tbody')));
            });
        });
    }
    async onCreateStart() {
        const data = await this.controller.onCreateStart();
        this.anjCreateStart.emit({ data, key: undefined, index: 0 });
    }
    async onCreateEnd(event) {
        event.stopPropagation();
        const row = await this.controller.onCreateEnd(event);
        if (!row)
            return;
        this.pushHistory({ delete: [row] });
        this.anjCreateEnd.emit({ data: row, key: undefined });
        this.save({ create: [row] });
    }
    async onUpdateStart(event) {
        event.stopPropagation();
        const [index, data] = await this.controller.onUpdateStart(event);
        this.anjUpdateStart.emit(Object.assign(event.detail, { index, data }));
    }
    async onUpdateEnd(event) {
        event.stopPropagation();
        const change = await this.controller.onUpdateEnd(event);
        if (!change)
            return;
        const [update, row, index] = change;
        const data = Object.assign({}, row, update);
        this.pushHistory({ update: [row] });
        if (this.mode === 'row') {
            this.anjUpdateEnd.emit({ key: event.detail.key, data, index });
            this.save({ update: [data] });
        }
    }
    async onDelete(event) {
        event.stopPropagation();
        const [data, index] = await this.controller.onDelete(event);
        if (data[this.table.rowKey]) {
            this.pushHistory({ create: [data] });
        }
        this.anjDelete.emit({ index, data, key: event.detail.key });
        if (this.mode === 'row') {
            this.save({ delete: [data] });
        }
    }
    async onUndo() {
        const change = this.popHistory();
        await this.controller.undo(change);
        if (this.mode === 'row') {
            this.save(change);
        }
    }
    async onSuperSave() {
        const change = await this.controller.save();
        if (change) {
            this.clearHistory();
            this.save(change);
        }
    }
    save(patch) {
        if (!this.saving)
            return;
        this.anjEditWillSave.emit(patch);
    }
    clearHistory() {
        if (!this.undo)
            return;
        this.history = [];
    }
    pushHistory(change) {
        if (!this.undo)
            return;
        this.history = [change].concat(this.history);
    }
    popHistory() {
        if (!this.undo)
            return;
        const change = this.history[0];
        this.history = this.history.slice(1);
        return change;
    }
    control(data) {
        return h("anj-row-edit-control", { rowKey: data[this.table.rowKey], editing: this.controller ? this.controller.getEditType(data) : undefined, mode: this.mode, update: this.updating && this.mode !== 'batch', delete: this.deleting, deleteDisabled: this.deleteDisabled, onAnjCreateEnd: (e) => this.onCreateEnd(e), onAnjUpdateCancel: () => this.controller.onUpdateCancel(), onAnjUpdateStart: e => this.onUpdateStart(e), onAnjUpdateEnd: e => this.onUpdateEnd(e), onAnjDelete: e => this.onDelete(e) });
    }
    calculateColWidth() {
        const btnSize = 40;
        let multiplier = 0;
        if (this.deleting) {
            multiplier++;
        }
        if (this.updating && this.mode !== 'batch') {
            multiplier = 2;
        }
        const padding = multiplier > 0 ? 2 : 0;
        return `${(multiplier * btnSize) + padding}px`;
    }
    render() {
        return [
            h("anj-column", { filterable: false, internal: true, pinned: "right", editable: false, sizable: false, pinnable: false, orderable: false, selectable: false, name: "row-edit-control", width: this.calculateColWidth(), cellRenderer: (data) => this.control(data) }),
            this.mode === 'batch' && this.saving ?
                h("anj-button", { context: "icon", "aria-label": this.translator(Translations.SAVE_ALL), disabled: this.history.length === 0, onClick: async () => this.onSuperSave() },
                    h("svg", { slot: "icon-only", xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24" },
                        h("path", { d: "M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z" }))) : undefined,
            this.undo ?
                h("anj-button", { context: "icon", "aria-label": this.translator(Translations.UNDO), disabled: this.history.length === 0, onClick: () => this.onUndo() },
                    h("svg", { slot: "icon-only", xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24" },
                        h("path", { d: "M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z" }))) : undefined,
            this.creating ?
                h("anj-button", { context: "icon", "aria-label": this.translator(Translations.CREATE_NEW), disabled: this.createDisabled, onClick: () => this.onCreateStart() },
                    h("svg", { slot: "icon-only", xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24" },
                        h("path", { d: "M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" }))) : undefined
        ];
    }
    static get is() { return "anj-editing"; }
    static get originalStyleUrls() { return {
        "$": ["editing.scss"]
    }; }
    static get styleUrls() { return {
        "$": ["editing.css"]
    }; }
    static get properties() { return {
        "activeKey": {
            "type": "any",
            "mutable": true,
            "complexType": {
                "original": "number | string",
                "resolved": "number | string",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "The key of the record being edited (doesn't apply to batch mode). Is undefined when creating."
            },
            "attribute": "active-key",
            "reflect": false
        },
        "cell": {
            "type": "unknown",
            "mutable": false,
            "complexType": {
                "original": "CellRenderFn",
                "resolved": "(props: CellProps) => any",
                "references": {
                    "CellRenderFn": {
                        "location": "import",
                        "path": "../table.types"
                    },
                    "CellProps": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Renderer to use for cell content when the selected cell conditions are met"
            },
            "defaultValue": "(props: CellProps) => <EditCell {...props} />"
        },
        "createDisabled": {
            "type": "boolean",
            "mutable": true,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "If true, the user cannot create records"
            },
            "attribute": "create-disabled",
            "reflect": false,
            "defaultValue": "false"
        },
        "creating": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Can the user add a row? Defaults to false."
            },
            "attribute": "creating",
            "reflect": false,
            "defaultValue": "false"
        },
        "deleteDisabled": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "If true, the user cannot delete records"
            },
            "attribute": "delete-disabled",
            "reflect": false,
            "defaultValue": "false"
        },
        "deleting": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Can the user delete a row? Defaults to false."
            },
            "attribute": "deleting",
            "reflect": false,
            "defaultValue": "false"
        },
        "mode": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "EditingMode",
                "resolved": "\"batch\" | \"noop\" | \"row\"",
                "references": {
                    "EditingMode": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "The mode of editing\nPossible values are: `\"batch\"`, `\"row\"`, and `\"noop\"`. Defaults to \"noop\""
            },
            "attribute": "mode",
            "reflect": false,
            "defaultValue": "'noop'"
        },
        "saving": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "If true, will emit a cancelable event to signal the table to update the underlying data"
            },
            "attribute": "saving",
            "reflect": false,
            "defaultValue": "false"
        },
        "undo": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Can the user undo, defaults to true"
            },
            "attribute": "undo",
            "reflect": false,
            "defaultValue": "false"
        },
        "updating": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Can the user edit? Defaults to false."
            },
            "attribute": "updating",
            "reflect": false,
            "defaultValue": "false"
        },
        "when": {
            "type": "unknown",
            "mutable": false,
            "complexType": {
                "original": "CellRenderTest",
                "resolved": "(column: ColumnDefinition, rowIndex: number, columnIndex: number) => boolean",
                "references": {
                    "CellRenderTest": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": "Rules to use for using this as a renderer"
            },
            "defaultValue": "this.useAsRenderer.bind(this)"
        },
        "translator": {
            "type": "unknown",
            "mutable": false,
            "complexType": {
                "original": "IntlFormatFn",
                "resolved": "(value: any, variables?: any) => string",
                "references": {
                    "IntlFormatFn": {
                        "location": "import",
                        "path": "../../locale/i18n.provider"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [{
                        "text": undefined,
                        "name": "internal"
                    }],
                "text": ""
            }
        }
    }; }
    static get states() { return {
        "history": {}
    }; }
    static get events() { return [{
            "method": "anjCellControlDidLoad",
            "name": "anjCellControlDidLoad",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when the column has been created."
            },
            "complexType": {
                "original": "void",
                "resolved": "void",
                "references": {}
            }
        }, {
            "method": "anjCreateStart",
            "name": "anjCreateStart",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when creation of a record is started"
            },
            "complexType": {
                "original": "EditData",
                "resolved": "EditData",
                "references": {
                    "EditData": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            }
        }, {
            "method": "anjCreateEnd",
            "name": "anjCreateEnd",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when creation of a record is ended (except batch)"
            },
            "complexType": {
                "original": "EditData",
                "resolved": "EditData",
                "references": {
                    "EditData": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            }
        }, {
            "method": "anjDelete",
            "name": "anjDelete",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted when the user deletes a row"
            },
            "complexType": {
                "original": "EditData",
                "resolved": "EditData",
                "references": {
                    "EditData": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            }
        }, {
            "method": "anjUpdateStart",
            "name": "anjUpdateStart",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted inits update ends (except batch)"
            },
            "complexType": {
                "original": "EditData",
                "resolved": "EditData",
                "references": {
                    "EditData": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            }
        }, {
            "method": "anjUpdateEnd",
            "name": "anjUpdateEnd",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted inits update ends"
            },
            "complexType": {
                "original": "EditData",
                "resolved": "EditData",
                "references": {
                    "EditData": {
                        "location": "import",
                        "path": "../table.types"
                    }
                }
            }
        }, {
            "method": "anjEditWillSave",
            "name": "anjEditWillSave",
            "bubbles": true,
            "cancelable": true,
            "composed": true,
            "docs": {
                "tags": [],
                "text": "Emitted before attempting to save the data"
            },
            "complexType": {
                "original": "DataSourceChange",
                "resolved": "DataSourceChange",
                "references": {
                    "DataSourceChange": {
                        "location": "import",
                        "path": "../../../utils/data-source/data-source.types"
                    }
                }
            }
        }]; }
    static get elementRef() { return "element"; }
}
Tunnel.injectProps(Editing, ['translator']);
