/**
* maps.js
* Handles the interactive map for the international usage Customer Service page
* Pins are added dynamically to the map based off the pins.xml file
*
* The XML file defines various pins to be displayed on the page and how they are displayed
* including: pin color, visibility, countries associated with a pin, pin coordinates, and it's z-index
*
* @author dgalarza (dgalarza@mcdpartners.com)
*/

(function () {
	
	var map = {
		
		//Find what we need up front
		container : document.getElementById('international-map'),
		pinContainer : document.getElementById('pin-list'),
		tooltipContent : document.getElementById('tooltip-content'),
		tooltip : document.getElementById('map-tooltip'),
			
		//Store our AJAX Request here
		request : null,
		
		//Hold our pins here, this will be populated via the XML file
		pins : {},
		
		//Hold our processing status here
		status : 0,
		
		//Status Timeout checker
		timeout : null,
		
		//Hold our maximum number of rows of data displayed in the tooltip, set via XML
		maxRows : 0,
		
		/*
		* Set everything up
		*/
		init : function () {
			//Display the container (non-javascript user's will not see this map)
			mcd.dom.removeClass(map.container, 'hide');		
			
			//Call out status checking method to monitor the status of our map, hiding the throbber when ready
			map.statusCheck();
			
			//Fetch our XML feed
			map.fetchXML();
		},
		
		/**
		* Set up our XHR for the pins XML file, parsing it once
		* it's finished loading.
		*/
		fetchXML : function () {
			map.request = mcd.http.request({
				'method' : 'GET',
				'uri' : '/customer-service/account/xml/pins.xml',
				'onreadystatechange' : map.ajaxResponse
			});
			
			map.request.send('');
		},
		
		/**
		* Handles the AJAX ReadyStateChange
		*/
		ajaxResponse : function () {
			var request = map.request;
			if(request.readyState == 4) {			
				if(request.status !== 200) map.setError();
				else map.parseResponse(request.responseXML);
			}
		},
		
		/**
		* Reads through the XML file returned from the server and
		* parse all the pins into a javascript object for easy access later,
		* eliminate any pins that have their visible attribute set to false
		* 
		* @param {AJAX Response} XML
		*/
		parseResponse : function (pinsXML) {
			var pinObj = map.pins;
			var pins = pinsXML.getElementsByTagName('pin');
			
			var mapNode = pinsXML.getElementsByTagName('map')[0];
			map.maxRows = parseInt(mapNode.getAttribute('maxrows')) || 4;
			
			//Loop through each pin found in the XML file and set its attributes
			for(var i=0; i<pins.length; i++) {
				var _thisPin = pins[i];
					
				//If the pin is set to visible, set its properties, if not we'll skip it.
				if(_thisPin.getAttribute('visible') === 'true') {
				
					//Define our new pin object using the XML properties
					var pin = {
						'id'	 	: _thisPin.getAttribute('id'),
						'uri' 	 	: _thisPin.getAttribute('uri'),
						'color'  	: _thisPin.getAttribute('color'),
						'zindex' 	: parseInt(_thisPin.getAttribute('zindex')) || parseInt(_thisPin.getAttribute('piny')), 
						'xCoord' 	: parseInt(_thisPin.getAttribute('pinx')),
						'yCoord' 	: parseInt(_thisPin.getAttribute('piny')),
						'countries' : new Array()
					};
															
					//Establish the pin's countries for the tooltip
					var pinCountries = _thisPin.getElementsByTagName('country');
					for(var y=0; y<pinCountries.length;y++) {
						var _thisCountry = pinCountries[y];
						var countryName = map.getAttrValue(_thisCountry.attributes[0]);
						pin.countries.push(countryName);
					}
					
					var pinName = pin.id;
					pinObj[pinName] = pin;					
				}
			}

			//Once we're done parsing the pins, place them on the map
			map.mapPins();
		},
		
		/**
		* Return the value of an XML node's attribute by browser type
		* IE: node.text & Firefox etc node.nodeValue
		*
		* @param {XMLElement Attribute}
		* @return Attribute Contents
		*/
		getAttrValue : function(node) {
			if(node.nodeValue === null) return node.text;
			else return node.nodeValue;
		},
		
		/**
		* Iterate through all the pins that were found in the XML and display them on the page
		*/
		mapPins : function () {
			var pins = map.pins;
			
			/*
			* Create a document fragment where we can append each pin to so that
			* we can just push all the pins at once to the list rather than one at a time
			*/
			var pinFrag = document.createDocumentFragment();
			mcd.util.each(pins, function(_thisPin){
				var pin = pinFactory.createPin(_thisPin);
				pinFrag.appendChild(pin);
			});
			
			map.pinContainer.appendChild(pinFrag);
			map.status = 1;
		},
		
		/**
		* Our timeout function callback, checks to see if the map is finished intializing
		* to hide the throbber and display the map
		*/
		statusCheck : function () {
			if(map.status === 0) map.timeout = window.setTimeout(map.statusCheck, 500);
			else map.hideThrobber();	
		},
		
		/**
		* Reuseable function for hiding the map's throbber
		*/
		hideThrobber : function () {
			var throbber = document.getElementById('map-throbber');
			mcd.dom.addClass(throbber, 'hide');
		},
		
		/**
		* Display the error state for the map if an ajax error ocurrs
		*/
		setError : function () {
			//Clear our status timeout interval
			clearInterval(map.timeout);
			
			var eContainer = document.getElementById('map-error');
			mcd.dom.removeClass(eContainer, 'hide');
			
			map.hideThrobber();
		}
		
	};
	
	var pinFactory = {
		
		/**
		* Create a pin HTML element on the page from the pin data provided
		*
		* @param {Object} Representation of a pin on the map
		* @return {HTMLElement} Return a list item for the pin
		*/
		createPin : function (pinData) {
			//Create the pin and set it's base settings (color, id, pin class)
			var pin = document.createElement('li');
			mcd.dom.addClass(pin, 'pin');
			mcd.dom.addClass(pin, pinData.color + '-pin');
			pin.id = pinData.id;
			pin.style.zIndex = pinData.zindex;
			
			//Set the pin's position on the map
			var position = new Array(pinData.xCoord, pinData.yCoord);			
			mcd.dom.setPosition(pin, position);
			
			//The pin's top is represented as an anchor, set up the top with hover events
			var pinTop = document.createElement('a');
			pinTop.href = pinData.uri;
			mcd.dom.addClass(pinTop, 'pin-top');
			mcd.event.add(pinTop, 'mouseover', pinFactory.pinHover);
			mcd.event.add(pinTop, 'mouseout', pinFactory.pinOut);
			
			//Create the pin body
			var pinBody = document.createElement('span');
			mcd.dom.addClass(pinBody, 'pin-body');

			//Append pin pieces to list item and return the pin
			pin.appendChild(pinTop);
			pin.appendChild(pinBody);	
			return pin;
		},
		
		/**
		* Our pin's rollover functionality here, calling the tooltip to be displayed
		* after updating the tooltip's position and content appropriately for this pin
		*
		* @param {Event}
		*/
		pinHover : function (e) {
			//Bring the tooltip back in flow but still hidden(IE )
			mcd.dom.removeClass(map.tooltip, 'hide');
			
			mcd.event.preventDefault(e);
			var target = mcd.event.getTarget(e);
			var pin = target.parentNode;
			var pinID = pin.id;
			var _thisPin = map.pins[pinID];
						
			//Update the content inside the pin
			pinFactory.updateTooltip(_thisPin);
			
			//Find the tooltip's coordinates for this pin specified by the XML file and position it 
			tooltip.updateSize();
			pinFactory.setTooltipPosition(_thisPin.xCoord, _thisPin.yCoord)
			
			
			//Work around IE's visibility: hidden with position: absolute issue
			mcd.dom.removeClass(map.tooltip, 'invisible');
			map.tooltip.style.position = 'absolute';
		},
		
		/**
		* Our pin's rollout functionality here, simply hide the tooltip on mouseout
		*
		* @param {Event}
		*/
		pinOut : function (e) {
			mcd.event.preventDefault(e);		
			
			//Work around IE's visibility: hidden wth position: absolute issue
			map.tooltip.style.position = 'relative';			
			mcd.dom.addClass(map.tooltip, 'invisible');			
			mcd.dom.addClass(map.tooltip, 'hide');
			
			//Reset the position of the tooltip to work around IE positioning issue
			map.tooltip.style.left = 0;
		},
		
		/**
		* Update the tooltip's position based of the pin's position
		* and the height of the tooltip
		* 
		* @param {Int} X Coord
		* @param {Int} Y Coord
		*/
		setTooltipPosition : function (x, y) {
			var x = x + 23;
			
			/*
			* Offset the tooltip from the pin, half the height of the
			* tooltip, and plus 10 more pixels
			*/
			var height = tooltip.body.offsetHeight;								
			var y = y - (height / 2) + 3;
			
			mcd.dom.setPosition(map.tooltip, new Array(x, y));
		},
		
		/**
		* For the provided pin, iterate through all countries that are to
		* be displayed for this pin and push them to an unordered list which
		* will then be added to the overlay
		*
		* @param {Object} Pin object 
		*/
		updateTooltip : function (pin) {
			var countryFrag = document.createDocumentFragment();
			var countries = pin.countries;
			var list = null;
			var colCount = 0;
			
			//Reset the tooltip's content
			map.tooltipContent.innerHTML = '';
			tooltip.body.style.width = '';
					
			//Loop through all of the countries in the array for this pin
			for(var i=0; i<countries.length; i++) {
				
				var _thisCountry = countries[i];
				var li = document.createElement('li');
				var content = document.createTextNode(_thisCountry);
				
				li.appendChild(content);
				
				//Every four entries, create a new column
				if( i % map.maxRows === 0 ){
					if(list !== null) countryFrag.appendChild(list);
					list = document.createElement('ul');
					colCount++;
				}
				
				list.appendChild(li);
			}
			
			countryFrag.appendChild(list);
			map.tooltipContent.appendChild(countryFrag);
			tooltip.updateSize();
			
		}		
		
	};
	
	var tooltip = {
		
		//Store references to various tooltip parts
		body : mcd.dom.getElementsByAttribute('class', 'body', map.tooltip, 'div', true)[0],
		top : mcd.dom.getElementsByAttribute('class', 'top-repeat', map.tooltip, 'div', true)[0],
		right : mcd.dom.getElementsByAttribute('class', 'tooltip-right', map.tooltip, 'div', true)[0],
		bottom : mcd.dom.getElementsByAttribute('class', 'btm-repeat', map.tooltip, 'div', true)[0],
		tail : mcd.dom.getElementsByAttribute('class', 'tooltip-tail', map.tooltip, 'div',  true)[0],
		
		updateSize : function () {
			var bWidth = tooltip.body.offsetWidth;
			var bHeight = tooltip.body.offsetHeight;
			
			tooltip.top.style.width = bWidth - 9 + 'px';
			tooltip.bottom.style.width = bWidth - 9 + 'px';
			tooltip.body.style.width = bWidth + 7 + 'px';	
		}
			
	};
	
	//Ready? Go!
	mcd.dom.ready(function () {
		map.init();
	});
	
})();