export var EPriceType;
(function (EPriceType) {
    /** There are no prices included or if, they should be ignored */
    EPriceType[EPriceType["None"] = 0] = "None";
    /** The included prices are purchase ("EK") prices */
    EPriceType[EPriceType["Purchase"] = 1] = "Purchase";
    /** The included prices are sales ("VK") prices */
    EPriceType[EPriceType["Sales"] = 2] = "Sales";
})(EPriceType || (EPriceType = {}));
/**
 * All possible types of price entries per article
 */
export var EPriceLevel;
(function (EPriceLevel) {
    /** Base price */
    EPriceLevel[EPriceLevel["Base"] = 0] = "Base";
    /** Addition price, if currency is %, calculate absolute value on base
     *  price
     */
    EPriceLevel[EPriceLevel["AddToBase"] = 1] = "AddToBase";
    /** Addition price, if currency is %, calculate absolute value on the
     *  sum of base price and all additional prices
     */
    EPriceLevel[EPriceLevel["AddToSum"] = 2] = "AddToSum";
})(EPriceLevel || (EPriceLevel = {}));
/**
 * All possible types of properties
 */
export var EPropertyType;
(function (EPropertyType) {
    EPropertyType[EPropertyType["Bool"] = 0] = "Bool";
    EPropertyType[EPropertyType["Float"] = 1] = "Float";
    EPropertyType[EPropertyType["Int"] = 2] = "Int";
    EPropertyType[EPropertyType["String"] = 3] = "String";
    EPropertyType[EPropertyType["Material"] = 4] = "Material";
})(EPropertyType || (EPropertyType = {}));
/**
 * How condition operators can be compared
 */
export var EConditionCompare;
(function (EConditionCompare) {
    /** op1 == op2 */
    EConditionCompare[EConditionCompare["Equal"] = 10] = "Equal";
    /** op1 > op2 */
    EConditionCompare[EConditionCompare["Greater"] = 11] = "Greater";
    /** op1 >= op2 */
    EConditionCompare[EConditionCompare["GreaterOrEqual"] = 12] = "GreaterOrEqual";
    /** op1 < op2 */
    EConditionCompare[EConditionCompare["Smaller"] = 13] = "Smaller";
    /** op1 <= op2 */
    EConditionCompare[EConditionCompare["SmallerOrEqual"] = 14] = "SmallerOrEqual";
    /** op1 IN [a, b, c] */
    EConditionCompare[EConditionCompare["In"] = 15] = "In";
})(EConditionCompare || (EConditionCompare = {}));
/**
 * How conditions can be chained. op1 and op2 have to be of type ICondition
 */
