
/**
 * (./) map.js, v0.2, 10 sept. 09
 * (by) cousot stephane @ http://www.ubaa.net/
 * (cc) some right reserved
 *
 * Googel MAP API integration for Locus Sonus sound map projet
 * ‹ http://locusonus.org/soundmap/ ›
 *
 *
 * thanks for DaylightMap for the Dayligth and clouds modules
 * ‹ http://www.daylightmap.com ›
 *
 * This script is released under a Creative Commons Attribution 3.0 License
 * ‹ http://creativecommons.org/licenses/by/3.0/ ›
 */





// Google MAP constant
var MAP_CONTROL_NONE  = 0;
var MAP_CONTROL_LARGE = 1;
var MAP_CONTROL_SMALL = 2;

var MAP_TYPE_NORMAL		= 0;
var MAP_TYPE_SATELLITE	= 1;
var MAP_TYPE_HYBRID		= 2;
var MAP_TYPE_TERRAIN	= 3;


// Daylight MAP constant
var DAYNIGHT_NORMAL_OPACITY 	= 0.3;		// street and terrain view
var DAYNIGHT_SATELLITE_OPACITY	= 0.5;		// satellite and hybrid view



// -------------------------------------------------------------------------------------------------
// MAP PROPERTIES : 
// THESE PROPERTIES ARE USED TO INITIALIZE THE MAP
// -------------------------------------------------------------------------------------------------

// element dimensions
// for the public map only
var MAP_MIN_WIDTH 		= 520;
var MAP_MIN_HEIGHT 		= 300; 
var MAP_OPTIONS_WIDTH	= 240;
// zoom
var MAP_ZOOM_DEFAULT	= 2;
var MAP_ZOOM_MINIMUM	= 2;
var MAP_USE_WHEEL		= true;
var MAP_USE_PINCH		= true;
// coordinates
var MAP_LATITUDE_DEFAULT	= 13;
var MAP_LONGITUDE_DEFAULT	= 11;
// style :
// could be MAP_TYPE_NORMAL, MAP_TYPE_SATELLITE, MAP_TYPE_HYBRID or MAP_TYPE_TERRAIN
var MAP_TYPE_DEFAULT	= MAP_TYPE_TERRAIN;
// control
// could be MAP_CONTROL_NONE, MAP_CONTROL_LARGE or MAP_CONTROL_SMALL
var MAP_CONTROL_DEFAULT	= MAP_CONTROL_LARGE;
// Day & night
var MAP_DAYNIGHT_BY_DEFAULT  = true;
var MAP_CITYLIGHT_BY_DEFAULT = true;
// clouds
var MAP_CLOUDS_BY_DEFAULT = true;

// -------------------------------------------------------------------------------------------------












/////////////////////////////// CODE BELOW SHOULD NOT BE MODIFIED //////////////////////////////////



var _gmap = null;		// the Google MAP object
var _daynight = null;	// the DaylightMap layer object
var _clouds = null;		// the DaylightMap Clouds layer object 
var _markers = [];		// marker's definition (before initialization) -> markers instance
var _curmarker = null;	// the current selected marker
var _control = null;	// the current map control
var _debmarker = null;	// admin marker for debug

// icon set
var _icons = { on: null, off: null };





/**
 * Setup Google MAP.
 */
