/**
 * IHT.com 
 * Script for Google Maps (August 2007)
 * Display the article's location on Google Maps and adds search function to IHT.com based on that location.  
 */

//create the LittleInfoWindow overlay onject
function LittleInfoWindow(marker,html,width) {
	this.html_ = html;
	this.width_ = ( width ? width + 'px' : 'auto');
	this.marker_ = marker;
}

//use the GOverlay class
LittleInfoWindow.prototype = new GOverlay();

//initialize the container and shadowContainer
LittleInfoWindow.prototype.initialize = function(map) {
	this.map_ = map;
	var container = document.createElement("div");
	container.style.display='none';
	map.getPane(G_MAP_FLOAT_PANE).appendChild(container);
	this.container_ = container;

	/*var shadowContainer = document.createElement("div");
	shadowContainer.style.display='none';
	map.getPane(G_MAP_FLOAT_SHADOW_PANE).appendChild(shadowContainer);
	this.shadowContainer_ = shadowContainer;*/
}

LittleInfoWindow.prototype.remove = function() {
	this.container_.parentNode.removeChild(this.container_);
	//don't forget to remove the shadow as well
	//this.shadowContainer_.parentNode.removeChild(this.shadowContainer_);
}

LittleInfoWindow.prototype.copy = function() {
	return new LittleInfoWindow(this.marker_,this.html_,this.width_);
}

LittleInfoWindow.prototype.redraw = function(force) {
	if (!force) return;

	//get the content div
	var content = document.createElement("span");
	content.innerHTML = this.html_;
	content.style.font='bold 11px Arial';
	content.style.margin='0';
	content.style.padding='0';
	content.style.border='0';
	content.style.display='inline';

	if(!this.width_ || this.width_=='auto' || this.width_ <= 0) {
		//the width is unknown so set arough maximum and minimum
		content.style.minWidth = '10px';
		content.style.maxWidth = '300px';
		content.style.width = 'auto';
	} else {
		//the width was set when creating the window
		content.style.width= width + 'px';
	}

	//make it invisible for now
	content.style.visibility='hidden';

	//temporarily append the content to the map container
	this.map_.getContainer().appendChild(content);

	//retrieve the rendered width and height
	var contentWidth = content.offsetWidth;
	var contentHeight = content.offsetHeight;

	//remove the content from the map
	content.parentNode.removeChild(content);
	content.style.visibility='visible';

	//set the width and height to ensure they
	//stay that size when drawn again
	content.style.width=contentWidth+'px';
	content.style.height=contentHeight+'px';

	//set up the actual position relative to your images
	content.style.position='absolute';
	content.style.left='7px';
	content.style.top='7px';
	content.style.background='white';

	//create the wrapper for the window
	var wrapper = document.createElement("div");

	//first append the content so the wrapper is above
	wrapper.appendChild(content);

	//create an object to reference each image
	var wrapperParts = {
		tl:{l:0, t:0, w:7, h:7},
		t:{l:7, t:0, w:(contentWidth-1), h:7},
		tr:{l:(contentWidth+6), t:0, w:8, h:7},
		l:{l:0, t:7, w:7, h:contentHeight},
		r:{l:(contentWidth+6), t:7, w:8, h:(contentHeight)},
		bl:{l:0, t:(contentHeight+7), w:7, h:8},
		p:{l:7, t:(contentHeight+7), w:8, h:12},
		b:{l:15, t:(contentHeight+7), w:(contentWidth-9), h:8},
		br:{l:(contentWidth+6), t:(contentHeight+7), w:8, h:8}
	}

	//create the image DOM objects
	for (i in wrapperParts) {
		var img = document.createElement('img');
		//load the image from your local image directory
		//based on the property name of the wrapperParts object
		img.src = 'http://img.iht.com/images/article/gmap/' + i + '.png';
		//set the appropriate positioning attributes
		img.style.position='absolute';
		img.style.top=wrapperParts[i].t+'px';
		img.style.left=wrapperParts[i].l+'px';
		img.style.width=wrapperParts[i].w+'px';
		img.style.height=wrapperParts[i].h+'px';
		wrapper.appendChild(img);
		wrapperParts[i].img = img;
	}

	//add any event handlers like the close box
	var marker = this.marker_;
	GEvent.addDomListener(wrapperParts.tr.img, "click", function() {
		marker.closeLittleInfoWindow();
	});

	//get the X,Y pixel location of the marker
	var pixelLocation = this.map_.fromLatLngToDivPixel(
	this.marker_.getPoint()
	);

	//position the container div for the window
	this.container_.style.position='absolute';
	this.container_.style.left = (pixelLocation.x-10) + "px";
	this.container_.style.top = (pixelLocation.y
		- contentHeight
		- 25
		- this.marker_.getIcon().iconSize.height
	) + "px";
	
	this.container_.style.border = '0';
	this.container_.style.margin = '0';
	this.container_.style.padding = '0';
	this.container_.style.display = 'block';
	
	//append the styled info window to the container
	this.container_.appendChild(wrapper);

	//add ashadow
	/*this.shadowContainer_.style.position='absolute';
	this.shadowContainer_.style.left = (pixelLocation.x+15) + "px";
	this.shadowContainer_.style.top = (pixelLocation.y
		- 10
		- this.marker_.getIcon().iconSize.height
	) + "px";

	this.shadowContainer_.style.border = '1px solid black';
	this.shadowContainer_.style.margin = '0';
	this.shadowContainer_.style.padding = '0';
	this.shadowContainer_.style.display = 'block';

	var shadowParts = {
		sl:{l:0, t:0, w:35, h:26},
		s:{l:35, t:0, w:(contentWidth-40), h:26},
		sr:{l:(contentWidth-5), t:0, w:35, h:26}
	}

	for (i in shadowParts) {
		var img = document.createElement('img');		
		img.src = '/images/article/gmap/' + i + '.png';
		img.style.position='absolute';
		img.style.top=shadowParts[i].t+'px';
		img.style.left=shadowParts[i].l+'px';
		img.style.width=shadowParts[i].w+'px';
		img.style.height=shadowParts[i].h+'px';
		this.shadowContainer_.appendChild(img);
	}*/

	//pan if necessary so it shows on the screen
	var mapNE = this.map_.fromLatLngToDivPixel(
		this.map_.getBounds().getNorthEast()
	);

	var panX=0;
	var panY=0;

	if(this.container_.offsetTop < mapNE.y) {
		//top of window is above the top edge of the map container
		panY = mapNE.y - this.container_.offsetTop;
	}

	if(this.container_.offsetLeft+contentWidth+10 > mapNE.x) {
		//right edge of window is outside the right edge of the map container
		panX = (this.container_.offsetLeft+contentWidth+10) - mapNE.x;
	}

	if(panX!=0 || panY!=0) {
		//pan the map
		this.map_.panBy(new GSize(-panX-10,panY+30));
	}
}

