import { __decorate, __metadata } from "tslib";
import '@material/web/icon/icon.js';
import '@material/web/fab/fab.js';
import '@operato/p13n/ox-user-preferences-provider.js';
import '@operato/process/ox-process-modeller.js';
import './things-scene-components.import';
import '../viewpart/process-report';
import '../viewpart/equipment-evaluator';
import gql from 'graphql-tag';
import { css, html } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { connect } from 'pwa-helpers/connect-mixin.js';
import { Model } from '@hatiolab/things-scene';
import { client, gqlContext } from '@operato/graphql';
import { OxPropertyEditor } from '@operato/property-editor';
import { PageView, store } from '@operato/shell';
import { i18next } from '@operato/i18n';
import { openPopup } from '@operato/layout';
import { OxProcessModeller } from '@operato/process/ox-process-modeller.js';
import { OxPrompt } from '@operato/popup/ox-prompt.js';
import { provider } from '../process-provider';
import components from './things-scene-components-with-tools.import';
// find loops in the process
import { StedProcessCycles } from '../utils/sted-process-cycles';
import { evaluateEnergyConsumption } from '../graphql/evaluate-energy-consumption';
const NOOP = () => { };
let ProcessModellerPage = class ProcessModellerPage extends connect(store)(PageView) {
    constructor() {
        super();
        this.processId = '';
        this.processName = '';
        this.model = {
            width: 1920,
            height: 1080
        };
        this.baseUrl = '';
        this.selected = [];
        this.mode = 1;
        this.hideProperty = false;
        this.overlay = '';
        this.scene = null;
        this.componentGroupList = OxProcessModeller.groups;
        this.fonts = [];
        this._showSpinner = false;
        this.process = null;
        this.analizedModel = {
            stedDataMap: {},
            stedNodes: [],
            smartGuides: []
        };
        this.isAnalysisDone = false;
        this.onShowEquipmentEvaluator = (equipment) => {
            var _a;
            if (!equipment) {
                return;
            }
            try {
                if (!this.isAnalysisDone) {
                    throw new Error(i18next.t('text.need-to-evaluate-lv1'));
                }
                const { type, refid } = (equipment === null || equipment === void 0 ? void 0 : equipment.state) || {};
                if ((_a = this.modeller) === null || _a === void 0 ? void 0 : _a.scene) {
                    this.modeller.scene.dataByRefid = this.analizedModel.stedDataMap;
                }
                var template = html `
        <equipment-evaluator .equipment=${equipment} .processId=${this.processId}></equipment-evaluator>
      `;
                openPopup(template, {
                    backdrop: true,
                    size: 'large',
                    title: `${i18next.t('title.equipment-evaluator')} - ${i18next.t(`component.${type}`)}(${(type +
                        ' ' +
                        refid).toUpperCase()})`
                });
            }
            catch (err) {
                OxPrompt.open({
                    type: 'error',
                    title: i18next.t('title.equipment-evaluator'),
                    text: String(err),
                    confirmButton: { text: i18next.t('button.confirm') }
                });
            }
        };
        components.forEach((component) => {
            OxProcessModeller.registerTemplate(component.templates);
        });
        /* 컴포넌트에서 정의된 에디터들을 MODELLER_EDITORS에 등록 */
        var addedEditors = {};
        for (let component in components) {
            let { editors } = components[component];
            editors &&
                editors.forEach((editor) => {
                    let { type, element } = editor;
                    addedEditors[type] = element;
                });
        }
        OxPropertyEditor.register(addedEditors);
    }
    get context() {
        return {
            title: this.process ? this.processName : this._showSpinner ? 'Fetching process...' : 'Process Not Found',
            help: 'process-modeller/modeller',
            widebleed: true
        };
    }
    get oopsNote() {
        return {
            icon: 'color_lens',
            title: 'EMPTY PROCESS',
            description: 'There are no process to be designed',
            click: NOOP
        };
    }
    async refresh() {
        var _a, _b;
        if (!this.processId) {
            this.process = null;
            this.model = {
                width: 1920,
                height: 1080
            };
            return;
        }
        try {
            this._showSpinner = true;
            this.updateContext();
            var response = await client.query({
                query: gql `
          query FetchProcessById($id: String!) {
            process(id: $id) {
              id
              name
              model
            }
          }
        `,
                variables: { id: this.processId },
                context: gqlContext()
            });
            var process = response.data.process;
            if (!process) {
                this.process = null;
                throw 'process not found';
            }
            this.process = Object.assign(Object.assign({}, process), { model: JSON.parse(process.model) });
            this.processName = (_a = this.process) === null || _a === void 0 ? void 0 : _a.name;
            this.model = Object.assign({}, (_b = this.process) === null || _b === void 0 ? void 0 : _b.model);
        }
        catch (ex) {
            document.dispatchEvent(new CustomEvent('notify', {
                detail: {
                    level: 'error',
                    message: ex,
                    ex
                }
            }));
        }
        finally {
            this._showSpinner = false;
            this.updateContext();
        }
    }
    updated(changes) {
        if (changes.has('processId')) {
            this.refresh();
        }
    }
    pageUpdated(changes, lifecycle) {
        var _a;
        if (this.active) {
            this.processId = lifecycle.resourceId;
        }
        else {
            this.processId = '';
            this.model = {
                width: 1280,
                height: 1020,
                components: []
            };
            (_a = this.modeller) === null || _a === void 0 ? void 0 : _a.close();
        }
    }
    stateChanged(state) {
        this.baseUrl = state.route.rootPath;
        this.fonts = state.font;
    }
    render() {
        var _a;
        const selected = (_a = this.selected) === null || _a === void 0 ? void 0 : _a[0];
        const equipment = selected && 'isEquipment' in selected ? selected : null;
        var oops = (!this._showSpinner && !this.model && this.oopsNote);
        return oops
            ? html `
          <oops-note
            icon=${oops.icon}
            title=${oops.title}
            description=${oops.description}
            @click=${oops.click || NOOP}
          ></oops-note>
        `
            : html `
          <ox-process-modeller
            .mode=${this.mode}
            @mode-changed=${(e) => {
                this.mode = e.detail.value;
            }}
            .model=${this.model}
            @model-changed=${(e) => {
                this.model = e.detail.value;
            }}
            .scene=${this.scene}
            @scene-changed=${(e) => {
                this.scene = e.detail.value;
            }}
            .selected=${this.selected}
            @selected-changed=${(e) => {
                this.selected = e.detail.value;
            }}
            .baseUrl=${this.baseUrl}
            .provider=${provider}
            @save-model=${(e) => this.saveProcess()}
            .componentGroupList=${this.componentGroupList}
            .fonts=${this.fonts}
            .hideProperty=${this.hideProperty}
            hide-data-binding
          >
            <div commands>
              ${!this.isAnalysisDone || !equipment
                ? html `
                    <md-fab
                      @click=${() => this.onShowReport()}
                      label="${String(i18next.t('title.show-process-report'))}"
                    >
                      <md-icon slot="icon">function</md-icon>
                    </md-fab>
                  `
                : html `
                    <md-fab
                      @click=${() => this.onShowEquipmentEvaluator(equipment)}
                      label="${String(i18next.t('title.show-equipment-evaluator'))}"
                    >
                      <md-icon slot="icon">heat_pump</md-icon>
                    </md-fab>
                  `}
            </div>
          </ox-process-modeller>

          <oops-spinner ?show=${this._showSpinner}></oops-spinner>
        `;
        return html ``;
    }
    async updateProcess() {
        var _a, _b;
        try {
            this._showSpinner = true;
            var { id, name, description, groupId } = this.process || {};
            var model = JSON.stringify((_a = this.scene) === null || _a === void 0 ? void 0 : _a.model);
            /*
            DEMO: find nodes cycled in the process
            you will get the result like [['11', '22, '33'], ['44', '55', '66']] where each array is a cycle
            */
            let processCycles = new StedProcessCycles().run((_b = this.scene) === null || _b === void 0 ? void 0 : _b.model);
            console.log(`processCycles: `, processCycles.map(cycle => console.log(cycle)));
            await client.mutate({
                mutation: gql `
          mutation UpdateProcess($id: String!, $patch: ProcessPatch!) {
            updateProcess(id: $id, patch: $patch) {
              id
            }
          }
        `,
                variables: {
                    id,
                    patch: { name, description, model, groupId }
                },
                context: gqlContext()
            });
            const response = await client.query({
                query: gql `
          query CheckAnalysisAvailability($id: String!) {
            checkAnalysisAvailability(id: $id) {
              result
              detail
            }
          }
        `,
                variables: {
                    id
                },
                context: gqlContext()
            });
            if (response.data.checkAnalysisAvailability.result === false) {
                document.dispatchEvent(new CustomEvent('notify', {
                    detail: {
                        level: 'error',
                        message: response.data.checkAnalysisAvailability.detail
                    }
                }));
            }
            else {
                document.dispatchEvent(new CustomEvent('notify', {
                    detail: {
                        level: 'info',
                        message: 'saved'
                    }
                }));
            }
        }
        catch (ex) {
            document.dispatchEvent(new CustomEvent('notify', {
                detail: {
                    level: 'error',
                    message: ex,
                    ex: ex
                }
            }));
        }
        finally {
            this._showSpinner = false;
        }
        this.updateContext();
    }
    async saveProcess() {
        await this.updateProcess();
    }
    async fetchProcess(processId) {
        var response = await client.query({
            query: gql `
        query FetchProcessById($id: String!) {
          process(id: $id) {
            id
            name
            model
            diagram
          }
        }
      `,
            variables: { id: processId },
            context: gqlContext()
        });
        var process = response.data.process;
        return Object.assign(Object.assign({}, process), { model: JSON.parse(process.model) });
    }
    async onShowReport() {
        var _a;
        try {
            this.isAnalysisDone = false;
            const processId = this.processId;
            if (!processId) {
                throw new Error('process should not be empty.');
            }
            try {
                var { stedNodes, stedDataMap, smartGuides } = await evaluateEnergyConsumption(processId);
            }
            catch (error) {
                console.error(error);
            }
            if ((_a = this.modeller) === null || _a === void 0 ? void 0 : _a.scene) {
                this.modeller.scene.dataByRefid = stedDataMap;
            }
            // check if stedNodes is empty
            // ,which means the lv1 evaluation was falied before.
            if (!stedNodes) {
                return;
            }
            this.isAnalysisDone = true;
            const process = await this.fetchProcess(processId);
            this.analizedModel = {
                stedNodes,
                stedDataMap,
                smartGuides
            };
            /*
             * 기존 설정된 이미지가 선택된 상태가 되게 하기 위해서는 selector에 value를 전달해줄 필요가 있음.
             * 주의. value는 object일 수도 있고, string일 수도 있다.
             * string인 경우에는 해당 보드의 id로 해석한다.
             */
            var template = html `
        <process-report .stedNodes=${stedNodes} .smartGuides=${smartGuides} .process=${process}></process-report>
      `;
            openPopup(template, {
                backdrop: true,
                size: 'large',
                title: i18next.t('title.process-report')
            });
        }
        catch (err) {
            console.error(err);
        }
    }
    showStreamInfo(e) {
        const stream = e.detail;
        if (!this.popup) {
            const popup = document.createElement('stream-info');
            popup.addEventListener('close', e => {
                e.stopPropagation();
                this.hidePopup();
            });
            this.appendChild(popup);
            this.popup = popup;
        }
        this.popup.stream = stream;
    }
    hidePopup() {
        if (this.popup) {
            this.removeChild(this.popup);
            delete this.popup;
        }
    }
};
ProcessModellerPage.styles = [
    css `
      :host {
        display: flex;
        flex-direction: column;

        overflow: hidden;
        position: relative;

        --component-menu-item-icon-size-width: 24px;
        --component-menu-item-icon-size-height: 24px;
      }

      process-modeller {
        flex: 1;
      }

      [commands] {
        position: absolute;
        right: 10px;
        top: 10px;
        display: flex;
        justify-content: flex-end;
      }

      oops-spinner {
        display: none;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
      }

      oops-spinner[show] {
        display: block;
      }

      oops-note {
        display: block;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
      }
    `
];
__decorate([
    property({ type: String }),
    __metadata("design:type", String)
], ProcessModellerPage.prototype, "processId", void 0);
__decorate([
    property({ type: String }),
    __metadata("design:type", String)
], ProcessModellerPage.prototype, "processName", void 0);
__decorate([
    property({ type: Object }),
    __metadata("design:type", Model)
], ProcessModellerPage.prototype, "model", void 0);
__decorate([
    property({ type: String }),
    __metadata("design:type", String)
], ProcessModellerPage.prototype, "baseUrl", void 0);
__decorate([
    property({ type: Array }),
    __metadata("design:type", Array)
], ProcessModellerPage.prototype, "selected", void 0);
__decorate([
    property({ type: Number }),
    __metadata("design:type", Number)
], ProcessModellerPage.prototype, "mode", void 0);
__decorate([
    property({ type: Boolean }),
    __metadata("design:type", Boolean)
], ProcessModellerPage.prototype, "hideProperty", void 0);
__decorate([
    property({ type: String }),
    __metadata("design:type", String)
], ProcessModellerPage.prototype, "overlay", void 0);
__decorate([
    property({ type: Object }),
    __metadata("design:type", Object)
], ProcessModellerPage.prototype, "scene", void 0);
__decorate([
    property({ type: Array }),
    __metadata("design:type", Array)
], ProcessModellerPage.prototype, "componentGroupList", void 0);
__decorate([
    property({ type: Array }),
    __metadata("design:type", Array)
], ProcessModellerPage.prototype, "fonts", void 0);
__decorate([
    property({ type: Boolean }),
    __metadata("design:type", Boolean)
], ProcessModellerPage.prototype, "_showSpinner", void 0);
__decorate([
    query('ox-process-modeller'),
    __metadata("design:type", OxProcessModeller)
], ProcessModellerPage.prototype, "modeller", void 0);
ProcessModellerPage = __decorate([
    customElement('process-modeller-page'),
    __metadata("design:paramtypes", [])
], ProcessModellerPage);
export { ProcessModellerPage };
//# sourceMappingURL=process-modeller-page.js.map