1 /**
  2  * The Render Engine
  3  * AbstractResourceLoader
  4  *
  5  * @fileoverview The base class for all resource loaders.  It has the functionality
  6  *               for managing a local cache of loaded objects.
  7  *
  8  * @author: Brett Fattori (brettf@renderengine.com)
  9  * @author: $Author: bfattori $
 10  * @version: $Revision: 1555 $
 11  *
 12  * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com)
 13  *
 14  * Permission is hereby granted, free of charge, to any person obtaining a copy
 15  * of this software and associated documentation files (the "Software"), to deal
 16  * in the Software without restriction, including without limitation the rights
 17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 18  * copies of the Software, and to permit persons to whom the Software is
 19  * furnished to do so, subject to the following conditions:
 20  *
 21  * The above copyright notice and this permission notice shall be included in
 22  * all copies or substantial portions of the Software.
 23  *
 24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 29  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 30  * THE SOFTWARE.
 31  *
 32  */
 33 
 34 // The class this file defines and its required classes
 35 R.Engine.define({
 36     "class":"R.resources.loaders.AbstractResourceLoader",
 37     "requires":[
 38         "R.engine.BaseObject"
 39     ]
 40 });
 41 
 42 /**
 43  * @class  A resource loader is a generalized interface used by all resource
 44  *         loaders.  It is designed to provide a common set of routines for
 45  *         loading resources (fonts, images, game data, etc...) from some
 46  *         location.  Additionally, objects are cached by this base class,
 47  *         although some classes make use of other methods to enhance the
 48  *         caching, such as the {@link R.resources.loaders.ImageLoader} class.
 49  *
 50  * @param [name=ResourceLoader] {String} The name of the resource loader.
 51  * @constructor
 52  * @extends R.engine.BaseObject
 53  * @description Create a resource loader
 54  */
 55 R.resources.loaders.AbstractResourceLoader = function () {
 56     return R.engine.BaseObject.extend(/** @scope R.resources.loaders.AbstractResourceLoader.prototype */{
 57 
 58         cache:null,
 59         length:0,
 60         loadTimeout:null,
 61 
 62         /** @private */
 63         constructor:function (name) {
 64             this.base(name || "ResourceLoader");
 65             this.cache = {};
 66             this.loadTimeout = null;
 67         },
 68 
 69         /**
 70          * Releases the resource loader back into the pool
 71          */
 72         release:function () {
 73             this.base();
 74             this.cache = null;
 75             this.length = 0;
 76         },
 77 
 78         /**
 79          * Destroy the resource loader and all cached resources.
 80          */
 81         destroy:function () {
 82             this.clear();
 83             this.base();
 84         },
 85 
 86         /**
 87          * Load an object via this resource loader, and add it to the cache.  When
 88          * all resources being loaded by this resource loader are ready, fires the
 89          * <code>isready</code> event.
 90          *
 91          * @param name {String} The name to refer to the loaded object
 92          * @param data {Object} The data to store in the cache
 93          * @param isReady {Boolean} A flag that states whether or not a resource
 94          *                          is ready to use.
 95          */
 96         load:function (name, data, isReady) {
 97             var obj = { data:data, ready:isReady || false};
 98             this.cache[name] = obj;
 99             this.length++;
100             R.debug.Console.log("Loading " + this.getResourceType() + ": " + name);
101 
102             // The event trigger when all resources are loaded and ready
103             var self = this;
104             if (!this.loadTimeout) {
105                 this.loadTimeout = R.lang.Timeout.create("LoadTimeout", 100, function () {
106                     if (self.isReady()) {
107                         this.destroy();
108                         self.fireReadyEvent();
109                     } else {
110                         this.restart();
111                     }
112                 });
113             }
114             return obj.data;
115         },
116 
117         /**
118          * Set the "ready" state of the resource.  When a resource has been completely
119          * loaded, set the resource "ready" state to <tt>true</tt> to allow objects
120          * waiting for those resources to utilize them.  Fires the <code>resourceready</code>
121          * event, with the name of the resource, when the resource is ready to use.
122          *
123          * @param name {String} The name of the resource
124          * @param isReady {Boolean} <tt>true</tt> to set the resource to "ready for use"
125          */
126         setReady:function (name, isReady) {
127             this.cache[name].ready = isReady;
128             if (isReady) {
129                 this.triggerEvent("resourceready", [name]);
130                 R.debug.Console.log(this.getResourceType() + " " + name + " ready...");
131             }
132         },
133 
134         /**
135          * Check to see if a named resource is, or all resources are, "ready for use".
136          * @param name {String} The name of the resource to check ready status for,
137          *             or <tt>null</tt> for all resources in loader.
138          * @return {Boolean} <tt>true</tt> if the resource is loaded and ready to use
139          */
140         isReady:function (name) {
141             if (name) {
142                 return this.cache[name] ? this.cache[name].ready : false;
143             } else {
144                 // Check the status of all loader elements
145                 var rList = this.getResources();
146                 if (rList.length == 0) {
147                     // Early out, no resources to load
148                     return true;
149                 }
150                 for (var r in rList) {
151                     if (!this.isReady(rList[r])) {
152                         return false;
153                     }
154                 }
155                 return true;
156             }
157         },
158 
159         /**
160          * Fires an event when all of the resources being loaded by this loader are
161          * ready for use.
162          * @private
163          */
164         fireReadyEvent:function () {
165             this.triggerEvent("isready");
166             this.loadTimeout = null;
167         },
168 
169         /**
170          * Unload an object from this resource loader.  Removes the object
171          * from the cache.
172          *
173          * @param name {String} The name of the object to remove
174          */
175         unload:function (name) {
176             if (this.cache[name].data.destroy) {
177                 // Make sure that cached objects have a chance to clean up
178                 this.cache[name].data.destroy();
179             }
180 
181             this.cache[name] = null;
182             delete this.cache[name];
183             this.length--;
184         },
185 
186         /**
187          * Get the object with the specified name from the cache.
188          *
189          * @param name {String} The name of the object to retrieve
190          * @return {Object} The object stored within the cache
191          */
192         get:function (name) {
193             if (this.cache[name]) {
194                 return this.cache[name].data;
195             } else {
196                 return null;
197             }
198         },
199 
200         /**
201          * Get the specific resource supported by the resource loader.
202          * @param name {String} The name of the resource
203          * @return {Object}
204          */
205         getResourceObject:function (name) {
206             return this.get(name);
207         },
208 
209         /**
210          * Set the data associated with the name.  The ready state is set
211          * to <tt>false</tt>, so it will be up to the developer to call
212          * {@link #setReady} on the object if the object is truly ready for use.
213          * @param name {String} The name of the cache record
214          * @param data {Object} Data to store
215          */
216         set:function (name, data) {
217             var obj = { data:data, ready:false};
218             this.cache[name] = obj;
219         },
220 
221         /**
222          * Returns the cache.  You should not manipulate the cache directly.
223          * instead, call methods to update the cache.
224          * @return {Object} The cache
225          */
226         getCachedObjects:function () {
227             return this.cache;
228         },
229 
230         /**
231          * Clear the objects contained in the cache.
232          */
233         clear:function () {
234             for (var o in this.cache) {
235                 this.cache[o] = null;
236             }
237 
238             this.cache = {};
239             this.length = 0;
240         },
241 
242         /**
243          * Get the names of all the resources available in this resource loader.
244          * @return {Array} An array of resource names
245          */
246         getResources:function () {
247             var n = [];
248             for (var i in this.cache) {
249                 n.push(i);
250             }
251             return n;
252         },
253 
254         /**
255          * Export all of the resources in this loader, as a JavaScript object, with the
256          * resource name as the key and the corresponding object as the value.
257          * @param [resourceNames] {Array} An optional array of resources to export, by name,
258          *       or <code>null</tt> to export all resources
259          */
260         exportAll:function (resourceNames) {
261             var o = {};
262             var resources = this.getResources();
263             for (var i in resources) {
264                 if (!resourceNames || R.engine.Support.indexOf(resourceNames, resources[i]) != -1) {
265                     o[resources[i]] = this.getResourceObject(resources[i]);
266                 }
267             }
268             return o;
269         },
270 
271         /**
272          * The name of the resource this loader will get.
273          * @return {String} The string "default"
274          */
275         getResourceType:function () {
276             return "default";
277         }
278     }, /** @scope R.resources.loaders.AbstractResourceLoader.prototype */{
279 
280         /**
281          * Get the class name of this object
282          * @return {String} "R.resources.loaders.AbstractResourceLoader"
283          */
284         getClassName:function () {
285             return "R.resources.loaders.AbstractResourceLoader";
286         }
287 
288     });
289 
290 }