/*

name         Google Maps support
author       Mark de Jong (http://www.spellcoder.nl)
copyright    (c) Senna Multimedia / Mark de Jong
version      march 2010

*/

function spcGMap()
{
	this.name = 'spcGMap';

	this.debug = false;
	this.initialized = false;
	this.editmode = false;

	this.baseIcons = [];
	this.trackrefs = [];
}

spcGMap.prototype.applyNewSettings = function()
{
	//        .view
	//        .items
	var view = mapdata.view;
	
	// defaults
	var mapdefaults = 
		{ initialzoom:  15
		, minzoom:      13
		, maxzoom:      17
		};

	// enrich view object with defaults for undefined properties
	for(prop in mapdefaults)
		if (typeof view[prop] == 'undefined')
			view[prop] = mapdefaults[prop];


	this.applySettings(view);

	//this.removeAllItems();

	this.drawAllItems();

	this.drawMinimapPoints();
}

spcGMap.prototype.showMapBounds = function()
{
	testbounds = mapdata.bounds;
	var newitem =	{ "name":		'Bounds van de kaart'
					, "type":		1
					, "icon":		3
					, shape:		3 // Rectangle
					, "shortdesc":	''
					, "photo":		null
					, "south":		testbounds.south //testbounds.slat
					, "west":		testbounds.west //slng
					, "north":		testbounds.north //blat
					, "east":		testbounds.east //blng

					, "lat":        null
					, "long":       null
					, "published":	true
					, temporary:	true
					, "volatile":	true
					};

	console.log(newitem);
	var newitemobj = mapmeta.addMapItem2(newitem);
	console.log(newitemobj);
	mygmap.drawItemByRef(newitemobj);	
}



spcGMap.prototype.getMapTypeId = function(maptypename)
{
	var mapTypeId = google.maps.MapTypeId.ROADMAP;
	switch(maptypename.toUpperCase())
	{
		case "HYBRID":		mapTypeId = google.maps.MapTypeId.HYBRID;
							break;
		case "ROADMAP":		mapTypeId = google.maps.MapTypeId.ROADMAP;
							break;
		case "SATELLITE":	mapTypeId = google.maps.MapTypeId.SATELLITE;
							break;
		case "SATELLITE":	mapTypeId = google.maps.MapTypeId.TERRAIN;
							break;
	}
	return mapTypeId;
}

spcGMap.prototype.applySettings = function(view)
{
	console.log("Map / applySettings");

	if (!this.initialized)
		this.init(view);
	else
	{
		console.log('Map / centering on '+view.centerlat+' , '+view.centerlng+' x '+view.initialzoom);

		var options =	{ center:				new google.maps.LatLng(view.centerlat, view.centerlng)
						, zoom:					view.initialzoom
						, mapTypeId:			this.getMapTypeId(view.mapdisplaytype)
						}
		this.gmap.setOptions(options);
	}

	//this.gmap.clearOverlays();
	this.popup.hide();

	this.zoomlevel = view.initialzoom;

//	console.log('Map / centering on '+view.centerlat+' , '+view.centerlng+' x '+view.initialzoom);
//	this.gmap.setCenter(new google.maps.LatLng(view.centerlat, view.centerlng))
//	this.gmap.setZoom(view.initialzoom);	

	console.log(view.minimap);

	if (typeof view.minimap.width != 'undefined')
		this.setMinimapSize(view.minimap.width, view.minimap.height);
	
	console.info('Minimap: '+view.minimap.centerlat+' , '+view.minimap.centerlng+' x '+view.minimap.zoom);

	this.gminimap.setCenter(new google.maps.LatLng(view.minimap.centerlat, view.minimap.centerlng));
	this.gminimap.setZoom(view.minimap.zoom);

	this.updateMinimap();

	this.killMinimapLogo();
}


function spcPanoramaProxy()
{
	alert("woot");
}

