1 /**
  2  * The Render Engine
  3  * HashContainer
  4  *
  5  * @fileoverview A set of objects which can be used to create a collection
  6  *               of objects, and to iterate over a container.
  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.struct.HashContainer",
 37     "requires":[
 38         "R.struct.Container"
 39     ]
 40 });
 41 
 42 /**
 43  * @class A hash container is a logical collection of objects.  A hash container
 44  *        is a container with a backing object for faster lookups.  Objects within
 45  *        the container must have unique names. When the container is destroyed, none of the
 46  *        objects within the container are destroyed with it.  Call {@link #cleanUp} to
 47  *        destroy all of the objects in the container.
 48  *
 49  * @param containerName {String} The name of the container. Default: Container
 50  * @extends R.struct.Container
 51  * @constructor
 52  * @description Create a hashed container object.
 53  */
 54 R.struct.HashContainer = function () {
 55     return R.struct.Container.extend(/** @scope R.struct.HashContainer.prototype */{
 56 
 57         objHash:null,
 58 
 59         /**
 60          * @private
 61          */
 62         constructor:function (containerName) {
 63             this.base(containerName || "HashContainer");
 64             this.objHash = {};
 65         },
 66 
 67         /**
 68          * Release the object back into the object pool.
 69          */
 70         release:function () {
 71             this.base();
 72             this.objHash = null;
 73         },
 74 
 75         /**
 76          * Returns <tt>true</tt> if the object name is already in
 77          * the hash.
 78          *
 79          * @param name {String} The name of the hash to check
 80          * @return {Boolean}
 81          */
 82         isInHash:function (key) {
 83             key = (key.charAt(0) === "_" ? key : "_" + String(key));
 84             return (this.objHash[key] != null);
 85         },
 86 
 87         /**
 88          * Add an object to the container.
 89          *
 90          * @param key {String} The name of the object to store.  Names must be unique
 91          *                      or the object with that name will be overwritten.
 92          * @param obj {BaseObject} The object to add to the container.
 93          */
 94         add:function (key, obj) {
 95             AssertWarn(!this.isInHash(key), "Object already exists within hash!");
 96 
 97             if (this.isInHash(key)) {
 98                 // Remove the old one first
 99                 this.removeHash(key);
100             }
101 
102             // Some keys weren't being accepted (like "MOVE") so added
103             // an underscore to prevent keyword collisions
104             this.objHash["_" + String(key)] = obj;
105             this.base(obj);
106             return this.objHash["_" + String(key)];
107         },
108 
109         /** @private */
110         addAll:function () {
111             R._unsupported("addAll()", this);
112         },
113 
114         /** @private */
115         clone:function () {
116             R._unsupported("clone()", this);
117         },
118 
119         /** @private */
120         concat:function () {
121             R._unsupported("concat()", this);
122         },
123 
124         /** @private */
125         reduce:function () {
126             R._unsupported("reduce()", this);
127         },
128 
129         /**
130          * Remove an object from the container.  The object is
131          * not destroyed when it is removed from the container.
132          *
133          * @param obj {BaseObject} The object to remove from the container.
134          * @return {Object} The object removed from the container
135          */
136         remove:function (obj) {
137             for (var o in this.objHash) {
138                 if (this.objHash[o] === obj) {
139                     // removeHash() takes care of removing the actual object, so we don't
140                     // call the base class - otherwise we delete the wrong object
141                     this.removeHash(o);
142                     break;
143                 }
144             }
145             return obj;
146         },
147 
148         /**
149          * Remove the object with the given key name from the container.
150          *
151          * @param name {String} The object to remove
152          * @return {Object} The object removed
153          */
154         removeHash:function (key) {
155             key = (key.charAt(0) === "_" ? key : "_" + String(key));
156             var obj = this.objHash[key];
157             R.engine.Support.arrayRemove(this.objects, obj);
158             delete this.objHash[key];
159             return obj;
160         },
161 
162         /**
163          * Remove an object from the container at the specified index.
164          * The object is not destroyed when it is removed.
165          *
166          * @param idx {Number} An index between zero and the size of the container minus 1.
167          * @return {Object} The object removed from the container.
168          */
169         removeAtIndex:function (idx) {
170             var obj = this.base(idx);
171             for (var o in this.objHash) {
172                 if (this.objHash[o] === obj) {
173                     this.removeHash(o);
174                     break;
175                 }
176             }
177 
178             return obj;
179         },
180 
181         /**
182          * If a number is provided, the request will be passed to the
183          * base object, otherwise a name is assumed and the hash will
184          * be retrieved.
185          *
186          * @param idx {Number|String} The index or hash of the object to get
187          * @return {Object}
188          */
189         get:function (idx) {
190             if (idx.substr && idx.toLowerCase) {
191                 return this.objHash["_" + idx];
192             } else {
193                 return this.base(idx);
194             }
195         },
196 
197         /**
198          * Remove all objects from the container.  None of the objects are
199          * destroyed.
200          */
201         clear:function () {
202             this.base();
203             this.objHash = {};
204         },
205 
206         /**
207          * Cleans up the references to the objects (destroys them) within
208          * the container.
209          */
210         cleanUp:function () {
211             this.base();
212         }
213 
214     }, /** @scope R.struct.HashContainer.prototype */ {
215         /**
216          * Get the class name of this object
217          *
218          * @return {String} "R.struct.HashContainer"
219          */
220         getClassName:function () {
221             return "R.struct.HashContainer";
222         }
223 
224     });
225 
226 };