import { __awaiter, __decorate, __generator, __read, __spread, __values } from "tslib";
import * as Core from "@intelligentgraphics/ig.gfx.core";
import { generateId } from "@intelligentgraphics/ig.utilities";
import { IGXE } from "@intelligentgraphics/igd.core";
import Logger from "../Logger";
export var EIGXEProductDataManagerDebugInfo;
(function (EIGXEProductDataManagerDebugInfo) {
    EIGXEProductDataManagerDebugInfo[EIGXEProductDataManagerDebugInfo["All"] = 1] = "All";
    EIGXEProductDataManagerDebugInfo[EIGXEProductDataManagerDebugInfo["Condition"] = 2] = "Condition";
    EIGXEProductDataManagerDebugInfo[EIGXEProductDataManagerDebugInfo["Properties"] = 3] = "Properties";
    EIGXEProductDataManagerDebugInfo[EIGXEProductDataManagerDebugInfo["ArticlePolymorphy"] = 4] = "ArticlePolymorphy";
    EIGXEProductDataManagerDebugInfo[EIGXEProductDataManagerDebugInfo["Init"] = 5] = "Init";
})(EIGXEProductDataManagerDebugInfo || (EIGXEProductDataManagerDebugInfo = {}));
var ECheckConditionResult;
(function (ECheckConditionResult) {
    ECheckConditionResult[ECheckConditionResult["Invalid"] = 1] = "Invalid";
    ECheckConditionResult[ECheckConditionResult["Valid"] = 2] = "Valid";
    ECheckConditionResult[ECheckConditionResult["Unresolvable"] = 3] = "Unresolvable";
})(ECheckConditionResult || (ECheckConditionResult = {}));
var CheckComId = function (target, propertyKey, descriptor) {
    var tOgFunction = descriptor.value;
    descriptor.value = function (comId) {
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        if (!this["basket"][comId]) {
            return Promise.resolve(undefined);
        }
        return tOgFunction.call.apply(tOgFunction, __spread([this, comId], args));
    };
};
/**
 * IGXEProductDataManager is an implementation of the IProductDataManager interface
 * that uses the IGD.IGXE product data format as data source.
 */
