/* file: DataLoader.js */
/**
 * Manage loading (& potentially caching) data, and
 * emitting events.
 * This is sort of a placeholder for future development.
 * 
 * Events:
 *  - "loaded" with data = Text/Person/etc object
 *  Example usage:
 *  $(DataLoader).bind('loaded', function(event) {
  		if (event.data.xid != myXId) return;
  		alert(myXId+" was (re)loaded");
	}); 
 */
var DataLoader = {
	load: function(url, params, callback, undoItem, item) {	
		// Trigger optimistic event	
		if(undoItem !== undefined && item !== undefined) {
			$(DataLoader).trigger(
				new jQuery.Event('loaded', {'item':item})
			);
		}

		// Rollback upon failure/error
		function undo() {
			if(undoItem !== undefined && item !== undefined) {
				$(DataLoader).trigger(
					new jQuery.Event('loaded', {'item':undoItem})
				);
			}
		};
		// the request should be made as the current user on this page
		url = addArg2(url, "as", Creole.user.xid);

		console.log(url);
		
		$.ajax({
			url : url,
			data : params,
			dataType : "json",
			success : function(response) {
				if (response.success) {					
					// Emit useful events: loaded
					var dataObjects = DataLoader.selectDataObjects(response);
				
					console.log("DataObjects from " + url, dataObjects);
				
					for(var i = 0; i < dataObjects.length; i++) {
						$(DataLoader).trigger(
							new jQuery.Event('loaded', {'item' : dataObjects[i]})
						);
					}
				} else {
					undo();
				}

				// Call the callback
				if (callback !== undefined) callback(response, params);
			},
			error : function(response) {
				console.log("DataLoader:error", response);

				if (callback !== undefined) {
					callback(
						{
							'success' : false, 
							'errors' : [response.statusText]
						}, 
						params
					);
				}

				undo();
			},
			complete : handleAjaxResponse // messaging
		});		
	},
	/** 
	 * Traverse a json object, selecting the SoDash data objects. 
	 * Only picks out the top-level objects (e.g. a text, but not the text.owner). 
	 * @param jsonObject
	 * @param list The list that gets returned. Usually unset (gets initialised to []).
	 * @param visited Prevent infinite loops. Usually unset (gets initialised to {}).
	 * @return list, may be empty, never null
	 * */
	selectDataObjects: function(jsonObject, list, visited) {		
		if (!list) list = [];
		
		if (!jsonObject) return list;
		
		// prevent infinite loops if we have self-referencing data
		if (!visited) visited = {};
		
		if (visited[jsonObject]) return list;
		
		visited[jsonObject] = true;
		
		// ignore some types
		if (
			_.isString(jsonObject) || 
			_.isNumber(jsonObject) || 
			_.isFunction(jsonObject) || 
			_.isElement(jsonObject)
		) {
			return list;
		}
		
		// is this a data object? then add and stop
		if(jsonObject) {
			if (jsonObject.xid) {
				list.push(jsonObject);
				return list;
			}
			
			// recurse
			if (_.isArray(jsonObject)) {
				for(var i=0; i<jsonObject.length; i++) {
					DataLoader.selectDataObjects(jsonObject[i], list);
				}
			} else {
				for(var prop in jsonObject) {
					DataLoader.selectDataObjects(jsonObject[prop], list);
				}
			}
		}
		
		return list;
	},
	
	/**
	 * A cache of SoDash items.
	 * Currently: only holds a very few values, explicitly poked in. 
	 * And nothing is ever removed.
	 * TODO use Html5 storage??
	 * @return item or null
	 */
	getItem: function(xid, fetchIfNeedBe) {
		var cached = DataLoader._xid2item[xid];
		
		if (cached) return cached;
		
		if (!fetchIfNeedBe) return null;
		
		throw "TODO";
	},
	
	cacheItem: function(item) {
		if (!item) return;
		
		DataLoader._xid2item[item.xid] = item;
	},
	
	_xid2item: {}
};

