/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { observable, action, makeObservable, computed } from 'mobx';
import { ExecutionPlan, ExecutionNode, StoreMappingGlobalGraphFetchExecutionNode, RelationalGraphFetchExecutionNode, } from '@finos/legend-graph';
import { addUniqueEntry, filterByType, guaranteeNonNullable, } from '@finos/legend-shared';
import { generateExecutionNodeLabel } from '../../components/execution-plan/ExecutionPlanViewer.js';
export class ExecutionPlanViewTreeNodeData {
    id;
    label;
    isSelected;
    isOpen;
    childrenIds;
    executionPlan;
    constructor(id, label, executionPlan) {
        makeObservable(this, {
            isSelected: observable,
            isOpen: observable,
            setIsSelected: action,
            setIsOpen: action,
        });
        this.id = id;
        this.label = label;
        this.executionPlan = executionPlan;
    }
    setIsSelected(val) {
        this.isSelected = val;
    }
    setIsOpen(val) {
        this.isOpen = val;
    }
}
export class ExecutionNodeTreeNodeData {
    id;
    label;
    isSelected;
    isOpen;
    childrenIds;
    executionNode;
    parentNodeId;
    constructor(id, label, executionNode, parentNodeId) {
        makeObservable(this, {
            isSelected: observable,
            isOpen: observable,
            setIsSelected: action,
            setIsOpen: action,
        });
        this.id = id;
        this.label = label;
        this.executionNode = executionNode;
        this.parentNodeId = parentNodeId;
    }
    setIsSelected(val) {
        this.isSelected = val;
    }
    setIsOpen(val) {
        this.isOpen = val;
    }
}
export const generateExecutionNodeTreeNodeData = (executionNode, label, parentNode) => {
    const executionNodeTreeNode = new ExecutionNodeTreeNodeData(executionNode._UUID, label, executionNode, parentNode instanceof ExecutionNodeTreeNodeData
        ? generateExecutionNodeLabel(parentNode.executionNode)
        : undefined);
    const childrenIds = [];
    executionNode.executionNodes
        .slice()
        .filter(filterByType(ExecutionNode))
        .forEach((childExecutionNode) => {
        addUniqueEntry(childrenIds, childExecutionNode._UUID);
    });
    if (executionNode instanceof StoreMappingGlobalGraphFetchExecutionNode) {
        addUniqueEntry(childrenIds, executionNode.localGraphFetchExecutionNode._UUID);
        executionNode.children
            .slice()
            .filter(filterByType(ExecutionNode))
            .forEach((childExecutionNode) => {
            addUniqueEntry(childrenIds, childExecutionNode._UUID);
        });
    }
    if (executionNode instanceof RelationalGraphFetchExecutionNode) {
        executionNode.children
            .slice()
            .filter(filterByType(ExecutionNode))
            .forEach((childExecutionNode) => {
            addUniqueEntry(childrenIds, childExecutionNode._UUID);
        });
    }
    executionNodeTreeNode.childrenIds = childrenIds;
    return executionNodeTreeNode;
};
export const generateExecutionPlanTreeNodeData = (executionPlan) => {
    const executionPlanNode = new ExecutionPlanViewTreeNodeData(`Execution Plan`, `Execution Plan`, executionPlan);
    const childrenIds = [];
    const rootNodeId = executionPlan.rootExecutionNode._UUID;
    addUniqueEntry(childrenIds, rootNodeId);
    executionPlanNode.childrenIds = childrenIds;
    return executionPlanNode;
};
export const getExecutionPlanTreeData = (executionPlan) => {
    const rootIds = [];
    const nodes = new Map();
    const executionPlanTreeNode = generateExecutionPlanTreeNodeData(executionPlan);
    addUniqueEntry(rootIds, executionPlanTreeNode.id);
    nodes.set(executionPlanTreeNode.id, executionPlanTreeNode);
    return { rootIds, nodes };
};
export var EXECUTION_PLAN_VIEW_MODE;
(function (EXECUTION_PLAN_VIEW_MODE) {
    EXECUTION_PLAN_VIEW_MODE["FORM"] = "Form";
    EXECUTION_PLAN_VIEW_MODE["JSON"] = "JSON";
})(EXECUTION_PLAN_VIEW_MODE || (EXECUTION_PLAN_VIEW_MODE = {}));
export var PLAN_TABS;
(function (PLAN_TABS) {
    PLAN_TABS["GENERAL"] = "GENERAL";
    PLAN_TABS["GLOBAL_IMPLEMENTATION_SUPPORT"] = "GLOBAL_IMPLEMENTATION_SUPPORT";
})(PLAN_TABS || (PLAN_TABS = {}));
class GlobalImplementationSupportState {
    selectedTab = PLAN_TABS.GENERAL;
    selectedJavaClass = undefined;
    constructor() {
        makeObservable(this, {
            selectedTab: observable,
            selectedJavaClass: observable,
            setSelectedTab: action,
            setSelectedJavaClass: action,
        });
    }
    setSelectedTab(tab) {
        this.selectedTab = tab;
    }
    setSelectedJavaClass(javaClass) {
        this.selectedJavaClass = javaClass;
    }
}
export class ExecutionPlanState {
    applicationStore;
    graphManagerState;
    displayDataJson = {};
    displayData = '';
    selectedNode = undefined;
    viewMode = EXECUTION_PLAN_VIEW_MODE.FORM;
    treeData;
    rawPlan;
    plan;
    debugText;
    globalImplementationSupportState = new GlobalImplementationSupportState();
    constructor(applicationStore, graphManagerState) {
        makeObservable(this, {
            displayData: observable,
            displayDataJson: observable,
            viewMode: observable,
            rawPlan: observable,
            plan: observable,
            debugText: observable,
            treeData: observable,
            setExecutionPlanDisplayData: action,
            setExecutionPlanDisplayDataJson: action,
            transformMetadataToProtocolJson: action,
            setSelectedNode: action,
            setRawPlan: action,
            setPlan: action,
            setViewMode: action,
            setDebugText: action,
            setTreeNode: action,
            setTreeData: action,
            refreshTreeData: action,
            nonNullableTreeData: computed,
            initialize: action,
            globalImplementationSupportState: observable,
        });
        this.applicationStore = applicationStore;
        this.graphManagerState = graphManagerState;
    }
    setViewMode(val) {
        this.viewMode = val;
    }
    setTreeNode(id, node) {
        this.treeData?.nodes.set(id, node);
    }
    setTreeData(val) {
        this.treeData = val;
    }
    refreshTreeData() {
        if (this.treeData) {
            this.setTreeData({ ...this.treeData });
        }
    }
    get nonNullableTreeData() {
        return guaranteeNonNullable(this.treeData, 'Execution plan viewer tree data has not been initialized');
    }
    setRawPlan = (val) => {
        this.rawPlan = val;
    };
    setPlan = (val) => {
        this.plan = val;
    };
    initialize = (val) => {
        this.setPlan(val);
        if (val !== undefined) {
            this.setTreeData(getExecutionPlanTreeData(val));
        }
        else {
            this.setTreeData(undefined);
        }
    };
    setDebugText(val) {
        this.debugText = val;
    }
    setSelectedNode(node) {
        if (this.selectedNode) {
            this.selectedNode.setIsSelected(false);
        }
        if (node) {
            node.setIsSelected(true);
        }
        this.selectedNode = node;
    }
    setExecutionPlanDisplayData(val) {
        this.displayData = val;
    }
    setExecutionPlanDisplayDataJson(val) {
        this.displayDataJson = val;
        this.setExecutionPlanDisplayData(JSON.stringify(this.displayDataJson, undefined, 2));
    }
    transformMetadataToProtocolJson(metaModel) {
        if (metaModel instanceof ExecutionPlan) {
            const protocolJson = this.graphManagerState.graphManager.serializeExecutionPlan(metaModel);
            this.setExecutionPlanDisplayDataJson(protocolJson);
        }
        else if (metaModel instanceof ExecutionNode) {
            const protocolJson = this.graphManagerState.graphManager.serializeExecutionNode(metaModel);
            this.setExecutionPlanDisplayDataJson(protocolJson);
        }
    }
}
//# sourceMappingURL=ExecutionPlanState.js.map