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, query } from "lit/decorators.js";
import "@openremote/or-asset-viewer";
import { OrAssetViewerEditToggleEvent, OrAssetViewerRequestEditToggleEvent, OrAssetViewerSaveEvent, OrAssetViewerLoadUserEvent, saveAsset, OrAssetViewerLoadAlarmEvent, OrAssetViewerRequestSaveEvent } from "@openremote/or-asset-viewer";
import { OrAssetTreeFilter, OrAssetTreeAddEvent, OrAssetTreeAssetEvent, OrAssetTreeChangeParentEvent, OrAssetTreeRequestAddEvent, OrAssetTreeRequestSelectionEvent, OrAssetTreeSelectionEvent } from "@openremote/or-asset-tree";
import manager, { DefaultBoxShadow, DefaultColor5, Util } from "@openremote/core";
import { Page, router } from "@openremote/or-app";
import { createSlice, createSelector } from "@reduxjs/toolkit";
import { OrMwcDialog, showDialog, showOkCancelDialog } from "@openremote/or-mwc-components/or-mwc-dialog";
import { i18next } from "@openremote/or-translate";
import "@openremote/or-json-forms";
import { getAlarmsRoute, getAssetsRoute, getUsersRoute } from "../routes";
import { showSnackbar } from "@openremote/or-mwc-components/or-mwc-snackbar";
import { InputType } from "@openremote/or-mwc-components/or-mwc-input";
const INITIAL_STATE = {};
const pageAssetsSlice = createSlice({
    name: "pageAssets",
    initialState: INITIAL_STATE,
    reducers: {}
});
export const pageAssetsReducer = pageAssetsSlice.reducer;
export const PAGE_ASSETS_CONFIG_DEFAULT = {
    tree: {
        add: {
            typesParent: {
                default: {
                    exclude: [
                        "TradfriLightAsset" /* WellknownAssets.TRADFRILIGHTASSET */,
                        "TradfriPlugAsset" /* WellknownAssets.TRADFRIPLUGASSET */,
                        "ArtnetLightAsset" /* WellknownAssets.ARTNETLIGHTASSET */,
                        "ConsoleAsset" /* WellknownAssets.CONSOLEASSET */
                    ]
                }
            }
        }
    }
};
export function pageAssetsProvider(store, config) {
    return {
        name: "assets",
        routes: [
            "assets",
            "assets/:editMode",
            "assets/:editMode/:ids"
        ],
        pageCreator: () => {
            const page = new PageAssets(store);
            if (config) {
                page.config = config;
            }
            return page;
        }
    };
}
let PageAssets = class PageAssets extends Page {
    static get styles() {
        // language=CSS
        return css `

            or-asset-tree {
                align-items: stretch;
                z-index: 1;
            }

            .hideMobile {
                display: none;
            }

            or-asset-viewer {
                align-items: stretch;
                z-index: 0;
            }

            .multipleAssetsView {
                display: flex;
                justify-content: center;
                align-items: center;
                text-align: center;
                height: 100%;
                width: 100%;
            }

            .multipleAssetsView > div {
                display: flex;
                flex-direction: column;
            }

            .multipleAssetsView > div > *:first-child {
                margin: 30px;                
            }

            @media only screen and (min-width: 768px){
                or-asset-tree {
                    width: 300px;
                    min-width: 300px;
                    box-shadow: ${unsafeCSS(DefaultBoxShadow)}
                }

                .hideMobile {
                    display: flex;
                }

                or-asset-viewer,
                or-asset-viewer.hideMobile {
                    display: initial;
                    max-width: calc(100vw - 300px);
                }
            }
        `;
    }
    get name() {
        return "assets";
    }
    constructor(store) {
        super(store);
        this._editMode = false;
        this._realmSelector = (state) => state.app.realm || manager.displayRealm;
        this.getRealmState = createSelector([this._realmSelector], (realm) => __awaiter(this, void 0, void 0, function* () {
            // Prevent execution on initial load
            if (this.isUpdatePending) {
                return;
            }
            this._assetIds = undefined;
            if (this._viewer) {
                this._viewer.assetId = undefined;
            }
            if (this._tree) {
                this._tree.refresh();
            }
            this._updateRoute(true);
        }));
        this.addEventListener(OrAssetTreeRequestSelectionEvent.NAME, this._onAssetSelectionRequested);
        this.addEventListener(OrAssetTreeSelectionEvent.NAME, (ev) => this._onAssetSelectionChanged(false, ev.detail.newNodes.map((node) => node.asset.id)));
        this.addEventListener(OrAssetViewerRequestEditToggleEvent.NAME, this._onEditToggleRequested);
        this.addEventListener(OrAssetViewerEditToggleEvent.NAME, this._onEditToggle);
        this.addEventListener(OrAssetTreeRequestAddEvent.NAME, this._onAssetAddRequested);
        this.addEventListener(OrAssetTreeAddEvent.NAME, (ev) => this._onAssetAdd(ev.detail.asset));
        this.addEventListener(OrAssetViewerRequestSaveEvent.NAME, this._onAssetViewerSaveRequested);
        this.addEventListener(OrAssetTreeAssetEvent.NAME, this._onAssetTreeAssetEvent);
        this.addEventListener(OrAssetTreeChangeParentEvent.NAME, (ev) => this._onAssetParentChange(ev.detail));
        this.addEventListener(OrAssetViewerLoadUserEvent.NAME, this._onLoadUserEvent);
        this.addEventListener(OrAssetViewerLoadAlarmEvent.NAME, (ev) => this._onLoadAlarmEvent(ev));
    }
    render() {
        let viewerHTML;
        const multiSelection = this._assetIds && this._assetIds.length > 1;
        if (multiSelection) {
            viewerHTML = html `
                <div class="multipleAssetsView hideMobile">
                    <div>
                        <or-translate value="multiAssetSelected" .options="${{ assetNbr: this._assetIds.length }}"></or-translate>
                        <or-mwc-input .type="${InputType.BUTTON}" label="changeParent" @or-mwc-input-changed="${() => this._onParentChangeClick()}" outlined></or-mwc-input>
                    </div>
                </div>
            `;
        }
        else {
            const assetId = this._assetIds && this._assetIds.length === 1 ? this._assetIds[0] : undefined;
            viewerHTML = html `
                <or-asset-viewer id="viewer"
                                 .config="${this.config && this.config.viewer ? this.config.viewer : undefined}"
                                 class="${!assetId ? "hideMobile" : ""}" .assetId="${assetId}"
                                 .editMode="${this._editMode}"
                ></or-asset-viewer>
            `;
        }
        return html `
            <or-asset-tree id="tree" .config="${this.config && this.config.tree ? this.config.tree : PAGE_ASSETS_CONFIG_DEFAULT.tree}"
                           class="${this._assetIds && this._assetIds.length === 1 ? "hideMobile" : ""}"
                           .selectedIds="${this._assetIds}"
            ></or-asset-tree>
            ${viewerHTML}
        `;
    }
    // State is only utilised for initial loading, and for changes within the store.
    // On the assets page, we shouldn't change editMode nor assetIds if the URL/state hasn't changed.
    stateChanged(state) {
        var _a;
        this.getRealmState(state); // Order is important here!
        this._editMode = !!(state.app.params && state.app.params.editMode === "true");
        if ((_a = state.app.params) === null || _a === void 0 ? void 0 : _a.ids) {
            const newIds = state.app.params.ids.split(",");
            if (!Util.objectsEqual(this._assetIds, newIds, true)) {
                this._assetIds = newIds;
                if (this._assetIds.length === 1) {
                    this.updateComplete.finally(() => { var _a; return (_a = this._tree) === null || _a === void 0 ? void 0 : _a.applyFilter(new OrAssetTreeFilter(this._assetIds[0]), true); });
                }
            }
        }
        else {
            this._assetIds = undefined;
        }
    }
    _onParentChangeClick() {
        let dialog;
        const blockEvent = (ev) => {
            ev.stopPropagation();
        };
        const dialogContent = html `
            <or-asset-tree id="parent-asset-tree" disableSubscribe readonly .selectedIds="${[]}"
                           @or-asset-tree-request-select="${blockEvent}"
                           @or-asset-tree-selection-changed="${blockEvent}"></or-asset-tree>`;
        const setParent = () => {
            const assetTree = dialog.shadowRoot.getElementById("parent-asset-tree");
            let idd = assetTree.selectedIds.length === 1 ? assetTree.selectedIds[0] : undefined;
            this._onAssetParentChange({ parentId: idd, assetIds: this._assetIds });
        };
        const clearParent = () => {
            this._onAssetParentChange({ parentId: undefined, assetIds: this._assetIds });
        };
        const dialogActions = [
            {
                actionName: "clear",
                content: "none",
                action: clearParent
            },
            {
                actionName: "ok",
                content: "ok",
                action: setParent
            },
            {
                default: true,
                actionName: "cancel",
                content: "cancel"
            }
        ];
        dialog = showDialog(new OrMwcDialog()
            .setContent(dialogContent)
            .setActions(dialogActions)
            .setStyles(html `
                <style>
                    .mdc-dialog__surface {
                        width: 400px;
                        height: 800px;
                        display: flex;
                        overflow: visible;
                        overflow-x: visible !important;
                        overflow-y: visible !important;
                    }

                    #dialog-content {
                        flex: 1;
                        overflow: visible;
                        min-height: 0;
                        padding: 0;
                    }

                    footer.mdc-dialog__actions {
                        border-top: 1px solid ${unsafeCSS(DefaultColor5)};
                    }

                    or-asset-tree {
                        height: 100%;
                    }
                </style>
            `)
            .setHeading(i18next.t("setParent"))
            .setDismissAction(null));
    }
    _onAssetSelectionRequested(event) {
        const isModified = this._viewer && this._viewer.isModified();
        if (!isModified) {
            return;
        }
        // Prevent the request and check if user wants to lose changes
        event.detail.allow = false;
        this._confirmContinue(() => {
            var _a;
            this._onAssetSelectionChanged(true, (_a = event.detail.detail.newNodes) === null || _a === void 0 ? void 0 : _a.map((node) => node.asset.id));
        });
    }
    // This is where we set the asset loaded in the asset viewer
    _onAssetSelectionChanged(userInitiated, assetIds) {
        if (Util.objectsEqual(this._assetIds, assetIds)) {
            if (!userInitiated) {
                // Asset name or parent has changed and we don't need to react to it here
                return;
            }
            // User has clicked the same node(s)
            if (assetIds.length === 1) {
                // force refresh the selected asset
                if (this._viewer) {
                    this._viewer.assetId = undefined;
                    setTimeout(() => {
                        if (this._viewer) {
                            this._viewer.assetId = assetIds[0];
                        }
                    }, 0);
                }
            }
        }
        else {
            this._assetIds = assetIds;
            if (this._viewer) {
                console.debug(`Asset viewer is now showing asset ${assetIds && assetIds.length === 1 ? assetIds[0] : 'undefined'}`);
                this._viewer.assetId = assetIds && assetIds.length === 1 ? assetIds[0] : undefined;
            }
            this._updateRoute(false);
        }
    }
    _onEditToggleRequested(event) {
        // Block the request if current asset is modified then show dialog then navigate
        const isModified = this._viewer.isModified();
        if (!isModified) {
            return;
        }
        event.detail.allow = false;
        this._confirmContinue(() => {
            var _a;
            this._editMode = event.detail.detail;
            this._updateRoute(false);
            if (((_a = this._assetIds) === null || _a === void 0 ? void 0 : _a.length) === 1) {
                // force refresh the selected asset
                if (this._viewer) {
                    this._viewer.assetId = undefined;
                    setTimeout(() => {
                        if (this._viewer) {
                            this._viewer.assetId = this._assetIds[0];
                        }
                    }, 0);
                }
            }
        });
    }
    _onEditToggle(event) {
        this._editMode = event.detail;
        this._updateRoute(false);
    }
    _confirmContinue(action) {
        if (this._viewer.isModified()) {
            showOkCancelDialog(i18next.t("loseChanges"), i18next.t("confirmContinueAssetModified"), i18next.t("discard"))
                .then((ok) => {
                if (ok) {
                    action();
                }
            });
        }
        else {
            action();
        }
    }
    _onAssetAddRequested(ev) {
        const isModified = this._viewer && this._viewer.isModified();
        if (!isModified) {
            return;
        }
        // Prevent the request and check if user wants to lose changes
        ev.detail.allow = false;
        this._confirmContinue(() => {
            this._onAssetAdd(ev.detail.detail.asset);
        });
    }
    _onAssetAdd(asset) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this._editMode) {
                // Just load the asset into the viewer
                this._viewer.asset = asset;
            }
            else {
                // Save and load
                this._doSaveAndLoad(asset);
            }
        });
    }
    _onAssetViewerSaveRequested(ev) {
        var _a;
        const isModified = this._viewer && this._viewer.isModified();
        if (!isModified) {
            return;
        }
        if (((_a = this._viewer) === null || _a === void 0 ? void 0 : _a.asset) && !this._viewer.asset.id) {
            // Prevent the request and handle at this level to allow selection within the tree
            ev.detail.allow = false;
            this._doSaveAndLoad(this._viewer.asset);
        }
    }
    _doSaveAndLoad(asset) {
        return __awaiter(this, void 0, void 0, function* () {
            let saveResult;
            const assetTreeAssets = [];
            this._addCallback = (assetTreeCreatedAsset) => {
                if (saveResult) {
                    // Save has completed before asset tree node created
                    completedCallback();
                }
                else {
                    // Store as it might be asset we are trying to save
                    assetTreeAssets.push(assetTreeCreatedAsset);
                }
            };
            const completedCallback = () => {
                var _a;
                this._onAssetSelectionChanged(true, ((_a = saveResult.asset) === null || _a === void 0 ? void 0 : _a.id) ? [saveResult.asset.id] : undefined);
                this._viewer.dispatchEvent(new OrAssetViewerSaveEvent(saveResult));
            };
            saveResult = yield saveAsset(asset);
            if (saveResult.success) {
                const assetTreeCreatedNode = assetTreeAssets.find(a => a.id === saveResult.asset.id);
                if (assetTreeCreatedNode) {
                    // Asset tree node creation completed before save callback executed
                    completedCallback();
                }
            }
            else {
                this._addCallback = undefined;
            }
        });
    }
    _onAssetParentChange(parentChange) {
        return __awaiter(this, void 0, void 0, function* () {
            let parentId = parentChange.parentId;
            let assetsIds = parentChange.assetIds;
            try {
                if (parentId) {
                    if (!assetsIds.includes(parentId)) {
                        yield manager.rest.api.AssetResource.updateParent(parentId, { assetIds: assetsIds });
                    }
                    else {
                        showSnackbar(undefined, "moveAssetFailed", "dismiss");
                    }
                }
                else {
                    //So need to remove parent from all the selected assets
                    yield manager.rest.api.AssetResource.updateNoneParent({ assetIds: assetsIds });
                }
            }
            catch (e) {
                showSnackbar(undefined, "moveAssetFailed", "dismiss");
            }
        });
    }
    _onAssetTreeAssetEvent(ev) {
        // If new asset created and add callback defined then we pass to there for handling
        if (ev.detail.cause === "CREATE" /* AssetEventCause.CREATE */ && this._addCallback) {
            this._addCallback(ev.detail.asset);
        }
    }
    _updateRoute(silent = true) {
        const assetIds = this._assetIds ? this._assetIds.toString() : undefined;
        router.navigate(getAssetsRoute(this._editMode, assetIds), {
            callHooks: !silent,
            callHandler: !silent
        });
    }
    _onLoadUserEvent(event, silent = false) {
        router.navigate(getUsersRoute(event.detail), {
            callHooks: !silent,
            callHandler: !silent
        });
    }
    _onLoadAlarmEvent(event, silent = false) {
        router.navigate(getAlarmsRoute(event.detail.toString()), {
            callHooks: !silent,
            callHandler: !silent
        });
    }
};
__decorate([
    property()
], PageAssets.prototype, "config", void 0);
__decorate([
    property()
], PageAssets.prototype, "_editMode", void 0);
__decorate([
    property() // selected asset ids
], PageAssets.prototype, "_assetIds", void 0);
__decorate([
    query("#tree")
], PageAssets.prototype, "_tree", void 0);
__decorate([
    query("#viewer")
], PageAssets.prototype, "_viewer", void 0);
PageAssets = __decorate([
    customElement("page-assets")
], PageAssets);
export { PageAssets };
//# sourceMappingURL=page-assets.js.map