define(['Guard','Arrays','Unit','UnitType', 'DerivedUnitType','logic/SystemDefinitionFixer'],
function(Guard, Arrays, Unit, UnitType, DerivedUnitType, SystemDefinitionFixer) {
/**
* @classdesc
* A System of units of measure.
* @class
* @alias System
* @param {SystemDefinition} def - the system definition.
* @hideconstructor
*/
function System(def) {
Guard(def.name, "def.name").isTruthy().isString();
var name = def.name;
/**
* Returns the name of the System.
* @method
* @type {string}
*/
this.name = function name() { return name; };
Guard(def.base, "def.base").isObject();
def = SystemDefinitionFixer(def);
var that = this;
var allUnits = [];
UnitType.values().forEach(function(unitType) {
var unitTypeName = unitType.name();
if (!def.base.hasOwnProperty(unitTypeName)) {
throw new Error("System definition for '" + name + "' is missing base unit for " + unitTypeName);
}
var unit = def.base[unitTypeName];
Guard(unit, "def.base." + unitTypeName).instanceOf(Unit);
allUnits.push(unit);
that[unitTypeName] = (function(v) {
return function() { return v; };
})(unit);
});
Guard(def.derived, "def.derived").isObject();
DerivedUnitType.values().forEach(function(unitType) {
var unitTypeName = unitType.name();
var derivedUnit = def.derived[unitTypeName];
if (!derivedUnit) {
return;
}
allUnits.push(derivedUnit);
that[unitTypeName] = (function(v) {
return function() { return v; };
})(derivedUnit);
});
var other = def.other || [];
other.forEach(function(unit) {
allUnits.push(unit);
});
/**
* A list of all "other" (non-defining) [Units]{@link Unit} in the System.
* An example of this type of Unit would be the kilometer: it is
* part of the SI System, but is not defining part of the System
* as the meter is.
* @member {Unit[]}
* @alias System#other
*/
that.other = Arrays.frozenClone(other);
Object.freeze(allUnits);
/**
* Returns an array of all Unit types in the system.
* @method
* @type {Unit[]}
*/
this.allUnits = function() {
return allUnits;
};
Object.freeze(this);
}
System.prototype =
/** @lends System# */
{
/**
* Returns the name of the System.
* @method
* @type {string}
*/
toString: function() {
return this.name();
}
};
Object.defineProperty(System.prototype, 'constructor', {
value: System,
enumerable: false,
writable: true
});
/**
* @param {SystemDefinition} def
* @private
*/
System.create = function(def) {
return new System(def);
};
return System;
});