if (!ws) var ws = {};
if (!ws.cr) ws.cr = {};
if (!ws.cr.util) ws.cr.util = {};
if (WSUtils == null) var WSUtils = ws.cr.util;

/**
 * Parses the number of miliseconds and returns an 
 * array with each component of the time. Data will be 
 * returned in the following format, parsing all fields: 
 * 	  [ days, hours, minutes, seconds, milliseconds ]
 * @param millis - the number of milliseconds to parse
 */
WSUtils.parseMillis = function (millis) {
	
	var MILLIS_IN_SECOND = 1000;
	var HOURS_IN_DAY = 24;
	var MINUTES_IN_HOURS = 60;
	var SECONDS_IN_MINUTE = 60; 
			
	var seconds = Math.floor(millis / MILLIS_IN_SECOND);	
	millis %= MILLIS_IN_SECOND;
	
	var minutes = Math.floor(seconds / SECONDS_IN_MINUTE);
	seconds %= SECONDS_IN_MINUTE;
	
	var hours = Math.floor(minutes / MINUTES_IN_HOURS);
	minutes %= MINUTES_IN_HOURS;

	var days = Math.floor(hours /HOURS_IN_DAY);
	hours %= HOURS_IN_DAY;
	
	var result = new Array();
	result.push(days);
	result.push(hours);
	result.push(minutes);
	result.push(seconds);
	result.push(millis);	
	return result;		
};


/**
 * Add rows to table body
 * @param id - the id of the <code><tbody></code> to add rows to
 * @param cellFuncs - the function that will generate the content for that cell
 */
WSUtils.addRows = function(id, array, cellFuncs, options) {
		
	if(!id || !array || !cellFuncs) { 
		return;
	}

	if (!options) {		
		options = WSUtils.defaultTableOptions();
	}

	for(var row = 0; row < array.length ; row++) {
		
		var item = array[row];				
		var cellData = "";		
		for(var cell = 0; cell < cellFuncs.length ; cell++) {
			
			var innerCell = WSUtils._buildCell(cellFuncs[cell](item, row), options.cellOptions(cell, item));			
			cellData += innerCell;			
		}
		var rowData = WSUtils._buildRow(cellData, options.rowOptions(row, item));	
		jQuery("#" + id).append(rowData);
	}
};

WSUtils.addFixedRows = function(id, array, row, column, cellFunction, options) {
	
	if(!id || !array || !cellFunction) { 
		return;
	}

	if (!options) {		
		options = WSUtils.defaultTableOptions();
	}
	
	for(var index = 0; index < array.length ; ) {
		
		var cellData = "";		
		
		for(var offset = 0; offset < column ; offset++) {
			
			// empty cells
			var innerCell = "";
			if(index >= array.length) {
				innerCell =	WSUtils._buildCell("");
			}
			else {
				var item = array[index];
				innerCell = WSUtils._buildCell(cellFunction(item), options.cellOptions());
			}
						
			cellData += innerCell;
			index++;			
		}
		
		var rowData = WSUtils._buildRow(cellData, options.rowOptions());	
		jQuery("#"+id).append(rowData);
	}
};

WSUtils.removeAllRows = function (id) {
	jQuery("#" + id).empty();
};

/**
 * Write a pagination string to the specified HTML element
 * @param total - the total number of records
 * @param id    - the HTML element to write the pagination string to
 * @param perPage - how many results per page
 * @param url   - URL to assign to each link. You can dynamically inject variables (like page ) into the URL
 * 				  Ex.  {page} inside the url will get replaced with the actual page number link
 * @page  page  - current page number
 * @param clickHandler - click handler for every pagination item
 * @param pageLimit? - how many pages at once (optional)  
 */
