// If the dependencies are not found, throw an exception
if (typeof mcd === undefined || !mcd.dom || !mcd.event) {
	throw 'Can\'t initialize discover.liveSearch. mcd.dom and mcd.event are required dependencies';
}

// If the discover namespace doesn't exists, create it
if (typeof discover === 'undefined') {
	var discover = {};
}

/**
 * The Discover Live Search API
 * 
 * @requires mcd.dom
 * @requires mcd.event
 * @author Michael Girouard (mgirouard@mcdpartners.com)
 */
discover.liveSearch = (function () {
	
	// ========================================================================
	// ===== Private API  =====================================================
	// ========================================================================
	
	/**
	 * Black-listed pages which live search is NOT allowed on
	 * 
	 * @type {Array}
	 * @private
	 */
	var pageBlackList = [
		'/search/results-advanced.html', 
		'/search/results-tips.html'
	];

	/**
	 * Callback timeout reference
	 * @private
	 * @type {Integer}
	 */
	var requestTimeout = null;
	
	var lastQuery = '';	
	
	/**
	 * Checks to see if a document is blacklisted
	 * 
	 * @param {String} path
	 * @return {Boolean}
	 */
	var isBlackListed = function (path) {
		var delim = '|';
		return (delim + pageBlackList.join('|') + delim).indexOf(delim + path + delim) > -1;
	}

	/**
	 * The Callback which performs the search
	 * @private
	 */
	var queryTimeoutCallback = function () {
		if (discover.liveSearch.elements.searchBox.value.length >= 1)
		{
			discover.liveSearch.query(discover.liveSearch.elements.searchBox.value);
		}
		else
		{
			clearResults();			
		}
	};
	
	/**
	 * Cancels a search
	 */
	var cancelTimeoutCallback = function () {
		if (requestTimeout !== null) {
			window.clearTimeout(requestTimeout);
		}
	};

	/**
	 * Parses a response and delegates the page update
	 * 
	 * @param {mixed} responseData
	 */	 
	var parseResponse = function (responseData) {		
		var listItems;
		
		/* XML Response */
		if (responseData.childNodes) {
			listItems = getResultsFromXML(responseData);			
			appendResults(listItems);
		}		
		/* JSON Response */
		else if (responseData.constructor === Object) {
			listItems = getResultsFromJSON(responseData);
			appendResults(listItems);
		}
		/* String Response (Sets innerHTML) */
		else if (responseData.constructor === String) {
			discover.liveSearch.elements.searchResults.getElementsByTagName('ul')[0].innerHTML = responseData;
		}
	};

	/**
	 * Returns a template collection which can be appended into the DOM
	 * 
	 * @return {HTMLElement}
	 */
	var getTemplateCollection = function () {
		var collection, title, list;

		/* Create the Nodes */
		collection = document.createElement('li');
		title      = document.createElement('h3');
		list       = document.createElement('ul');

		/* Build the Structure */
		collection.className = 'category';
		collection.appendChild(title);
		collection.appendChild(list);
		
		/* collection, title, and list are now available via closure. We simply
		 * need to deep clone the collection each time we need to add another
		 * collection to the results stack. */
		return function () {
			var out = {};
			
			out.nodes = collection.cloneNode(true);
			out.title = out.nodes.getElementsByTagName('h3')[0];
			out.list  = out.nodes.getElementsByTagName('ul')[0];
			
			return out;
		};
	}();

	/**
	 * Parses a response and delegates the page update
	 * @param {String} responseData
	 */	 
	var parseResponseXML = function (responseData) {		
		var listItems;
		/* XML Response */
		listItems = getResultsFromXML(responseData);			
		appendResults(listItems);
	};

	
	/**
	 * Returns a template result item which can be appended into the DOM
	 * 
	 * @return {HTMLElement}
	 */
	var getTemplateItem = function () {
		var item, imageAnchor, image, title, titleAnchor, description, descriptionAnchor;

		/* Create the nodes */
		item              = document.createElement('li');
		imageAnchor       = document.createElement('a');
		titleAnchor       = document.createElement('a');
		descriptionAnchor = document.createElement('a');
		image             = document.createElement('img');
		title             = document.createElement('h4');
		description       = document.createElement('p');

		/* Build the structure */
		imageAnchor.appendChild(image);
		title.appendChild(titleAnchor);
		description.appendChild(descriptionAnchor);
		
		item.className = 'item';
		item.appendChild(imageAnchor);
		item.appendChild(title);
		item.appendChild(description);

		return function () {
			var out = {};
			
			out.nodes       = item.cloneNode(true);
			out.anchors     = out.nodes.getElementsByTagName('a');
			out.title       = out.anchors[1];
			out.image       = out.nodes.getElementsByTagName('img')[0];
			out.description = out.anchors[2];			
			return out;
		};
	}();

	/**
	 * Appends elements to the search results list
	 * 
	 * @param {Array} results
	 */
	var appendResults = function (results) {
		var i;
		clearResults();
		for (i = 0; i < results.length; i++) {
			discover.liveSearch.elements.searchResults.getElementsByTagName('ul')[0].appendChild(results[i]);
		}		
		
		document.getElementById('view-all-results')
            .getElementsByTagName('a')[0]
            .setAttribute(
                'href', 
                'http://search.discovercard.com/search?q=' + 
                lastQuery +
                '&site=internet_cm_corp&client=internet_cm_fe&output=xml_no_dtd&proxystylesheet=internet_cm_fe' +
				'&gcmpgn=0811_ZZ_sro_all_txt' //VS tagging
            );
		
		if( results.length > 0)
		{
			mcd.dom.removeClass('view-all-results', 'hide');
			mcd.dom.removeClass('search-results', 'hide');
		}
		
		
	};

	/**
	 * Returns an array of html collections from JSON data
	 * 
	 * @param  {Object} json
	 * @return {Array}
	 */

	var getResultsFromJSON = function (json) {
		var collectionName, collection, itemName, item;
		var out = [];

		for (collectionName in json.results) {
			collection = getTemplateCollection();
			collection.title.innerHTML = collectionName;
			
			for (itemName in json.results[collectionName]) {
				item = getTemplateItem();

				item.title.innerHTML = itemName;
				item.description.innerHTML = json.results[collectionName][itemName].description;
				item.image.src = json.results[collectionName][itemName].image;
				item.anchors[0].href =
					item.anchors[1].href =
					item.anchors[2].href = json.results[collectionName][itemName].href;
				collection.list.appendChild(item.nodes);
			}

			out.push(collection.nodes);
		}

		return out;
	};

	/**
	 * Returns an array of html collections from XML data
	 * 
	 * @param  {XML} json
	 * @return {Array}
	 */
	 //sgoff0 see if there is a way to limit the returned list to X results
	var getResultsFromXML = function (xml) {
		var collection, results, item;

		var out = [];
		var collections = xml.getElementsByTagName('collection');
		var displayedCollections = collections.length;
		if (displayedCollections > 3)
		{
			displayedCollections = 3;
		}
		var dd;
		for (var i = 0; i < displayedCollections; i++) {
			collection = getTemplateCollection();
			var escapedCollectionName = escape(collections[i].getAttribute('name'));
			collection.title.innerHTML = collections[i].getAttribute('name');
			out.push(collection.nodes);
			
			results = collections[i].getElementsByTagName('result');	
			var displayedResults = results.length;			
			
			if (displayedCollections == 2 && displayedResults > 3)
			{
				displayedResults = 3;
			}
			else if (displayedCollections == 3 && displayedResults > 2)
			{			
				displayedResults = 2;
			}			
			dd = 0;
			for (var j = 0; j < displayedResults; j++) {
				dd++;
				var ddPadded = (dd < 10) ? "0" + dd :  dd;

				item = getTemplateItem();				
				item.title.innerHTML = results[j].getElementsByTagName('title')[0].childNodes[0].nodeValue;
				item.description.innerHTML = results[j].getElementsByTagName('description')[0].childNodes[0].nodeValue;
				item.image.src = results[j].getAttribute('image');	//good
				item.anchors[0].href = results[j].getAttribute('href') + '_ZZ_sro_' + ddPadded + '_img&category=' + escapedCollectionName;
					item.anchors[1].href = 
					item.anchors[2].href = results[j].getAttribute('href') + '_ZZ_sro_' + ddPadded + '_txt&category=' + escapedCollectionName;	//good
				collection.list.appendChild(item.nodes);				
			}
		}

		return out;
	};

	/**
	 * Clears the search results list
	 */
	var clearResults = function () {
		var resultList = discover.liveSearch.elements.searchResults.getElementsByTagName('ul')[0];

		while (resultList.firstChild) {
			resultList.removeChild(resultList.firstChild);
		}
		
		mcd.dom.addClass('view-all-results', 'hide');
		mcd.dom.addClass('search-results', 'hide');
	};

	/**
	 * Generates a cross-browser request object
	 * 
	 * Note the self-invoking method
	 * 
	 * @return {XMLHttpRequest|ActiveXObject}
	 */
	var getRequestObject = function () {
		if (window.XMLHttpRequest) {
			return function () {
				return new XMLHttpRequest;
			};
		}
		else if (window.ActiveXObject) {
			return function () {
				try {
					return new ActiveXObject('Microsoft.XMLHTTP');
				}
				catch (e) {
					try {
						return new ActiveXObject('Msxml2.XMLHTTP');
					}
					catch (e) {
						try {
							return new ActiveXObject('Msxml3.XMLHTTP');
						}
						catch (e) {}
					}
				}
			};
		}
	}();

	/**
	 * An XHR Instance
	 * 
	 * @type {XMLHttpRequest|ActiveXObject}
	 */
	var request;

	/**
	 * Callback for readystatechange
	 */
	var requestCallback = function () {
		if (request.readyState !== 4) {
			return;
		}
		alert("hi");
		var contentType = request.getResponseHeader('Content-type');

		// We have to match against a regex because IE adds charset data
		if (contentType.match(/^text\/xml/)) {
			//alert(request.responseXML);
			parseResponse(request.responseXML);
		}
		else if (contentType.match(/^text\/html/)) {
			parseResponse(request.responseText);
		}
		else if (contentType.match(/^application\/x\-javascript/)) {
			eval('var json = ' + request.responseText)
			parseResponse(json);
		}
	};

	/**
	 * Sends an XHR
	 * 
	 * @param {String} term
	 * @param {String} format
	 */
	var sendRequest = function (term, format) {
		var endPoint;

		format = format || discover.liveSearch.outputFormat;
		endPoint = discover.liveSearch.endPoint + '?output=' + format + '&q=' + escape(term);

		var oScript = document.createElement("script");
		oScript.src = endPoint;
        document.body.appendChild(oScript);		
		
	};	

	// ========================================================================
	// ===== Public API  ======================================================
	// ========================================================================

	var liveSearch = {
		/**
		 * The live-search endpoint
		 * @type {String}
		 */

		'endPoint' : 'https://www.discovercard.com/cardmembersvcs/searchasyoutype/livesearch/SAYT',
		
		/**
		 * The default value in the search box
		 * @type {String}
		 */
		'defaultValue' : '',
		
		/**
		 * The preferred output format from the service
		 */
		'outputFormat' : 'json',

		/**
		 * Named element shortcuts
		 * @type {Object}
		 */
		'elements' : {
			'searchBox'     : 'searchbox',
			'clearSearch'   : 'clear-livesearch',
			'searchResults' : 'search-results'
		},

		/**
		* for the callback function which is set to do XML
		* sgoff0
		*/
		
		'callback' : function (xmlString) {
			try //Internet Explorer
			{
				xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
				xmlDoc.async="false";
				xmlDoc.loadXML(xmlString);
				parseResponseXML(xmlDoc);
			}
			catch(e)
			{
				try //Firefox, Mozilla, Opera, etc.
				{
					parser=new DOMParser();
					xmlDoc=parser.parseFromString(xmlString,"text/xml");
					parseResponseXML(xmlDoc);
				}
				catch(e) {alert(e.message)}
			}
		},
				
		/**
		 * The main query method
		 * @return {Object}
		 */
		'query' : function (term) {
		    lastQuery = term;
			sendRequest(term);
			return;
		},

		/**
		 * Clears the search box and cancels any active search in queue
		 */
		'clearSearch' : function () {
			mcd.dom.addClass(this.elements.clearSearch, 'hide');
			mcd.dom.addClass(this.elements.searchResults, 'hide');

			cancelTimeoutCallback();

			this.elements.searchBox.value = this.defaultValue;

			clearResults();
		}
	};

	// ========================================================================
	// ===== Initialization Routine ===========================================
	// ========================================================================
	
	mcd.dom.ready(function () {
		
		var i, defaultValue, searchWrap, searchResults, ul, p, a;
		
		var elements = discover.liveSearch.elements;
		
		var searchContainer = document.getElementById('header');
		
		/* Fail fast, if possible
		 * 	- If the page is blacklisted
		 *  - If the searchContainer was not found */
		if (isBlackListed(document.location.pathname) || !searchContainer) {
			return;
		}
		
		/* Set up the results container */
		
		searchWrap = document.createElement('div');
		searchResults = document.createElement('div');
		ul = document.createElement('ul');
		p = document.createElement('div');
		a = document.createElement('a');
		
		p.id = 'view-all-results';
		p.appendChild(a);
		
		a.href='#';
		a.appendChild(document.createTextNode('View All Search Results'));

		searchWrap.id = 'search-wrap';
		searchWrap.appendChild(searchResults);
		
		searchResults.id = 'search-results';
		mcd.dom.addClass(searchResults, 'hide')
		searchResults.appendChild(ul);
		searchResults.appendChild(p);
		searchContainer.appendChild(searchWrap);			
		
		//Position the search results beneath the search box.
        var search_box_position = mcd.dom.getPosition(elements.searchBox);
        var container_position = mcd.dom.getPosition("container");
        var target_x = search_box_position[0] - container_position[0];

        // This would align the menu to the left edge of the search box.
        // No idea why there needs to be a 10px adjustment
        // target_x -= 10

        // This aligns the menu to the right edge of the search box
        target_x -= 42;


        searchResults.style.left = target_x + 'px';

		/* Create element references */
		for (i in elements) {
			elements[i] = mcd.dom.getElement(elements[i]);
			if (elements[i] === null) return;
		}

		/* Apply the autocomplete=off attribute */
		elements.searchBox.setAttribute('autocomplete', 'off');

		/* Set the default search value */
		defaultValue = discover.liveSearch.defaultValue;

		/* Apply a click event for canceling the search */
		mcd.event.add(elements.clearSearch, 'click', function (event) {
			mcd.event.preventDefault(event);
			discover.liveSearch.clearSearch();
		});

		/* Apply focus event */
		mcd.event.add(elements.searchBox, 'focus', function () {
			if (this.value == defaultValue) {
				this.value = '';
			}
			else {
				this.select();
			}
		});

		/* Apply blur event */
		mcd.event.add(elements.searchBox, 'blur', function () {
			if (this.value == '') {
				this.value = defaultValue;
			}
		});

		/* Apply the keyup event */
		mcd.event.add(elements.searchBox, 'keyup', function (event) {
			if (!discover.liveSearch.endPoint) {
				return;
			}

			var clearSearch   = discover.liveSearch.elements.clearSearch,
				searchBox     = discover.liveSearch.elements.searchBox,
				searchResults = discover.liveSearch.elements.searchResults;

			cancelTimeoutCallback();

			if (searchBox.value !== '') {
				mcd.dom.removeClass(clearSearch, 'hide');	// x button
				//mcd.dom.removeClass(searchResults, 'hide');	// menu content box
			}
			else {
				mcd.dom.addClass(clearSearch, 'hide');
			}

			if (event.keyCode !== 27) {
				requestTimeout = window.setTimeout(queryTimeoutCallback, 200);
			}
			else {
				discover.liveSearch.clearSearch();
			}
		});
	});

	return liveSearch;
})();