//add anew method to GMarker so you
//can use asimilar API to the existing info window.
GMarker.prototype.LittleInfoWindowInstance = null;

GMarker.prototype.openLittleInfoWindow = function(content,width) {
	if(this.LittleInfoWindowInstance == null) {
		this.LittleInfoWindowInstance = new LittleInfoWindow(
			this,
			content,
			width
		);
		map.addOverlay(this.LittleInfoWindowInstance);
	}
}

GMarker.prototype.closeLittleInfoWindow = function() {
	if(this.LittleInfoWindowInstance != null) {
		map.removeOverlay(this.LittleInfoWindowInstance);
		this.LittleInfoWindowInstance = null;
	}
}

function gmap_init() {
	map = null;	
	geocoder = null;
	zoomCountryLevel = 3;	
	zoomCityLevel = 4;
	showMapFlag = null;
	firstRequest = false;
        exLocation = null;
	if (GBrowserIsCompatible()) {
		map = new GMap2(document.getElementById("gmap_map"));

	    // CapitalCitiesCache is a custom cache that extends the standard GeocodeCache.
	    // We call apply(this) to invoke the parent's class constructor.
	    function ihtGmapCache() {
	      GGeocodeCache.apply(this);
	    }
	
	    // Assigns an instance of the parent class as a prototype of the
	    // child class, to make sure that all methods defined on the parent
	    // class can be directly invoked on the child class.
	    ihtGmapCache.prototype = new GGeocodeCache();
		
		geocoder = new GClientGeocoder();	
		geocoder.setCache(new ihtGmapCache());			
		
		/**
		 * "Toggle" function so the map shows/hides everytime you click on the article location link.
		 * We had to write our own toggle function because the map can be hidden by two separate ways.
		 * @param {Object} e
		 */
		/*jQuery("a#articleLocation").click(function(e){*/
                jQuery("a[@id*=articleLocation]").click(function(e){
			
			if (exLocation != jQuery(this).text()) {
				showMapFlag = false;
				firstRequest = false;
			} else { 
				showMapFlag = false;
				firstRequest = true;
			}
			exLocation = jQuery(this).text();

			/**
			 * If the flag indicates the map is not being shown AND it has not been the first request yet, 
			 * we call the function loadAddress that sends the request to the google server and show the map.
			 */
			if (showMapFlag != true & firstRequest != true) {
				loadAddress(jQuery(this).text(), e, zoomCityLevel);	
				valueofzoom = zoomCityLevel;
				return false;
			}
			/**
			 * If the flag indicates the map is not being shown AND we already made a request to Google Maps , 
			 * we don't need to send another request to the google server and just need to show the map that is already loaded.
			 */			 
			else if (showMapFlag != true & firstRequest == true) {
				showMap(e);
				return false;
			} 
			/**
			 * If the flag indicates the map is being show then we hide the map
			 */
			else { 
				hideMap();
				return false;
			};
		});	
		
		/**
		 * If you click anywhere on the page while the map is being shownm, it will hide the map.
		 * But to avoid this when clicking on the map itself, we put logic in the showMap(e) function below.
		 * @param {Object} e
		 */
		jQuery(this).click(function(e){
			if (showMapFlag){
				hideMap();
			}
		});			
		
		/**
		 * Second handler way to hide the map
		 */
		jQuery("a#closeme").click(function() {	
			hideMap();
			return false;
		});	
		
		/**
		 * Prevents showing/hiding the map when the ENTER button is pushed while a#articleLocation has the focus
		 */
		/*jQuery("a#articleLocation").focus(function(){*/
                jQuery("a[@id*=articleLocation]").focus(function(){
			jQuery(this).keypress( function() { return false; })
		});
		
	} else { alert('Your browser is not compatible with Google Maps.');}
}