function mapSetup() {
	
	
	// Google MAP API not looded or browser imcompatible
	// -> exit
	if ( typeof(GMap2)=='undefined' || !GBrowserIsCompatible() ) return;
	
	
	
	// create Google map object
	_gmap = new GMap2( document.getElementById("Gmap") );
	
	// configure Google map object
	_gmap.setCenter( new GLatLng(MAP_LATITUDE_DEFAULT,MAP_LONGITUDE_DEFAULT), MAP_ZOOM_DEFAULT );
	if ( MAP_USE_WHEEL ) _gmap.enableScrollWheelZoom();
	if ( MAP_USE_PINCH ) _gmap.enablePinchToZoom();
	mapControl( MAP_CONTROL_DEFAULT );
	
	
	
	
	// create and configure the Daylight layers
	// day & night + clouds layer
	if ( typeof(daylightMap)!=='undefined' ) {
		
		// override the default opacity values
   		daylightMap._defaultMapOpacity = DAYNIGHT_NORMAL_OPACITY;
		daylightMap._defaultSatelliteOpacity = DAYNIGHT_SATELLITE_OPACITY;

   		_daynight = new daylightMap.daylightLayer();
   		_daynight.addToMap( _gmap );
		_daynight.addToMapType( G_NORMAL_MAP );
		_daynight.addToMapType( G_SATELLITE_MAP );
		_daynight.addToMapType( G_HYBRID_MAP );
		_daynight.addToMapType( G_PHYSICAL_MAP ); 		
   		
	
		// create and configure the Daylight Clouds layer
		if ( typeof(daylightMap.CloudLayer)!=='undefined' ) {
			
			// override to implement active (show/hide) option
			daylightMap.CloudLayer.prototype.getTileUrl = mapCloudGetTileUrl;
			daylightMap.CloudLayer.prototype.getCopyright =function() { return '' };
	
	    	try { // <-- because MarkerManager is not included in code : addToMap
	    		_clouds = new daylightMap.CloudLayer();
	    		_clouds.disableIcons = true;
				_clouds.addToMapType( G_NORMAL_MAP );
				_clouds.addToMapType( G_SATELLITE_MAP );
				_clouds.addToMapType( G_HYBRID_MAP );
				_clouds.addToMapType( G_PHYSICAL_MAP );
	    		_clouds.addToMap( _gmap );
	    	}
	    	catch(e) {}
		}
	}
	
	
	
	// set the map type
	mapType( MAP_TYPE_DEFAULT );
	mapDayNight( MAP_DAYNIGHT_BY_DEFAULT );
	mapCityLigth( MAP_CITYLIGHT_BY_DEFAULT );
	mapClouds( MAP_CLOUDS_BY_DEFAULT ); 
	

	// force zoom to a minimum value
	// zoomend(oldLevel:Number, newLevel:Number)
	GEvent.addListener(
		_gmap,
		"zoomend",
		function( oldLevel, newLevel ) {
			if ( newLevel<MAP_ZOOM_MINIMUM ) _gmap.setZoom( MAP_ZOOM_MINIMUM );
		}
	);
	
	
	// create our "locusonus" marker icons
	// (CC) http://openclipart.org/media/files/speciwoman/13181
	_icons.on   = new GIcon();
	_icons.off  = new GIcon();
	
	_icons.on.image = _root+"/img/map/marker-on.png";
	_icons.on.shadow = _root+"/img/map/marker-shadow.png";
	_icons.on.iconSize = new GSize( 24, 28 );
	_icons.on.shadowSize = new GSize( 24, 28 );
	_icons.on.iconAnchor = new GPoint( 12, 28 );
	_icons.on.infoWindowAnchor = new GPoint( 12, 28 );
	_icons.off.image = _root+"/img/map/marker-off.png";
	_icons.off.shadow = _root+"/img/map/marker-shadow.png";
	_icons.off.iconSize = new GSize( 24, 28 );
	_icons.off.shadowSize = new GSize( 24, 28 );
	_icons.off.iconAnchor = new GPoint( 12, 28 );
	_icons.off.infoWindowAnchor = new GPoint( 12, 28 );
	
	// add markers
	mapAddMarkers();
	
	// fix interface
	uiFix();
	
}


/**
 * Forget Google MAP element and free memory
 */
function mapDispose() {
	if ( typeof(GMap2)!='undefined' ) GUnload();
}



/**
 * Refresh map elements
 */
function mapRefresh() {
	if ( !_gmap ) return;
	
	// load OGG stream status
	if ( _markers.length!=0 ) {
		var xhr = new XHR(
			function( response ) {
				if ( response.search(/error/i)!=-1 ) return;
				
				if ( _curmarker ) mapMarkerCloseOverlay();
				
				for( var i=0; i<_markers.length; i++ ) {
					var status = response.search(_markers[i].name)==-1 ? "off" : "on";
					
					_markers[i].setImage( "img/map/marker-"+status+".png" );
					_markers[i].html = _markers[i].html.replace( /_on|_off/g, '_'+status );
				}
			},
			{
				method:'GET',
				url: "doc/icecast.php?do=status"
			}
		);
		xhr.send();
	}
	
	_gmap.returnToSavedPosition();
	if ( _daynight ) _daynight.refresh();	
}




