/**
 * Usability overlay to the table of products
 * 
 * @requires table.js (javascripttoolbox.com)
 * @requires jquery
 */
var CpoProducts = {
	/**
	 * @var DomElm
	 * Reference to the table dom element
	 */
	tableElm: null,

	/**
	 * @var object
	 * Holds a cache of the current table state
	 */
	_data: {},
	
	/**
	 * @var string
	 * Records the last sort
	 */
	_lastSortType: null,
	
	/**
	 * @var int
	 * Number of items to show per page
	 */
	_itemsPerPage: 10,
	
	/**
	 * @var string
	 * Current price filter
	 */
	_currentPriceFilter: "all", 
	
	/**
	 * @var object 
	 * Numeric index for columns used in sorting/filtering (zero-based)
	 */
	_columnIndex: {
		price: 3,
		modelNum: 4
	},
	
	/**
	 * @var array
	 * Observers
	 */
	_observers: [],
	
	/**
	 * @var object
	 * Messages that are fired at different events
	 */
	MESSAGES: {
		initialized: "Initialized",
		resultSetChanged: "Result set changed"
	},
	/*
         * @var boolean 
         * Check against this to ensure that setCurrentPage is not triggered unless we are fully loaded
         */
        loaded: false,
	/**
	 * Initialize the Cpo Products behaviour
	 * @param DomElm table element
	 */
	initialize: function(tableElm) {
		var self = CpoProducts;
		self.tableElm = tableElm;
		
		// one-off initialization
		self._initializePriceFilterControls();
		self._initializeSortingControls();
		self._initializePaginationControls();
		self._notifyObservers(self.MESSAGES.initialized);
		
		// filter with the current value
		self.setPriceFilter(CpoProducts._currentPriceFilter);
		
		// sort with the current value
		self.setSortType(CpoProducts._getSortSelector().val());
                
                self.loaded = true;
		// paginate
                // We are checking for the back button hash after a customer clicks on a product and presses the back button
                mhash = (window.location+"").match(/#(page\d)/)
                if(mhash && mhash.length ==2 ){
                  self.setCurrentPage( parseInt( mhash[1].replace(/page/, "") - 1 ) , {set_history: false});
                  //unFocus.History.addHistory( mhash[1]);
                }
                else{
                  // Default to first page
                  self.setCurrentPage(0, { set_history:  false});
                }
                self._updatePaginationControls();
	},
	
	/**
	 * Add an observer
	 * @param string
	 * @param object
	 * @param function
	 */
	addObserver: function(triggerMessage, observerObj, observerCallback) {
		var self = CpoProducts;
		self._observers.push({
			"triggerMessage": triggerMessage,
			"obj": observerObj,
			"callback": observerCallback
		});
	},
	
	/**
	 * Notify observers
	 * @param string
	 */
	_notifyObservers: function(message) {
		var self = CpoProducts;
		var observer;
		for (var i=0, length=self._observers.length; i<length; i++) {
			observer = self._observers[i];
			if (observer.triggerMessage == message) {
				observer.callback.apply(observer.obj);
			}
		}
	},
	
	/**
	 * Get range for the price filter
	 * @return object
	 */
	_getPriceFilterRange: function() {
		var self = CpoProducts;
		var filter = self._currentPriceFilter;
		var pattern = /(\d+)\-(\d+)/;
		var matches = filter.match(pattern);
		
		return (matches) ? {
			lower: parseFloat(matches[1]),
			upper: parseFloat(matches[2])
		} : null;
	},

	/**
	 * Set the price filter
	 * @param string
	 */
	setPriceFilter: function(filter) {
		var self = CpoProducts;
		self._currentPriceFilter = filter;
		self._updatePriceFilterControls();
		
		var range = self._getPriceFilterRange();
		if (range) { 
			// filter by price bucket
			Table.filter(self.tableElm, {
				filter: function(value, elm) {
					value = parseFloat(value);
					var rowElm = self._findParentRow(elm);
					var allow = self._isValueInRange(value, range.lower, range.upper);
						
					// matching recon row
					if (self._isMatchingReconRow(rowElm)) {
						rowElm.addClass("matchingrecon");
						rowElm.removeClass("visiblerecon");
						if (allow) {
							var matchingNewRow = self._findMatchingNewRow(rowElm);
							var matchingNewPrice = self._getRowPrice(matchingNewRow);
							if (self._isValueInRange(matchingNewPrice, range.lower, range.upper)) {
								// ignore the recon, whether it's in range or not
								allow = false;
							} else {
								// show the matching recon row
								rowElm.addClass("visiblerecon");
								rowElm.removeClass("matchingrecon");
							}
						}
					}
					
					return allow;
				},
				col: self._columnIndex.price
			});
		} else {
			// show all price buckets
			Table.filter(self.tableElm, {
				filter: function(value, elm) {
					var rowElm = self._findParentRow(elm);
					var allow = true;
			
					// ignore matching recon rows
					if (self._isMatchingReconRow(rowElm)) {
						rowElm.addClass("ignore");
						allow = false;
					}
					
					return allow;
				},
				col: self._columnIndex.price
			});
		}
		
		// Changing the filter should reset pagination to page 1
                // only execute if we are loaded
		if(self.loaded){ self.setCurrentPage(0); }
	},
	
	
	/**
	 * Set the type of sort to use
	 * @param string Predefined sort type
	 */
	setSortType: function(sortType) {
		var self = CpoProducts;
		if (sortType != self._lastSortType) {
			self._lastSortType = sortType;
			
			Table.sort(self.tableElm, 
				self._getSortArgs(sortType));
			
			// Changing the sorting should reset pagination to page 1
                        // Only execute if we are loaded
			if(self.loaded )
                        {
                          self.setCurrentPage(0);
			  self._notifyObservers(self.MESSAGES.resultSetChanged);
                        }
		}
	},
        current_page: 0,
	setCurrentPage: function(pageNum) {
		var self = CpoProducts;
                var opts = arguments[1] ? arguments[1] : {};
                if( !opts['set_history'] && opts['set_history']  != false ){ opts['set_history'] = true; }
		var tableElm = self.tableElm;
                var history = "";
		var args = {
		  pagesize: self._itemsPerPage
		}
		
		if (pageNum == "previous") {
		  //self._data = Table.pagePrevious(tableElm);
                  self.current_page = self.current_page > 0 ? self.current_page - 1 : 0;
                  //We determine the page, once we get our page, we add 1
                  history = "page"+(self.current_page+1);
                  self._data = Table.page(tableElm, self.current_page, args);
		}
		else if (pageNum == "next") {
                  //self._data = Table.pageNext(tableElm);
                  self.current_page = self.current_page < self._data.pagecount ? self.current_page + 1 : self._data.pagecount;
                  hpage = self.current_page < self._data.pagecount ? (self.current_page+1) : self._data.pagecount;
                  history = "page"+hpage;
                  self._data = Table.page(tableElm, self.current_page, args);
		}
		else {
                  self.current_page = pageNum;
                  history = "page"+(pageNum+1);
		  self._data = Table.page(tableElm, pageNum, args);			
		}
		
		self._updatePaginationControls();
		
		setTimeout(function() {
		  self._notifyObservers(self.MESSAGES.resultSetChanged);
		}, 500);
                // Add history entry
                if( opts['set_history'] == true ){
                  unFocus.History.addHistory(history);
                }
	},
	
	/**
	 * Get a reference to the price filter links
	 * @return jQueryElm
	 */
	_getPriceFilterLinks: function() {
		return jQuery("#narrowbypriceoptions a");
	},
	
	/**
	 * Get a reference to the sort selector
	 * @return jQueryElm
	 */
	_getSortSelector: function() {
		return jQuery("#sort-by");
	},
	
	/**
	 * Get a reference to the pagination list
	 * @return jQueryElm
	 */
	_getPaginationList: function() {
		return jQuery(".pagination");	
	},
	
	/**
	 * Initialize the behaviour for the "Narrow by Price" links
	 */
	_initializePriceFilterControls: function() {
		var self = CpoProducts;
		
		// listen for clicks on the price filter links
		self._getPriceFilterLinks().click(function(e) {
			var linkElm = this;
			var href = linkElm.href;
			var pattern = /\#price\-(\d+\-\d+|\w+)/i;
			var matches = href.match(pattern);
			
			self.setPriceFilter(matches[1] || "all");
			
			// stop the click event from continuing
			e.preventDefault();
		});
	},
	
	/**
	 * Update the "Narrow by Price" links
	 */
	_updatePriceFilterControls: function() {
		var self = CpoProducts;
		
		// highlight the selected option
		self._getPriceFilterLinks().each(function() {
			var linkElm = this;
			if (linkElm.href.indexOf("#price-" + self._currentPriceFilter) != -1) {
				jQuery(linkElm).addClass("selected");
			} else {
				jQuery(linkElm).removeClass("selected");
			}
		});
	},
	
	/**
	 * Initialize the behaviour for sort dropdown
	 */
	_initializeSortingControls: function() {
		var self = CpoProducts;
		
		// listen for a change in the sorting method
		var selectElm = self._getSortSelector();
		selectElm.bind("change", function() {
			self.setSortType(selectElm.val());
		});
	},
	
	/**
	 * Initialize the behaviour for the pagination links
	 */
	_initializePaginationControls: function() {
		var self = CpoProducts;
		
		// listen for clicks on the pagination links
		var container = self._getPaginationList();
		
		container.find(".pagelink a").click(self._doPageLinkClick);
		
		container.find(".previouspage a").click(function(e) {
			self.setCurrentPage("previous");
			e.preventDefault();
		});
		
		container.find(".nextpage a").click(function(e) {
			self.setCurrentPage("next");
			e.preventDefault();
		});
	},
	
	/**
	 * Click behaviour for page links
	 * @param event
	 */
	_doPageLinkClick: function(e) {
          
		var self = CpoProducts;
		var linkElm = jQuery(this);
                window.location = linkElm.attr("href")
              
		var newPage = parseInt(linkElm.text())-1;
		self.setCurrentPage(newPage);
		e.preventDefault();
              
	},
	/**
	 * Update the pagination controls
	 */
	_updatePaginationControls: function() {
		var self = CpoProducts;
		var data = self._data;
		var count = data.unfilteredcount || "0";
		var container = self._getPaginationList();
		var noItemsMsg = jQuery("#noproducts");
		var numContainers = container.size();
		
		// show page info
		if (count > 0) {
			container.show();
			noItemsMsg.hide();
			
			// starting item
			container.find(".startnum").html(data.pagestart);
			
			// ending item
			container.find(".endnum").html(Math.min(data.pageend, count));
			
			// total items
			container.find(".total").html(count);
			
			// plural
			var plural = container.find(".plural");
			if (count == 1) plural.hide();
			else plural.show();
		}
		// no items found, so hide the page info
		else {
			container.hide();
			noItemsMsg.show();
		}
		
		// show pagination links
		if (data.pagecount > 1) {
			container.find("li").show();
			
			// create pagination links
			for (var c=0; c < numContainers; c++) {
				var links = container.eq(c).find(".pagelink");
				var numLinks = links.size();
				var max = Math.max(numLinks, data.pagecount);
				var newLink;
				
                                // Set the default href
                                //links.eq(0).find("a").attr("href", "#page1");
				for (var i=0; i < max; i++) {
					// page link doesn't exist
					if (i >= numLinks) {
						// clone the first link
						newLink = links.eq(0).clone();
											
						// change the number
						newLink.find("a").text(i+1);
                                                
                                                //change the href
                                                //newLink.find("a").attr("href", "#page"+(i+1));
						
						// needs a whitespace after it, to match the source html
						newLink.html(newLink.html()+" ");
											
						// insert before the "Next" link
						container.eq(c).find(".nextpage").before(newLink);
						newLink.find("a").click(self._doPageLinkClick);
					}
					// redundant page
					else if (i >= data.pagecount) {
						links.eq(i).hide();
					}
					// valid page link
					else {
						links.eq(i).show();
					}
					
					/* hide all links except 4 */
					var k = data.page;
					if (i < (k-k%4) || i >= (k-k%4+4)) links.eq(i).hide();
					else links.eq(i).show();					
				}
				
				// find again, in case any new links were created
				var links = container.eq(c).find(".pagelink");
				
				// current page
				links.removeClass("current");
				links.eq(data.page).addClass("current");
			}
						
			
			// previous/next links
			var prevLink = container.find(".previouspage");
			var nextLink = container.find(".nextpage");
			
			if (data.pagecount <= 1 || data.page == 0) {
				prevLink.addClass("disabled");
			} else {
				prevLink.removeClass("disabled");
			}
			
			if (data.pagecount <= 1 || data.page == (data.pagecount-1)) {
				nextLink.addClass("disabled");
			} else {
				nextLink.removeClass("disabled");
			}
		}
		// less than two pages, so hide pagination links
		else {
			container.find("li").hide();
		}
		
		// re-assign the last-row class
		var tableElm = jQuery(self.tableElm);
		tableElm.find("tr.last-row").removeClass("last-row");
		
		var rows = tableElm.get(0).getElementsByTagName("tr");
		var i = rows.length-1;
		while (i >= 0) {
			// find the last visible row, add the class, and terminate the loop 
			if (rows[i].style.display != "none") {
				jQuery(rows[i]).addClass("last-row");
				break;
			}
			i--;
		}
	},
	
	/**
	 * Get arguments for a predefined sort
	 * @param string
	 * @return object
	 */
	_getSortArgs: function(sortType) {
		var self = CpoProducts;
		
		/**
		 * args should follow the format prescribed in table.js
		 */
		var args = {};
		
		switch(sortType) {
		case "priceHighToLow":
			args = self._getPriceSortArgs("desc");
			break;
			
		case "priceLowToHigh":
			args = self._getPriceSortArgs("asc");
			break;
			
		case "modelNum":
			args = self._getModelNumSortArgs();
			break;
		}
		
		return args;
	},
	
	/**
	 * Get arguments for a price sort
	 * @param string
	 * @return object
	 */
	_getPriceSortArgs: function(direction) {
		var self = CpoProducts;
		
		return {
			col: self._columnIndex.price,
			sorttype: Sort["currency"],
			desc: (direction == "desc")
		};
	},
	
	/**
	 * Get arguments for a model number sort
	 * @param string
	 * @return object
	 */
	_getModelNumSortArgs: function() {
		var self = CpoProducts;
		
		return {
			col: self._columnIndex.modelNum,
			sorttype: Sort["alphanumeric"],
			desc: false
		};
	},	
	
	/**
	 * Tell if a value is within a given range
	 * @param float
	 * @param float
	 * @param float
	 * @return boolean
	 */
	_isValueInRange: function(value, lower, upper) {
		return (value >= lower && value <= upper);
	},
	
	/**
	 * Find the parent row element a child element
	 * @param DomElm
	 * @return jQueryElm tr element
	 */
	_findParentRow: function(domElm) {
		return jQuery(domElm).parents("tr").eq(0);
	},
	
	/**
	 * Get the price of a row in the table
	 * @param DomElm tr element
	 * @return float
	 */
	_getRowPrice: function(rowElm) {
		var price;
		try {
			price = parseFloat(jQuery(rowElm).find("td.col-price").eq(0).text());
		} catch (e) {
			price = 0.0;
		}
		return price;
	},
	
	/**
	 * Tell if a row is a "Matching Recon" row
	 * @param DomElm tr element
	 * @return boolean 
	 */
	_isMatchingReconRow: function(rowElm) {
		return jQuery(rowElm).hasClass("matchingrecon") || jQuery(rowElm).hasClass("visiblerecon");
	},
	
	/**
	 * Find the "Matching New" row that relates to a "Matching Recon" row
	 * @param DomElm tr element
	 * @return jQueryElm
	 */
	_findMatchingNewRow: function(matchingReconRowElm) {
		var classes = jQuery(matchingReconRowElm).attr("class");
		var pattern = /\bmatches-([\w\d\-]+)\b/;
		var matches = classes.match(pattern);

		return (matches[1]) ? jQuery("#"+matches[1]) : null;
	},
        last_history: false,
        historyListener: function(){
          
          var self = CpoProducts;
          
          current_page = unFocus.History.getCurrent();
          self.logger( "Current History: "+current_page );
          if( current_page.match(/page/) ) {
            self.setCurrentPage( parseInt( current_page.replace(/page/, "") - 1 ) , { set_history:  false});
          }
          else{
            self.setCurrentPage(0 , { set_history:  false});
            /*
            if( self.last_history && self.last_history.match(/page/) ) {
              /** Do we assume that they are goig to page1 **//*
              self.setCurrentPage(0 , { set_history:  false});
            }
            else{
              self.logger("Failed to get a history hash that started with page");
            }
            */
          }
          self.last_history = current_page;
        },
        enable_logger: false,
        logger: function(s){
          var self = CpoProducts;
          if( typeof console == "object" && self.enable_logger == true){
            console.log(s)
          }
        }
        
};


// initialize when the dom is ready
jQuery(document).ready(function() {
	var tableElm = document.getElementById("resultproducts");
	CpoProducts.initialize(tableElm);
        // Disable these, all images are being loaded anyway
	Xteam.ImageLoader.initialize(tableElm);
	Xteam.ImageLoader.observe(CpoProducts, CpoProducts.MESSAGES.resultSetChanged);
        
        try{
          // init history
          unFocus.History.addEventListener('historyChange', CpoProducts.historyListener);
        }catch(e){ alert(e) }
});