var IGXEProductDataManager = /** @class */ (function () {
    function IGXEProductDataManager(config) {
        var _this = this;
        this.pd = config.nativeData;
        this.ipPropsTop =
            config.pushInterProductPropertysToTop === undefined
                ? false
                : config.pushInterProductPropertysToTop;
        this.basket = {};
        this.dbgInfo = config.debugInfos || [];
        this.debug(EIGXEProductDataManagerDebugInfo.Init, "initialized IGXEProductDataManager", config);
        config.additionalData = config.additionalData || [];
        config.additionalData.forEach(function (ad) {
            _this.mergeIGXE(_this.pd, ad);
        });
        this.debug(EIGXEProductDataManagerDebugInfo.Init, "merged all pdata", this.pd);
    }
    IGXEProductDataManager.prototype.is = function () {
        return false;
    };
    IGXEProductDataManager.prototype.addArticle = function (articleNo, initialConfiguration, source) {
        return __awaiter(this, void 0, void 0, function () {
            var tArticleId, uid, tAC, tK, tNewAc, err_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        tArticleId = articleNo.baseArticleNumber;
                        if (!this.pd.Articles[tArticleId]) {
                            throw new Error("Unknown article " + tArticleId);
                        }
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        uid = generateId();
                        if (typeof initialConfiguration === "string") {
                            tAC = {};
                            for (tK in this.basket[initialConfiguration]
                                .articleConfiguration) {
                                tAC[tK] = this.basket[initialConfiguration].articleConfiguration[tK].Value;
                            }
                            initialConfiguration = tAC;
                        }
                        return [4 /*yield*/, this._intGetArticleConfiguration(tArticleId, {}, initialConfiguration === undefined
                                ? {}
                                : IGXE.createArticleConfigurationValuesFromChanges(initialConfiguration))];
                    case 2:
                        tNewAc = _a.sent();
                        this.basket[uid] = {
                            articleID: tArticleId,
                            articleConfiguration: tNewAc,
                            source: source,
                        };
                        return [2 /*return*/, uid];
                    case 3:
                        err_1 = _a.sent();
                        throw new Error("Initial configuration error " + err_1);
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    IGXEProductDataManager.prototype.removeArticle = function (comID) {
        delete this.basket[comID];
        return Promise.resolve(true);
    };
    IGXEProductDataManager.prototype.duplicateArticle = function (comID) {
        var tUID = generateId();
        this.basket[tUID] = {
            articleID: this.basket[comID].articleID,
            articleConfiguration: this.basket[comID].articleConfiguration,
            source: this.basket[comID],
        };
        return Promise.resolve(tUID);
    };
    IGXEProductDataManager.prototype.getArticleType = function (comId) {
        return Promise.resolve("graphical");
    };
    IGXEProductDataManager.prototype.getArticleID = function (comID) {
        return Promise.resolve(this.basket[comID].articleID);
    };
    IGXEProductDataManager.prototype.getArticleName = function (comId) {
        return Promise.resolve(undefined);
    };
    IGXEProductDataManager.prototype.getArticleShortText = function (comID) {
        return Promise.resolve(this.pd.Articles[this.basket[comID].articleID].ShortText);
    };
    IGXEProductDataManager.prototype.getArticleLongText = function (comID) {
        return Promise.resolve(this.pd.Articles[this.basket[comID].articleID].LongText);
    };
    IGXEProductDataManager.prototype.getArticleVariantText = function (comID) {
        return __awaiter(this, void 0, void 0, function () {
            var tR, articleConfiguration, tList;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        tR = new Array();
                        articleConfiguration = this.basket[comID].articleConfiguration;
                        return [4 /*yield*/, this.getArticlePropertyKeys(comID)];
                    case 1:
                        tList = _a.sent();
                        if (tList.length) {
                            tList.forEach(function (pkey) {
                                var tProp = _this.getProperty(pkey);
                                if (tProp && tProp.InVarCode) {
                                    var value = articleConfiguration[pkey];
                                    if (value === undefined || value.Text === undefined) {
                                        return;
                                    }
                                    tR.push({
                                        key: tProp.Text.join(" "),
                                        value: value.Text.join(" "),
                                    });
                                }
                            });
                        }
                        return [2 /*return*/, tR];
                }
            });
        });
    };
    IGXEProductDataManager.prototype.getArticleVariantCode = function (comID) {
        var _this = this;
        var tR = "";
        return this.getArticlePropertyKeys(comID).then(function (list) {
            if (list.length) {
                list.forEach(function (pkey) {
                    var tProp = _this.getProperty(pkey);
                    if (tProp && tProp.InVarCode) {
                        if (tR.length) {
                            tR += ";";
                        }
                        tR +=
                            pkey +
                                "=" +
                                _this.basket[comID].articleConfiguration[pkey].Value;
                    }
                });
            }
            return tR;
        });
    };
    IGXEProductDataManager.prototype.getArticleManufacturerID = function (comID) {
        return Promise.resolve(this.pd.Articles[this.basket[comID].articleID].Manufacturer);
    };
    IGXEProductDataManager.prototype.getArticleProgramID = function (comID) {
        return Promise.resolve(this.pd.Articles[this.basket[comID].articleID].Series);
    };
    IGXEProductDataManager.prototype.getArticleManufacturerName = function (comID) {
        return Promise.resolve("//TODO");
    };
    IGXEProductDataManager.prototype.getArticleProgramName = function (comID) {
        return Promise.resolve("//TODO");
    };
    IGXEProductDataManager.prototype.getArticleCategories = function (comId) {
        return Promise.resolve({});
    };
    IGXEProductDataManager.prototype.getArticleConfiguration = function (comID) {
        var tAC = {};
        for (var tK in this.basket[comID].articleConfiguration) {
            tAC[tK] = this.basket[comID].articleConfiguration[tK].Value;
        }
        return Promise.resolve(tAC);
    };
    IGXEProductDataManager.prototype.getArticleCatalogImage = function (comID) {
        return Promise.resolve(undefined);
    };
    IGXEProductDataManager.prototype._intGetArticleConfiguration = function (articleId, oldConfig, userSetOfValues, _intRecurseDepth) {
        var _this = this;
        return new Promise(function (resolve, reject) {
            var tAC = _this.mergeRecursive({}, userSetOfValues);
            var tCheckPrecondition = function (precondKey) {
                var tR = ECheckConditionResult.Valid;
                if (precondKey && precondKey.length) {
                    if (_this.pd.hasOwnProperty("Conditions") &&
                        _this.pd.Conditions[precondKey]) {
                        tR = _this.checkCondition(_this.pd.Conditions[precondKey], tAC);
                    }
                    else {
                        console.warn('Condition "' + precondKey + '" not found!');
                    }
                }
                return tR;
            };
            function tGetDefaultValue(PK) {
                var tR;
                var tPKDef = PK.Default;
                if (PK.Values) {
                    PK.Values.some(function (pv) {
                        if (tCheckPrecondition(pv.Precondition) ===
                            ECheckConditionResult.Valid) {
                            if (tPKDef === undefined || pv.Value === tPKDef) {
                                tR = pv;
                            }
                        }
                        return tR !== undefined;
                    });
                }
                // number properties doesn't need its default value specified in Values set
                if (tR === undefined &&
                    tPKDef &&
                    (PK.ValueType === IGXE.EPropertyType.Float ||
                        PK.ValueType === IGXE.EPropertyType.Int)) {
                    tR = {
                        Value: tPKDef,
                    };
                }
                return tR;
            }
            var tUnresolvedIssuesPresent = false;
            var tIPConfDefaults = {};
            _this.getInterProductID(articleId).then(function (ipid) {
                if (ipid) {
                    tIPConfDefaults = _this.pd.InterProduct.ArticlePolymorphy[ipid][articleId];
                }
                var tArt = _this.pd.Articles[articleId];
                if (tArt) {
                    if (tArt.PropertyClasses) {
                        tArt.PropertyClasses.forEach(function (pcid) {
                            var tPC = _this.pd.PropertyClasses[pcid];
                            var tCCR_PC = tCheckPrecondition(tPC.Precondition);
                            if (tCCR_PC === ECheckConditionResult.Unresolvable) {
                                // marking propclass as unresolved
                                tUnresolvedIssuesPresent = true;
                            }
                            else if (tCCR_PC === ECheckConditionResult.Valid) {
                                var _loop_1 = function (tPropKey) {
                                    if (tPC.Properties.hasOwnProperty(tPropKey)) {
                                        var tPK = tPC.Properties[tPropKey];
                                        var tKey_1 = pcid + "." + tPropKey;
                                        var tCCR_PK = tCheckPrecondition(tPK.Precondition);
                                        if (tCCR_PK ===
                                            ECheckConditionResult.Unresolvable) {
                                            // marking property as unresolved
                                            tUnresolvedIssuesPresent = true;
                                        }
                                        else if (tCCR_PK ===
                                            ECheckConditionResult.Valid) {
                                            // get PropValue
                                            var tValue_1;
                                            if (userSetOfValues[tKey_1] !=
                                                undefined) {
                                                tValue_1 = _this._intGetIPropValue(userSetOfValues[tKey_1], tPK);
                                                var tPV = tValue_1;
                                                if (tPV == undefined ||
                                                    tCheckPrecondition(tPV.Precondition) !==
                                                        ECheckConditionResult.Valid) {
                                                    tValue_1 = undefined;
                                                }
                                            }
                                            if (tValue_1 == undefined &&
                                                tIPConfDefaults[tKey_1] !=
                                                    undefined) {
                                                tPK.Values.some(function (pv) {
                                                    if (pv.Value ===
                                                        tIPConfDefaults[tKey_1]) {
                                                        tValue_1 = pv;
                                                        return true;
                                                    }
                                                    return false;
                                                });
                                            }
                                            if (tValue_1 == undefined &&
                                                oldConfig[tKey_1] != undefined) {
                                                tValue_1 = _this._intGetIPropValue(oldConfig[tKey_1], tPK);
                                                var tPV = tValue_1;
                                                if (tPV == undefined ||
                                                    tCheckPrecondition(tPV.Precondition) !==
                                                        ECheckConditionResult.Valid) {
                                                    tValue_1 = undefined;
                                                }
                                            }
                                            if (tValue_1 == undefined) {
                                                tValue_1 = tGetDefaultValue(tPK);
                                            }
                                            if (tValue_1 == undefined) {
                                                // marking propvalue as unresolved
                                                tUnresolvedIssuesPresent = true;
                                            }
                                            else {
                                                tAC[tKey_1] = _this.mergeRecursive({}, tValue_1);
                                            }
                                        }
                                    }
                                };
                                // iterate though properties
                                for (var tPropKey in tPC.Properties) {
                                    _loop_1(tPropKey);
                                }
                            }
                        });
                    }
                    if (!tUnresolvedIssuesPresent) {
                        if (tArt.Condition) {
                            switch (tCheckPrecondition(tArt.Condition)) {
                                case ECheckConditionResult.Unresolvable:
                                    tUnresolvedIssuesPresent = true;
                                case ECheckConditionResult.Invalid:
                                    reject("Article condition not met");
                            }
                        }
                    }
                }
                if (tUnresolvedIssuesPresent) {
                    var tRD = (_intRecurseDepth || 0) + 1;
                    if (tRD < Object.keys(tAC).length) {
                        _this.debug(EIGXEProductDataManagerDebugInfo.Condition, "Retry solving conditions\n", JSON.stringify(tAC));
                        resolve(_this._intGetArticleConfiguration(articleId, oldConfig, tAC, tRD));
                    }
                    else {
                        console.warn("Could not solve conditions in a reasonable number of tries!\n", JSON.stringify(tAC));
                    }
                }
                resolve(tAC);
            });
        });
    };
    /**
     * @param propKey Property key in the format <PropClassId>.<PropertyID>
     * @returns IProperty object
     */
    IGXEProductDataManager.prototype.getProperty = function (propKey) {
        var tPCP = propKey.split(".");
        var tProp;
        if (this.pd &&
            this.pd.PropertyClasses &&
            this.pd.PropertyClasses[tPCP[0]] &&
            this.pd.PropertyClasses[tPCP[0]].Properties[tPCP[1]]) {
            tProp = this.pd.PropertyClasses[tPCP[0]].Properties[tPCP[1]];
        }
        this.debug(EIGXEProductDataManagerDebugInfo.Properties, "getProperty", propKey, tProp);
        return tProp;
    };
    /**
     * @param articleID The article whose properties should be aquired
     * @param articleConfiguration The article configuration, this is used
     * to check preconditions of property classes and properties
     * @returns An Array of property keys in the format <PropClassId>.<PropertyID>,
     * sorted by PropClass and the .Position value of IProperty
     */
    IGXEProductDataManager.prototype.getArticlePropertyKeys = function (comID) {
        return __awaiter(this, void 0, void 0, function () {
            var tR, tIpId, tPrioProps_1, err_2;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        tR = new Array();
                        if (!this.pd.Articles[this.basket[comID].articleID].PropertyClasses) {
                            return [2 /*return*/, tR];
                        }
                        this.pd.Articles[this.basket[comID].articleID].PropertyClasses.forEach(function (pcid) {
                            var tPropClass = _this.pd.PropertyClasses[pcid];
                            if (_this.checkCondition(tPropClass.Precondition, _this.basket[comID].articleConfiguration) !== ECheckConditionResult.Valid) {
                                return;
                            }
                            // propclass is valid
                            var tProps = new Array();
                            for (var tPropKey in tPropClass.Properties) {
                                if (!tPropClass.Properties.hasOwnProperty(tPropKey)) {
                                    continue;
                                }
                                var tProp = tPropClass.Properties[tPropKey];
                                if (_this.checkCondition(tProp.Precondition, _this.basket[comID].articleConfiguration) === ECheckConditionResult.Valid) {
                                    tProps.push({
                                        key: pcid + "." + tPropKey,
                                        prop: tPropClass.Properties[tPropKey],
                                    });
                                }
                            }
                            // sort by position (still inside propclass)
                            tProps.sort(function (a, b) {
                                if (a.prop.Position !== undefined &&
                                    b.prop.Position !== undefined) {
                                    if (a.prop.Position > b.prop.Position) {
                                        return 1;
                                    }
                                    if (a.prop.Position < b.prop.Position) {
                                        return -1;
                                    }
                                }
                                return 0;
                            });
                            tProps.forEach(function (prop) { return tR.push(prop.key); });
                        });
                        if (!this.ipPropsTop) return [3 /*break*/, 5];
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 4, , 5]);
                        return [4 /*yield*/, this.getInterProductID(this.basket[comID].articleID)];
                    case 2:
                        tIpId = _a.sent();
                        if (tIpId === undefined) {
                            return [2 /*return*/, tR];
                        }
                        return [4 /*yield*/, this.getInterProductPropertyKeys(tIpId)];
                    case 3:
                        tPrioProps_1 = _a.sent();
                        // push interproduct props to top
                        tR.sort(function (a, b) {
                            if (tPrioProps_1.indexOf(a) < 0 &&
                                tPrioProps_1.indexOf(b) < 0) {
                                return 0;
                            }
                            if (tPrioProps_1.indexOf(a) > -1 &&
                                tPrioProps_1.indexOf(b) > -1) {
                                return 0;
                            }
                            if (tPrioProps_1.indexOf(a) > -1) {
                                return -1;
                            }
                            return 1;
                        });
                        return [3 /*break*/, 5];
                    case 4:
                        err_2 = _a.sent();
                        return [3 /*break*/, 5];
                    case 5: return [2 /*return*/, tR];
                }
            });
        });
    };
    IGXEProductDataManager.prototype.getArticlePropertyList = function (comID) {
        var _this = this;
        if (!this.basket[comID] || !this.basket[comID].articleConfiguration) {
            return Promise.reject("Can not retrieve properties of unknown article \"" + comID + "\"");
        }
        var articleConfiguration = this.basket[comID].articleConfiguration;
        return this.getArticlePropertyKeys(comID).then(function (keys) {
            return keys
                .filter(function (key) { return articleConfiguration[key]; })
                .map(function (propkey) {
                var tProp = _this.getProperty(propkey);
                if (!tProp) {
                    return undefined;
                }
                var values = _this.getPropertyValues(tProp, articleConfiguration).map(function (val) { return ({
                    Image: val.Image,
                    Text: val.Text,
                    Value: val.Value,
                }); });
                var editable = values.length > 0;
                return {
                    Key: propkey,
                    Text: tProp.Text,
                    AdditionalValues: tProp.AdditionalValues,
                    ValueRangeFrom: tProp.ValueRangeFrom,
                    ValueRangeTo: tProp.ValueRangeTo,
                    ValueType: tProp.ValueType,
                    ValueUnit: tProp.ValueUnit,
                    Value: articleConfiguration[propkey].Value,
                    Values: values,
                    Visible: editable &&
                        articleConfiguration[propkey].Value !==
                            undefined,
                    Editable: editable,
                    Type: "choiceList",
                    SubProperties: [],
                };
            })
                .filter(Boolean);
        });
    };
    IGXEProductDataManager.prototype.getArticleSubProperties = function (comID, parentPropertyKey) {
        return Promise.resolve([]);
    };
    IGXEProductDataManager.prototype.getPropertyValues = function (property, articleConfiguration) {
        var _this = this;
        var resolvedProperty = typeof property === "string"
            ? this.getProperty(property)
            : property;
        if (resolvedProperty === undefined) {
            return [];
        }
        return resolvedProperty.Values.filter(function (value) {
            return _this.checkCondition(value.Precondition, articleConfiguration) === ECheckConditionResult.Valid;
        });
    };
    IGXEProductDataManager.prototype.getArticlePrices = function (comID) {
        var _this = this;
        var tR = new Array();
        if (this.pd.Price_Type === IGXE.EPriceType.None) {
            // no prices
            return Promise.resolve(tR);
        }
        if (!this.pd.Articles[this.basket[comID].articleID]) {
            console.error("Article not found!", this.basket[comID].articleID);
            return Promise.reject(new Error("Article not found! " + this.basket[comID].articleID));
        }
        this.pd.Articles[this.basket[comID].articleID].Prices.forEach(function (ap) {
            if (_this.checkCondition(ap.Precondition, _this.basket[comID].articleConfiguration) === ECheckConditionResult.Valid) {
                tR.push({
                    Currency: ap.Currency,
                    Level: ap.Level,
                    Text: ap.Text,
                    Value: ap.Value,
                });
            }
        });
        // sort base prices to the top, leave other unchanged
        tR.sort(function (a, b) {
            if (a.Level === IGXE.EPriceLevel.Base) {
                return -1;
            }
            if (b.Level === IGXE.EPriceLevel.Base) {
                return 1;
            }
            return 0;
        });
        return Promise.resolve(tR);
    };
    /**
     * Returns true if the article should be added to basket/BOM upon creation
     * @param comID: Commercial ID of the article instance.
     */
    IGXEProductDataManager.prototype.articleIsCommercial = function (comID) {
        return Promise.resolve(this.pd.Articles[this.basket[comID].articleID].IsCommercial);
    };
    /**
     * Returns true if the article has a graphic representation that
     * getGfxRepresentation can process
     * @param comID: Commercial ID of the article instance.
     */
    IGXEProductDataManager.prototype.articleHasGraphics = function (comID) {
        return Promise.resolve(this.pd.Articles[this.basket[comID].articleID].HasGraphics);
    };
    IGXEProductDataManager.prototype.isGeometricProperty = function (comID, propKey) {
        var _this = this;
        var tProps = typeof propKey === "string" ? [propKey] : propKey;
        return Promise.resolve(tProps.some(function (pk) {
            var tProp = _this.getProperty(pk);
            if (tProp !== undefined && tProp.Geometric) {
                return true;
            }
            return false;
        }));
    };
    IGXEProductDataManager.prototype.getMaterialAssignment = function (comID, propKey) {
        return __awaiter(this, void 0, void 0, function () {
            var propertyKeys, assignments;
            var _this = this;
            return __generator(this, function (_a) {
                propertyKeys = typeof propKey === "string" ? [propKey] : propKey;
                assignments = {};
                propertyKeys.forEach(function (pk) {
                    var tProp = _this.getProperty(pk);
                    if (tProp !== undefined &&
                        tProp.MaterialCategory &&
                        tProp.ValueType === IGXE.EPropertyType.Material) {
                        var tAC = _this.basket[comID].articleConfiguration;
                        if (tAC[pk]) {
                            assignments[tProp.MaterialCategory] = tAC[pk]
                                .Value;
                        }
                        return true;
                    }
                });
                return [2 /*return*/, assignments];
            });
        });
    };
    // InterProduct methods
    IGXEProductDataManager.prototype.getInterProductPropertyKeys = function (interProductID) {
        var tR = new Array();
        if (interProductID &&
            this.pd.InterProduct &&
            this.pd.InterProduct.ArticlePolymorphy) {
            var tIP = this.pd.InterProduct.ArticlePolymorphy[interProductID];
            if (tIP) {
                var tAllArtIDs = Object.keys(tIP);
                if (tAllArtIDs.length) {
                    var tFirst = tIP[tAllArtIDs[0]];
                    tR = tR.concat(Object.keys(tFirst));
                }
            }
        }
        this.debug(EIGXEProductDataManagerDebugInfo.ArticlePolymorphy, "getInterProductPropertyKeys", interProductID, "=>", tR);
        return Promise.resolve(tR);
    };
    IGXEProductDataManager.prototype.getFirstArticleIdOfInterProduct = function (interProductID) {
        var tRes;
        if (this.pd &&
            this.pd.InterProduct &&
            this.pd.InterProduct.ArticlePolymorphy) {
            var tIP = this.pd.InterProduct.ArticlePolymorphy[interProductID];
            if (tIP) {
                var tAllArtIDs = Object.keys(tIP);
                if (tAllArtIDs.length) {
                    tRes = tAllArtIDs[0];
                }
            }
        }
        this.debug(EIGXEProductDataManagerDebugInfo.ArticlePolymorphy, "getFirstArticleIdOfInterProduct", interProductID, "=>", tRes);
        return Promise.resolve(tRes);
    };
    IGXEProductDataManager.prototype.getInterProductID = function (articleID) {
        var _this = this;
        var tR;
        if (this.pd &&
            this.pd.InterProduct &&
            this.pd.InterProduct.ArticlePolymorphy) {
            Object.keys(this.pd.InterProduct.ArticlePolymorphy).some(function (cgid) {
                var tCG = _this.pd.InterProduct.ArticlePolymorphy[cgid];
                if (Object.keys(tCG).indexOf(articleID) > -1) {
                    tR = cgid;
                    return true;
                }
                return false;
            });
        }
        this.debug(EIGXEProductDataManagerDebugInfo.ArticlePolymorphy, "getInterProductID", articleID, "=>", tR);
        return Promise.resolve(tR);
    };
    /**
     * Searches all sub-articles for the given main article based on its configuration
     */
    IGXEProductDataManager.prototype.getSubArticleIDs = function (comID) {
        return Promise.resolve([]);
        // const tR: string[] = [];
        // if (
        // 	!this.pd ||
        // 	!this.pd.InterProduct ||
        // 	/*!this.pd.InterProduct.ArticlePolymorphy || */ !this.pd
        // 		.InterProduct.SubArticles
        // ) {
        // 	return tR;
        // }
        // const tIpId = await this.getInterProductID(
        // 	this.basket[comID].articleID
        // );
        // Object.keys(this.pd.InterProduct.SubArticles).forEach(subartID => {
        // 	const tSA = this.pd.InterProduct!.SubArticles![subartID];
        // 	if (tSA.MainArticleIDs.indexOf(this.basket[comID].articleID) > -1) {
        // 		if (
        // 			this.checkMatchingConfiguration(
        // 				this.basket[comID].articleConfiguration,
        // 				tSA.Configuration
        // 			)
        // 		) {
        // 			tR.push(subartID);
        // 		}
        // 	}
        // 	if (tIpId && tSA.MainArticleIDs.indexOf(tIpId) > -1) {
        // 		if (
        // 			this.checkMatchingConfiguration(
        // 				this.basket[comID].articleConfiguration,
        // 				tSA.Configuration
        // 			)
        // 		) {
        // 			tR.push(subartID);
        // 		}
        // 	}
        // });
        // return tR;
    };
    IGXEProductDataManager.prototype.setPropValue = function (comID, changedPropKey, newPropValue) {
        return __awaiter(this, void 0, void 0, function () {
            var tAID, tAC, tList, err_3, tProp, tPV, tModdedAC, tNewArticleConfiguration, tIpId, tNewArtID, err_4;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 7, , 8]);
                        tAID = this.basket[comID].articleID;
                        tAC = this.basket[comID].articleConfiguration;
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, this.getArticlePropertyKeys(comID)];
                    case 2:
                        tList = _a.sent();
                        if (tList.indexOf(changedPropKey) < 0) {
                            throw new Error("No properties changed");
                        }
                        return [3 /*break*/, 4];
                    case 3:
                        err_3 = _a.sent();
                        return [2 /*return*/];
                    case 4:
                        tProp = this.getProperty(changedPropKey);
                        tPV = this._intGetIPropValue(newPropValue, tProp);
                        tModdedAC = {};
                        tModdedAC[changedPropKey] = tPV;
                        return [4 /*yield*/, this._intGetArticleConfiguration(tAID, tAC, tModdedAC).catch(function (err) {
                                _this.debug(EIGXEProductDataManagerDebugInfo.Condition, err);
                                throw err;
                            })];
                    case 5:
                        tNewArticleConfiguration = _a.sent();
                        this.basket[comID].articleConfiguration = tNewArticleConfiguration;
                        return [4 /*yield*/, this.getInterProductID(tAID)];
                    case 6:
                        tIpId = _a.sent();
                        if (tIpId) {
                            tNewArtID = this._intGetInterProductArticleID(tIpId, this.basket[comID].articleConfiguration);
                            this.basket[comID].articleID = tNewArtID;
                        }
                        return [3 /*break*/, 8];
                    case 7:
                        err_4 = _a.sent();
                        throw err_4;
                    case 8: return [2 /*return*/];
                }
            });
        });
    };
    IGXEProductDataManager.prototype.setPropValues = function (comId, values) {
        return __awaiter(this, void 0, void 0, function () {
            var changes, changes_1, changes_1_1, _a, key, value, e_1_1;
            var e_1, _b;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        changes = IGXE.normalizePropertyValueChanges(values);
                        _c.label = 1;
                    case 1:
                        _c.trys.push([1, 6, 7, 8]);
                        changes_1 = __values(changes), changes_1_1 = changes_1.next();
                        _c.label = 2;
                    case 2:
                        if (!!changes_1_1.done) return [3 /*break*/, 5];
                        _a = changes_1_1.value, key = _a.key, value = _a.value;
                        return [4 /*yield*/, this.setPropValue(comId, key, value)];
                    case 3:
                        _c.sent();
                        _c.label = 4;
                    case 4:
                        changes_1_1 = changes_1.next();
                        return [3 /*break*/, 2];
                    case 5: return [3 /*break*/, 8];
                    case 6:
                        e_1_1 = _c.sent();
                        e_1 = { error: e_1_1 };
                        return [3 /*break*/, 8];
                    case 7:
                        try {
                            if (changes_1_1 && !changes_1_1.done && (_b = changes_1.return)) _b.call(changes_1);
                        }
                        finally { if (e_1) throw e_1.error; }
                        return [7 /*endfinally*/];
                    case 8: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * This IGXEProductDataManager-specific method returns the native IGXE property
     * definition of the given property.
     * @param propKey Property key in the format <PropClassId>.<PropertyID>
     * @returns IGXE.IProperty object
     */
    IGXEProductDataManager.prototype.getIGXEProperty = function (propKey) {
        return this.getProperty(propKey);
    };
    IGXEProductDataManager.prototype.assignMaterialPropertyValues = function (article) {
        return __awaiter(this, void 0, void 0, function () {
            var propertyKeys, materialAssignment;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!article.comId || !article.gfxId) {
                            return [2 /*return*/, Logger.error("IGXEProductDataManager.assignMaterialPropertyValues: article under-specified.", article)];
                        }
                        return [4 /*yield*/, this.getArticlePropertyKeys(article.comId)];
                    case 1:
                        propertyKeys = _a.sent();
                        return [4 /*yield*/, this.getMaterialAssignment(article.comId, propertyKeys)];
                    case 2:
                        materialAssignment = _a.sent();
                        return [2 /*return*/, Core.State.API.SetCategoryMaterials(article.gfxId, materialAssignment)];
                }
            });
        });
    };
    IGXEProductDataManager.prototype.checkCondition = function (condition, currentConfig) {
        if (condition === undefined) {
            return ECheckConditionResult.Valid;
        }
        var tCond;
        if (typeof condition === "string") {
            if (condition.length === 0) {
                return ECheckConditionResult.Valid;
            }
            if (this.pd.hasOwnProperty("Conditions") &&
                this.pd.Conditions[condition]) {
                tCond = this.pd.Conditions[condition];
            }
            else {
                console.warn("Condition", condition, "not found in product data!");
                return ECheckConditionResult.Invalid;
            }
        }
        else {
            tCond = condition;
        }
        this.debug(EIGXEProductDataManagerDebugInfo.Condition, "Parsing", JSON.stringify(tCond));
        var tEvalStr = "";
        function tGetValidVarName(propid) {
            if (typeof propid === "string") {
                return propid.replace(/\./g, "___");
            }
            return undefined;
        }
        function tGetPropNameWithoutClass(propid) {
            var tP = propid.lastIndexOf(".");
            return propid.substr(tP + 1);
        }
        for (var propid in currentConfig) {
            if (currentConfig.hasOwnProperty(propid) &&
                propid.indexOf("$") < 0) {
                // creating two local vars per property: with and without propclass
                var tVal = typeof currentConfig[propid] === "object"
                    ? currentConfig[propid]
                        .Value
                    : currentConfig[propid];
                tEvalStr +=
                    "var " +
                        tGetValidVarName(propid) +
                        "=" +
                        tGetPropNameWithoutClass(propid) +
                        "=" +
                        JSON.stringify(tVal) +
                        ";";
            }
        }
        function tGetConditionEvalString(c, isSubEval) {
            var tCType = typeof c;
            if (tCType === "string" ||
                tCType === "number" ||
                tCType === "boolean") {
                if (tCType === "string") {
                    return tGetValidVarName(c);
                }
                return c.toString();
            }
            else {
                if (Array.isArray(c)) {
                    return JSON.stringify(c);
                }
            }
            var tC = c;
            var tS = "(";
            if (tC.Not === true) {
                tS += "!";
            }
            tS += "(";
            switch (tC.Comp) {
                case IGXE.EConditionJoin.AND:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " && ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionJoin.OR:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " || ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionJoin.PLUS:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " + ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionJoin.MINUS:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " - ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionJoin.MUL:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " * ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionJoin.DIV:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " / ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionCompare.Equal:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " === ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionCompare.Greater:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " > ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionCompare.GreaterOrEqual:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " >= ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionCompare.Smaller:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " < ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionCompare.SmallerOrEqual:
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += " <= ";
                    tS += tGetConditionEvalString(tC.Op2, true);
                    break;
                case IGXE.EConditionCompare.In:
                    tS += tGetConditionEvalString(tC.Op2, true);
                    tS += ".indexOf(";
                    tS += tGetConditionEvalString(tC.Op1, true);
                    tS += ") > -1";
                    break;
            }
            tS += "))";
            if (isSubEval !== true) {
                tS += ";";
            }
            return tS;
        }
        tEvalStr += tGetConditionEvalString(tCond);
        this.debug(EIGXEProductDataManagerDebugInfo.Condition, "Evaluate", tEvalStr);
        var tRes = ECheckConditionResult.Invalid;
        try {
            var tR = eval(tEvalStr);
            if (tR === true) {
                tRes = ECheckConditionResult.Valid;
            }
        }
        catch (e) {
            if (e instanceof ReferenceError) {
                tRes = ECheckConditionResult.Unresolvable;
            }
            else {
                tRes = ECheckConditionResult.Invalid;
                console.warn(e);
            }
        }
        this.debug(EIGXEProductDataManagerDebugInfo.Condition, "Result =", ECheckConditionResult[tRes]);
        return tRes;
    };
    IGXEProductDataManager.prototype.mergeIGXE = function (obj1, obj2) {
        for (var p in obj2) {
            if (obj2[p] === undefined) {
                // never overwrite with undefined
                continue;
            }
            switch (p) {
                case "Articles":
                    // merge articles
                    if (obj1[p] == undefined) {
                        obj1[p] = {};
                    }
                    for (var artNum in obj2[p]) {
                        if (obj1[p][artNum] == undefined) {
                            obj1[p][artNum] = obj2[p][artNum];
                        }
                        else {
                            for (var artKey in obj2[p][artNum]) {
                                switch (artKey) {
                                    case "ShortText":
                                    case "LongText":
                                        // overwrite article texts
                                        // TODO: only overwrite languages
                                        if (obj2[p][artNum][artKey] &&
                                            obj2[p][artNum][artKey].length) {
                                            obj1[p][artNum][artKey] =
                                                obj2[p][artNum][artKey];
                                        }
                                        break;
                                    case "PropertyClasses":
                                        // concat PropClasses
                                        obj1[p][artNum][artKey] = (obj1[p][artNum][artKey] || []).concat(obj2[p][artNum][artKey] || []);
                                        break;
                                    case "Prices":
                                        if (obj1[p][artNum][artKey] == undefined) {
                                            obj1[p][artNum][artKey] =
                                                obj2[p][artNum][artKey];
                                        }
                                        else {
                                            if (obj1[p][artNum][artKey]
                                                .length ===
                                                obj2[p][artNum][artKey].length) {
                                                // if both price array have the same length, merge their contents
                                                for (var idx = 0; idx <
                                                    obj1[p][artNum][artKey]
                                                        .length; idx++) {
                                                    obj1[p][artNum][artKey][idx] = this.mergeRecursive(obj1[p][artNum][artKey][idx], obj2[p][artNum][artKey][idx]);
                                                }
                                            }
                                        }
                                        break;
                                    default:
                                        // overwrite all other
                                        if (obj2[p][artNum][artKey]) {
                                            obj1[p][artNum][artKey] =
                                                obj2[p][artNum][artKey];
                                        }
                                }
                            }
                        }
                    }
                    break;
                case "PropertyClasses":
                    // merge PCs
                    this.mergeRecursive(obj1[p], obj2[p]);
                    break;
                case "Conditions":
                    // merge Conds
                    this.mergeRecursive(obj1[p], obj2[p]);
                    break;
                default:
                    // all other keys
                    obj1[p] = this.mergeRecursive(obj1[p], obj2[p]);
            }
        }
        return obj1;
    };
    IGXEProductDataManager.prototype.mergeRecursive = function (obj1, obj2) {
        if (typeof obj2 === "object") {
            for (var p in obj2) {
                if (obj2[p] === undefined) {
                    // never overwrite with undefined
                    continue;
                }
                try {
                    // Property in destination object set; update its value.
                    if (Array.isArray(obj2[p])) {
                        if (Array.isArray(obj1[p])) {
                            obj1[p] = obj1[p].concat(obj2[p]);
                        }
                        else {
                            obj1[p] = obj2[p];
                        }
                    }
                    else {
                        if (typeof obj2[p] === "object") {
                            obj1[p] = this.mergeRecursive(obj1[p], obj2[p]);
                        }
                        else {
                            obj1[p] = obj2[p];
                        }
                    }
                }
                catch (e) {
                    // Property in destination object not set; create it and set its value.
                    obj1[p] = obj2[p];
                }
            }
        }
        else {
            if (obj2 !== undefined) {
                obj1 = obj2;
            }
        }
        return obj1;
    };
    IGXEProductDataManager.prototype.debug = function (lvl) {
        var message = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            message[_i - 1] = arguments[_i];
        }
        if (this.dbgInfo.indexOf(EIGXEProductDataManagerDebugInfo.All) > -1 ||
            this.dbgInfo.indexOf(lvl) > -1) {
            // tslint:disable-next-line:no-console
            console.debug.apply(console, __spread([EIGXEProductDataManagerDebugInfo[lvl] + ":"], message));
        }
    };
    IGXEProductDataManager.prototype._intGetTPropValue = function (pv) {
        var tR;
        if (typeof pv === "object") {
            tR = pv.Value;
        }
        else {
            tR = pv;
        }
        return tR;
    };
    IGXEProductDataManager.prototype._intGetIPropValue = function (pv, propdef) {
        var tTVal = this._intGetTPropValue(pv);
        var tR = propdef.Values.find(function (val) { return val.Value === tTVal; });
        if (tR === undefined && propdef.AdditionalValues) {
            // new value is not in Values, but additional values are allowed
            return {
                Value: tTVal,
            };
        }
        return tR;
    };
    IGXEProductDataManager.prototype._intGetInterProductArticleID = function (interProductID, articleConfiguration) {
        var tR;
        if (interProductID &&
            this.pd.InterProduct &&
            this.pd.InterProduct.ArticlePolymorphy) {
            var tCG_1 = this.pd.InterProduct.ArticlePolymorphy[interProductID];
            if (tCG_1) {
                // iterate through articles, check if all config items are fullfilled
                Object.keys(tCG_1).some(function (artid) {
                    var tK = Object.keys(tCG_1[artid]);
                    var tMatches = 0;
                    tK.forEach(function (ac) {
                        // find ac in articleConfiguration
                        if (Object.keys(articleConfiguration).some(function (ackey) {
                            return (ac === ackey &&
                                tCG_1[artid][ac] ===
                                    articleConfiguration[ackey].Value);
                        })) {
                            tMatches++;
                        }
                    });
                    if (tMatches >= tK.length) {
                        tR = artid;
                        return true;
                    }
                    return false;
                });
            }
        }
        this.debug(EIGXEProductDataManagerDebugInfo.ArticlePolymorphy, "getInterProductArticleID", interProductID, articleConfiguration, "=>", tR);
        return tR;
    };
    IGXEProductDataManager.prototype.getIGXCRepresentation = function (comId) {
        return Promise.resolve(undefined);
    };
    IGXEProductDataManager.prototype.getGfxRepresentation = function (comID) {
        return __awaiter(this, void 0, void 0, function () {
            var hasGfx, scene, materialAssignment, _a, _b;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0: return [4 /*yield*/, this.articleHasGraphics(comID)];
                    case 1:
                        hasGfx = _c.sent();
                        if (!hasGfx) {
                            Logger.warn("Article has no graphical representation");
                            return [2 /*return*/, undefined];
                        }
                        scene = Core.IGXC.createScene();
                        _a = this.getMaterialAssignment;
                        _b = [comID];
                        return [4 /*yield*/, this.getArticlePropertyKeys(comID)];
                    case 2: return [4 /*yield*/, _a.apply(this, _b.concat([_c.sent()]))];
                    case 3:
                        materialAssignment = _c.sent();
                        scene.CommercialId = comID;
                        scene.Categories = materialAssignment;
                        return [2 /*return*/, {
                                scene: scene,
                            }];
                }
            });
        });
    };
    /**
     * Get the connected articles based on comIDs.
     * @param comIDs Commercial IDs of the base articles (i.e. the one the user clicks on)
     * @returns Array of the comIDs of all articles in the group (incl. comID)
     */
    IGXEProductDataManager.prototype.getConnectedArticles = function (comIDs) {
        return Promise.resolve(comIDs);
    };
    IGXEProductDataManager.prototype.getArticlePlacement = function (comId) {
        return Promise.resolve(undefined);
    };
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "removeArticle", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "duplicateArticle", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleType", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleID", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleName", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleShortText", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleLongText", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleVariantText", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleVariantCode", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleManufacturerID", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleProgramID", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleManufacturerName", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleProgramName", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleCategories", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticleConfiguration", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticlePropertyKeys", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getArticlePrices", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "articleIsCommercial", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "articleHasGraphics", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "isGeometricProperty", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "getMaterialAssignment", null);
    __decorate([
        CheckComId
    ], IGXEProductDataManager.prototype, "setPropValue", null);
    return IGXEProductDataManager;
}());
export { IGXEProductDataManager };