spcGMap.prototype.init = function(view)
{
	console.log("Map / Initializing spcGMap");

	this.MapOverlay = function(gmap) { this.setMap(gmap); } 
	this.MapOverlay.prototype = new google.maps.OverlayView();
	this.MapOverlay.prototype.onAdd = function() { }
	this.MapOverlay.prototype.onRemove = function() { }
	this.MapOverlay.prototype.draw = function() { }
	
	var _this = this;
	this.popup = new spcPopup();

	var options =	{ center:					new google.maps.LatLng(view.centerlat, view.centerlng)
					, zoom:						view.initialzoom
					, mapTypeId:				this.getMapTypeId(view.mapdisplaytype)

					, disableDoubleClickZoom:	false
					, draggable:				true
					, keyboardShortcuts:		true
					, scrollwheel:				true

					, navigationControl:	 	true
					, navigationControlOptions:
							{ position: google.maps.ControlPosition.BOTTOM_LEFT
							}

					, mapTypeControl:			true
					, mapTypeControlOptions:
							{ position: google.maps.ControlPosition.BOTTOM_LEFT
							}

					, scaleControl:				false
					, streetViewControl:		true // FIXME: sure to do this?
					};
					
	// FIXME: don't use global
	// FIXME: don't hardcode div to use here
	// FIXME: apply options if the map information is allready loaded
	gmap = new google.maps.Map(document.getElementById("googleMap"), options);
	this.gmap = gmap;
	
	//	var streetview = gmap.getStreetView();
	this.gmap_streetview_container = document.createElement("div");
	this.gmap_streetview_container.style.cssText = "position: absolute; left: 0px; top: 0px; overflow: hidden; width: 100%; height: 100%; background-color: rgb(229, 227, 223); z-index: 1; display: none;";
	document.body.appendChild(this.gmap_streetview_container);
	var options = { addressControl: true
					, addressControlOptions: { position: google.maps.ControlPosition.BOTTOM_LEFT
											, style: {}
											}
					, navigationControl: true
					, navigationControlOptions: { position: google.maps.ControlPosition.BOTTOM_LEFT
												, style: google.maps.NavigationControlStyle.ZOOM_PAN
												}
					, visible: false
					};
	var streetview = new google.maps.StreetViewPanorama(this.gmap_streetview_container, options);
	this.gmap.setStreetView(streetview);

	google.maps.event.addListener(streetview, "visible_changed", function()
		{
			var visible = _this.gmap.getStreetView().getVisible();

			_this.gmap_streetview_container.style.display = visible ? "block" : "none";

			if (product.sidebar)
			{
				if (visible)
					product.sidebar.hide();
				else
					product.sidebar.show();
			}
			
			if (visible)
				product.hideAppTitleBar();
			else
				product.showAppTitleBar();
		});
		

	helper = new google.maps.OverlayView();
	helper.setMap(gmap);
	helper.draw = function () { 
		if (!this.ready) { 
			this.ready = true; 
			google.maps.event.trigger(this, 'ready'); 
		} 
	}; 


	google.maps.event.addListener(gmap, "drag", function()
		{
		_this.updateMinimap();
		});

/*		
	google.maps.event.addListener(gmap, "maptypeid_changed", function()
		{
			console.log("maptypeid_changed");
		});
	google.maps.event.addListener(gmap, "projection_changed", function()
		{
			console.log("projection_changed");
		});
*/	
/*		
maptypeid_changed
projection_changed
google.maps.event.trigger(map, 'resize') .
zoom_changed
*/



/*
	google.maps.event.addListener(gmap, "click", function(marker,latlng)
		{
	//	alert("Event on map");
//		alert(marker);
		console.log(marker);
		
			if (marker)
				_this.onitemselect(marker.realid);
		});
	*/

	// Minimap
	this.cntMinimap = document.getElementById('ecatcher');//'miniGMap');
	this.minimapCatcher = this.cntMinimap;
	this.cntMinimapFull = document.getElementById('miniGMap');
	this.frmWindow = document.getElementById('gmapwindow');

	this.cntMinimap.onmousedown = function(e) { _this.dragMinimapStart(e) };
	this.frmWindow.onmouseup = function(e) { _this.dragMinimapEnd(e) };
	
	this.mapPanels = document.getElementById('GMapPanels');

	this.setupMinimap(view.minimap);

	this.initialized = true;
}