export var EConditionJoin;
(function (EConditionJoin) {
    EConditionJoin[EConditionJoin["AND"] = 1] = "AND";
    EConditionJoin[EConditionJoin["OR"] = 2] = "OR";
    EConditionJoin[EConditionJoin["PLUS"] = 3] = "PLUS";
    EConditionJoin[EConditionJoin["MINUS"] = 4] = "MINUS";
    EConditionJoin[EConditionJoin["MUL"] = 5] = "MUL";
    EConditionJoin[EConditionJoin["DIV"] = 6] = "DIV";
})(EConditionJoin || (EConditionJoin = {}));
export var EPropertyValueUnitGroup;
(function (EPropertyValueUnitGroup) {
    EPropertyValueUnitGroup["LENGTH"] = "LENGTH";
    EPropertyValueUnitGroup["AREA"] = "AREA";
    EPropertyValueUnitGroup["VOL"] = "VOL";
    EPropertyValueUnitGroup["MASS"] = "MASS";
    EPropertyValueUnitGroup["ANGLE"] = "ANGLE";
})(EPropertyValueUnitGroup || (EPropertyValueUnitGroup = {}));
export var EPropertyValueUnit;
(function (EPropertyValueUnit) {
    /** Meter */
    EPropertyValueUnit[EPropertyValueUnit["LENGTH_M"] = 100] = "LENGTH_M";
    /** Centimeter */
    EPropertyValueUnit[EPropertyValueUnit["LENGTH_CM"] = 101] = "LENGTH_CM";
    /** Millimeter */
    EPropertyValueUnit[EPropertyValueUnit["LENGTH_MM"] = 102] = "LENGTH_MM";
    /** Feet */
    EPropertyValueUnit[EPropertyValueUnit["LENGTH_FT"] = 103] = "LENGTH_FT";
    /** Inches */
    EPropertyValueUnit[EPropertyValueUnit["LENGTH_IN"] = 104] = "LENGTH_IN";
    /** Square Meter */
    EPropertyValueUnit[EPropertyValueUnit["AREA_M2"] = 200] = "AREA_M2";
    /** Square Centimeter */
    EPropertyValueUnit[EPropertyValueUnit["AREA_CM2"] = 201] = "AREA_CM2";
    /** Square Millimeter */
    EPropertyValueUnit[EPropertyValueUnit["AREA_MM2"] = 202] = "AREA_MM2";
    /** Square Feet */
    EPropertyValueUnit[EPropertyValueUnit["AREA_FT2"] = 203] = "AREA_FT2";
    /** Square Inches */
    EPropertyValueUnit[EPropertyValueUnit["AREA_IN2"] = 204] = "AREA_IN2";
    /** Cubic Meter */
    EPropertyValueUnit[EPropertyValueUnit["VOL_M3"] = 300] = "VOL_M3";
    /** Cubic Centimeter */
    EPropertyValueUnit[EPropertyValueUnit["VOL_CM3"] = 301] = "VOL_CM3";
    /** Cubic Millimeter */
    EPropertyValueUnit[EPropertyValueUnit["VOL_MM3"] = 302] = "VOL_MM3";
    /** Cubic Foot */
    EPropertyValueUnit[EPropertyValueUnit["VOL_FT3"] = 303] = "VOL_FT3";
    /** Cubic Inches */
    EPropertyValueUnit[EPropertyValueUnit["VOL_IN3"] = 304] = "VOL_IN3";
    /** Liter */
    EPropertyValueUnit[EPropertyValueUnit["VOL_L"] = 305] = "VOL_L";
    /** US Gallon */
    EPropertyValueUnit[EPropertyValueUnit["VOL_GAL"] = 306] = "VOL_GAL";
    /** Metric Kilogram */
    EPropertyValueUnit[EPropertyValueUnit["MASS_KG"] = 400] = "MASS_KG";
    /** Metric gram */
    EPropertyValueUnit[EPropertyValueUnit["MASS_G"] = 401] = "MASS_G";
    /** Metric Milligram */
    EPropertyValueUnit[EPropertyValueUnit["MASS_MG"] = 402] = "MASS_MG";
    /** Metric Ton */
    EPropertyValueUnit[EPropertyValueUnit["MASS_T"] = 403] = "MASS_T";
    /** US Pounds */
    EPropertyValueUnit[EPropertyValueUnit["MASS_LBS"] = 404] = "MASS_LBS";
    /** US Ounces */
    EPropertyValueUnit[EPropertyValueUnit["MASS_OZ"] = 405] = "MASS_OZ";
    /** Angle (Degree) */
    EPropertyValueUnit[EPropertyValueUnit["ANGLE_DEG"] = 500] = "ANGLE_DEG";
})(EPropertyValueUnit || (EPropertyValueUnit = {}));
const DEFAULT_GROUP_DESCRIPTION = {
    Key: "default",
};
/**
 * Creates a list of groups using the group definition of the properties.
 *
 * All properties without a definition will be added to a default group. This default group
 * can be identified using the value of its IsDefault property.
 *
 * @param {IProperty[]} properties
 * @returns
 */
export const createPropertyGroups = (properties) => {
    const groups = new Map();
    for (const property of properties) {
        const description = property.Group !== undefined
            ? property.Group
            : DEFAULT_GROUP_DESCRIPTION;
        let group = groups.get(description.Key);
        if (group === undefined) {
            group = {
                ...description,
                IsDefault: description === DEFAULT_GROUP_DESCRIPTION,
                Properties: [],
            };
            groups.set(description.Key, group);
        }
        group.Properties.push(property);
    }
    return Array.from(groups.values());
};
const DEFAULT_SECTION_DESCRIPTION = {
    Key: "default",
};
/**
 * Creates a list of sections using the section definition of the properties values.
 *
 * All values without a definition will be added to a default section. This default section
 * can be identified using the value of its IsDefault property.
 *
 * @param {IProperty} property
 */
export const createPropertyValueSections = (property) => {
    const sections = new Map();
    for (const value of property.Values) {
        const description = value.Section !== undefined
            ? value.Section
            : DEFAULT_SECTION_DESCRIPTION;
        let section = sections.get(description.Key);
        if (section === undefined) {
            section = {
                ...description,
                IsDefault: description === DEFAULT_SECTION_DESCRIPTION,
                Values: [],
            };
            sections.set(description.Key, section);
        }
        section.Values.push(value);
    }
    return Array.from(sections.values());
};
export const normalizePropertyValueChanges = (rawChanges) => {
    if (Array.isArray(rawChanges)) {
        return rawChanges;
    }
    const changes = [];
    for (const key in rawChanges) {
        changes.push({
            key,
            value: rawChanges[key],
        });
    }
    return changes;
};
/**
 * Merges two property value changes
 *
 * @param {PropertyValueChanges} a
 * @param {PropertyValueChanges} b
 * @returns {PropertyValueChanges[]}
 */
