/**
 * @classdescription 
 * @author Sebastian Martens - sebastian@sebastian-martens.de
 * @copyright 2009 Sebastian Martens
 */
var usatour = new Object({
	
	googleMapKey: "ABQIAAAAAaAkO6sD4La47_jYKxiksxSwvbCWtbK3ZG8NAiwJLBhM9NlEFBS5hVjidmKwvl7lpF8j3FMRy3HHhQ",
	map: null,
	
	actionURI: "/eu2010_map/server/",
	saveActionURI: "/eu2010_map/server/?action=save",
	imagePath: "/eu2010_map/server/images/",
	
	nodeid:"googlemap",
	node: null,
	
	requestData: null,
	request: null,
	loseCoords: 0,
	latForEqlDistance: 0.0005,
	
	googleGeoCoder: null,
	setPoints: null,
	
	/**
	 * 
	 */
	init: function(){
		this.setPoints = [];
		this.node = this.byId( this.nodeid );
		this.loadGoogle();
		
	},
	
	/**
	 * returns an DOM node by its id
	 * @param String id - DOM node id
	 * @return DOM node
	 */
	byId: function( id ){
		return document.getElementById( id );
	},
	
	/**
	 * dynmically creates script node and starts loading google api
	 * 
	 */
	loadGoogle: function(){
		var script = document.createElement("script");
  		script.src = "http://www.google.com/jsapi?key="+this.googleMapKey+"&callback=usatour.googleInit";
  		script.type = "text/javascript";
  		document.getElementsByTagName("head")[0].appendChild(script);
	},
	
	/**
	 * callback method for loaded google api, load google maps api
	 */
	googleInit: function(){
		google.load("maps", "2", {"callback" : mapsLoaded});
	},
	
	/**
	 * callback method for loaded google maps api
	 */
	mapsLoaded: function(){
		this.googleGeoCoder = new GClientGeocoder();
		var gPosition = new GControlPosition();
		
		this.map = new google.maps.Map2( this.node );
		this.map.setCenter(new google.maps.LatLng(53.97888,9.1266), 10);

		// mouse wheel zoom
		this.map.enableScrollWheelZoom();
		this.map.enableContinuousZoom();
		
		// set control elements
		this.map.addControl( new GLargeMapControl(), gPosition.G_ANCHOR_TOP_LEFT  );
		this.map.addControl( new GMapTypeControl(), gPosition.G_ANCHOR_TOP_RIGHT );
		// this.map.addControl( new GOverviewMapControl()  );
		
		this.sendRequest();
	},
	
	/**
	 * get the browser specific xmlhttp object for ajax request
	 * @return XMLHttp Object
	 */
	prepareAjaxRequest: function(){
		 var activexmodes=["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]; //activeX versions to check for in IE
		 if (window.ActiveXObject){
		 	for (var i=0; i<activexmodes.length; i++){
		   		try{
		    		return new ActiveXObject(activexmodes[i])
		   		}catch(e){
		    	}
		  	}
		 }else if (window.XMLHttpRequest){ // if Mozilla, Safari etc
		 	return new XMLHttpRequest();
		 }else return false
	},
	
	/**
	 * state change handler for XMLHttp Object
	 * save data on successful data transmittion
	 */
	requestStateHandler: function(){
		if (usatour.request.readyState==4){
			if (usatour.request.status==200){
				usatour.requestData = eval( "("+usatour.request.responseText+")" );
				usatour.handleResponseData();
			}
		 }
	},
	
	/**
	 * send the AJAX request
	 */
	sendRequest: function(){
		this.request=new this.prepareAjaxRequest();
		this.request.onreadystatechange = this.requestStateHandler;
		this.request.open("GET", this.actionURI, true);
		this.request.send(null)
	},
	
	round: function(x, n) {
  		if (n < 1 || n > 14) return false;
  		var e = Math.pow(10, n);
  		var k = (Math.round(x * e) / e).toString();
  		if (k.indexOf('.') == -1) k += '.';
  		k += e.toString().substring(1);
  		return k.substring(0, k.indexOf('.') + n+1);
	},
	
	
	/**
	 * calculates the center of all dealers in a maximum range
	 * @return Object - object with latitude/longitude value for center of actual dealers
	 */
	_getGeoCenterOfList: function(){
		var max_x,min_x,max_y,min_y;
		var result = {'lat':0,'lon':0,'optZoom':0};
		var imgList; 
		var DELTA = 0.0005;
		
		if( this.requestData.imglist.length<1 ) return;
		imgList = this.requestData.imglist;
		
		// default ist user position
		max_x = imgList[0].lon;
		min_x = imgList[0].lon;
		max_y = imgList[0].lat;
		min_y = imgList[0].lat;
		
		// get min/ max values 
		for(i=0;i<imgList.length;i++){
			if( imgList[i].lon>max_x ) max_x = imgList[i].lon;
			if( imgList[i].lon<min_x ) min_x = imgList[i].lon;
			if( imgList[i].lat>max_y ) max_y = imgList[i].lat;
			if( imgList[i].lat<min_y ) min_y = imgList[i].lat;
		}
		
		max_x = this.round(parseFloat(max_x)+parseFloat(DELTA),7);
		min_x = this.round(parseFloat(min_x)-parseFloat(DELTA),7);
		max_y = this.round(parseFloat(max_y)+parseFloat(DELTA),7);
		min_y = this.round(parseFloat(min_y)-parseFloat(DELTA),7);
		
		result.lat = 0 + parseFloat(min_x) + ((max_x-min_x)/2);
		result.lon = 0 + parseFloat(min_y) + ((max_y-min_y)/2);
		
		//console.info(max_y,min_x,min_y,max_x);
		
		// get optimal zoom
		//var gBounds = new GLatLngBounds( new GLatLng(parseFloat(max_y),parseFloat(min_x)), new GLatLng(parseFloat(min_y),parseFloat(max_x)) );
		
		//console.info( gBounds.isEmpty() );
		result.optZoom = 4; // this.map.getBoundsZoomLevel( gBounds );
		return result;
	},
	
	/**
	 * @return true if another obj with equal values already exists
	 */
	checkForEqual: function( obj ){
		if( !obj || !obj.lon || !obj.lat ) return false;
		var i;
		for(i=0;i<this.setPoints.length;i++){
			if( this.setPoints[i].lat &&
				this.setPoints[i].lon &&
				obj.lat==this.setPoints[i].lat && 
				obj.lon==this.setPoints[i].lon ) return true;
		}
		
		return false;
	},
	
	/**
	 * creates a new marker for the map
	 * @param Object item - item that contains the data
	 * @return GMarker marker to place on the map
	 */
	createMarker: function( item ){
		var html;
		
		// geocode marker if necessary
		// this.geoCodeForMarker( item );
		
		// changes the position as long as an double entry is found
		while( this.checkForEqual( item ) ){
			item.lon = parseFloat(item.lon) + this.latForEqlDistance;
		}
		
		if( item.lat!=0 && item.lon!=0 ){
			var point = new GLatLng(item.lat, item.lon);
			var marker = new GMarker(point);
			
			GEvent.addListener(marker, "click", function() {
				html = '<div>';
				html += '<div style="margin:0 0 10px 0;">Datum: '+item.date+' ('+item.time+'Uhr)</div>';
				html += '<img src="'+item.thumb+'" style="width:200px; height:150px; margin: 0 0 10px 0;" />';
				if(item.comment) html += '<div style="width:200px; margin:0 0 10px 0;">'+item.comment+'</div>';
				html += '<div><a href="'+item.file+'" target="_blank">see full image</a></div>';
				html += '</div>';
				
				marker.openInfoWindowHtml(html);
			});
			
			// save point data to local store for checking for double items
			this.setPoints.push( item );
		}
		
		return marker;
	},
	
	/**
	 * creates a geocooding request
	 * @param Object item - point object
	 */
	geoCodeForMarker: function( item ){
		this.googleGeoCoder.getLocations( item.street, function( obj ){
			usatour.handleGeoCoder( obj );
		});
	},
	
	/**
	 * checks the list of result images for images without geoccords to be coded before
	 */
	checkGeoCoords: function(){
		var item;
		var imgList = this.requestData.imglist;
		
		for(i=0;i<imgList.length;i++ ){
			item = imgList[i];
			if( item.street && item.street!='' && (item.lat==0 && item.lon==0) ){
				this.loseCoords++;
			}
		}
		
		// console.info("items without geocode: ", this.loseCoords);
		if( this.loseCoords==0 ) this.allCoordsHandled();
		
		for(i=0;i<imgList.length;i++ ){
			item = imgList[i];
			if( item.street && item.street!='' && (item.lat==0 && item.lon==0) ){
				this.geoCodeForMarker( item );
			}
		}
	},
	
	/**
	 * handler method called if all images got geo coords
	 */
	allCoordsHandled: function(){
		var imgList = this.requestData.imglist;
		for(i=0;i<imgList.length;i++ ){
			if(imgList[i].lat!=0 && imgList[i].lon!=0) 
				this.map.addOverlay( this.createMarker( imgList[i] ) );
		}
		
		// set maps center
		var geoMid = this._getGeoCenterOfList();
		this.map.setZoom( geoMid.optZoom );
		this.map.panTo( new GLatLng(geoMid.lon, geoMid.lat) );
	},
	
	/**
	 * updates an single item ( image ) from list
	 * @param String string - street which were geocoded
	 * @param Float lon - result longitude
	 * @param Float lat - result latitude
	 */
	updateItem: function( string, lon, lat ){
		// console.info("success geocode", string, lon, lat);
		imgList = this.requestData.imglist;
		for(i=0;i<imgList.length;i++ ){
			if( imgList[i].street==string ){
				imgList[i].lon = lon;
				imgList[i].lat = lat;
			}
		}
	},
	
	/**
	 * 
	 */
	updateServerDataRequest: function( name, lon, lat ){
		this.request.open("GET", this.saveActionURI+"&lon="+lon+"&lat="+lat+"&street="+name, true);
		this.request.send(null)
	},
	
	/**
	 * handles the geocode result
	 * @param Object gLatLng - Google Geocode result object
	 */
	handleGeoCoder: function( gLatLng ){
		this.loseCoords--;
		
		if( gLatLng && gLatLng.Placemark ){
			this.updateItem( gLatLng.name, gLatLng.Placemark[0].Point.coordinates[0], gLatLng.Placemark[0].Point.coordinates[1] );
			this.updateServerDataRequest( gLatLng.name, gLatLng.Placemark[0].Point.coordinates[0], gLatLng.Placemark[0].Point.coordinates[1] );
		}// else consoleinfo( "error on geocode", gLatLng );
		
		if( this.loseCoords==0 ){
			this.allCoordsHandled();
		}
	},
	
	/**
	 * ajax request response handler. handles successfully saved data of request
	 */
	handleResponseData: function(){
		var imgList = this.requestData.imglist;
		
		if( imgList.length<1 ) return false;
		this.checkGeoCoords();
	}
	
});

/**
 * scope helper method for google
 */
function mapsLoaded(){
	usatour.mapsLoaded();
}
	
