import { IGXE } from "@intelligentgraphics/igd.core";
/** Specific error class for import errors. */
export class IGXEImportException {
    constructor(message) {
        this.name = "ImportError";
        this.message = message;
    }
}
/** Loader for IGXE data. */
export class IGXELoader {
    /**
     * Reads IGD.Core.IGXE data. The source
     * should match the IGXE interface declaration. The import
     * algorithm tolerates the following differences:
     *  - Format_Version can be ommitted (will be set to the current)
     *  - Content_Version can be ommitted (will be set to the actual date)
     *  - Enum values can be represented as strings (i.e. EPriceLevel.Base == "Base")
     *  - Missing entries will be created empty/undefined
     * This function throws exceptions when anything fails and put warnings on the
     * console if anything is skipped during import.
     * @param src Javascript Object
     * @param isAdditional mandatory fields are treated as optional
     * @returns the imported product data
     */
    static readProductDataNative(src, isAdditional) {
        const tImport = src;
        if (tImport == undefined) {
            throw new IGXEImportException("Source could not be read.");
        }
        const tPD = {
            Format_Version: 1,
            Content_Version: new Date().toUTCString(),
            Price_Type: IGXE.EPriceType.None,
            VAT: undefined,
            Articles: {},
            PropertyClasses: {},
            Conditions: {},
            InterProduct: {},
        };
        if (tImport.hasOwnProperty("Price_Type")) {
            switch (typeof tImport["Price_Type"]) {
                case "string":
                    tPD.Price_Type =
                        IGXE.EPriceType[tImport["Price_Type"]];
                    break;
                case "number":
                    tPD.Price_Type = tImport["Price_Type"];
                    break;
            }
        }
        if (tImport.hasOwnProperty("VAT")) {
            if (typeof tImport["VAT"] === "number") {
                tPD.VAT = tImport["VAT"];
            }
        }
        if (tImport.hasOwnProperty("Articles")) {
            for (const artnum in tImport["Articles"]) {
                if (tImport["Articles"].hasOwnProperty(artnum)) {
                    const tArt = tImport["Articles"][artnum];
                    const tIA = {
                        Manufacturer: tArt["Manufacturer"],
                        Series: tArt["Series"],
                        ShortText: tArt["ShortText"],
                        LongText: tArt["LongText"],
                        Prices: IGXELoader.parsePrices(tArt["Prices"]),
                        EAN: tArt["EAN"],
                        PropertyClasses: tArt["PropertyClasses"],
                        HasGraphics: tArt["HasGraphics"] === undefined
                            ? true
                            : tArt["HasGraphics"],
                        IsCommercial: tArt["IsCommercial"] === undefined
                            ? true
                            : tArt["IsCommercial"],
                        Condition: tArt["Condition"]
                            ? tArt["Condition"].toString()
                            : tArt["Condition"],
                    };
                    tPD.Articles[artnum] = tIA;
                }
            }
        }
        else {
            if (!isAdditional) {
                throw new IGXEImportException('"Articles" key missing in src.');
            }
        }
        if (tImport.hasOwnProperty("PropertyClasses")) {
            for (const pcid in tImport["PropertyClasses"]) {
                if (tImport["PropertyClasses"].hasOwnProperty(pcid)) {
                    const tPC = tImport["PropertyClasses"][pcid];
                    if (tPC.hasOwnProperty("Properties") &&
                        typeof tPC["Properties"] === "object") {
                        tPD.PropertyClasses[pcid] = {
                            Properties: IGXELoader.parseProperties(tPC["Properties"]),
                            Precondition: tPC["Precondition"]
                                ? tPC["Precondition"].toString()
                                : tPC["Precondition"],
                        };
                    }
                    else {
                        console.warn('IGXELoader: skipping property class "' +
                            pcid +
                            '", invalid format', tPC);
                    }
                }
            }
        }
        if (tImport.hasOwnProperty("Conditions")) {
            for (const cid in tImport["Conditions"]) {
                if (tImport["Conditions"].hasOwnProperty(cid)) {
                    const tC = IGXELoader.parseCondition(tImport["Conditions"][cid]);
                    if (tC !== undefined) {
                        tPD.Conditions[cid.toString()] = tC;
                    }
                    else {
                        console.warn('IGXELoader: skipping condition "' +
                            cid +
                            '", invalid format:', tImport["Conditions"][cid]);
                    }
                }
            }
        }
        if (tImport.hasOwnProperty("InterProduct")) {
            tPD.InterProduct = tImport["InterProduct"];
        }
        return tPD;
    }
    static parsePrices(input) {
        const tR = new Array();
        if (!input) {
            return tR;
        }
        input.forEach(inp => {
            if (inp.hasOwnProperty("Currency") &&
                typeof inp["Currency"] === "string" &&
                inp["Currency"].length > 0 &&
                inp.hasOwnProperty("Value") &&
                typeof inp["Value"] === "number") {
                tR.push({
                    Currency: inp["Currency"],
                    Value: inp["Value"],
                    Level: inp["Level"]
                        ? typeof inp["Level"] === "number"
                            ? inp["Level"]
                            : IGXE.EPriceLevel[inp["Level"]]
                        : inp["Level"],
                    Precondition: inp["Precondition"]
                        ? inp["Precondition"].toString()
                        : inp["Precondition"],
                    Text: inp["Text"] || [],
                });
            }
        });
        return tR;
    }
    static parseProperties(input) {
        const tProps = {};
        function tParseUnit(source) {
            let tRes;
            switch (typeof source) {
                case "undefined":
                    tRes = undefined;
                    break;
                case "number":
                    if (IGXE.EPropertyValueUnit[source] !== undefined) {
                        tRes = source;
                    }
                    break;
                case "string":
                    const tUpper = source.toUpperCase();
                    if (IGXE.EPropertyValueUnit[tUpper] !== undefined) {
                        tRes = IGXE.EPropertyValueUnit[tUpper];
                    }
                    else {
                        // custom unit
                        tRes = source.trim();
                        console.warn("IGXELoader: found non-standard unit in", input, source);
                    }
                    break;
                default:
                    console.warn("IGXELoader: invalid value unit in", input, source);
                    break;
            }
            return tRes;
        }
        for (const propkey in input) {
            if (input.hasOwnProperty(propkey)) {
                const tProp = input[propkey];
                if (tProp.hasOwnProperty("ValueType") &&
                    ((typeof tProp["ValueType"] === "string" &&
                        tProp["ValueType"].length > 0) ||
                        (typeof tProp["ValueType"] === "number" &&
                            tProp["ValueType"] >= 0))) {
                    const tValues = tProp.hasOwnProperty("Values") &&
                        typeof tProp["Values"] === "object" &&
                        tProp["Values"].length > 0
                        ? tProp["Values"]
                        : [];
                    const tValueType = typeof tProp["ValueType"] === "number"
                        ? tProp["ValueType"]
                        : IGXE.EPropertyType[tProp["ValueType"]];
                    if (tValueType !== undefined) {
                        tProps[propkey] = {
                            Key: propkey,
                            Type: "choiceList",
                            Text: tProp["Text"],
                            ValueType: tValueType,
                            ValueUnit: tParseUnit(tProp["ValueUnit"]),
                            Values: IGXELoader.parsePropValues(tValues, tValueType),
                            Precondition: tProp["Precondition"]
                                ? tProp["Precondition"].toString()
                                : tProp["Precondition"],
                            AdditionalValues: tProp["AdditionalValues"],
                            ValueRangeFrom: tProp["ValueRangeFrom"],
                            ValueRangeTo: tProp["ValueRangeTo"],
                            Position: tProp["Position"],
                            Virtual: tProp["Virtual"],
                            InVarCode: tProp["InVarCode"],
                            MaterialCategory: tProp["MaterialCategory"],
                            Default: tProp["Default"],
                            Geometric: tProp["Geometric"],
                            SubProperties: [],
                        };
                    }
                    else {
                        console.warn('IGXELoader: skipping property "' +
                            propkey +
                            '", unrecognized ValueType "' +
                            tProp["ValueType"] +
                            '"');
                    }
                }
                else {
                    console.warn('IGXELoader: skipping property "' +
                        propkey +
                        '", invalid format', tProp);
                }
            }
        }
        return tProps;
    }
    static parsePropValues(input, valType) {
        const tR = new Array();
        let tReqType = "none";
        switch (valType) {
            case IGXE.EPropertyType.Bool:
                tReqType = typeof true;
                break;
            case IGXE.EPropertyType.Float:
            case IGXE.EPropertyType.Int:
                tReqType = typeof 1;
                break;
            case IGXE.EPropertyType.String:
            case IGXE.EPropertyType.Material:
                tReqType = typeof "";
                break;
        }
        input.forEach(inp => {
            if (inp.hasOwnProperty("Value") &&
                typeof inp["Value"] === tReqType) {
                tR.push({
                    Value: inp["Value"],
                    Text: inp["Text"],
                    Precondition: inp["Precondition"]
                        ? inp["Precondition"].toString()
                        : inp["Precondition"],
                    Image: inp["Image"],
                });
            }
        });
        return tR;
    }
    static parseCondition(input) {
        let tC;
        if (input.hasOwnProperty("Op1") &&
            input.hasOwnProperty("Op2") &&
            input.hasOwnProperty("Comp")) {
            const tOp1Type = typeof input["Op1"];
            const tOp2Type = typeof input["Op2"];
            const tCompType = typeof input["Comp"];
            if (["object", "string", "number", "boolean"].indexOf(tOp1Type) >
                -1 &&
                ["object", "string", "number", "boolean"].indexOf(tOp2Type) >
                    -1 &&
                ["string", "number"].indexOf(tCompType) > -1) {
                let tSOp1;
                let tSOp2;
                let tSComp;
                switch (typeof input["Comp"]) {
                    case "number":
                        tSComp = input["Comp"];
                        break;
                    case "string":
                        tSComp =
                            IGXE.EConditionCompare[input["Comp"]] ||
                                IGXE.EConditionJoin[input["Comp"]];
                        break;
                    default:
                        tSComp = undefined;
                }
                switch (typeof input["Op1"]) {
                    case "number":
                    case "string":
                    case "boolean":
                        tSOp1 = input["Op1"];
                        break;
                    case "object":
                        tSOp1 = IGXELoader.parseCondition(input["Op1"]);
                        break;
                    default:
                        tSOp1 = undefined;
                }
                switch (typeof input["Op2"]) {
                    case "number":
                    case "string":
                    case "boolean":
                        tSOp2 = input["Op2"];
                        break;
                    case "object":
                        if (tSComp === IGXE.EConditionCompare.In &&
                            input["Op2"].length) {
                            tSOp2 = input["Op2"];
                        }
                        else {
                            tSOp2 = IGXELoader.parseCondition(input["Op2"]);
                        }
                        break;
                    default:
                        tSOp2 = undefined;
                }
                if (tSComp !== undefined && tSOp1 !== undefined) {
                    tC = {
                        Op1: tSOp1,
                        Op2: tSOp2,
                        Comp: tSComp,
                        Not: input["Not"],
                    };
                }
            }
        }
        return tC;
    }
    static EPDFReader(srcData, lang) {
        const tPD = {
            Format_Version: 1,
            Content_Version: new Date().toUTCString(),
            Price_Type: IGXE.EPriceType.Purchase,
            VAT: undefined,
            Articles: {},
            PropertyClasses: {},
            Conditions: {},
        };
        //console.log(srcData);
        const tArticleDat = new Array();
        const tPriceDat = new Array();
        const tPropClassDat = new Array();
        const tPropertyDat = new Array();
        const tPropValueDat = new Array();
        const tRelObjectDat = new Array();
        const tRelationDat = new Array();
        const tArtLongTxt = new Array();
        const tArtShortTxt = new Array();
        const tPropertyTxt = new Array();
        const tPropValueTxt = new Array();
        const tPriceTxt = new Array();
        if (srcData["article_dat"]) {
            srcData["article_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 50) {
                    const tNewArticle = {};
                    tNewArticle["article_nr"] = line.substr(0, 18).trim();
                    tNewArticle["art_type"] = line.substr(18, 1).trim();
                    tNewArticle["manufacturer"] = line.substr(19, 2).trim();
                    tNewArticle["series"] = line.substr(21, 4).trim();
                    tNewArticle["art_textnr"] = line.substr(25, 18).trim();
                    tNewArticle["rel_obj"] = parseInt(line.substr(43, 8).trim());
                    tNewArticle["version"] = line.substr(51, 10).trim();
                    tNewArticle["date_from"] = line.substr(61, 8).trim();
                    tNewArticle["date_to"] = line.substr(69, 8).trim();
                    tNewArticle["source"] = line.substr(77, 1).trim();
                    tNewArticle["account_group"] = line.substr(78, 2).trim();
                    tNewArticle["control_code"] = line.substr(80, 1).trim();
                    tNewArticle["product_hier"] = line.substr(81, 18).trim();
                    tArticleDat.push(tNewArticle);
                }
            });
            //console.log(tArticleDat);
        }
        if (srcData["price_dat"]) {
            srcData["price_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 90) {
                    const tNewPrice = {};
                    tNewPrice["article_nr"] = line.substr(0, 18).trim();
                    tNewPrice["rel_name"] = line.substr(18, 30).trim();
                    tNewPrice["price_type"] = line.substr(48, 2).trim();
                    tNewPrice["price_level"] = line.substr(50, 1).trim();
                    tNewPrice["price_rule"] = line.substr(51, 1).trim();
                    tNewPrice["price_textnr"] = line.substr(52, 18).trim();
                    tNewPrice["price"] =
                        parseInt(line.substr(70, 15).trim()) / 100.0;
                    tNewPrice["currency"] = line.substr(85, 5).trim();
                    tNewPrice["date_from"] = line.substr(90, 8).trim();
                    tNewPrice["date_to"] = line.substr(98, 8).trim();
                    tPriceDat.push(tNewPrice);
                }
            });
            //console.log(tPriceDat);
        }
        if (srcData["propclass_dat"]) {
            srcData["propclass_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 39) {
                    const tNewPC = {};
                    tNewPC["article_nr"] = line.substr(0, 18).trim();
                    tNewPC["pos_class"] = parseInt(line.substr(18, 3).trim());
                    tNewPC["prop_class"] = line.substr(21, 18).trim();
                    tNewPC["rel_obj"] = parseInt(line.substr(39, 8).trim());
                    tPropClassDat.push(tNewPC);
                }
            });
            //console.log(tPropClassDat);
        }
        if (srcData["property_dat"]) {
            srcData["property_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 78) {
                    for (let tI = 1; tI < 89 - 78; tI++)
                        line += " ";
                    const tNewProp = {};
                    tNewProp["prop_class"] = line.substr(0, 18).trim();
                    tNewProp["pos_prop"] = parseInt(line.substr(18, 3).trim());
                    tNewProp["property"] = line.substr(21, 30).trim();
                    tNewProp["prop_textnr"] = line.substr(51, 18).trim();
                    tNewProp["rel_obj"] = parseInt(line.substr(69, 8).trim());
                    tNewProp["prop_type"] = line.substr(77, 1).trim();
                    tNewProp["digits"] = parseInt(line.substr(78, 3).trim());
                    tNewProp["dec_digits"] = parseInt(line.substr(81, 1).trim());
                    tNewProp["unit"] = line.substr(82, 3).trim();
                    tNewProp["need_input"] = line.substr(85, 1).trim();
                    tNewProp["restrict"] = line.substr(86, 1).trim();
                    tNewProp["add_values"] = line.substr(87, 1).trim();
                    tNewProp["low_case"] = line.substr(88, 1).trim();
                    tNewProp["scope"] = line.substr(89, 1).trim();
                    tPropertyDat.push(tNewProp);
                }
            });
        }
        if (srcData["propvalue_dat"]) {
            srcData["propvalue_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 85) {
                    for (let tI = 1; tI < 146 - 85; tI++)
                        line += " ";
                    const tNewPropVal = {};
                    tNewPropVal["prop_class"] = line.substr(0, 18).trim();
                    tNewPropVal["pos_prop"] = parseInt(line.substr(18, 3).trim());
                    tNewPropVal["pos_pval"] = parseInt(line.substr(21, 4).trim());
                    tNewPropVal["property"] = line.substr(25, 30).trim();
                    tNewPropVal["pval_textnr"] = line.substr(55, 18).trim();
                    tNewPropVal["rel_obj"] = parseInt(line.substr(73, 8).trim());
                    tNewPropVal["is_default"] = line.substr(81, 1).trim();
                    tNewPropVal["op_from"] = line.substr(82, 2).trim();
                    tNewPropVal["value_from"] = line.substr(84, 30).trim();
                    tNewPropVal["op_to"] = line.substr(114, 2).trim();
                    tNewPropVal["value_to"] = line.substr(116, 30).trim();
                    tPropValueDat.push(tNewPropVal);
                }
            });
        }
        if (srcData["relobject_dat"]) {
            srcData["relobject_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 42) {
                    const tNewRelObj = {};
                    tNewRelObj["rel_obj"] = parseInt(line.substr(0, 8).trim());
                    tNewRelObj["rel_name"] = line.substr(8, 30).trim();
                    tNewRelObj["rel_type"] = line.substr(38, 4).trim();
                    tNewRelObj["rel_domain"] = line.substr(42, 1).trim();
                    tRelObjectDat.push(tNewRelObj);
                }
            });
        }
        if (srcData["relation_dat"]) {
            srcData["relation_dat"].split(/\n/).forEach((line) => {
                if (line.length >= 35) {
                    const tNewRelation = {};
                    tNewRelation["rel_name"] = line.substr(0, 30).trim();
                    tNewRelation["rel_blocknr"] = parseInt(line.substr(30, 4).trim());
                    tNewRelation["rel_block"] = line.substr(34).trim();
                    tRelationDat.push(tNewRelation);
                }
            });
        }
        if (srcData["artlong_txt"]) {
            srcData["artlong_txt"].split(/\n/).forEach((line) => {
                if (line.length >= 22) {
                    const tNewText = {};
                    tNewText["textnr"] = line.substr(0, 18).trim();
                    tNewText["language"] = line.substr(18, 2).trim();
                    tNewText["line_nr"] = line.substr(20, 2).trim();
                    tNewText["text"] = line.substr(22, 80).trim();
                    tArtLongTxt.push(tNewText);
                }
            });
        }
        if (srcData["artshort_txt"]) {
            srcData["artshort_txt"].split(/\n/).forEach((line) => {
                if (line.length >= 22) {
                    const tNewText = {};
                    tNewText["textnr"] = line.substr(0, 18).trim();
                    tNewText["language"] = line.substr(18, 2).trim();
                    tNewText["line_nr"] = line.substr(20, 2).trim();
                    tNewText["text"] = line.substr(22, 80).trim();
                    tArtShortTxt.push(tNewText);
                }
            });
        }
        if (srcData["property_txt"]) {
            srcData["property_txt"].split(/\n/).forEach((line) => {
                if (line.length >= 22) {
                    const tNewText = {};
                    tNewText["textnr"] = line.substr(0, 18).trim();
                    tNewText["language"] = line.substr(18, 2).trim();
                    tNewText["line_nr"] = line.substr(20, 2).trim();
                    tNewText["text"] = line.substr(22, 80).trim();
                    tPropertyTxt.push(tNewText);
                }
            });
        }
        if (srcData["propvalue_txt"]) {
            srcData["propvalue_txt"].split(/\n/).forEach((line) => {
                if (line.length >= 22) {
                    const tNewText = {};
                    tNewText["textnr"] = line.substr(0, 18).trim();
                    tNewText["language"] = line.substr(18, 2).trim();
                    tNewText["line_nr"] = line.substr(20, 2).trim();
                    tNewText["text"] = line.substr(22, 80).trim();
                    tPropValueTxt.push(tNewText);
                }
            });
        }
        if (srcData["price_txt"]) {
            srcData["price_txt"].split(/\n/).forEach((line) => {
                if (line.length >= 22) {
                    const tNewText = {};
                    tNewText["textnr"] = line.substr(0, 18).trim();
                    tNewText["language"] = line.substr(18, 2).trim();
                    tNewText["line_nr"] = line.substr(20, 2).trim();
                    tNewText["text"] = line.substr(22, 80).trim();
                    tPriceTxt.push(tNewText);
                }
            });
        }
        function getText(src, textnr, lang) {
            const tA = new Array();
            if (src) {
                const tLines = new Array();
                src.forEach(srcline => {
                    if (srcline.textnr === textnr &&
                        srcline.language === lang) {
                        tLines.push({
                            line_nr: srcline.textnr,
                            text: srcline.text,
                        });
                    }
                });
                tLines.sort(function (a, b) {
                    return a.line_nr > b.line_nr ? 1 : -1;
                });
                tLines.forEach(line => {
                    tA.push(line.text);
                });
            }
            return tA;
        }
        function getPrices(artnr, art_rel_obj) {
            const tA = new Array();
            tPriceDat.forEach(price => {
                if (price["article_nr"] === artnr) {
                    let tLvl = IGXE.EPriceLevel.Base;
                    if (price["price_level"] === "Z" ||
                        price["price_level"] === "D") {
                        if (price["price_rule"] === "1") {
                            tLvl = IGXE.EPriceLevel.AddToBase;
                        }
                        else {
                            tLvl = IGXE.EPriceLevel.AddToSum;
                        }
                    }
                    let tPrecond = undefined;
                    if (price["rel_name"].length) {
                        const tCondName = art_rel_obj + "_" + price["rel_name"];
                        if (tPD.Conditions[tCondName]) {
                            tPrecond = tCondName;
                        }
                    }
                    const tP = {
                        Currency: price["currency"],
                        Value: price["price"],
                        Level: tLvl,
                        Text: getText(tPriceTxt, price["price_textnr"], lang),
                        Precondition: tPrecond,
                    };
                    tA.push(tP);
                }
            });
            return tA;
        }
        function getPropClasses(artnr) {
            const tPCs = new Array();
            tPropClassDat.forEach(pc => {
                if (tPD.PropertyClasses[pc["prop_class"]] &&
                    pc["article_nr"] === artnr) {
                    tPCs.push({
                        propclass: pc["prop_class"],
                        pos: pc["pos_class"],
                    });
                    if (pc["rel_obj"] && tPD.Conditions[pc["rel_obj"]]) {
                        tPD.PropertyClasses[pc["prop_class"]].Precondition =
                            pc["rel_obj"];
                    }
                }
            });
            tPCs.sort((a, b) => {
                return a.pos > b.pos ? 1 : -1;
            });
            const tR = new Array();
            tPCs.forEach(pc => {
                tR.push(pc.propclass);
            });
            return tR;
        }
        function getRelationData(rel_name) {
            const tA = new Array();
            tRelationDat.forEach(rel => {
                if (rel["rel_name"] === rel_name) {
                    tA.push({
                        nr: rel["rel_blocknr"],
                        block: rel["rel_block"],
                    });
                }
            });
            tA.sort(function (a, b) {
                return a.nr > b.nr ? 1 : -1;
            });
            let tR = "";
            tA.forEach(bl => {
                tR += bl["block"] + " ";
            });
            return tR.trim();
        }
        function decodeCondition(str) {
            // Fallback, manuelle Korrektur notwendig
            str = str.replace(/\$self./g, "");
            let tCond = {
                Comp: IGXE.EConditionCompare.Equal,
                Op1: "### FIX ME ###",
                Op2: str,
            };
            const tRE = /^(.+) *(AND|OR) *(.+)$/;
            if (tRE.test(str)) {
                if (RegExp.$2.toString() === "AND") {
                    tCond.Comp = IGXE.EConditionJoin.AND;
                }
                else {
                    tCond.Comp = IGXE.EConditionJoin.OR;
                }
                const tOp1s = RegExp.$1.toString();
                const tOp2s = RegExp.$3.toString();
                tCond.Op1 = decodeCondition(tOp1s);
                tCond.Op2 = decodeCondition(tOp2s);
            }
            else {
                const tRE = /^(\w+) *= *(.*)$/;
                if (tRE.test(str)) {
                    // PreConds A = B:
                    tRE.exec(str);
                    const tOp1 = RegExp.$1.toString();
                    let tOp2 = RegExp.$2.trim();
                    if (tOp2.indexOf("'") === 0) {
                        tOp2 = tOp2.replace(/'/g, "");
                    }
                    else {
                        tOp2 = parseFloat(tOp2);
                    }
                    tCond = {
                        Comp: IGXE.EConditionCompare.Equal,
                        Op1: tOp1,
                        Op2: tOp2,
                    };
                }
                else {
                    const tRE = /^(\w+) +in +\((.*)\)$/;
                    if (tRE.test(str)) {
                        // PreConds A in B:
                        tRE.exec(str);
                        const tOp1 = RegExp.$1.toString();
                        const tOp2b = new Array();
                        const tOp2Raw = RegExp.$2.trim().split(",");
                        tOp2Raw.forEach((pv) => {
                            pv = pv.trim();
                            if (pv.indexOf("'") === 0) {
                                tOp2b.push(pv.replace(/'/g, ""));
                            }
                            else {
                                tOp2b.push(parseFloat(pv));
                            }
                        });
                        tCond = {
                            Comp: IGXE.EConditionCompare.In,
                            Op1: tOp1,
                            Op2: tOp2b,
                        };
                    }
                    else {
                        const tRE = /^(\w+) +SPECIFIED *$/;
                        if (tRE.test(str)) {
                            tRE.exec(str);
                            tCond = {
                                Comp: IGXE.EConditionCompare.Equal,
                                Not: true,
                                Op1: RegExp.$1.toString(),
                                Op2: null,
                            };
                        }
                    }
                }
            }
            return tCond;
        }
        tRelObjectDat.forEach(ro => {
            const tObjName = ro["rel_obj"].toString();
            const tName = ro["rel_name"];
            const tRAWDATA = getRelationData(tName);
            if (ro["rel_type"] === "2") {
                // Vorbedingung für Werte usw.
                tPD.Conditions[tObjName] = decodeCondition(tRAWDATA);
            }
            else {
                if (ro["rel_type"] === "3") {
                    // Preisbedingung
                    const tRE = /\$self.variant_condition *= *'(\w*)' +if +\((.*)\)/;
                    if (tRE.test(tRAWDATA)) {
                        tRE.exec(tRAWDATA);
                        tPD.Conditions[tObjName + "_" + RegExp.$1] = decodeCondition(RegExp.$2.trim());
                    }
                }
            }
        });
        tPropertyDat.forEach(pr => {
            let tPropClass;
            if (tPD.PropertyClasses.hasOwnProperty(pr["prop_class"])) {
                tPropClass = tPD.PropertyClasses[pr["prop_class"]];
            }
            else {
                tPropClass = {
                    Properties: {},
                    Precondition: undefined,
                };
            }
            let tPropType = IGXE.EPropertyType.String;
            let tPropUnit;
            switch (pr["prop_type"]) {
                case "C":
                    tPropType = IGXE.EPropertyType.String;
                    break;
                case "N":
                    tPropType = IGXE.EPropertyType.Int;
                    if (pr["dec_digits"] > 0) {
                        tPropType = IGXE.EPropertyType.Float;
                    }
                    break;
                case "L":
                    tPropType = IGXE.EPropertyType.Float;
                    tPropUnit = IGXE.EPropertyValueUnit.LENGTH_M;
                    break;
            }
            const tNewProperty = {
                Key: undefined,
                Type: undefined,
                AdditionalValues: pr["add_values"].length > 0,
                Geometric: true,
                InVarCode: true,
                MaterialCategory: undefined,
                Position: pr["pos_prop"],
                Precondition: pr["rel_obj"] && tPD.Conditions[pr["rel_obj"]]
                    ? pr["rel_obj"]
                    : undefined,
                Text: getText(tPropertyTxt, pr["prop_textnr"], lang),
                Virtual: false,
                Values: new Array(),
                ValueRangeFrom: undefined,
                ValueRangeTo: undefined,
                ValueType: tPropType,
                ValueUnit: tPropUnit,
                SubProperties: [],
            };
            tPropValueDat.forEach(pv => {
                if (pv["prop_class"] === pr["prop_class"] &&
                    pv["property"] === pr["property"]) {
                    let tVal;
                    if (pv["op_from"] === "EQ") {
                        if (tPropType === IGXE.EPropertyType.String) {
                            tVal = pv["value_from"];
                        }
                        else {
                            tVal = parseFloat(pv["value_from"]);
                        }
                    }
                    const tNewPVal = {
                        Precondition: pv["rel_obj"] && tPD.Conditions[pv["rel_obj"]]
                            ? pv["rel_obj"]
                            : undefined,
                        Text: getText(tPropValueTxt, pv["pval_textnr"], lang),
                        Value: tVal,
                        _pos: pv["pos_pval"],
                    };
                    if (pv["is_default"].length > 0) {
                        tNewProperty.Default = tVal;
                    }
                    tNewProperty.Values.push(tNewPVal);
                }
            });
            tNewProperty.Values.sort((a, b) => {
                return a["_pos"] > b["_pos"] ? 1 : -1;
            });
            tNewProperty.Values.forEach(pv => {
                delete pv["_pos"];
            });
            tPropClass.Properties[pr["property"]] = tNewProperty;
            tPD.PropertyClasses[pr["prop_class"]] = tPropClass;
        });
        tArticleDat.forEach(art => {
            const tArt = {
                Manufacturer: art["manufacturer"],
                Series: art["series"],
                ShortText: getText(tArtShortTxt, art["art_textnr"], lang),
                LongText: getText(tArtLongTxt, art["art_textnr"], lang),
                Prices: getPrices(art["article_nr"], art["rel_obj"]),
                PropertyClasses: getPropClasses(art["article_nr"]),
                EAN: undefined,
            };
            tPD.Articles[art["article_nr"]] = tArt;
        });
        return tPD;
    }
}