export const mergePropertyValueChanges = (a, b) => {
    const aNormalized = normalizePropertyValueChanges(a);
    const bNormalized = normalizePropertyValueChanges(b);
    const result = new Map();
    for (const { key, value } of aNormalized) {
        result.set(key, value);
    }
    for (const { key, value } of bNormalized) {
        result.set(key, value);
    }
    return Array.from(result, ([key, value]) => ({ key, value }));
};
/**
 * Creates a flat configuration object from a list of changes
 *
 * @param {PropertyValueChanges} changes
 * @returns
 */
export const createArticleConfigurationValuesFromChanges = (changes) => {
    const normalizedChanges = normalizePropertyValueChanges(changes);
    const configuration = {};
    for (const { key, value } of normalizedChanges) {
        configuration[key] = value;
    }
    return configuration;
};
const PROPERTY_PATH_PART_SEPERATOR = "@@";
export const createPropertyKey = (path) => path.join(PROPERTY_PATH_PART_SEPERATOR);
export const getPropertyNamesFromKey = (propertyKey) => {
    const segments = propertyKey.split(PROPERTY_PATH_PART_SEPERATOR);
    const result = [];
    for (let index = 0; index < segments.length; index++) {
        result.push(segments.slice(0, index + 1).join(PROPERTY_PATH_PART_SEPERATOR));
    }
    return result;
};
/**
 * Retrieves the actual active value of a property. This can either be a value of the input property, or the value of a subproperty
 *
 * @param {IProperty} property
 * @returns {(IPropertyValue | undefined)}
 */
export const getFinalPropertyValue = (property) => {
    if (property.Value === undefined) {
        return undefined;
    }
    const definition = findValueDefinition(property, property.Value);
    if (definition === undefined || !isProperty(definition)) {
        return definition;
    }
    return getFinalPropertyValue(definition);
};
/**
 * Retrieves a property from the property tree
 *
 * @template T
 * @param {T[]} properties
 * @param {(string | string[])} propertyPathOrKey
 * @returns
 */
export const findProperty = (properties, propertyPathOrKey) => {
    const propertyNames = typeof propertyPathOrKey === "string"
        ? getPropertyNamesFromKey(propertyPathOrKey)
        : propertyPathOrKey;
    let property = properties.find(property => property.Key === propertyNames[0]);
    for (let index = 1; index < propertyNames.length; index++) {
        if (property === undefined) {
            break;
        }
        property = property.SubProperties.find(property => property.Key === propertyNames[index]);
    }
    return property;
};
/**
 * Finds the definition for a value inside the properties direct subproperties and values.
 *
 * @param {IProperty} property
 * @param {TPropertyValue} targetValue
 * @returns
 */
export const findValueDefinition = (property, targetValue) => {
    const normalizedValue = targetValue.toString();
    for (const value of property.Values) {
        if (value.Value.toString() === normalizedValue) {
            return value;
        }
    }
    for (const subProperty of property.SubProperties) {
        if (subProperty.Key === normalizedValue) {
            return subProperty;
        }
    }
};
export const isProperty = (item) => "Key" in item;
/**
 * Retrieves all currently active subproperties for a property
 *
 * @param {IProperty} property
 * @returns
 */
export const findActiveSubProperties = (property) => {
    const properties = [];
    let parentProperty = property;
    while (parentProperty.SubProperties.length > 0 &&
        parentProperty.Value !== undefined) {
        const activeDefinition = findValueDefinition(parentProperty, parentProperty.Value);
        if (activeDefinition === undefined || !isProperty(activeDefinition)) {
            break;
        }
        properties.push(activeDefinition);
        parentProperty = activeDefinition;
    }
    return properties;
};
/**
 * Creates a flat list of properties where all active subproperties are listed after their base property
 *
 * @param {IProperty[]} properties
 * @returns
 */
export const createActiveSubPropertyInjectedPropertyList = (properties) => {
    const result = [];
    for (const property of properties) {
        result.push(property, ...findActiveSubProperties(property));
    }
    return result;
};
/**
 * Creates a fake value representation from a property
 *
 * @param {IProperty} property
 * @returns {IPropertyValue}
 */
export const createFakeValueFromProperty = (property) => ({
    Value: property.Key,
    Text: property.Text,
    Image: property.Image,
    Enabled: property.Enabled,
    Visible: property.Visible,
});
