/**
 *  This is the main javaScript controller driving the ISV GUI
 *  @author luisat
 *  @requires jQuery 1.2.3
 *  @requires string-utils.js
 *  @requires array-utils.js
 *  @requires utils.js 
 */

if(!isLoggingEnabled) var isLoggingEnabled = false;
if(!citrix) var citrix = {};
if(!citrix.ws) citrix.ws = {};
if(!citrix.ws.isv) citrix.ws.isv = {};
if(ISV == null) var ISV = citrix.ws.isv;
if(ISV.log == null && isLoggingEnabled) ISV.log = log4javascript.getDefaultLogger();


ISV.FeedSourceAggregator = function(sources) {
	
	if(!ArrayUtils.isArray(sources)) {
		throw {
			name: "IllegalArgumentException",
			message: "Provide array argument for datasources to aggregate!"
		}
	}
	
	//// default constants ////	
	var timeoutIters = 50;        // do 50 iterations and then timeout and stop trying to wait for data
	var timeoutInterval = 1000;   // 1 second checks for data fetched to be ready
	var perFeedSourceLimit = 2;   // default value for source groups
 	
	///// define global private vars /////	
	var feedSources = sources;            // holds the array of data sources
	var _feedItems = {};                  // feed items is a bucket that maps feed sources to a list of feed items
	var _flattenFeedItems = new Array();  // the flatten items is a list of all items grouped by source for easy pagination
	var _currentPage = 1;                 // stored the current page for the portlet
	
		
	// this function will take the flatten list of items and print to the configured div
	// inner private function helper to display portlet contents such as 
	//	  selector boxes
	//	  pagination
	//    feed content
	var displayPortlet = function(pageConfig, selectorConfig) {
		
		///// extract config parameters /////		
		// content containers
		var feedDiv = pageConfig.mainContent; 
		var paginationDiv = pageConfig.pageContent;		
		
		// page config
		var from = pageConfig.from;
		var to = pageConfig.to;
		var perPage = pageConfig.perPage;
	
		// hide loading animation
		jQuery("#loadingAnimation").hide();														
		var pageItems =  new Array();
										
		if(from >= 0 && to > 0) {
			
			// the flatten list will always contain the filtered content
			// if to > 0 paginate into array
			if(to > _flattenFeedItems.length) {
				to = _flattenFeedItems.length;
			}
			// paginate into the array					
			for(var i = 0; i < _flattenFeedItems.length; i++) {
				if(i >= from && i < to) {
					pageItems.push(_flattenFeedItems[i]);
				}
			}			
		}
		else {
			// otherwise, show all
			pageItems = _flattenFeedItems;
		}
			
		WSUtils.removeAllRows(feedDiv);					
		if(pageItems.length > 0) {		
			
			// draw table cells with this function helper					
			var cellBeanFuncs = [						
				
				function(feedItem) {
					
					var displayDate = "";
					try {
						displayDate = (function(before,after) {
	
							if(!before || !after) {
								throw {
									name: "IllegalArgumentException",
									message: "Expected non-null date arguments"
								}
							}
							
							var beforeMillis = Date.parse(before);
							var afterMillis  = Date.parse(after);
							var diff = afterMillis - beforeMillis;
							
							if(diff > 0) {
								var timeSlots = WSUtils.parseMillis(diff);
								var time = " - " + ((timeSlots[0] > 0) ? timeSlots[0] + " days ": "") + 
												   ((timeSlots[1] > 0) ? timeSlots[1] + " hours " : "") +
												   ((timeSlots[2] > 0) ? timeSlots[2] + " minutes " : "") +
												   " ago";
								return time; 				   								
							}
							return StringUtils.EMPTY;														
						})(feedItem.getPubDate(), new Date());
					}
					catch(e) {
						if(isLoggingEnabled) {
							ISV.log.error("Exception: " + e.message);
						}
					}
										    
					return "<div id='feedBody'><img src='" + pageConfig.server + feedItem.getIcon() + "'/>&nbsp;" 						 
						+  "<strong>" + feedItem.getDisplayName()+ "</strong>" + displayDate +  "<strong>" 
						+  "<a href='#' onclick='window.open(\"" + feedItem.getLink() + "\", \"feedPopupWindow\", \"width=1000,height=690,resizable=no,scrollbars=yes,toolbar=no,location=no,directories=no,status=no,menubar=no\" )'>" + 
							feedItem.getTitle() + "</a></strong>" + 
							feedItem.getDescription() + 
							"<br/>" + StringUtils.splitWords(feedItem.getLink(), 20).slice(0, 10 * 10) + " ..." + "<br/></div>";
				}												 	
			];		
			
			// write to table
			WSUtils.addRows(feedDiv, pageItems, cellBeanFuncs, { 
				
				// add css to the table cells and rows
				rowOptions: function(i,o) {				    	
				var color = ((i%2) == 1) ? '#ffffff' : '#f7f7f7';	
				return "style='background-color:"+color+"'";
			    	 
			  	},
			  	
			  	cellOptions: function() {
			 
			  		
			  		
			  		return " valign='top' height='25'";
			  	}
			});		
			
			// write to pagination (not used right now)	
			if(false) {
			//if(to !== 0) {				
				WSUtils.generatePagination(paginationDiv, _flattenFeedItems.length, perPage, "#switchpage", _currentPage, 				
	
					function() {
						
						// function computes new pagination bounds
						var id = this.getAttribute('class');
						var regex = /^page_(.*)$/;
						var pageNumber = regex.exec(id)[1];				
						
						_currentPage = pageNumber;				
						
						var from = pageNumber * perPage - perPage;					
						var to = pageNumber * perPage;
						if(to > _flattenFeedItems.length) {
							to = _flattenFeedItems.length;
						}
						
						var newPageConfig = {
							mainContent : feedDiv,
							pageContent : paginationDiv,
							perPage : perPage,
							from: from,
							to: to
						}
						
						// pass the newPageConfig and the selectorConfig object untouched
						displayPortlet(newPageConfig, selectorConfig);				
						return false;  // return false from click handler for client side behavior only
					}			
				);
			}			
		}
		else {
			jQuery("#" + feedDiv).append("<div align='center'><p>Could not find any feed content</p></div>");
		}
		
		// after the rows were added, display content with a fade in effect		
		jQuery("#" + feedDiv).hide();
		jQuery("#" + feedDiv).fadeIn("slow");		
	}
	
	// private helper method
	var extractData = function() {
		// process the sources array and group feed items by source
		feedSources.forEach(function(datasource, pos, array) {
			
			// we are assuming that at this point the data is ready
			// currently the only feed source is yahoo pipes
			if(datasource) {						
				var sourceItems = datasource.getFeedItems();								
				if(sourceItems) {					
					sourceItems.forEach(function(feedItem, feedPos, items) {
						
						if(feedItem) {							
							var list = _feedItems[feedItem.getSource()];
							if(!list) {
								list = new Array();
								_feedItems[feedItem.getSource()] = list;
							}
							list.push(feedItem);
						}
					});							 
				}			
			}
		});
	}
	
	// TODO: do the math where if there not enough items from one source then fill up with another
	// private method to flatten the items list
	var flattenList = function(selectorConfig) {
		_flattenFeedItems = new Array();
		// flatten feed data map for easy traversal and pagination					
		for(var source in _feedItems) {
			// loop through its inmediate properties (avoid any inherited properties)						
			if(_feedItems.hasOwnProperty(source)) {
				if(selectorConfig.sources[source] && selectorConfig.sources[source] === true) {
					var limit = selectorConfig["itemsPerGroup"] ? selectorConfig["itemsPerGroup"] : perFeedSourceLimit; 													
					_flattenFeedItems = _flattenFeedItems.concat(_feedItems[source].slice(0, limit));
				}				
			}
		}
	}
	
	//// public interface for the aggregator ////
	return {
		setFeedSources : function(items) {
			feedSources = items;
		},
		
		getFeedSources : function() {
			return feedSources;
		},
		
		getFeedSourceNames : function() {
			var sourceNames = new Array();
			for(var key in _feedItems) {			
				if(_feedItems.hasOwnProperty(key)) {
					sourceNames.push(key);
				}				
			}
			return sourceNames;
		},
	
		renderFeedPortlet : function(pageConfig, selectorConfig) {
			
			// fetches all items from each datasource (in our case the only one is Yahoo Pipes)			
			// asynchronously call fetchItems on each datasource until they are all ready			
			feedSources.forEach(function(datasource, pos, array) {
				if(isLoggingEnabled) {
					ISV.log.debug("fetching feed items for " + datasource.getDataSource());
				}								
				datasource.fetchFeedItems();															
			});
			
			var intervalId = 0;
			var localIters = 0;
			
			// set a scheduled task inner class that runs every second to check if the data is ready
			// this is the main loop of execution where the data is fetched and all of the
			// portlet information is generated
			
			// hold reference to the object so that we don't lose it the closure context
			// javascript will see a global that which references this instance of the aggregator
			// 'that' refers to the aggregator
			var that = this;  
			
			intervalId = setInterval(function() {
				
				// if the iterations exceeds timeoutIters unschedule task and return
				if(localIters > timeoutIters) {
					clearInterval(intervalId);	
					alert("Timeout error while fetching RSS data. Try again later");
					return;
				}
				
				// checks whether all datasources have finished fetching their data
				var allReady = true;
				
				// check datasources for ready
				feedSources.forEach(function(datasource, pos, array) {					
					if(!datasource.isReady()) {										
						allReady = false;
					}
				});
				
				// all the data has already been fetched, render portlet
				if(allReady) {	
												
					clearInterval(intervalId);
					
					// clear _feedItems data structure on subsequent fetches
					_feedItems = {};
									
					// extract data into _feedItems
					extractData();					
								
					// populate filter config object with all fetched sources
					if(!selectorConfig.sources) {
						selectorConfig.sources = {};
						
						that.getFeedSourceNames().forEach(function(sourcename, pos, array) {
							selectorConfig.sources[sourcename] = true;						
						});
					}
										 
										
					// update selectors enable and disable filters
					var selectorDiv = selectorConfig.selectorContent;
					
					jQuery("input[id^=selector_]").each(function() {	
						var regex = /^selector_(.*)$/;
						var source = regex.exec(jQuery(this).attr("id"))[1];									
						
						if(selectorConfig.sources.hasOwnProperty(source)) {
							// enable or disable the appropiage filters
							if(_feedItems[source] && 
							   _feedItems[source].length > 0 && 
							   selectorConfig.sources[source]) {
								jQuery("input[id^=selector_" + source +"]").attr("checked", "checked");
								jQuery("input[id^=selector_" + source +"]").attr("disabled", "");																
							}							
						}																																														 												
					}).click(function() {
							var regex = /^selector_(.*)$/;							
							var source = regex.exec(jQuery(this).attr("id"))[1];
							
							// toggle corresponding config source
							selectorConfig.sources[source] = jQuery(this).attr("checked") ? true : false;						
								
							_currentPage = 1;
							pageConfig.from = 0;
							pageConfig.to = pageConfig.perPage;
							selectorConfig.itemsPerGroup = jQuery("#rowSelector").val() || 0;						
							flattenList(selectorConfig);			
							displayPortlet(pageConfig, selectorConfig);								
						});						
					
					jQuery("#rowSelector").change(function() {
						
						var numberOfRows = jQuery(this).val() || 1;
						selectorConfig.itemsPerGroup = numberOfRows;
						flattenList(selectorConfig);			
						displayPortlet(pageConfig, selectorConfig);
					});
					
					// populate _flattenItems
					selectorConfig.itemsPerGroup = jQuery("#rowSelector").val() || 0;					
					flattenList(selectorConfig);
					
					// print all items
					displayPortlet(pageConfig, selectorConfig);							
				}				
				localIters++;
			},timeoutInterval);			
		}	
	}		
};