spcGMap.prototype.zoomIn = function()
{
}
spcGMap.prototype.zoomOut = function()
{
}

spcGMap.prototype.killMinimapLogo = function()
{
	// ADDME: kill any link within the minimap?

	var minicontainer = document.getElementById("googleMiniMap");

	var node1 = minicontainer.firstChild;
	if (node1)
	{
		var node2 = node1.firstChild;
		if (node2)
		{
			var logocontainernode = node2.nextSibling;
			if (logocontainernode)
			{
				var anchorwithimage = logocontainernode.firstChild;
				if (anchorwithimage && anchorwithimage.tagName == "A")
					logocontainernode.removeChild(anchorwithimage);
			}
		}
	}
}

spcGMap.prototype.setupMinimap = function(view)
{
	console.log("Map / Setting up minimap");

	var _this = this;

	var minicontainer = document.getElementById("googleMiniMap");
	this.minimapMapContainer = minicontainer;

	var options =	{ center:					new google.maps.LatLng(view.centerlat, view.centerlng)
					, zoom:						view.zoom
					, mapTypeId:				google.maps.MapTypeId.ROADMAP

					, disableDoubleClickZoom:	true
					, draggable:				false
					, keyboardShortcuts:		false
					, scrollwheel:				false

					, navigationControl:	 	false
					, mapTypeControl:			false
					, scaleControl:				false
					, streetViewControl:		false
					};

	var gminimap = new google.maps.Map(minicontainer, options);
	this.gminimap = gminimap;

helpermini = new google.maps.OverlayView();
helpermini.setMap(gminimap);
helpermini.draw = function () { 
    if (!this.ready) { 
        this.ready = true; 
        google.maps.event.trigger(this, 'ready'); 
    } 
}; 

	/*
	console.group("Initial minimap settings");
	console.log(options);
	console.groupEnd();
	*/

	//minicontainer.removeChild(minicontainer.firstChild.nextSibling);
	//minicontainer.removeChild(minicontainer.firstChild.nextSibling);

	google.maps.event.addListener(gmap, "move", function() {
		_this.updateMinimap();
	});

	google.maps.event.addListener(gmap, "moveend", function() {
		_this.updateMinimap();
	});	

	addEvent(window, 'resize', function() {
		_this.updateMinimap();
	});
}


spcGMap.prototype.setMinimapSize = function(width, height)
{
	this.minimapW = width;
	this.minimapH = height;

	this.minimapMapContainer.style.width = this.minimapW+'px';
	this.minimapMapContainer.style.height = this.minimapH+'px';
	this.minimapCatcher.style.width = this.minimapW+'px';
	this.minimapCatcher.style.height = this.minimapH+'px';

	if (this.gminimap)
		google.maps.event.trigger(this.gminimap, 'resize')
}

spcGMap.prototype.centerOnItemById = function(itemid)
{
  var item = mapmeta.getItemById(itemid);
  this.gmap.setCenter(new google.maps.LatLng(item.lat, item.long));
}

spcGMap.prototype.panToItemById = function(itemid)
{
  var item = mapmeta.getItemById(itemid);
  //this.gmap.setCenter(new google.maps.LatLng(view.centerlat, view.centerlng), view.initialzoom);	
  //console.log(item.lat+'x'+item.long);
  this.gmap.panTo(new google.maps.LatLng(item.lat, item.long));
}

spcGMap.prototype.setCenter = function(latlng, zoom)
{
	this.gmap.setCenter(latlng, zoom);	
}

spcGMap.prototype.setZoom = function(zoom)
{
	this.gmap.setZoom(zoom);
}

// FIXME: make absolete?
spcGMap.prototype.settypes = function(types)
{
	this.types = types;
}