WSUtils.generatePagination = function(id, total, perPage, url, page, clickHandler, pageLimit) {

	if(StringUtils.isEmpty(id)) {
		return;
	}	
							//// declare helper methods ////
		
	// private helper
	var _applyInjections = function(url, page) {
		var newUrl = "" + url;
		if(!StringUtils.isEmpty(url)) {
			var newUrl = url.replace(/{page}/g, page);
		}	
		return newUrl;
	}
	
	// private helper
    var _writePaginationItems = function(from, to, id, page, url, clickHandler) {
	
		for(var i = from ; i <= to ; i++) {
			
			var txtNode = document.createTextNode(i + " ");   // the number
			
			var span = document.createElement('span');				
			span.setAttribute('class', 'paginationSpacer');
			
			var link = null;
			if(i == page) {
				link = document.createElement('b');					
			}
			else {
				 link = document.createElement('a');					 
				 link.setAttribute('class', 'page_' + i);					 					
				 // look for dynamically injected variables				 
				 link.setAttribute('href', _applyInjections(url, i));			 					 
				 if(clickHandler) link.onclick = clickHandler;
			}				
			link.appendChild(txtNode);
			span.appendChild(link);			
			jQuery("#"+id).append(span);								
		}	
	}
	
	// private helper
	var _createLink = function (className, url, clickHandler) {
		var link = document.createElement('a');
		link.setAttribute('class', className);					         	
		link.setAttribute('href', url);    					 
	    if(clickHandler) link.onclick = clickHandler;
	    return link;
	}
	
	// private
	var _createTextNode = function (text) {
		return document.createTextNode(text);
	}
	
	
										////// core logic /////
	
	// clean previous pagination
	jQuery("#"+id).empty();
		
	if(!pageLimit || pageLimit == 0) {
		pageLimit = 10;
	}	
	
	if(!page) page = 1;
		
	if(!url) {
		url = "#page_{page}";
	}
			
	if(!total)   total = 0;
	if(!perPage) perPage = 10;
			
	if(total > 0 && perPage > 0 && total > perPage) {
							
		var paginationItems = Math.ceil(total/perPage); 
		
		var paginationGroups = 1;
		var prevPage = 0;
		var nextPage = 0;
		
		if(paginationItems > pageLimit) {
			paginationGroups = Math.ceil(paginationItems/pageLimit);				
		}
		else {
			pageLimit = paginationItems;				
		}
					
		// keep track of limits within group			
		var groupNum = Math.ceil(page / pageLimit);			
		var upperLimit = groupNum * pageLimit;
		var lowerLimit = upperLimit - pageLimit + 1;  
		
		// adjust upperLimit
		if(upperLimit > paginationItems) {
			upperLimit = paginationItems;
		}
		
		if(page >= lowerLimit) {
			prevPage = page - 1;
			if(page < upperLimit) {
				nextPage = page - 1 + 2;
			}
			else {
				nextPage = upperLimit - 1 + 2;
			}		
		}
		else {
			prevPage = 1;
			nextPage = 2;
		}
					
		// previous link
		var prevNode = _createTextNode("<< Prev");
		var preLink = null;
		
		if(page == 1) {
			prevLink = document.createElement('b');
		}
		else {
			prevLink = _createLink('page_' + prevPage, _applyInjections(url, prevPage) , clickHandler);							
		}		
				
		_writePaginationItems(lowerLimit, upperLimit, id, page, url, clickHandler);
				
		// next link
		var nextNode = _createTextNode("Next >>");
		var link = null;
		
		if(page == paginationItems) {
			link = document.createElement('b');
		}
		else {
			link = _createLink('page_' + nextPage, _applyInjections(url, nextPage), clickHandler);				 			    				
		}
					
		if(paginationGroups > 1) {
			
			if(groupNum > 1) {
				
				// previous group link
				
				var spanPrev = document.createElement('span');				
				spanPrev.setAttribute('class', 'paginationSpacer');
				
				var prevGroupNode = _createTextNode( (lowerLimit - pageLimit) + "-" + (lowerLimit - 1) );
				var prevGroupLink = _createLink('page_' + (lowerLimit - pageLimit), _applyInjections(url, lowerLimit - pageLimit), clickHandler);
				prevGroupLink.appendChild(prevGroupNode);		
				spanPrev.appendChild(prevGroupLink);
				jQuery("#"+id).prepend(spanPrev);
			}
			
			if(groupNum < paginationGroups) {
				
				// next group link
				var upper = upperLimit + pageLimit;
				
				// adjust upper limit for next group
				if(upper > paginationItems) {
					upper = paginationItems;
				}
				
				var spanNext = document.createElement('span');				
				spanNext.setAttribute('class', 'paginationSpacer');
				
				var nextGroupNode;
				if((lowerLimit + pageLimit) == upper) {
					nextGroupNode = _createTextNode( upper );
				}
				else {
					nextGroupNode = _createTextNode( (lowerLimit + pageLimit) + "-" + upper );
				}
				 
				var nextGroupLink = _createLink('page_' + (lowerLimit + pageLimit), _applyInjections(url, lowerLimit + pageLimit), clickHandler);
				nextGroupLink.appendChild(nextGroupNode);	
				spanNext.appendChild(nextGroupLink);					
				jQuery("#"+id).append(spanNext);					
			}
		}	

		// append next link
		jQuery("#"+id).append("&nbsp;&nbsp;");
		link.appendChild(nextNode);
		jQuery("#"+id).append(link);	
		
		// prepend previous link
		prevLink.appendChild(prevNode);
		jQuery("#"+id).prepend("&nbsp;&nbsp;");
		jQuery("#"+id).prepend(prevLink);				
	}				
}


// shared private
WSUtils._buildRow = function (data, options) {
	if (options)
		return "<tr " + options + ">" + data + "</tr>";
	return "<tr>" + data + "</tr>";	
}

// private 
WSUtils._buildCell = function (data, options) {
	if (options)
		return "<td " + options + " valign='top'>" + data + "</td>";
	else
		return "<td valign='top'>" + data + "</td>";
}

WSUtils.defaultTableOptions = function() {
	return { 				
		rowOptions: function() {				    	
	    	return "";
	  	},
	  	
	  	cellOptions: function() {
	    	return "";
	  	}
	}
}

WSUtils.printMessage = function(id, message) {
	jQuery("#" + id).empty().append(message);	
}
