"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/* eslint-disable no-prototype-builtins */
var node_1 = tslib_1.__importDefault(require("./node"));
var unit_conversions_1 = tslib_1.__importDefault(require("../data/unit-conversions"));
var unit_1 = tslib_1.__importDefault(require("./unit"));
var color_1 = tslib_1.__importDefault(require("./color"));
//
// A number with a unit
//
var Dimension = function (value, unit) {
    this.value = parseFloat(value);
    if (isNaN(this.value)) {
        throw new Error('Dimension is not a number.');
    }
    this.unit = (unit && unit instanceof unit_1.default) ? unit :
        new unit_1.default(unit ? [unit] : undefined);
    this.setParent(this.unit, this);
};
Dimension.prototype = Object.assign(new node_1.default(), {
    type: 'Dimension',
    accept: function (visitor) {
        this.unit = visitor.visit(this.unit);
    },
    // remove when Nodes have JSDoc types
    // eslint-disable-next-line no-unused-vars
    eval: function (context) {
        return this;
    },
    toColor: function () {
        return new color_1.default([this.value, this.value, this.value]);
    },
    genCSS: function (context, output) {
        if ((context && context.strictUnits) && !this.unit.isSingular()) {
            throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: ".concat(this.unit.toString()));
        }
        var value = this.fround(context, this.value);
        var strValue = String(value);
        if (value !== 0 && value < 0.000001 && value > -0.000001) {
            // would be output 1e-6 etc.
            strValue = value.toFixed(20).replace(/0+$/, '');
        }
        if (context && context.compress) {
            // Zero values doesn't need a unit
            if (value === 0 && this.unit.isLength()) {
                output.add(strValue);
                return;
            }
            // Float values doesn't need a leading zero
            if (value > 0 && value < 1) {
                strValue = (strValue).substr(1);
            }
        }
        output.add(strValue);
        this.unit.genCSS(context, output);
    },
    // In an operation between two Dimensions,
    // we default to the first Dimension's unit,
    // so `1px + 2` will yield `3px`.
    operate: function (context, op, other) {
        /* jshint noempty:false */
        var value = this._operate(context, op, this.value, other.value);
        var unit = this.unit.clone();
        if (op === '+' || op === '-') {
            if (unit.numerator.length === 0 && unit.denominator.length === 0) {
                unit = other.unit.clone();
                if (this.unit.backupUnit) {
                    unit.backupUnit = this.unit.backupUnit;
                }
            }
            else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
                // do nothing
            }
            else {
                other = other.convertTo(this.unit.usedUnits());
                if (context.strictUnits && other.unit.toString() !== unit.toString()) {
                    throw new Error('Incompatible units. Change the units or use the unit function. '
                        + "Bad units: '".concat(unit.toString(), "' and '").concat(other.unit.toString(), "'."));
                }
                value = this._operate(context, op, this.value, other.value);
            }
        }
        else if (op === '*') {
            unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
            unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
            unit.cancel();
        }
        else if (op === '/') {
            unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
            unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
            unit.cancel();
        }
        return new Dimension(value, unit);
    },
    compare: function (other) {
        var a, b;
        if (!(other instanceof Dimension)) {
            return undefined;
        }
        if (this.unit.isEmpty() || other.unit.isEmpty()) {
            a = this;
            b = other;
        }
        else {
            a = this.unify();
            b = other.unify();
            if (a.unit.compare(b.unit) !== 0) {
                return undefined;
            }
        }
        return node_1.default.numericCompare(a.value, b.value);
    },
    unify: function () {
        return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
    },
    convertTo: function (conversions) {
        var value = this.value;
        var unit = this.unit.clone();
        var i;
        var groupName;
        var group;
        var targetUnit;
        var derivedConversions = {};
        var applyUnit;
        if (typeof conversions === 'string') {
            for (i in unit_conversions_1.default) {
                if (unit_conversions_1.default[i].hasOwnProperty(conversions)) {
                    derivedConversions = {};
                    derivedConversions[i] = conversions;
                }
            }
            conversions = derivedConversions;
        }
        applyUnit = function (atomicUnit, denominator) {
            if (group.hasOwnProperty(atomicUnit)) {
                if (denominator) {
                    value = value / (group[atomicUnit] / group[targetUnit]);
                }
                else {
                    value = value * (group[atomicUnit] / group[targetUnit]);
                }
                return targetUnit;
            }
            return atomicUnit;
        };
        for (groupName in conversions) {
            if (conversions.hasOwnProperty(groupName)) {
                targetUnit = conversions[groupName];
                group = unit_conversions_1.default[groupName];
                unit.map(applyUnit);
            }
        }
        unit.cancel();
        return new Dimension(value, unit);
    }
});
exports.default = Dimension;
//# sourceMappingURL=dimension.js.map