ondefine(['Guard', 'Arrays'], function(Guard, Arrays) {

	/**
	 * @classdesc
	 * Represents a dimensional magnitude vector
	 * related to some Quantity or UnitExpression.
	 * 
	 * The magnitude of each dimension is its power.
	 * 
	 * For instance, the Dimensions of the UnitExpression
	 * representing "kilometers per second squared" would be:
	 * 	* displacement: 1
	 *  * time: -2
	 * 
	 * This data structure is extremely useful for determining if
	 * different Quantities or UnitExpressions are dimensionally
	 * compatible.
	 * @class
	 * @alias Dimensions
	 * @hideconstructor
	 * @param {array<number>} dim
	 */
	function Dimensions(dim) {
		Guard(dim, "dim").isValue().isArray();
		this._values = Arrays.frozenClone(dim);
		Object.freeze(this);
	}

	/**
	 * @lends Dimensions#
	 */
	Dimensions.prototype = {
		/**
		 * Returns the magnitude (power) of
		 * the dimension in slot `i`.
		 * @method
		 * @param {number} i 
		 * @type {number}
		 */
		get: function(i) {
			Guard(i, 'i').isNumber();
			return this._values[i];
		},
		/**
		 * Returns the size of the vector.
		 * @method
		 * @type {number}
		 */
		size: function() {
			return this._values.length;
		},
		/**
		 * Returns true if the Dimensions `rhs` is equivalent to
		 * this Dimensions object; false otherwise.
		 * @method
		 * @param {Dimensions} rhs 
		 * @type {boolean}
		 */
		equals: function(rhs) {
			var lhs = this;
			if (lhs.size() !== rhs.size()) {
				return false;
			}
			for(var i = 0; i < lhs.size(); i++) {
				if (lhs.get(i) !== rhs.get(i)) {
					return false;
				}
			}
			return true;
		},
		/**
		 * Adds another Dimensions instance to this instance and
		 * returns a new Dimensions.
		 * 
		 * This method is an implementation of vector addition.
		 * 
		 * This operation is useful for Quantity multiplication.
		 * @method
		 * @param {Dimensions} rhs 
		 * @type {Dimensions}
		 */
		add: function(rhs) {
			var lhs = this;
			var lhs_i, rhs_i;
			var newDimensions = [];
			var i;
			for(i = 0; i < lhs.size(); i++) {
				lhs_i = lhs.get(i) || 0;
				newDimensions[i] = lhs_i;
			}
			var i_max = Math.max(lhs.size(), rhs.size());
			for(i = 0; i < i_max; i++) {
				rhs_i = rhs.get(i) || 0;
				lhs_i = lhs.get(i) || 0;
				newDimensions[i] = lhs_i + rhs_i;
			}
			return new Dimensions(newDimensions);
		},
		/**
		 * Multiplies this Dimensions by a scalar and returns a new Dimensions.
		 * 
		 * This method is an implementation of scalar vector multiplication.
		 * 
		 * This operation is useful for Quantity exponentiation.
		 * @method
		 * @param {number} scalar - the scalar by which to multiply these Dimensions.
		 * @type {Dimensions}
		 */
		mult: function(scalar) {
			var lhs = this;
			var newDimensions = [];
			var i;
			newDimensions.length = lhs.size();
			for(i = 0; i < lhs.size(); i++) {
				var value = lhs.get(i) || 0;
				newDimensions[i] = value * scalar;
			}
			return new Dimensions(newDimensions);
		}
	};

	Object.defineProperty(Dimensions.prototype, 'constructor', {
		value: Dimensions,
		enumerable: false,
		writable: true
	});

	var empty = new Dimensions([]);

	/**
	 * Static method of the Dimensions constructor
	 * that returns a value that represents the "zero"
	 * of the Dimensions type.
	 * @method
	 * @type {Dimensions}
	 */
	Dimensions.empty = function() {
		return empty;
	};

	return Dimensions;
});