1 (function (GCN) {
  2 
  3 	'use strict';
  4 
  5 	/**
  6 	 * Maps contracts that were fetched via the Rest API into a flat hash map.
  7 	 *
  8 	 * @param {object<string, object>} categories
  9 	 * @return {object<string, object>}
 10 	 */
 11 	function mapConstructs(categories) {
 12 		var groupName;
 13 		var group;
 14 		var constructName;
 15 		var construct;
 16 		var map = {};
 17 
 18 		for (groupName in categories) {
 19 			if (categories.hasOwnProperty(groupName)) {
 20 				group = categories[groupName].constructs;
 21 
 22 				for (constructName in group) {
 23 					if (group.hasOwnProperty(constructName)) {
 24 						construct = group[constructName];
 25 						map[constructName] = construct;
 26 					}
 27 				}
 28 			}
 29 		}
 30 
 31 		return map;
 32 	}
 33 
 34 	/**
 35 	 * Node object.
 36 	 *
 37 	 * @name NodeAPI
 38 	 * @class
 39 	 * @augments Chainback
 40 	 */
 41 	var NodeAPI = GCN.defineChainback({
 42 		/** @lends NodeAPI */
 43 
 44 		__chainbacktype__: 'NodeAPI',
 45 		_extends: GCN.ContentObjectAPI,
 46 		_type: 'folder',
 47 
 48 		_data: {
 49 			folderId: null
 50 		},
 51 
 52 		/**
 53 		 * @private
 54 		 * @type {object<string, number} Constructs for this node are cached
 55 		 *                               here so that we only need to fetch
 56 		 *                               this once.
 57 		 */
 58 		_constructs: null,
 59 
 60 		/**
 61 		 * @private
 62 		 * @type {object<string, object} Constructs categories for this node.
 63 		 *                               Cached here so that we only need to
 64 		 *                               fetch this once.
 65 		 */
 66 		_constructCategories: null,
 67 
 68 		/**
 69 		 * Retrieves a list of constructs and constructs categories that are
 70 		 * assigned to this node and passes it as the only argument into the
 71 		 * the `success()' callback.
 72 		 *
 73 		 * @param {function(Array.<object>)=} success Callback to receive an
 74 		 *                                            array of constructs.
 75 		 * @param {function(GCNError):boolean=} error Custom error handler.
 76 		 * @return Returns the constructs / categories
 77 		 * @throws INVALID_ARGUMENTS
 78 		 */
 79 		constructs: function (success, error) {
 80 			if (!success) {
 81 				GCN.error('INVALID_ARGUMENTS', 'the `constructs()\' method ' +
 82 					'requires at least a success callback to be given');
 83 			}
 84 
 85 			if (this._constructs) {
 86 				success(this._constructs);
 87 			} else {
 88 				var that = this;
 89 				this._continueWith(function (child) {
 90 					that._data.id = child._data.nodeId;
 91 
 92 					that.constructCategories(function (categories) {
 93 						that._constructs = mapConstructs(categories);
 94 						success(that._constructs);
 95 					}, error);
 96 				}, error);
 97 			}
 98 		},
 99 
100 		/**
101 		 * Removes this node object.
102 		 *
103 		 * @param {function=} success Callback.
104 		 * @param {function(GCNError):boolean=} error Custom error handler.
105 		 * @param {function} success callback
106 		 */
107 		remove: function (success, error) {
108 
109 		},
110 
111 		/**
112 		 * @FIXME: Is it really possible to save changes to a node?  If not,
113 		 *         then we should not surface this method.
114 		 */
115 		save: function () {},
116 
117 		/**
118 		 * Retreives the top-level folders of this node's root folder.
119 		 *
120 		 * @param {function(FolderAPI)=} success
121 		 * @param {function(GCNError):boolean=} error Custom error handler.
122 		 */
123 		'!folders': function (success, error) {
124 			return this.folder(null, error).folders(success, error);
125 		},
126 
127 		/**
128 		 * Helper method that will load the constructs of this node.
129 		 *
130 		 * @private
131 		 * @this {NodeAPI}
132 		 * @param {function(Array.<object>)} success callback
133 		 * @param {function(GCNError):boolean=} error callback
134 		 */
135 		constructCategories: function (success, error) {
136 			if (this._constructCategories) {
137 				success(this._constructCategories);
138 			} else {
139 				var that = this;
140 				this._authAjax({
141 					url   : GCN.settings.BACKEND_PATH +
142 					        '/rest/construct/load.json',
143 					type  : 'GET',
144 					error : function (xhr, status, msg) {
145 						GCN.handleHttpError(xhr, msg, error);
146 					},
147 					success: function (response) {
148 						if (GCN.getResponseCode(response) === 'OK') {
149 							that._constructCategories =
150 								response.constructCategories;
151 							success(response.constructCategories);
152 						} else {
153 							GCN.handleResponseError(response, error);
154 						}
155 					}
156 				});
157 			}
158 		}
159 
160 	});
161 
162 	GCN.node = GCN.exposeAPI(NodeAPI);
163 	GCN.NodeAPI = NodeAPI;
164 
165 }(GCN));
166