/** 
 * @fileoverview This api provides functionality for meadan ui widgets to communicate with the server
 * @author Darren Shaw - ibm.com, meadan.org
 * @version 0.1 
 */

/*
-------------------------------------------------------------------------------
  Globals
-------------------------------------------------------------------------------
*/
var URL_POSTS = "service.php?type=post";

/*
-------------------------------------------------------------------------------
  WidgetApi Class
-------------------------------------------------------------------------------
*/

/**
 * Construct a new WidgetApi object.  These objects should only be created via the singleton
 * getInstance() method.
 * @class This is the WidgetApi class.  It should only be instantiated via the 
 * WidgetApi.getInstance static method
 * @constructor
 * @return A new WidgetApi
 */
function WidgetApi(){
	this.listenersPostAdded = new Array();
	this.listenersPostRemoved = new Array();
	this.listenersFilterChanged = new Array();
	this.listenersTargetPostChanged = new Array();
	this.listenersPostsLoaded = new Array();
    // TODO: is this.posts used at all?	remove.
	this.posts = new Array();
	this.targetPost = null;
	this.filter = new WidgetFilter();
	this.postList = new PostList();
	this.postList.addListener(this.postsReloaded);
}

/**
 * Get the singleton WidgetApi class
 * @requires WidgetApi The WidgetApi class
 * @returns the singletone WidgetApi
 * @type WidgetApi
 */
WidgetApi.getInstance = function(){
	if(WidgetApi.inst == null){
		WidgetApi.inst = new WidgetApi();
	}
	return WidgetApi.inst;
}

/**
 * Add a listener for when posts are added
 * @param {listener} the listener
 */
function widgetApiAddPostAddedListener(listener){
	this.listenersPostAdded[this.listenersPostAdded.length] = listener;
}

/**
 * Add a listener for when posts are loaded
 * @param {listener} the listener
 */
function widgetApiPostsLoadedListener(listener){
	this.listenersPostsLoaded[this.listenersPostsLoaded.length] = listener;
}

/**
 * Add a listener for when posts are removed
 * @param {listener} the listener
 */
function widgetApiAddPostRemovedListener(listener){
	this.listenersPostRemoved[this.listenersPostRemoved.length] = listener;
}

/**
 * Add a listener for when the filter is changed
 * @param {listener} the listener
 */
function widgetApiAddFilterChangedListener(listener){
	this.listenersFilterChanged[this.listenersFilterChanged.length] = listener;
}

/**
 * Set the filter to be used.  Setting a filter will automatically cause the posts
 * to be reloaded according to that filter
 * @param {WidgetFilter} the filter
 */
function widgetApiSetFilter(filter){
	this.filter = filter;	
	for(var i=0; i < this.listenersFilterChanged.length; i++){
		var listener = this.listenersFilterChanged[i];
		listener(this.filter);
	}
	this.postList.reload(this.filter);
}

/**
 * Get the currently applied filter
 * @type WidgetFilter
 */
function widgetApiGetFilter(){
	return this.filter;
}

/**
 * Remove the current filter.  Removing a filter will reset to an empty filter and 
 * reload posts according to that empty filter
 */
function widgetApiRemoveFilter(){
	this.filter = new WidgetFilter();
	for(var i=0; i < this.listenersFilterChanged.length; i++){
		var listener = this.listenersFilterChanged[i];
		listener(this.filter);
	}
	this.postList.reload(this.filter);
}

/**
 * Sets the post that is to be the current focus
 * @param {Post} the post to become the target of focus
 */
function widgetApiSetTargetPost(post){
	this.targetPost = post;
	for(var i=0; i < this.listenersTargetPostChanged.length; i++){
		var listener = this.listenersTargetPostChanged[i];
		listener(post);
	}
}

/**
 * Get the currently target post
 * @type Post
 */
function widgetApiGetTargetPost(){
	return this.targetPost;
}

/**
 * Reload the currently visible posts according to the currently applied filter
 * TODO: why is there a widgetapi API AND a postlist API if both are coupled?
 */
function widgetApiReloadPosts(){
	this.postList.reload(this.filter);
}

/**
 * Reload the currently visible posts according to the currently applied filter forcing to get
 * the live (none cached) data
 */
function widgetApiReloadPostsNoCache(){
	this.postList.reloadNoCache(this.filter);
}

/**
 * Redisplay all the posts in the list, for example after they have been resorted
 */
function widgetApiRedisplayPosts(){
	this.postList.redisplayPosts();
}


/**
 * Notify listeners on each new post reloaded or removed AND on all posts updated.
 */