spcGMap.prototype.createBaseIcons = function()
{
	console.log('Map / creating icon prototypes');

	var zfactor = 1;

    for (var typeid in this.types)
	{
		var type = this.types[typeid];

		if (type.icon == undefined)
		{
			console.warn('Mappoint type %i (%s) has no icon information.', typeid, type.name);
			continue;
		}

		var iwidth = type.icon.width;
		var iheight = type.icon.height;
		/*
		var icon = new google.maps.MarkerImage(
				  'gfx/map_icons/'+type.icon.filename
				, new google.maps.Size(iwidth, iheight)
				, new google.maps.Point(0,0) // origin
				, new google.maps.Point(0, 32)
				); // anchor
		*/

		var icon = new google.maps.MarkerImage(
				  'gfx/map_icons/'+type.icon.filename
				, new google.maps.Size(iwidth, iheight)
				, new google.maps.Point(0,0) // origin
				, new google.maps.Point(iwidth/2, iheight/2)
				); // anchor

		this.baseIcons[typeid] = icon;
	}
}




spcGMap.prototype.hoverpoint = function(pointid)
{
	var item = mapmeta.getItemById(pointid);
	if (!item) {
		item = mapmeta.getAccidentById(pointid);
	}

	if (!item)
	{
		console.error('Hoverout did not find item #'+pointid);
		return;
	}

	switch(item.shape)
	{
		case 1:		console.log('mouse over mapitem #'+pointid+' ('+item.name+')');
					var itemList = [];
					//itemList[0] = mapmeta.getItemPosById(pointid);
					itemList[0] = item;

					//this.popup.showItem(mapmeta.getItemById(pointid));
					this.popup.showItem(item);
					//this.placePopupNextToItem(pointid);
					this.placePopupNextToItem(item);
					this.drawPing( itemList );

					break;

		case 2:		console.log('mouse over track #'+item.trackid+' ('+item.name+') (temp mapid: #'+pointid+')');
					item.instance.setHover(true);
					break;
	}	
}

spcGMap.prototype.hoveroutpoint = function(pointid)
{
	var item = mapmeta.getItemById(pointid);
	if (!item) {
		item = mapmeta.getAccidentById(pointid);
	}

	if (!item)
	{
		console.error('Hoverout did not find item #'+pointid);
		return;
	}

	switch(item.shape)
	{
		case 1:		console.log('mouse out mapitem #'+pointid+' ('+item.name+')');
					this.pulsePingStop();	
					this.popup.hide();
					break;

		case 2:		console.log('mouse out track #'+item.trackid+' ('+item.name+') (temp mapid: #'+pointid+')');
					item.instance.setHover(false);
					break;
	}
}

spcGMap.prototype.onitemselect = function(itemid)
{
}

spcGMap.prototype.onitemhover = function(hovering)
{	
}




/* *****************************************************************************************
Draw icons on the map
***************************************************************************************** */

spcGMap.prototype.attachEventListeners = function(marker, id, itemclass)
{
	var mapobj = this;
	var pointid = id;

	google.maps.event.addListener(marker, "mouseover", function()
		{
			console.log("map / hover over item #%i", pointid);
			mygmap.hoverpoint(pointid);
		});

	google.maps.event.addListener(marker, "mouseout", function()
		{
			console.log("map / hover out item #%i", pointid);
			mygmap.hoveroutpoint(pointid);
		});

	google.maps.event.addListener(marker, "click", function(marker)
		{
			console.log("map / click on item #%i", pointid);
			mapobj.onitemselect(pointid, itemclass);
		});
return;
		
	// bind?
	google.maps.event.addListener(marker, "dragend", this, function(latlng)
		{
			var itempos = mapmeta.getItemPosById(this.realid);
			console.log('Moved point '+this.realid+' to '+latlng.lat()+' / '+latlng.lng()+' (array pos is '+arrpos+')');
			mapdata.items[arrpos].lat = latlng.lat();
			mapdata.items[arrpos].long = latlng.lng();
		});
}

spcGMap.prototype.createMarker = function(mapitemid, mapinstance, latlng, icon, allowdragging)
{
	//console.log("map / createMarker");

	var options = { draggable: false
		, flat:		true
		, map:		this.gmap
		, icon:		icon
		, position:	latlng
		};

	var marker = new google.maps.Marker(options);
	//marker.realid = mapitemid;
	this.attachEventListeners(marker, mapitemid);
	
	return marker;
}