/**
 * Hides the map with visibility style
 */
function hideMap() {
	if (marker.LittleInfoWindowInstance){	
		marker.closeLittleInfoWindow();
	}
	document.getElementById("gmap_shell").style.visibility = "hidden";	
	showMapFlag = false;
}

/**
 * Shows the map with visibility style
 * It prevents the map itself to hide when someone clikc on it 
 * but we need to keep the link contained in the bubble window active.
 */
function showMap(e) {
		
	document.getElementById("gmap_shell").style.position = "absolute";
	document.getElementById("gmap_shell").style.top = e.pageY+8 + "px";
	document.getElementById("gmap_shell").style.left = e.pageX-18 + "px";				
	document.getElementById("gmap_shell").style.visibility = "visible";
	marker.openLittleInfoWindow(bubbleContent);	
	
	bubbleSearchClicked = false;	
	jQuery("div#gmap_shell").click(function(e){
		if (!bubbleSearchClicked) {
			return false;
		}
	});	
	jQuery("a#bubbleSearch").click(function(e){
		bubbleSearchClicked = true;
	});	
	showMapFlag = true;
}


/**
 * Makes a request to Google servers to obtain geocodes for the article specified location.
 * If the request was not successful and returns a null point :
 * 	  a) we retrieve the country from the location that is in a 'CITY, Country' format, so we can display at
 *       least the country of the location on the map.
 * @param {Object} address
 */
function loadAddress(address, e, zoomLevel) {	  
  if (geocoder) {  	
    geocoder.getLocations(
      address,
      function (response) {
		if (response.Status.code == G_GEO_SUCCESS) {
			/*if ( address.indexOf(",") != -1 ) {				
				city = capitalize(address.split(",")[0]);
				country = address.split(",")[1];
				address = city + ", " + country;
			} else {
				address = capitalize(address.split(",")[0]);
			}*/	
			place = response.Placemark[0];
			point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
		    map.setCenter(point, zoomLevel); 
			marker = new GMarker(point);
			map.addOverlay(marker);
			bubbleContent = "Find more articles related to:<br/><a id=\"bubbleSearch\" href=\"http://www.iht.com/cgi-bin/search.cgi?query=" + address + "&sort=publicationdate&submit=Search\" class=\"bubbleStyle\">" + address + "</a>";
			marker.openLittleInfoWindow(bubbleContent);
			
			GEvent.addListener(marker, "click", function() {
				 if (marker.LittleInfoWindowInstance){
				 	marker.closeLittleInfoWindow();
				 } else {
				 	marker.openLittleInfoWindow(bubbleContent);
				 }
			});						

			map.addControl(new GSmallMapControl());
			map.addControl(new GMapTypeControl());				
			showMap(e);	
			firstRequest = true;
		} 
		// code 602
		else if (response.Status.code == G_GEO_UNKNOWN_ADDRESS) {
			if ( address.indexOf(",") == -1 ) {
				alert("Sorry, we were unable to locate this address.");
			} else {
				country = address.split(",")[1];
				loadAddress(country, e, zoomCountryLevel);
				valueofzoom = zoomCountryLevel;
			}
		}
		// code 603
		else if (response.Status.code == G_GEO_UNAVAILABLE_ADDRESS) {
			alert("The geocode for the given address or the route for the given directions query cannot be returned by Google Maps due to legal or contractual reasons.");						
		}	
		// code 500
		else if (response.Status.code == G_GEO_SERVER_ERROR) {
			alert("	A geocoding or directions request could not be successfully processed by Google Maps, yet the exact reason for the failure is not known.");						
		}			
		else {	
			alert("Sorry, we were unable to locate this address.");
		} 
      }
    );
  }
}

function capitalize(pattern) {
	return pattern.charAt(0).toUpperCase() + pattern.substr(1).toLowerCase();
}

// add to list of functions which run on window load
womAdd('gmap_init()');

// ensure that jQuery doesn't conflict with other libraries
// but still uses short names for objects
jQuery.noConflict();
