File:AssetSizes.js

/**
 * @module Core
 * @namespace springroll
 */
(function()
{
	var Debug;
	var devicePixelRatio = include('devicePixelRatio', false) || 1;

	/**
	 * Manages filtering of loads to load assets sized for the current device.
	 * @class AssetSizes
	 * @private
	 */
	var AssetSizes = function()
	{
		if (Debug === undefined)
		{
			Debug = include('springroll.Debug', false);
		}

		/**
		 * The collection of size objects
		 * @property {Array} _sizes
		 * @private
		 */
		this._sizes = [];

		/**
		 * The map of size objects
		 * @property {_sizesMap} _sizesMap
		 * @private
		 */
		this._sizesMap = {};

		/**
		 * The preferred size
		 * @property {Object} _preferredSize
		 * @readOnly
		 */
		this._preferredSize = null;
	};

	// Reference to the prototype
	var p = extend(AssetSizes);

	/**
	 * The URL substitution string.
	 * @property {String} SIZE_TOKEN
	 * @static
	 * @default  "%SIZE%"
	 */
	AssetSizes.SIZE_TOKEN = "%SIZE%";

	/**
	 * Removes all currently defined sizes.
	 * @method  reset
	 */
	p.reset = function()
	{
		this._sizes.length = 0;
		this._sizesMap = {};
	};

	/**
	 * Adds a new size definition.
	 * @method define
	 * @param {String} id The name of the folder which contains assets of this size.
	 * @param {int} maxSize The maximum size in points capable of using this size.
	 * @param {Number} scale The scale of assets
	 * @param {Array} fallback The size fallbacks if this size isn't available
	 *      for the current asset request.
	 */
	p.define = function(id, maxSize, scale, fallback)
	{
		var size = {
			id: id,
			maxSize: maxSize,
			scale: scale,
			fallback: fallback
		};

		this._sizesMap[id] = size;
		this._sizes.push(size);

		// Sor from smallest to largest maxSize
		this._sizes.sort(function(a, b)
		{
			return a.maxSize - b.maxSize;
		});
	};

	/**
	 * Update a URL by size
	 * @method  filter
	 * @param  {String} url The asset to load
	 * @param {Object} [size] The currrent size object
	 * @param {Object} [size.id] The name of the current size
	 * @return {String} The formatted url
	 */
	p.filter = function(url, size)
	{
		size = size || this._preferredSize;
		return url.replace(AssetSizes.SIZE_TOKEN, size.id);
	};

	/**
	 * Make sure we have a token
	 * @method  test
	 * @param  {String}  url The URL to test
	 * @return {Boolean} If we have the token
	 */
	p.test = function(url)
	{
		return url.indexOf(AssetSizes.SIZE_TOKEN) > -1;
	};

	/**
	 * Get a size based on the current asset sizes supported
	 * @method size
	 * @param  {Object} [supported] Return the preferred size if nothing is set
	 * @return {Object} Return the size object with id, scale, maxSize and fallback keys
	 */
	p.size = function(supported)
	{
		var size = this._preferredSize;
		var fallback = size.fallback;

		// There's custom support and it says we don't support
		// the default size.
		if (supported && !supported[size.id])
		{
			for (var i = 0, len = fallback.length; i < len; i++)
			{
				var alt = fallback[i];

				// Undefined means we support it, or true
				if (supported[alt] !== false)
				{
					size = this._sizesMap[alt];
					break;
				}
			}
		}
		// Umm something's wrong, the asset doesn't support
		// either the current size or any of the fallbacks
		if (!size)
		{
			throw "Asset does not support any valid size";
		}
		return size;
	};

	/**
	 * Recalculate the current preferred size based on width and height
	 * @method refresh
	 * @param  {Number} width  The width of the stage
	 * @param  {Number} height The height of the stage
	 * @return {Object} The size
	 */
	p.refresh = function(width, height)
	{
		var minSize = Math.min(width, height);
		var size = null;
		var sizes = this._sizes;

		// Check the largest first
		for (var i = sizes.length - 1; i >= 0; --i)
		{
			if (sizes[i].maxSize / devicePixelRatio > minSize)
			{
				size = sizes[i];
			}
			else
			{
				break;
			}
		}
		this._preferredSize = size;
	};

	/**
	 * Destroy and don't use after this
	 * @method destroy
	 */
	p.destroy = function()
	{
		this._preferredSize = null;
		this._sizes = null;
		this._sizesMap = null;
	};

	// Assign to namespace
	namespace('springroll').AssetSizes = AssetSizes;

}());