import { Executable } from "../../Common/Execution/Executable";
import { XExpressionDefinition } from "../../Expressions/XExpressionDefinition";
import { DataUtilities } from "../../Common/DataUtilities";
import { NumberDataDefinition } from "../../Common/Data/Definitions/NumberDataDefinition";
import { ValidationIssue } from "../../Common/IDesignValidationProvider";
import { ObjectDataDefinition } from "../../Common/Data/Definitions/ObjectDataDefinition";
import { XMappingConstants } from "./XMappingConstants";
export var MappingRuleViewType;
(function (MappingRuleViewType) {
    MappingRuleViewType["HIDDEN"] = "hidden";
    MappingRuleViewType["SMALL"] = "small";
    MappingRuleViewType["EXPANDED"] = "Expanded";
})(MappingRuleViewType || (MappingRuleViewType = {}));
export class MappingRule {
    constructor(desiredX, desiredY, targetPath) {
        this.targetPath = "";
        this.x = XMappingConstants.DEFAULT_POSITION_X;
        this.y = XMappingConstants.DEFAULT_POSITION_Y;
        this._viewType = MappingRuleViewType.EXPANDED;
        this.desiredX = desiredX;
        this.desiredY = desiredY;
        if (targetPath) {
            this.targetPath = targetPath;
        }
        this.id = DataUtilities.generateUniqueId();
        this.mapping = new XExpressionDefinition();
    }
    set viewType(viewType) {
        this._viewType = viewType;
    }
    get viewType() {
        return this._viewType;
    }
    getInboundPaths() {
        return this.mapping.getAllVariables();
    }
    getStorageData() {
        let obj = {};
        Reflect.set(obj, "id", this.id);
        Reflect.set(obj, "targetPath", this.targetPath);
        Reflect.set(obj, "mapping", this.mapping.getStorageData());
        Reflect.set(obj, "x", this.x);
        Reflect.set(obj, "y", this.y);
        Reflect.set(obj, "viewType", this.viewType);
        Reflect.set(obj, "desiredX", this.desiredX);
        Reflect.set(obj, "desiredY", this.desiredY);
        return obj;
    }
    setStorageData(data) {
        this.id = Reflect.get(data, "id");
        this.targetPath = Reflect.get(data, "targetPath");
        this.mapping.setStorageData(Reflect.get(data, "mapping"));
        this.x = Reflect.get(data, "x");
        this.y = Reflect.get(data, "y");
        this.viewType = Reflect.get(data, "viewType");
        this.desiredX = Reflect.get(data, "desiredX");
        this.desiredY = Reflect.get(data, "desiredY");
    }
    deleteTarget() {
        this.mapping.executionResult = () => new NumberDataDefinition();
        this.targetPath = "";
    }
    getValidationIssue(odatadef) {
        let issues = [];
        if (this.targetPath === "") {
            issues.push(new ValidationIssue("target path is required."));
        }
        else {
            try {
                DataUtilities.getFieldFromDataDefinitionByProperty(odatadef.fields, this.targetPath, "name");
            }
            catch (e) {
                issues.push(new ValidationIssue("incorrect target path"));
            }
        }
        issues.push(...this.mapping.getDesignValidationIssues());
        return issues;
    }
}
export class XMappingDefinition extends Executable {
    constructor() {
        super(...arguments);
        this._mappingRules = [];
    }
    get mappingRules() {
        return this._mappingRules;
    }
    run(data, testContext) {
        throw new Error("not implemented");
    }
    addMappingRule(mappingRule) {
        var _a;
        let maprule = mappingRule
            ? mappingRule
            : new MappingRule(XMappingConstants.DEFAULT_POSITION_X, XMappingConstants.DEFAULT_POSITION_Y);
        maprule.mapping.inputData = () => this.getInputDefinition();
        this._mappingRules.push(maprule);
        (_a = this.editContext) === null || _a === void 0 ? void 0 : _a.onAddMappingRule();
        return maprule;
    }
    addMappingRuleFromDestination(destinationPath) {
        let mappingRule = this.addMappingRule();
        try {
            this.setRuleTarget(mappingRule, destinationPath);
            return mappingRule;
        }
        catch (e) {
            this.removeMappingRule(mappingRule.id);
            throw e;
        }
    }
    removeMappingRule(id) {
        this._mappingRules = this._mappingRules.filter((m) => m.id !== id);
    }
    directConnect(sourcePath, targetPath) {
        let idatadef = this.getInputDefinition();
        // not sure if it needs
        DataUtilities.getFieldFromDataDefinitionByProperty(idatadef.fields, sourcePath, "name");
        let odatadef = this.getExecutionResult();
        DataUtilities.getFieldFromDataDefinitionByProperty(odatadef.fields, targetPath, "name");
        let maprule = this.addMappingRule();
        maprule.viewType = MappingRuleViewType.HIDDEN;
        maprule.mapping.variableName = sourcePath;
        try {
            this.setRuleTarget(maprule, targetPath);
        }
        catch (e) {
            this.removeMappingRule(maprule.id);
        }
        return maprule;
    }
    // todo: needs implementing
    getStorageData() {
        let obj = {};
        Reflect.set(obj, "mappingRules", this.mappingRules.map((m) => m.getStorageData()));
        return obj;
    }
    // todo: needs implementing
    setStorageData(data) {
        super.setStorageData(data);
        let mappingRules = Reflect.get(data, "mappingRules");
        this._mappingRules = mappingRules.map((m) => {
            let mappingRule = new MappingRule(XMappingConstants.DEFAULT_POSITION_X, XMappingConstants.DEFAULT_POSITION_Y);
            mappingRule.setStorageData(m);
            return mappingRule;
        });
    }
    getMappingRuleByTargetPath(targetPath) {
        for (let mappingRule of this.mappingRules) {
            if (mappingRule.targetPath === targetPath) {
                return mappingRule;
            }
        }
        return undefined;
    }
    setRuleTarget(mappingRule, targetPath) {
        if (targetPath === "") {
            mappingRule.deleteTarget();
            return;
        }
        let outputdef = this.getExecutionResult();
        if (mappingRule.targetPath === targetPath) {
            let field = DataUtilities.getFieldFromDataDefinitionByProperty(outputdef.fields, targetPath, "name");
            mappingRule.mapping.executionResult = () => field;
            mappingRule.targetPath = targetPath;
        }
        if (this.getMappingRuleByTargetPath(targetPath)) {
            throw new Error("there is same target path with " + targetPath);
        }
        else {
            let field = DataUtilities.getFieldFromDataDefinitionByProperty(outputdef.fields, targetPath, "name");
            mappingRule.mapping.executionResult = () => field;
            mappingRule.targetPath = targetPath;
        }
    }
    find(id) {
        return this.mappingRules.find((m) => m.id === id);
    }
    checkTargetFieldConfigured(field) {
        if (field instanceof ObjectDataDefinition) {
            let result = true;
            for (let subfield of field.fields) {
                result = result && this.checkTargetFieldConfigured(subfield);
            }
            return result;
        }
        else {
            for (let mappingrule of this.mappingRules) {
                if (mappingrule.mapping.getRuleResult() === field) {
                    return true;
                }
            }
            return false;
        }
    }
    getDesignValidationIssues() {
        let issues = [];
        for (let mappingrule of this._mappingRules) {
            issues.push(...mappingrule.getValidationIssue(this.getExecutionResult()));
        }
        if (this.getInputDefinition().fields.length === 0) {
            issues.push(new ValidationIssue("input datadef is not configured"));
        }
        if (this.getExecutionResult().fields.length === 0) {
            issues.push(new ValidationIssue("output datadef is not configured"));
        }
        if (this._mappingRules.length === 0) {
            issues.push(new ValidationIssue("mapping rules are required."));
        }
        for (let field of this.getExecutionResult().fields) {
            if (!this.checkTargetFieldConfigured(field)) {
                issues.push(new ValidationIssue(`target [${field.name}] is not configured`));
            }
        }
        return issues;
    }
}
//# sourceMappingURL=XMappingDefinition.js.map