function widgetApiPostsReloaded(addedPosts, removedPosts, allPosts){
	if(!WidgetApi) return;
        var inst = WidgetApi.getInstance();
	for(var i=0; i < removedPosts.length; i++){
		var post = removedPosts[i];
		for(var j=0; j < inst.listenersPostRemoved.length; j++){
			var listener = inst.listenersPostRemoved[j];
			listener(post);
		}
	}
	for(var i=0; i < addedPosts.length; i++){
		var post = addedPosts[i];
		for(var j=0; j < inst.listenersPostAdded.length; j++){
			var listener = inst.listenersPostAdded[j];
			listener(post);
		}
	}
	for(var i=0; i < inst.listenersPostsLoaded.length; i++){
		var listener = inst.listenersPostsLoaded[i];
		listener(addedPosts,removedPosts,allPosts);
	}
}

/**
 * Sort the postlist
 */
function widgetApiSortPosts(sortOrder){
	this.postList.sort(sortOrder);
}


/**
 * Allow new posts to goto the server
 * TODO: inefficient to submit and then ask again - do as a single event.
 */
function widgetSubmitPosts(formnodes){

	var data = "action=add&return_type=xml&";
	for(var i=0; i < formnodes.length; i++){
		var node = formnodes[i];
		
		//Validate URL
		if (node.name=='url'){
			var url = validateURL(node.value);
			if (url==null){
				return null;
			} 
			data = data + node.name + "=" + url+"&";
		} else {
			data = data + node.name + "=" + node.value+"&";
		}
	}
	
	// need to show in progress
	showPostSubmitProgress();
	
	sendData(URL_POSTS, data, function() {
		hidePostSubmitProgress();
		WidgetApi.getInstance().reloadPostsNoCache(); //don't use cache (to get new post)
		// need to hide in progress
	});
}

/**
 * Allow new posts to goto the server
 * TODO: inefficient to submit and then ask again - do as a single event.
 */
function widgetSubmitMediaPost(formnodes){

	var data = "action=addmedialink&return_type=xml&";
	for(var i=0; i < formnodes.length; i++){
		var node = formnodes[i];
		
		//Validate URL
		if (node.name=='url'){
			var url = validateURL(node.value);
			if (url==null){
				return null;
			} 
			data = data + node.name + "=" + url+"&";
		} else {
			data = data + node.name + "=" + node.value+"&";
		}
	}
	
	// need to show in progress
	showPostSubmitProgress();
	
	sendData(URL_POSTS, data, function() {
		hidePostSubmitProgress();
		WidgetApi.getInstance().reloadPostsNoCache(); //don't use cache (to get new post)
		// need to hide in progress
	});
}

/**
 * Think of the children.
 */
function widgetExpand(postId) {
    var post = WidgetApi.getInstance().postList.getPostFromAllById(postId);
    if(post) {
        post.visible = true;
        for(var i = 0; post.relations && i < post.relations.length;i++) {
            post.relations[i].visible = true;
        }
    }
    WidgetApi.getInstance().postList.loadChildren(postId);
}

/**
 * Mark post as not visible; painting algorithm has to deal with everything else
 */
function widgetShrink(postId) {
    var post = WidgetApi.getInstance().postList.getPostFromAllById(postId);
    if(post) {
        post.visible = false;
    }
}

/*
 * Build the class
 */
WidgetApi.prototype.addPostAddedListener = widgetApiAddPostAddedListener;
WidgetApi.prototype.addPostsLoadedListener = widgetApiPostsLoadedListener;
WidgetApi.prototype.addPostRemovedListener = widgetApiAddPostRemovedListener;
WidgetApi.prototype.addFilterChangedListener = widgetApiAddFilterChangedListener;
WidgetApi.prototype.setFilter = widgetApiSetFilter;
WidgetApi.prototype.getFilter = widgetApiGetFilter;
WidgetApi.prototype.removeFilter = widgetApiRemoveFilter;
WidgetApi.prototype.setTargetPost = widgetApiSetTargetPost;
WidgetApi.prototype.getTargetPost = widgetApiGetTargetPost;
WidgetApi.prototype.reloadPosts = widgetApiReloadPosts;
WidgetApi.prototype.reloadPostsNoCache = widgetApiReloadPostsNoCache;
WidgetApi.prototype.postsReloaded = widgetApiPostsReloaded;
WidgetApi.prototype.submitPosts = widgetSubmitPosts;
WidgetApi.prototype.widgetSubmitMediaPost= widgetSubmitMediaPost;
WidgetApi.prototype.expand = widgetExpand;
WidgetApi.prototype.shrink = widgetShrink;
WidgetApi.prototype.sortPosts = widgetApiSortPosts;
WidgetApi.prototype.redisplayPosts = widgetApiRedisplayPosts;
