import { __values } from "tslib";
import { Obj, isNullOrUndefined } from "@intelligentgraphics/ig.utilities";
import { EPropertyValueUnit, EPropertyValueUnitGroup, EPropertyType, } from "./Types";
export var getDefaultUnitString = function (unit) {
    if (typeof unit === "string") {
        return unit;
    }
    var tR = "";
    switch (unit) {
        case EPropertyValueUnit.LENGTH_M:
            tR = "m";
            break;
        case EPropertyValueUnit.LENGTH_CM:
            tR = "cm";
            break;
        case EPropertyValueUnit.LENGTH_MM:
            tR = "mm";
            break;
        case EPropertyValueUnit.LENGTH_FT:
            tR = "ft";
            break;
        case EPropertyValueUnit.LENGTH_IN:
            tR = "in";
            break;
        case EPropertyValueUnit.AREA_M2:
            tR = "m²";
            break;
        case EPropertyValueUnit.AREA_CM2:
            tR = "cm²";
            break;
        case EPropertyValueUnit.AREA_MM2:
            tR = "mm²";
            break;
        case EPropertyValueUnit.AREA_FT2:
            tR = "sq ft";
            break;
        case EPropertyValueUnit.AREA_IN2:
            tR = "sq in";
            break;
        case EPropertyValueUnit.VOL_M3:
            tR = "m³";
            break;
        case EPropertyValueUnit.VOL_CM3:
            tR = "cm³";
            break;
        case EPropertyValueUnit.VOL_MM3:
            tR = "mm³";
            break;
        case EPropertyValueUnit.VOL_FT3:
            tR = "cu ft";
            break;
        case EPropertyValueUnit.VOL_IN3:
            tR = "cu in";
            break;
        case EPropertyValueUnit.VOL_L:
            tR = "l";
            break;
        case EPropertyValueUnit.VOL_GAL:
            tR = "gal";
            break;
        case EPropertyValueUnit.MASS_KG:
            tR = "kg";
            break;
        case EPropertyValueUnit.MASS_G:
            tR = "g";
            break;
        case EPropertyValueUnit.MASS_MG:
            tR = "mg";
            break;
        case EPropertyValueUnit.MASS_T:
            tR = "t";
            break;
        case EPropertyValueUnit.MASS_LBS:
            tR = "lb";
            break;
        case EPropertyValueUnit.MASS_OZ:
            tR = "oz";
            break;
        case EPropertyValueUnit.ANGLE_DEG:
            tR = "°";
            break;
        default:
            throw new Error("Can not convert unknown unit \"" + unit + "\"");
    }
    return tR;
};
export var getDefaultUnitPrecision = function (unit) {
    var tR = 1;
    if (unit === undefined || typeof unit === "string") {
        return tR;
    }
    switch (unit) {
        case EPropertyValueUnit.LENGTH_M:
            tR = 0.001;
            break;
        case EPropertyValueUnit.LENGTH_CM:
            tR = 0.1;
            break;
        case EPropertyValueUnit.LENGTH_MM:
            tR = 1;
            break;
        case EPropertyValueUnit.LENGTH_FT:
            tR = 1 / 12; // 1ft = 12in, so 3.1415 => 3ft 2in
            break;
        case EPropertyValueUnit.LENGTH_IN:
            tR = 1 / 16; // round to 1/16in, so 3.1415 => 3 1/8in
            break;
        case EPropertyValueUnit.AREA_M2:
            tR = 0.1;
            break;
        case EPropertyValueUnit.AREA_CM2:
            tR = 1;
            break;
        case EPropertyValueUnit.AREA_MM2:
            tR = 1;
            break;
        case EPropertyValueUnit.AREA_FT2:
            tR = 0.1;
            break;
        case EPropertyValueUnit.AREA_IN2:
            tR = 1;
            break;
        case EPropertyValueUnit.VOL_M3:
            tR = 0.01;
            break;
        case EPropertyValueUnit.VOL_CM3:
            tR = 1;
            break;
        case EPropertyValueUnit.VOL_MM3:
            tR = 1;
            break;
        case EPropertyValueUnit.VOL_FT3:
            tR = 0.01;
            break;
        case EPropertyValueUnit.VOL_IN3:
            tR = 0.1;
            break;
        case EPropertyValueUnit.VOL_L:
            tR = 0.1;
            break;
        case EPropertyValueUnit.VOL_GAL:
            tR = 0.01;
            break;
        case EPropertyValueUnit.MASS_KG:
            tR = 0.01;
            break;
        case EPropertyValueUnit.MASS_G:
            tR = 1;
            break;
        case EPropertyValueUnit.MASS_MG:
            tR = 1;
            break;
        case EPropertyValueUnit.MASS_T:
            tR = 0.001;
            break;
        case EPropertyValueUnit.MASS_LBS:
            tR = 0.01;
            break;
        case EPropertyValueUnit.MASS_OZ:
            tR = 0.1;
            break;
        case EPropertyValueUnit.ANGLE_DEG:
            tR = 1;
            break;
        default:
            throw new Error("Can not convert unknown unit \"" + unit + "\"");
    }
    return tR;
};
export var getDefaultRoundedValue = function (value, unit) {
    if (unit === undefined || typeof unit === "string") {
        return value;
    }
    var round = function (input, precision) {
        var tR = Math.round(input / precision) * precision;
        return Math.round(tR * 10000) / 10000; // to avoid floating point corner cases like .0000000001
    };
    return round(value, getDefaultUnitPrecision(unit));
};
export var getUnitValueAsString = function (value, unit, locale) {
    var tVal = getDefaultRoundedValue(value, unit);
    //special case imperial length units
    if (unit === EPropertyValueUnit.LENGTH_IN) {
        var tFullInches = Math.floor(tVal);
        var tFracInches = Math.round((tVal - tFullInches) * 16);
        // TODO: shorten fraction
        return (tFullInches.toString() +
            " " +
            tFracInches.toString() +
            "/16" +
            +getDefaultUnitString(unit));
    }
    if (unit === EPropertyValueUnit.LENGTH_FT) {
        // TODO: format like "3ft 5 1/8in"
        return tVal.toString() + getDefaultUnitString(unit);
    }
    function log10(v) {
        return Math.log(v) / Math.log(10);
    }
    var tDecimals = log10(Math.round(1 / getDefaultUnitPrecision(unit)));
    return (tVal.toLocaleString(locale, {
        minimumFractionDigits: tDecimals,
    }) + getDefaultUnitString(unit));
};
export var convert = function (value, from, to) {
    function convertLength() {
        var tMeter;
        switch (from) {
            case EPropertyValueUnit.LENGTH_CM:
                tMeter = value / 100.0;
                break;
            case EPropertyValueUnit.LENGTH_MM:
                tMeter = value / 1000.0;
                break;
            case EPropertyValueUnit.LENGTH_FT:
                tMeter = value / (12 * 0.0254);
                break;
            case EPropertyValueUnit.LENGTH_IN:
                tMeter = value / 0.0254;
                break;
            default:
                tMeter = value;
        }
        var tTargetValue = tMeter;
        switch (to) {
            case EPropertyValueUnit.LENGTH_M:
                tTargetValue = tMeter;
                break;
            case EPropertyValueUnit.LENGTH_CM:
                tTargetValue = tMeter * 100.0;
                break;
            case EPropertyValueUnit.LENGTH_MM:
                tTargetValue = tMeter * 1000.0;
                break;
            case EPropertyValueUnit.LENGTH_FT:
                tTargetValue = (tMeter * 100) / 2.54 / 12.0;
                break;
            case EPropertyValueUnit.LENGTH_IN:
                tTargetValue = (tMeter * 100) / 2.54;
                break;
        }
        return getDefaultRoundedValue(tTargetValue, to);
    }
    var convertArea = function () {
        var tSqM;
        switch (from) {
            case EPropertyValueUnit.AREA_CM2:
                tSqM = value / Math.pow(100.0, 2);
                break;
            case EPropertyValueUnit.AREA_MM2:
                tSqM = value / Math.pow(1000.0, 2);
                break;
            case EPropertyValueUnit.AREA_FT2:
                tSqM = value / Math.pow(12 * 0.0254, 2);
                break;
            case EPropertyValueUnit.AREA_IN2:
                tSqM = value / Math.pow(0.0254, 2);
                break;
            default:
                tSqM = value;
        }
        var tTargetValue = tSqM;
        switch (to) {
            case EPropertyValueUnit.AREA_M2:
                tTargetValue = tSqM;
                break;
            case EPropertyValueUnit.AREA_CM2:
                tTargetValue = tSqM * Math.pow(100.0, 2);
                break;
            case EPropertyValueUnit.AREA_MM2:
                tTargetValue = tSqM * Math.pow(1000.0, 2);
                break;
            case EPropertyValueUnit.AREA_FT2:
                tTargetValue = tSqM / Math.pow(12 * 0.0254, 2);
                break;
            case EPropertyValueUnit.AREA_IN2:
                tTargetValue = tSqM / Math.pow(0.0254, 2);
                break;
        }
        return getDefaultRoundedValue(tTargetValue, to);
    };
    if (from === to) {
        return value;
    }
    var tR;
    switch (getGroupOfUnit(from)) {
        case EPropertyValueUnitGroup.LENGTH:
            tR = convertLength();
            break;
        case EPropertyValueUnitGroup.AREA:
            tR = convertArea();
            break;
        case EPropertyValueUnitGroup.VOL:
            // TODO
            break;
        case EPropertyValueUnitGroup.MASS:
            // TODO
            break;
        case EPropertyValueUnitGroup.ANGLE:
            break;
    }
    if (tR === undefined) {
        throw new Error("Invalid conversion");
    }
    return tR;
};
export var getGroupOfUnit = function (unit) {
    var tR;
    switch (unit) {
        // lengths
        case EPropertyValueUnit.LENGTH_M:
        case EPropertyValueUnit.LENGTH_CM:
        case EPropertyValueUnit.LENGTH_MM:
        case EPropertyValueUnit.LENGTH_FT:
        case EPropertyValueUnit.LENGTH_IN:
            tR = EPropertyValueUnitGroup.LENGTH;
            break;
        // areas
        case EPropertyValueUnit.AREA_M2:
        case EPropertyValueUnit.AREA_CM2:
        case EPropertyValueUnit.AREA_MM2:
        case EPropertyValueUnit.AREA_FT2:
        case EPropertyValueUnit.AREA_IN2:
            tR = EPropertyValueUnitGroup.AREA;
            break;
        // volumes
        case EPropertyValueUnit.VOL_M3:
        case EPropertyValueUnit.VOL_CM3:
        case EPropertyValueUnit.VOL_MM3:
        case EPropertyValueUnit.VOL_FT3:
        case EPropertyValueUnit.VOL_IN3:
        case EPropertyValueUnit.VOL_L:
        case EPropertyValueUnit.VOL_GAL:
            tR = EPropertyValueUnitGroup.VOL;
            break;
        // weights
        case EPropertyValueUnit.MASS_KG:
        case EPropertyValueUnit.MASS_G:
        case EPropertyValueUnit.MASS_MG:
        case EPropertyValueUnit.MASS_T:
        case EPropertyValueUnit.MASS_LBS:
        case EPropertyValueUnit.MASS_OZ:
            tR = EPropertyValueUnitGroup.MASS;
            break;
        // angles
        case EPropertyValueUnit.ANGLE_DEG:
            tR = EPropertyValueUnitGroup.ANGLE;
            break;
    }
    return tR;
};
export var convertProperty = function (property, from, to) {
    var e_1, _a, e_2, _b;
    if (isNullOrUndefined(from) ||
        isNullOrUndefined(to) ||
        (property.ValueType !== EPropertyType.Int &&
            property.ValueType !== EPropertyType.Float) ||
        from === to) {
        return;
    }
    var resultProperty = Obj.deepClone(property);
    var keys = ["Value", "ValueRangeFrom", "ValueRangeTo"];
    try {
        for (var keys_1 = __values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
            var key = keys_1_1.value;
            var value = property[key];
            if (typeof value !== "undefined") {
                resultProperty[key] = convert(value, from, to);
            }
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    try {
        for (var _c = __values(resultProperty.Values), _d = _c.next(); !_d.done; _d = _c.next()) {
            var value = _d.value;
            var convertText = value.Text !== undefined &&
                value.Text.length === 1 &&
                value.Value.toString() === value.Text[0];
            value.Value = convert(value.Value, from, to);
            if (convertText) {
                value.Text = [value.Value.toString()];
            }
        }
    }
    catch (e_2_1) { e_2 = { error: e_2_1 }; }
    finally {
        try {
            if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
        }
        finally { if (e_2) throw e_2.error; }
    }
    resultProperty.ValueUnit = to;
    return resultProperty;
};