/** 
 * Add markers to Google map.
 */
function mapAddMarkers() {
	if ( !_gmap ) return;
	
	
	// add each markers
	for( var i=0; i<_markers.length; i++ ) {
		
		// create the marker
		var marker = new GMarker(
			new GLatLng( _markers[i].lat, _markers[i].lng ),
			 {
			 	icon: _markers[i].status ? _icons.on : _icons.off,
			 	draggable: _markers[i].draggable,
			 	title: _markers[i].title,
			 	zIndexProcess : function() { return (!_markers[i] || _markers[i].status) ? 1 : -1; }
			 }
		);
		
		
		// add draggable listeners
		if ( _markers[i].draggable ) {
			_debmarker = marker;
			GEvent.addListener( marker, "dragstart", mapMarkerCloseOverlay );
        	GEvent.addListener( marker, "dragend", function() { refresh('coordinate'); });
		}
		
		
		// store HTML and create the marker infoWindow
		// and add the marker 'click' listener
		marker.name = _markers[i].name;
		marker.html = _markers[i].html;
		marker.overlay = new _MapInfoWindow( marker );
		GEvent.addListener(
			marker,
			"click",
			function() {
				
				// show the '_MapInfoWindow'
				if ( typeof(_MapInfoWindow)!='undefined') {
					if ( _curmarker ) mapMarkerCloseOverlay(); // close previous window first
				 	_curmarker = this;
				 	_gmap.addOverlay( this.overlay );
				 	//this.hide();
				}
				// or use the Google MAP default InfoWindow
				else this.openInfoWindowHtml( this.html );
			}
		);
		
		// add to the map
		_gmap.addOverlay( marker );
		
		// store marker instance
		_markers[i] = marker;
	}
}


/**
 * Center the map and open the specified marker definition.
 * @param idx	the marker index
 */
function mapFocusToMarker( idx ) {
	if ( _gmap ) {
		
		// hide previous panel first
		mapMarkerCloseOverlay();
		
		// open the selected marker
		_curmarker = _markers[idx];
		_gmap.setZoom( 12 );
		if ( typeof(_MapInfoWindow)!='undefined' ) _gmap.addOverlay( _curmarker.overlay );
		else _curmarker.openInfoWindowHtml( _markers[idx].html );

	}
}


/**
 * Center the map to the given point
 * @param lat	the new map lattitude coordinate
 * @param lng	the new map longitude coordinate
 */
function mapPanTo( lat, lng ) {
	if ( _gmap ) _gmap.panTo( new GLatLng(lat,lng) );
}



/**
 * Move the current map by the given distance in pixels.
 * @param x	the x offset value
 * @param y	the y offset value
 */
function mapPanBy( x, y ) {
	if ( _gmap ) _gmap.panBy( new GSize(x,y) );
}


/**
 * Enables /disable zooming using a mouse's scroll wheel
 * @param type the new map type
 */
function mapUseWheelZoom( bval ) {
	if ( _gmap ) {
		if ( bval ) _gmap.enableScrollWheelZoom();
		else _gmap.disableScrollWheelZoom();
	}
}
	

/**
 * Change map display type.
 * @param type the new map type
 */
function mapType( type ) {
	if ( !_gmap ) return;
	
	try { // <-- if Daylight Map object doesn't exist
	
		switch( type ) {
			case MAP_TYPE_NORMAL :
				_gmap.setMapType( G_NORMAL_MAP );
				break;
			case MAP_TYPE_SATELLITE :
				_gmap.setMapType( G_SATELLITE_MAP );
				break;
			case MAP_TYPE_HYBRID :
				_gmap.setMapType( G_HYBRID_MAP );
				break;
			case MAP_TYPE_TERRAIN :
				_gmap.setMapType( G_PHYSICAL_MAP );
				break;
			default:
				_gmap.setMapType( type );
				break;
		}
	}
	catch(e) {}
	
}


