// See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html
import { HTMLBox, HTMLBoxView } from "@bokehjs/models/layouts/html_box";
import { div } from "@bokehjs/core/dom";
// See https://docs.bokeh.org/en/latest/docs/reference/core/properties.html
import * as p from "@bokehjs/core/properties";
export function set_size(el, model) {
    let width_policy = model.width != null ? "fixed" : "fit";
    let height_policy = model.height != null ? "fixed" : "fit";
    const { sizing_mode } = model;
    if (sizing_mode != null) {
        if (sizing_mode == "fixed")
            width_policy = height_policy = "fixed";
        else if (sizing_mode == "stretch_both")
            width_policy = height_policy = "max";
        else if (sizing_mode == "stretch_width")
            width_policy = "max";
        else if (sizing_mode == "stretch_height")
            height_policy = "max";
        else {
            switch (sizing_mode) {
                case "scale_width":
                    width_policy = "max";
                    height_policy = "min";
                    break;
                case "scale_height":
                    width_policy = "min";
                    height_policy = "max";
                    break;
                case "scale_both":
                    width_policy = "max";
                    height_policy = "max";
                    break;
                default:
                    throw new Error("unreachable");
            }
        }
    }
    if (width_policy == "fixed" && model.width)
        el.style.width = model.width + "px";
    else if (width_policy == "max")
        el.style.width = "100%";
    if (height_policy == "fixed" && model.height)
        el.style.height = model.height + "px";
    else if (height_policy == "max")
        el.style.height = "100%";
}
function transform_cds_to_records(cds) {
    const data = [];
    const columns = cds.columns();
    const cdsLength = cds.get_length();
    if (columns.length === 0 || cdsLength === null) {
        return [];
    }
    for (let i = 0; i < cdsLength; i++) {
        const item = {};
        for (const column of columns) {
            let array = cds.get_array(column);
            const shape = array[0].shape == null ? null : array[0].shape;
            if ((shape != null) && (shape.length > 1) && (typeof shape[0] == "number"))
                item[column] = array.slice(i * shape[1], i * shape[1] + shape[1]);
            else
                item[column] = array[i];
        }
        data.push(item);
    }
    return data;
}
// The view of the Bokeh extension/ HTML element
// Here you can define how to render the model as well as react to model changes or View events.
export class TabulatorModelView extends HTMLBoxView {
    constructor() {
        super(...arguments);
        this._tabulator_cell_updating = false;
    }
    // objectElement: any // Element
    connect_signals() {
        super.connect_signals();
        this.connect(this.model.properties.configuration.change, () => {
            this.render();
        });
        // this.connect(this.model.source.change, () => this.setData())
        this.connect(this.model.source.properties.data.change, () => {
            this.setData();
        });
        this.connect(this.model.source.streaming, () => this.addData());
        this.connect(this.model.source.patching, () => this.updateOrAddData());
        // this.connect(this.model.source.selected.change, () => this.updateSelection())
        this.connect(this.model.source.selected.properties.indices.change, () => this.updateSelection());
    }
    render() {
        super.render();
        console.log("render");
        const container = div({ class: "pnx-tabulator" });
        set_size(container, this.model);
        let configuration = this.getConfiguration();
        // I'm working on getting this working in the notebook but have not yet found the solution
        // See [Issue 1529](https://github.com/holoviz/panel/issues/15299)
        if (typeof Tabulator === 'undefined') {
            // Tabulator=require("tabulator-tables")
            // requirejs(["https://unpkg.com/tabulator-tables"]);
            // Tabulator=requirejs("https://unpkg.com/tabulator-tables");
            console.log("Tabulator not loaded. See https://github.com/holoviz/panel/issues/15299");
        }
        console.log(Tabulator);
        this.tabulator = new Tabulator(container, configuration);
        this.el.appendChild(container);
    }
    getConfiguration() {
        // I refer to this via _view because this is the tabulator element when cellEdited is used
        let _view = this;
        function rowSelectionChanged(data, _) {
            console.log("rowSelectionChanged");
            let indices = data.map((row) => row.index);
            _view.model.source.selected.indices = indices;
        }
        function startUpdating() {
            _view._tabulator_cell_updating = true;
        }
        function endUpdating() {
            _view._tabulator_cell_updating = false;
        }
        function cellEdited(cell) {
            console.log("cellEdited");
            const field = cell._cell.column.field;
            const index = cell._cell.row.data.index;
            const value = cell._cell.value;
            startUpdating();
            _view.model.source.patch({ [field]: [[index, value]] });
            _view.model._cell_change = { "c": field, "i": index, "v": value };
            endUpdating();
        }
        let default_configuration = {
            "rowSelectionChanged": rowSelectionChanged,
            "cellEdited": cellEdited,
            "index": "index",
        };
        let configuration = Object.assign(Object.assign({}, this.model.configuration), default_configuration);
        let data = this.model.source;
        if (data === null || Object.keys(data.data).length === 0) {
            return configuration;
        }
        else {
            console.log("adding data to configuration");
            data = transform_cds_to_records(data);
            return Object.assign(Object.assign({}, configuration), { "data": data });
        }
    }
    after_layout() {
        console.log("after_layout");
        super.after_layout();
        this.tabulator.redraw(true);
    }
    setData() {
        console.log("setData");
        let data = transform_cds_to_records(this.model.source);
        this.tabulator.setData(data);
    }
    addData() {
        console.log("addData");
        let data = transform_cds_to_records(this.model.source);
        this.tabulator.setData(data);
    }
    updateOrAddData() {
        // To avoid double updating the tabulator data
        if (this._tabulator_cell_updating === true) {
            return;
        }
        console.log("updateData");
        let data = transform_cds_to_records(this.model.source);
        this.tabulator.setData(data);
    }
    updateSelection() {
        console.log("updateSelection");
        if (this.tabulator == null) {
            return;
        }
        let indices = this.model.source.selected.indices;
        let selectedRows = this.tabulator.getSelectedRows();
        for (let row of selectedRows) {
            if (!indices.includes(row.getData().index)) {
                row.toggleSelect();
            }
        }
        for (let index of indices) {
            // Improve this
            // Maybe tabulator should use id as index?
            this.tabulator.selectRow(index);
        }
    }
}
TabulatorModelView.__name__ = "TabulatorModelView";
// The Bokeh .ts model corresponding to the Bokeh .py model
export class TabulatorModel extends HTMLBox {
    constructor(attrs) {
        super(attrs);
    }
    static init_TabulatorModel() {
        this.prototype.default_view = TabulatorModelView;
        this.define({
            configuration: [p.Any,],
            source: [p.Any,],
            _cell_change: [p.Any,],
        });
    }
}
TabulatorModel.__name__ = "TabulatorModel";
TabulatorModel.__module__ = "awesome_panel_extensions.bokeh_extensions.tabulator_model";
TabulatorModel.init_TabulatorModel();
//# sourceMappingURL=tabulator_model.js.map