spcGMap.prototype.getMapPointsDistances = function(lat, lng, maxdistance)
{
	var latlng = new google.maps.LatLng(lat, lng);

	var points = [];
	
	for(var tel=0; tel<mapdata.items.length; tel++)
	{
		var point = mapdata.items[tel];
		var mp_latlng = new google.maps.LatLng(point.lat, point.long);
		var distance = latlng.distanceFrom(mp_latlng);
		if (distance < maxdistance)
			points.push({ id: point.id, name: point.name, distance: Math.round(distance) });
	}
	
	return points;
}



function getClone(obj)
{
	return eval(obj).toSource();
}

spcGMap.prototype.drawAllItems = function()
{
	var iList = mapdata.items;
	for(tel in iList)
		this.drawItemByRef(iList[tel]);
}

spcGMap.prototype.removeAllItems = function()
{
	//this.clearAllTracks(); // FIXME: needed??

	console.log("Map / removing all items from the map ("+mapmeta.items.length+" items)");

	for(var itemnr=0; itemnr < mapmeta.items.length; itemnr++)
	{
		var item = mapmeta.items[itemnr];
		
		// FIXME: some items will be undefined, it would be good to prevent this case from happening
		if (item.instance && item.instance.hide)
			item.instance.hide();
		//item.overlay.setMap(null);
		// ADDME: delete
	}
}

spcGMap.prototype.drawAllAccidents = function()
{

	console.log("Map / draw all accidents on the map ("+mapmeta.accidents.length+" accidents)");
	//console.log("Map / draw "+JSON.stringify(mapmeta.accidents[0]));
	//console.log("Map / draw "+JSON.stringify(mapmeta.accidents[1]));
	
	var iList = mapmeta.accidents;
	for(tel in iList) {
		iList[tel].shape = 1;
		
		var point = this.drawItemByRef(iList[tel]);
		point.show();
	}
	
	/*
	for (var i=0;i<mapmeta.accidents.length;i++)
	{
		var accident = mapmeta.accidents[i];
		var point = this.drawItemByRef(accident);
		point.show();
	}
	*/
}

spcGMap.prototype.removeAllAccidents = function()
{
	console.log("Map / removing all accidents from the map ("+mapmeta.accidents.length+" accidents)");

	for(var itemnr=0; itemnr < mapmeta.accidents.length; itemnr++)
	{
		var item = mapmeta.accidents[itemnr];
		
		// FIXME: some accidents will be undefined, it would be good to prevent this case from happening
		if (item.instance && item.instance.hide)
			item.instance.hide();
		//item.overlay.setMap(null);
		// ADDME: delete
	}
}

spcGMap.prototype.drawItemById = function(itemid)
{
	var arrpos = mapmeta.getItemPosById(itemid);
	this.drawItem(arrpos);
}
spcGMap.prototype.hideItemById = function(arrpos)
{
	var arrpos = mapmeta.getItemPosById(itemid);
	this.hideItem(arrpos);
}

spcGMap.prototype.drawItem = function(arrpos)
{
	var item = mapmeta.items[arrpos];
	this.drawItemByRef(item);
}

spcGMap.prototype.drawItemByRef = function(item, options)
{
	/*
	console.group();
	console.log('drawItemByRef');
	console.warn(item);
	console.groupEnd();
	*/

	var instance;

	if (!item)
	{	
		console.log("drawItemByRef on a non-existant item.");
		return;
	}
	
	if (item.instance)
	{
		if (item.instance.update)
		{
			item.instance.update();
			return;
		}
		else
			console.log('Cannot update an item of type '+item.shape);
		return;
	}
	
	
	
	switch(item.shape)
	{
		case 1:		instance = new spcMapPoint(this,item);
					break;
		case 2:		instance = new spcMapTrack(this,item,options);
					break;
		case 3:		instance = new spcMapRectangle(this,item);
					break;
		default:	console.warn('unknown mapitem type/shape '+item.shape);
					return;
	}

	item.instance = instance;
	item.overlay  = instance.overlay; // ref to Google Maps object // FIXME: also in googlemaps v3?

	//console.log('Item #'+item.id+' has been instanced.');
	//return instance.overlay;
	return instance;
}

