import { RuleExecutable } from "../../../Common/Execution/RuleExecutable";
import { TreeRuleNode, TreeRuleNodeType } from "./TreeRuleNode";
import { TreeRuleTestResult } from "./TreeRuleTestResult";
import { DataUtilities } from "../../../Common/DataUtilities";
import { EventLog, EventLogType } from "../../../Common/Event/EventLog";
export class TreeRuleDefinition extends RuleExecutable {
    constructor() {
        super();
        this._id = DataUtilities.generateUniqueId();
        this._root = new TreeRuleNode();
    }
    get executionResult() {
        return this._executionResult;
    }
    set executionResult(value) {
        this._executionResult = value;
        for (let node of this.getAllChildren(this.root)) {
            // not sure if it's needed;
            if (node.nodeType === TreeRuleNodeType.RESULT) {
                node.expression.executionResult = () => {
                    return this.getRuleResult();
                };
            }
        }
    }
    set root(node) {
        this._root = node;
    }
    get root() {
        return this._root;
    }
    run(data, testContext) {
        let node = this._root;
        let subContext;
        if (testContext) {
            subContext = new TreeRuleTestResult(this._id);
            testContext.addTestResultItem(subContext);
            subContext.addLogItem(new EventLog('TreeRule: start evaluating'));
            subContext.definition = this;
        }
        try {
            while (true) {
                if (node.nodeType === TreeRuleNodeType.UNDEFINED) {
                    throw new Error('tree rule node is not configured');
                }
                if (node.nodeType === TreeRuleNodeType.RESULT) {
                    let res = node.expression.run(data, subContext);
                    if (subContext) {
                        subContext.addLogItem(new EventLog(`TreeRule: end with result [${res}]`));
                        subContext.result = res.toString();
                    }
                    return res;
                }
                if (node.nodeType === TreeRuleNodeType.EVALUATION) {
                    let res = node.expression.run(data, subContext);
                    if (res) {
                        node = node.trueNode;
                    }
                    else {
                        node = node.falseNode;
                    }
                }
            }
        }
        catch (e) {
            if (subContext) {
                subContext.isError = true;
                subContext.result = e.message;
                subContext.addLogItem(new EventLog(`TreeRule: end with error [${e.message}]`, EventLogType.ERROR));
            }
            throw e;
        }
    }
    insert(node, isTrue) {
        let newNode = new TreeRuleNode();
        newNode.setupEvaluation(this.getInputDefinition());
        node.setupEvaluation(this.getInputDefinition());
        if (isTrue) {
            newNode.trueNode = node.trueNode;
            node.trueNode = newNode;
        }
        else {
            newNode.falseNode = node.falseNode;
            node.falseNode = newNode;
        }
    }
    getAllChildren(node) {
        let children = [];
        if (node.nodeType !== TreeRuleNodeType.UNDEFINED) {
            children.push(node);
        }
        if (node.nodeType === TreeRuleNodeType.EVALUATION) {
            children = [...children, ...this.getAllChildren(node.trueNode), ...this.getAllChildren(node.falseNode)];
        }
        return children;
    }
    getAllResults() {
        let results = [];
        for (let node of this.getAllChildren(this._root)) {
            if (node.nodeType === TreeRuleNodeType.RESULT) {
                results.push(node);
            }
        }
        return results;
    }
    getDesignValidationIssues() {
        let issues = [];
        const allnodes = this.getAllChildren(this.root);
        for (let nodeidx in allnodes) {
            let node = allnodes[nodeidx];
            issues.push(...node.getDesignValidationIssues().map((issue) => {
                if (node.nodeType === TreeRuleNodeType.RESULT) {
                    issue.issue = `[Result ${parseInt(nodeidx, 10) + 1}]:: ${issue.issue}`;
                }
                else if (node.nodeType === TreeRuleNodeType.EVALUATION) {
                    issue.issue = `[Expression ${parseInt(nodeidx, 10) + 1}]:: ${issue.issue}`;
                }
                return issue;
            }));
        }
        return issues;
    }
    getStorageData() {
        let data = super.getStorageData();
        Reflect.set(data, "_rootNode", this._root.getStorageData());
        return data;
    }
    setStorageData(data) {
        super.setStorageData(data);
        this._root.setStorageData(Reflect.get(data, "_rootNode"));
    }
}
//# sourceMappingURL=TreeRuleDefinition.js.map