/*
	Depends on JQuery version 1.5+
*/

var qmatic = qmatic || {};

(function($) {

	var errors = {
			illegalArgument : "Illegal argument"
		},
		SLIDE_DOWN_SPEED = 700;
		
		
	/*
	 * Call history component which displays a list of called tickets.
	 * Attached to public qmatic namespace
	 */
	qmatic.CallHistory = (function() {
		// private statics		
		var LIST_MAIN_CLASS = 'history-list',
	    	FOOTER_MASK_CLASS = 'history-footer-mask',
	    	HEADER_MASK_CLASS = 'history-header-mask',
 		   	DEFAULT_ENTRY_ADD_DELAY = 700; // number of milliseconds before processing next item from the queue
		
		// public
		var constructor = function(config) {
			var listElem,
				entryPane,
				entryPusher,
				footerMask,
				headerMask;
				
					
			if (config === undefined || config.id === undefined || config.id === '') {
				throw new Error(errors.illegalArgument);
			}
			
			this._p = {
				listElem: $('#' + config.id),
				entryHeight: config.entryHeight || DEFAULT_ENTRY_HEIGHT,
				entries: [],
				entryQueue: [],
				processingQueue: false,
				ticketsMax: parseInt(config.ticketsMax,10),
				ticketsFade: parseInt(config.ticketsFade,10)
			};
			
			var priv = this._p;

			listElem = priv.listElem;
			listElem.addClass(LIST_MAIN_CLASS);
			listElem.empty();
			
			if (config.backgroundColor) {
				listElem.css('background-color', config.backgroundColor);
			}
			
			// entryPane is where all entries are added. Some hidden room is left at the top to add new items there
			// and push them down to create the effect that the new item is pushed down from the top, causing all
			// existing items to be pushed down.
			entryPane = $('<div style="position: relative; top: -' + priv.entryHeight + ';"/>');
			listElem.append(entryPane);
			priv.entryPane = entryPane;
			
			// The element that pushes down items from the top to make it seem as items are pushed down
			entryPusher = $('<div/>').css('height', priv.entryHeight);
			entryPane.append(entryPusher);
			priv.entryPusher = entryPusher;
			this._resetEntryPusher();
			
			headerMask = $('<div/>').addClass(HEADER_MASK_CLASS);
			listElem.append(headerMask); 
			
			footerMask = $('<div/>').addClass(FOOTER_MASK_CLASS).css('top', listElem.innerHeight() - 9);
			listElem.append(footerMask);
		};
		
		constructor.prototype = {
		
			addEntry : function(config) {
				if (config === undefined) {
					throw new Error(errors.illegalArgument);
				}
				
				var priv = this._p;
				var newEntry = new HistoryEntry(config);
				
				if(priv.ticketsMax > 0 && priv.entries.length >= priv.ticketsMax) {
				  priv.entries.shift().getElement().fadeOut(priv.ticketsFade, function() { $(this).remove(); });
				}

				priv.entryQueue.push(newEntry);
				this._processEntryQueue();
			},
		
			clean : function() {
				var entries = this._p.entries;
				for (var index = 0, total = entries.length; index < total; index++) {
					entries[index].clean();
				}
			},

			/**
			 * Register to this callback to get a chance to manipulate the entry element before it is processed.
			 * Provided with one parameter which is the DOM element that will be presented to users.
			 */
			onBeforeShowEntry : undefined,
			
			// private
			_processEntryQueue : function() {
				var priv = this._p,
					theEntry,
					self = this;
					
				if (priv.entryQueue.length > 0 && !priv.processingQueue) {
					priv.processingQueue = true;
					theEntry = priv.entryQueue.shift();
					priv.entries.push(theEntry);
					
					// add the new entry after the pusher element, both still hidden above the visible entry pane, and then let the
					// entryPusher element grow in height to push the new element down and into the user's view.
					self._resetEntryPusher();
					priv.entryPusher.after(theEntry.getElement());

					if (this.onBeforeShowEntry) {
						this.onBeforeShowEntry(theEntry.getElement(), theEntry.getIsCustomerName());
					}
					
					priv.entryPusher.slideDown(SLIDE_DOWN_SPEED, null, function() {
						self._cullEntries();
						if (priv.entryQueue.length > 0) {
							setTimeout(function() {
								self._processEntryQueue();
							}, DEFAULT_ENTRY_ADD_DELAY);
						}
						priv.processingQueue = false;
					});
				}
			},
			
			// private
			_resetEntryPusher : function() {
				this._p.entryPusher.hide();
			},
			
			// private
			_cullEntries : function() {
				// remove oldest entry which is no longer visible
				var priv = this._p,
					parentHeight = priv.listElem.innerHeight(),
					entry;
				
				if (priv.entries.length > 0) {
					entry = priv.entries[0];
					if (entry.getElement().offset().top > parentHeight) {
						priv.entries.shift().getElement().remove();
					}
				}
			}
			
		};
		
		return constructor;

	})();


	/*
		Represents an entry in the list of called tickets.
		config = {
			html: string, // The html to display on the ticket call entry
			ticketBackgroundColor : string, // Color for ticket's background
			ticketTextColor : string, // Color for ticket text
		};
	*/
    var HistoryEntry = (function() {
    	
    	var ENTRY_MAIN_CLASS = 'history-entry',
    		DEFAULT_ENTRY_HEIGHT = '120px';

		var constructor = function(config) {
			this._p = {};	
			var entryElem = $('<div/>');
			entryElem.addClass(ENTRY_MAIN_CLASS);
			entryElem.append(config.html);
			
			this._p.theElem = entryElem;
			this._p.isCustomerName = config.isCustomerName;
		};
		
		constructor.prototype = {

			getElement : function() {
				return this._p.theElem;		
			},
			
			getIsCustomerName : function() {
				return this._p.isCustomerName;		
			},
			
			clean : function() {
				this._p.theElem.remove();
			}
		
		};
				
		return constructor;

	})();
	

})(jQuery);