spcGMap.prototype.hideItem = function(arrpos)
{
	var item = mapmeta.items[arrpos];
	item.instance.hide();
}

spcGMap.prototype.showItem = function(arrpos)
{
	var item = mapmeta.items[arrpos];
	item.instance.show();
}

spcGMap.prototype.deleteItem = function(arrpos)
{
	var item = mapmeta.items[arrpos];
	item.instance.destroy();
	mapmeta.items.splice(arrpos,1);
}


// FIXME: crap?
/*
spcGMap.prototype.removeItemsByOwnerId = function(itemid)
{
	var items = mapmeta.removeItemByOwnerId(trackid);

	for(var tel=0; tel<items.length; tel++)
	{
		//this.gmap.removeOverlay(items[tel].overlay); // GMaps V2
		items[tel].overlay.set_map(null);
		
		console.log(track.childoverlays[telchild]);
		this.gmap.removeOverlay(track.childoverlays[telchild]);
	}
	
}
*/




//spcGMap.prototype.placePopupNextToItem = function(itemid)
spcGMap.prototype.placePopupNextToItem = function(item)
{
	//var item = mapmeta.getItemById(itemid);

	// Google Maps V3 API docs are not correct on fromLatLngToContainerPixel ?!
	//pixelpos = { x: 0, y: 0 };

	var latlng = new google.maps.LatLng(item.lat, item.long);
	pixelpos = helper.getProjection().fromLatLngToContainerPixel(latlng);

	var iconloc = { x1: pixelpos.x-15
	              , x2: pixelpos.x+15
	              , y1: pixelpos.y-15
	              , y2: pixelpos.y+15
			};

	//	var	currentOffset = map.getOffset();
	//	var scrollX = currentOffset.offsetX;
	//	var scrollY = currentOffset.offsetY;

	var viewportWidth = document.body.offsetWidth;
	var viewportHeight = document.body.offsetHeight;

	var padLeft   = 40;
	var padRight  = 10;
	var padTop    = 65;
	var padBottom = 10;

	var roomTop		= pixelpos.y/*-scrollY*/-padTop;
	var roomRight	= viewportWidth-/*(iconXe-scrollX)*/pixelpos.x-padRight;
	var roomBottom	= viewportHeight-/*(iconYe-scrollY)*/pixelpos.y-padBottom;
	var roomLeft	= pixelpos.x/*-scrollX*/-padLeft;

	//		render the popup in the background
	//		map.elPopup.style.visibility	= 'hidden';		// don't show result yet
	//		map.elPopup.style.display		= 'block';		// but render it in as a block

	/*		read size op the popup
		NOTE: please force a size in the CSS for now, since you might get unreliable results otherwise
		NOTE 2: clientWidth uses internal width, offsetWidth = clientWidth+totalpaddingW+totalborderW
	*/
	var popupWidth	= this.popup.wndPopup.container.offsetWidth;
	var popupHeight	= this.popup.wndPopup.container.offsetHeight;

	//		calc position of popup
	//		var newLeft = roomLeft > roomRight  ? iconX - popupWidth  : iconXe;
	//		var newTop	= roomTop  > roomBottom ? iconY - popupHeight : iconYe;

	if (roomLeft > roomRight)
		var newLeft = roomLeft  < popupWidth ? /*scrollX+*/padLeft : iconloc.x1 - popupWidth;
	else
		var newLeft = roomRight < popupWidth ? /*scrollX+*/viewportWidth - popupWidth - padRight : iconloc.x2;

	if (roomTop > roomBottom)
		var newTop  = roomTop   < popupHeight ? /*scrollY+*/padTop : iconloc.y1 - popupHeight;
	else
		var newTop  = roomBottom < popupHeight ? /*scrollY*/viewportHeight - popupHeight - padBottom : iconloc.y2;

	//	map.elPopup.onresize = function() { alert('test') };

	this.popup.placePopup(newLeft,newTop,popupWidth,popupHeight);
}

//http://econym.org.uk/gmap/animated.htm