/**
 * Change map control.
 * @param type the new map type
 */
function mapControl( ctl ) {
	if ( _gmap ) {
		if ( _control ) _gmap.removeControl( _control );
		switch( ctl ) {
			case MAP_CONTROL_NONE :
				break;
			case MAP_CONTROL_LARGE :
				_control = new GLargeMapControl3D();
				_gmap.addControl( _control );
				break;
			case MAP_CONTROL_SMALL :
				_control = new GSmallZoomControl3D();
				_gmap.addControl( _control );
				break;
		}
	}
}




/**
 * Toogle elments to display the map in full/standard dimensions.
 */
function mapfullWindow() {
	
	var main = document.getElementById("main");
	var map  = document.getElementById("map");
	var gmap = document.getElementById("Gmap");
	var tool = document.getElementById("map_toolbar");
	var mftr = document.getElementById("map_footer");
	var opts = document.getElementById('map_options');
	var cls  = main.className=='fw' ? '' : 'fw';
	
	mftr.className = tool.className = map.className = gmap.className = main.className = cls;
	
	// clear update styles
	if ( opts.style.display!='block' && cls=='' ) tool.style.right = gmap.style.right = '';
	if ( opts.style.display=='block' && typeof(viewport)!='undefined' ) viewport.update();
		
	// update Google MAP size
	_gmap.checkResize();
	if ( _daynight ) _daynight.refresh();
}



/**
 * Show / hide option panel.
 */
function mapOptions() {
	
	// error
	if ( !document.getElementById('map_options') ) {
		document.getElementById('map_err').innerHTML += "<br />The options panel is only available with map";
		return;
	}
	
	
	var optelem   = document.getElementById('map_options');
	var mapelem   = document.getElementById('Gmap');
	var maptool   = document.getElementById("map_toolbar");
	var listelem  = document.getElementById('stream_list');
	var enabled   = optelem.style.display!='block';
	var mapoffset = mapelem.className=='fw' ? 1 : 10;
	
	// display/hide options and move map right edge
	optelem.style.display	= enabled ? 'block' : 'none';
	mapelem.style.right		= ( !enabled ? mapoffset : MAP_OPTIONS_WIDTH+10 ) + 'px';
	maptool.style.right		= mapelem.style.right;
	
	
	// arrange elements
	if ( enabled ) {
		optelem.style.width   = MAP_OPTIONS_WIDTH + 'px';
		if ( viewport ) {
			viewport.elem.style.top	  = (listelem.offsetTop+listelem.offsetHeight+3) + 'px';
			viewport.elem.style.width = MAP_OPTIONS_WIDTH-12 + 'px';
			viewport.update();
		}
	}
	
	// update Google MAP size
	_gmap.checkResize();
	if ( _daynight ) _daynight.refresh();
	
	// move the map
	//mapPanBy( optelem.style.display=='none' ? 200 : -200, 0 );
}



/**
 * Modify the current infowindow content.
 *
 * @param name	the element name
 * @param html	the new element content
 */
function mapUpdateInfoWindow( name, html ) {
	if ( !_gmap || !_markers[0] ) return;
	
	
	// create temporary DOM element to search 
	var DOM = document.createElement( "div" );
	DOM.innerHTML = _markers[0].html;
	
	
	// search and modify current HTML
	if ( name!='image' ) {
		var elems = DOM.getElementsByTagName('span');
		for( var i=0; i<elems.length; i++ ) {
			if ( elems[i].className=='infowin_'+name ) elems[i].innerHTML = html;
		}
	}
	else {
		var imgs = DOM.getElementsByTagName('img');
		imgs[0].src = html;
	}
	
	// modify map property/element HTML
	_markers[0].html = DOM.innerHTML;
	if ( _markers[0].overlay.div ) {
		_markers[0].overlay.div.innerHTML = DOM.innerHTML;
		_gmap.removeOverlay( _markers[0].overlay );
		_gmap.addOverlay( _markers[0].overlay );
	}
	
}



/**
 * Handler call to close the overlay when request.
 */
