var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { css, html, unsafeCSS } from "lit";
import { customElement, property } from "lit/decorators.js";
import "@openremote/or-rules";
import { Page } from "@openremote/or-app";
import { i18next } from "@openremote/or-translate";
import manager, { DefaultColor3, Util } from "@openremote/core";
import { InputType } from "@openremote/or-mwc-components/or-mwc-input";
import { OrAssetAttributePickerPickedEvent, OrAssetAttributePicker } from "@openremote/or-attribute-picker";
import moment from "moment";
import { buttonStyle } from "@openremote/or-rules";
import { createSelector } from "reselect";
import { isAxiosError } from "@openremote/rest";
import { showSnackbar } from "@openremote/or-mwc-components/or-mwc-snackbar";
import { showDialog } from "@openremote/or-mwc-components/or-mwc-dialog";
const tableStyle = require("@material/data-table/dist/mdc.data-table.css");
import { when } from "lit/directives/when.js";
export function pageExportProvider(store) {
    return {
        name: "export",
        routes: [
            "data-export"
        ],
        pageCreator: () => {
            return new PageExport(store);
        }
    };
}
let PageExport = class PageExport extends Page {
    static get styles() {
        // language=CSS
        return [
            unsafeCSS(tableStyle),
            unsafeCSS(buttonStyle),
            css `

                #wrapper {
                    height: 100%;
                    width: 100%;
                    display: flex;
                    flex-direction: column;
                    overflow: auto;
                }

                #title {
                    padding: 0 20px;
                    font-size: 18px;
                    font-weight: bold;
                    width: calc(100% - 40px);
                    max-width: 1360px;
                    margin: 20px auto;
                    align-items: center;
                    display: flex;
                    color: var(--or-app-color3, ${unsafeCSS(DefaultColor3)});
                }

                #title or-icon {
                    margin-right: 10px;
                    margin-left: 14px;
                }

                .panel {
                    width: calc(100% - 90px);
                    max-width: 1310px;
                    background-color: white;
                    border: 1px solid #e5e5e5;
                    border-radius: 5px;
                    position: relative;
                    margin: 0 auto;
                    padding: 24px;
                }

                .panel-title {
                    text-transform: uppercase;
                    font-weight: bolder;
                    line-height: 1em;
                    color: var(--internal-or-asset-viewer-title-text-color);
                    margin-bottom: 20px;
                    margin-top: 0;
                    flex: 0 0 auto;
                    letter-spacing: 0.025em;
                    color: var(--or-app-color3, ${unsafeCSS(DefaultColor3)});
                }

                th {
                    color: ${unsafeCSS(DefaultColor3)};
                }
                
                .mdc-data-table__row {
                    border-top-color: #D3D3D3;
                }

                td, th {
                    width: 25%
                }

                .meta-item-container {
                    flex-direction: row;
                    overflow: hidden;
                    max-height: 0;
                    transition: max-height 0.25s ease-out;
                    padding-left: 16px;
                }

                .mdc-data-table__header-cell {
                    font-weight: bold;
                    color: ${unsafeCSS(DefaultColor3)};
                }
                
                .button {
                    cursor: pointer;
                    display: flex;
                    flex-direction: row;
                    align-content: center;
                    padding: 16px;
                    align-items: center;
                    font-size: 14px;
                    text-transform: uppercase;
                    color: var(--or-app-color4);
                }
                .button or-icon {
                    --or-icon-fill: var(--or-app-color4);
                    margin-right: 5px;
                }

                .remove-button {
                    right: 20px;
                    top: 13px;
                    transform: translate(50%, -50%);
                    position: relative;
                }

                tr:hover .remove-button {
                    visibility: visible;
                }

                @media screen and (max-width: 768px) {
                    #title {
                        padding: 0;
                        width: 100%;
                    }

                    .hide-mobile {
                        display: none;
                    }

                    .panel {
                        border-radius: 0;
                        border-left: 0px;
                        border-right: 0px;
                        width: calc(100% - 48px);
                    }

                    td, th {
                        width: 50%
                    }
                }
                
                .timerange-wrapper {
                    margin-bottom: 1em
                }
                .options {
                    width: fit-content;
                    margin-bottom: 2em
                }
                .export-btn-wrapper {
                    display: flex;
                    justify-content: space-between;
                }

                .export-btn-wrapper .button {
                    padding: 0;
                    margin-right: 0;
                    margin-bottom: 0;
                }
            `,
        ];
    }
    get name() {
        return "export";
    }
    constructor(store) {
        super(store);
        this.oldestTimestamp = moment().subtract(1, 'months').valueOf();
        this.latestTimestamp = moment().valueOf();
        this._loading = false;
        this._exportFormats = {
            ["CSV" /* DatapointExportFormat.CSV */]: i18next.t('exportFormatCSV'),
            ["CSV_CROSSTAB" /* DatapointExportFormat.CSV_CROSSTAB */]: i18next.t('exportFormatCSVCrosstab'),
            ["CSV_CROSSTAB_MINUTE" /* DatapointExportFormat.CSV_CROSSTAB_MINUTE */]: i18next.t('exportFormatCSVCrosstabMinute')
        };
        this.selectedFormat = "CSV" /* DatapointExportFormat.CSV */;
        this.isClearExportBtnDisabled = true;
        this.isExportBtnDisabled = true;
        this.tableRows = [];
        this._realmSelector = (state) => state.app.realm || manager.displayRealm;
        this.getRealmState = createSelector([this._realmSelector], (realm) => __awaiter(this, void 0, void 0, function* () {
            this.realm = realm;
            this.loadConfig();
        }));
        this.export = () => {
            this._loading = true;
            manager.rest.api.AssetDatapointResource.getDatapointExport({
                attributeRefs: JSON.stringify(this.tableRows.map(attr => ({ id: attr.assetId, name: attr.attributeName }))),
                fromTimestamp: this.oldestTimestamp,
                toTimestamp: this.latestTimestamp,
                format: this.selectedFormat
            }, {
                responseType: "blob",
            }).then(response => {
                // This is the best we can do with xhr - would need to return a link to the file for proper streamed download support
                // @ts-ignore
                const url = window.URL.createObjectURL(new Blob([response.data]));
                const link = document.createElement('a');
                link.href = url;
                link.setAttribute("download", "dataexport.zip");
                document.body.appendChild(link);
                link.click();
                this._loading = false;
            }).catch(ex => {
                var _a;
                if (isAxiosError(ex)) {
                    if (((_a = ex.response) === null || _a === void 0 ? void 0 : _a.status) === 413) {
                        showSnackbar(undefined, "exportTooLargeError");
                    }
                    else if (ex.message.includes("timeout")) {
                        showSnackbar(undefined, "noAttributeDataTimeout");
                    }
                    else {
                        showSnackbar(undefined, "errorOccurred");
                    }
                }
                this._loading = false;
            });
        };
        this.clearSelection = () => {
            this.config = {
                realm: this.realm,
                selectedAttributes: []
            };
            this.saveConfig();
            this.tableRows = [];
            this.renderTableRows();
            this.isClearExportBtnDisabled = true;
            this.isExportBtnDisabled = true;
        };
    }
    render() {
        const headers = [
            i18next.t('assetName'),
            i18next.t('attributeName'),
            i18next.t('oldestDatapoint'),
            i18next.t('latestDatapoint')
        ];
        return html `
            <div id="wrapper">
                <div id="title">
                    <or-icon icon="database-export"></or-icon> 
                    ${i18next.t("dataExport")}
                </div>
                        
                <div class="panel">
                    <p class="panel-title">${i18next.t("dataSelection")}</p>
                    <div class="mdc-data-table" style="width: 100%; max-height: 500px; overflow-y: auto;margin-bottom: 2em">
                        <table class="mdc-data-table__table" aria-label="attribute list" >
                            <thead>
                            ${when(this._loading, () => html `
                                <div style="position: absolute; height: 100%; width: 100%;">
                                    <or-loading-indicator ?overlay="false"></or-loading-indicator>
                                </div>
                            `)}
                            <tr class="mdc-data-table__header-row">
                            ${headers.map(header => html `
                                <th class="mdc-data-table__header-cell" role="columnheader" scope="col">${header}</th>
                            `)}
                                <th></th>
                            </tr>
                            </thead>
                            <tbody id="table-body" class="mdc-data-table__content">
                            ${this.tableRowsHtml}
                            <tr class="mdc-data-table__row">
                                <td colspan="100%">
                                    <a class="button" @click="${() => this._openDialog()}"><or-icon icon="plus"></or-icon>${i18next.t("addAssetAttribute")}</a>
                                </td>
                            </tr>
                            </tbody>
                        </table>
                    </div>
                    <div class="options">
                        <div class="timerange-wrapper">
                            <or-mwc-input .type="${InputType.DATETIME}" label="${Util.capitaliseFirstLetter(i18next.t("exportFrom"))}" .value="${moment(this.oldestTimestamp).toDate()}" @or-mwc-input-changed="${(evt) => this.oldestTimestamp = evt.detail.value}"></or-mwc-input>
                            <or-mwc-input .type="${InputType.DATETIME}" label="${Util.capitaliseFirstLetter(i18next.t("to"))}" .value="${moment(this.latestTimestamp).toDate()}" @or-mwc-input-changed="${(evt) => this.latestTimestamp = evt.detail.value}"></or-mwc-input>
                        </div>
                        <div>
                            <or-mwc-input .type="${InputType.SELECT}" label="${i18next.t('exportFormat')}" .value="${this.selectedFormat}" style="width: 100%;" .options="${Object.entries(this._exportFormats)}"  @or-mwc-input-changed="${(ev) => this.selectedFormat = ev.detail.value}"></or-mwc-input>
                        </div>
                    </div>
                    <div class="export-btn-wrapper">
                        <or-mwc-input .disabled="${this.isClearExportBtnDisabled}" class="button" .type="${InputType.BUTTON}" label="clearTable" @or-mwc-input-changed="${() => this.clearSelection()}"></or-mwc-input>
                        <or-mwc-input .disabled="${this.isExportBtnDisabled}" class="button" raised .type="${InputType.BUTTON}" label="export" @or-mwc-input-changed="${() => this.export()}"></or-mwc-input>
                    </div>
                </div>
            </div>

        `;
    }
    renderTable(attributeRefs) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!attributeRefs || attributeRefs.length < 1) {
                this.clearSelection();
                return;
            }
            const dataPointInfoPromises = attributeRefs.map((attrRef) => {
                return manager.rest.api.AssetDatapointResource.getDatapointPeriod({
                    assetId: attrRef.id,
                    attributeName: attrRef.name,
                });
            });
            this._loading = true;
            Promise.all(dataPointInfoPromises).then(datapointPeriod => {
                const assetInfoPromises = datapointPeriod.map(result => {
                    return manager.rest.api.AssetResource.get(result.data.assetId);
                });
                Promise.all(assetInfoPromises).then(assetInfos => {
                    const allAssets = assetInfos.map(attr => attr.data);
                    const allDatapoints = datapointPeriod.map(datapoints => datapoints.data);
                    if (allDatapoints.length > 0) {
                        this.tableRows = allDatapoints.map(dataInfo => {
                            const relevantAssetInfo = allAssets.find(asset => asset.id === dataInfo.assetId);
                            return {
                                assetName: relevantAssetInfo.name,
                                assetId: relevantAssetInfo.id,
                                attributeName: dataInfo.attributeName,
                                oldestTimestamp: dataInfo.oldestTimestamp,
                                latestTimestamp: dataInfo.latestTimestamp
                            };
                        }).sort((a, b) => b.latestTimestamp - a.latestTimestamp);
                        this.renderTableRows();
                        this.isClearExportBtnDisabled = false;
                        this.isExportBtnDisabled = false;
                        this._loading = false;
                    }
                    else {
                        this.isClearExportBtnDisabled = true;
                        this.isExportBtnDisabled = true;
                    }
                });
            });
        });
    }
    renderTableRows() {
        this.tableRowsHtml = html `
            ${this.tableRows.map(attr => html `
                <tr class="mdc-data-table__row">
                    <td class="padded-cell mdc-data-table__cell">${attr.assetName}</td>
                    <td class="padded-cell mdc-data-table__cell">${Util.camelCaseToSentenceCase(attr.attributeName)}</td>
                    <td class="padded-cell mdc-data-table__cell">${moment(attr.oldestTimestamp).format('llll')}</td>
                    <td class="padded-cell mdc-data-table__cell">${moment(attr.latestTimestamp).format('llll')}</td>
                    <td>
                        <button class="remove-button button-clear" @click="${() => this._deleteAttribute(attr.assetId, attr.attributeName)}">
                            <or-icon icon="close-circle"></or-icon>
                        </button>
                    </td>
                </tr>
            `)}
        `;
    }
    _deleteAttribute(assetId, attributeName) {
        const indexTablerows = this.tableRows.findIndex(e => e.assetId === assetId && e.attributeName === attributeName);
        const indexSelectedAttrs = this.config.selectedAttributes.findIndex(e => e.id === assetId && e.name === attributeName);
        this.tableRows.splice(indexTablerows, 1);
        this.config.selectedAttributes.splice(indexSelectedAttrs, 1);
        this.saveConfig();
        this.renderTableRows();
    }
    _openDialog() {
        const dialog = showDialog(new OrAssetAttributePicker()
            .setShowOnlyDatapointAttrs(true)
            .setMultiSelect(true)
            .setSelectedAttributes(this.config.selectedAttributes));
        dialog.addEventListener(OrAssetAttributePickerPickedEvent.NAME, (ev) => __awaiter(this, void 0, void 0, function* () {
            const selectedAttributes = ev.detail;
            yield this.renderTable(selectedAttributes);
            this.config = {
                realm: this.realm,
                selectedAttributes: selectedAttributes
            };
            this.saveConfig();
        }));
    }
    loadConfig() {
        return __awaiter(this, void 0, void 0, function* () {
            let configs = (yield manager.console.retrieveData("OrExportConfig")) || [];
            if (!configs.length || !Object.getOwnPropertyNames(configs[0]).includes("realm")) {
                manager.console.storeData("OrExportConfig", null);
            }
            this.config = configs.find(e => e.realm === this.realm) || { realm: this.realm, selectedAttributes: [] };
            // prune removed assets that still exist in localstorage
            const response = yield manager.rest.api.AssetResource.queryAssets({
                ids: this.config.selectedAttributes.map(e => e.id)
            });
            const assetsIds = response.data.map(e => e.id) || [];
            this.config.selectedAttributes = this.config.selectedAttributes.filter(e => assetsIds.includes(e.id));
            this.saveConfig();
            this.renderTable(this.config.selectedAttributes);
        });
    }
    saveConfig() {
        return __awaiter(this, void 0, void 0, function* () {
            let configs = (yield manager.console.retrieveData("OrExportConfig")) || [];
            let config = configs.find(c => c.realm === this.realm);
            if (config) {
                config.selectedAttributes = this.config.selectedAttributes;
            }
            manager.console.storeData("OrExportConfig", [...configs, this.config]);
        });
    }
    stateChanged(state) {
        this.getRealmState(state);
    }
};
__decorate([
    property({ type: Object, attribute: false })
], PageExport.prototype, "tableRowsHtml", void 0);
__decorate([
    property({ type: Number })
], PageExport.prototype, "oldestTimestamp", void 0);
__decorate([
    property({ type: Number })
], PageExport.prototype, "latestTimestamp", void 0);
__decorate([
    property()
], PageExport.prototype, "_loading", void 0);
__decorate([
    property()
], PageExport.prototype, "selectedFormat", void 0);
PageExport = __decorate([
    customElement("page-export")
], PageExport);
export { PageExport };
//# sourceMappingURL=page-export.js.map