function mapMarkerCloseOverlay() {
	if ( _curmarker ) {
		_gmap.removeOverlay( _curmarker.overlay );
	 	//_curmarker.show();
	 	_curmarker = null;
	}
}




// -------------------------------------------------------------------------------------------------
//	EXTERNAL MODULE : DAYLIGHT & CLOUDS
// -------------------------------------------------------------------------------------------------


/**
 * Show / hide night layer.
 * @param enable	the layer status
 */
function mapDayNight( enable ) {
	if ( _daynight ) {
		_daynight.active = enable;
		_daynight.refresh();
	}
}

/**
 * Whether city lights are displayed on the night side.
 * @param enable	the layer status
 */
function mapCityLigth( enable ) {
	if ( _daynight ) {
		if ( enable && !_daynight.active ) _daynight.active = true;
		_daynight.cityLights = enable;
		_daynight.refresh();
	}
}


/**
 * Add or remove clouds on the map
 * @param enable	show or hide clouds layer
 */
function mapClouds( enable ) {
	if ( _clouds ) {
		_clouds.active = enable;
		_clouds.map.setZoom( _clouds.map.getZoom() ); // refresh
	}
}


/**
 * This function override the daylightMap.CloudLayer.prototype.getTileUrl to add show/hide option
 */
function mapCloudGetTileUrl( point, zoom ) {
	
	var result = '';
	
	if (!this.active) return result;
	
	if ( (this.map.getCurrentMapType() != G_NORMAL_MAP) && (this.map.getZoom() <= daylightMap.CloudLayer._maxZoom) ) {
		result = daylightMap._serverDomain + 'clouds/' + daylightMap.CloudLayer.tileDir + '/ir_' + zoom + '_' + point.x + '_' + point.y + '.png';
	}
	else {
		if ( this.map.getZoom()>1 ) result = daylightMap._serverDomain + 'clouds/map_tile.png.php?z=' + zoom + '&x=' + point.x + '&y=' + point.y;
	}
	
	return result;
}



// -------------------------------------------------------------------------------------------------
//	CUSTOM OVERLAY (INFOWINDOW)
// -------------------------------------------------------------------------------------------------


/**
 * the custom InfoWindow object
 */
var _MapInfoWindow = function( marker ) {
	this.marker = marker;
}


/**
 * The custom InfoWindow object inherit and functions. Functions defined below must exists 
 * (even if it's empty) to work properly.
 */
_MapInfoWindow.prototype = typeof(GOverlay)!='undefined' ? new GOverlay() : {};
_MapInfoWindow.prototype.initialize = function( map ) {
	
	var div = document.createElement( "div" );
	div.className = 'infowin';
	div.innerHTML = this.marker.html;
	
	// append element first to retrieve height property
	map.getPane( G_MAP_FLOAT_PANE ).appendChild( div );
	
	this.map  = map;
	this.div  = div;
	this.icon = div.getElementsByTagName('div')[2];
	
}


/**
 * Remove the main DIV from the map pane
 */
_MapInfoWindow.prototype.remove = function() {
	this.div.parentNode.removeChild( this.div );
}


/**
 * Copy our data to a new _MapInfoWindow
 */
_MapInfoWindow.prototype.copy = function() {
  return new _MapInfoWindow( this.marker );
}



/**
 * Redraw the rectangle based on the current projection and zoom level.
 * We only need to redraw if the coordinate system has changed
 */
_MapInfoWindow.prototype.redraw = function( force ) {
	if ( !force ) return;
  
  	var latlng  = this.marker.getLatLng();
  	var size	= this.map.getSize();
	var xoffset = _icons.on.iconSize.width/2;
	var yoffset = Math.min( size.height/2-10, this.div.offsetHeight/2 );
	var ioffset = yoffset-_icons.on.iconSize.height; //+30;
	
	this.div.style.top  = ( _gmap.fromLatLngToDivPixel(latlng).y - yoffset ) + 'px';
	this.div.style.left = ( _gmap.fromLatLngToDivPixel(latlng).x - xoffset ) + 'px';
	this.icon.style.top = ( ioffset ) + 'px';
	
	this.map.panTo( latlng );
}


