// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API
if ( typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) (function(){

// -- BEGIN GEARS_INIT
(function() {
  // We are already defined. Hooray!
  if (window.google && google.gears) {
    return;
  }

  var factory = null;

  // Firefox
  if (typeof GearsFactory != 'undefined') {
    factory = new GearsFactory();
  } else {
    // IE
    try {
      factory = new ActiveXObject('Gears.Factory');
      // privateSetGlobalObject is only required and supported on WinCE.
      if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
        factory.privateSetGlobalObject(this);
      }
    } catch (e) {
      // Safari
      if ((typeof navigator.mimeTypes != 'undefined')
           && navigator.mimeTypes["application/x-googlegears"]) {
        factory = document.createElement("object");
        factory.style.display = "none";
        factory.width = 0;
        factory.height = 0;
        factory.type = "application/x-googlegears";
        document.documentElement.appendChild(factory);
      }
    }
  }

  // *Do not* define any objects if Gears is not installed. This mimics the
  // behavior of Gears defining the objects in the future.
  if (!factory) {
    return;
  }

  // Now set up the objects, being careful not to overwrite anything.
  //
  // Note: In Internet Explorer for Windows Mobile, you can't add properties to
  // the window object. However, global objects are automatically added as
  // properties of the window object in all browsers.
  if (!window.google) {
    google = {};
  }

  if (!google.gears) {
    google.gears = {factory: factory};
  }
})();
// -- END GEARS_INIT

var GearsGeoLocation = (function() {
	if (!window.google || !google.gears) {
	    return;
	  }
	  
    // -- PRIVATE
    var geo = google.gears.factory.create('beta.geolocation');
    
    var wrapSuccess = function(callback, self) { // wrap it for lastPosition love
        return function(position) {
            callback(position);
            self.lastPosition = position;
        }
    }
    
    // -- PUBLIC
    return {
        shim: true,
        
        type: "Gears",
        
        lastPosition: null,
        
        getCurrentPosition: function(successCallback, errorCallback, options) {
            var self = this;
            var sc = wrapSuccess(successCallback, self);
            geo.getCurrentPosition(sc, errorCallback, options);
        },
        
        watchPosition: function(successCallback, errorCallback, options) {
            return geo.watchPosition(successCallback, errorCallback, options);
        },
        
        clearWatch: function(watchId) {
            geo.clearWatch(watchId);
        },
        
        getPermission: function(siteName, imageUrl, extraMessage) {
            geo.getPermission(siteName, imageUrl, extraMessage);
        }

    };
})();

var AjaxGeoLocation = (function() {
    // -- PRIVATE
    var loading = false;
    var loadGoogleLoader = function() {
        if (!hasGoogleLoader() && !loading) {
            loading = true;
            var s = document.createElement('script');
            s.src = 'http://www.google.com/jsapi?callback=_google_loader_apiLoaded&key=' + window.googleAjaxAPIKey;
            s.type = "text/javascript";
            document.getElementsByTagName('body')[0].appendChild(s);
        }
    };
    
    var queue = [];
    var addLocationQueue = function(callback) {
        queue.push(callback);
    }
    
    var runLocationQueue = function() {
        if (hasGoogleLoader()) {
            while (queue.length > 0) {
                var call = queue.pop();
                call();
            }
        }
    }
    
    window['_google_loader_apiLoaded'] = function() {
        runLocationQueue();
    }
    
    var hasGoogleLoader = function() {
        return (window['google'] && google['loader']);
    }
    
    var checkGoogleLoader = function(callback) {
        if (hasGoogleLoader()) return true;

        addLocationQueue(callback);
                
        loadGoogleLoader();
        
        return false;
    };
    
    loadGoogleLoader(); // start to load as soon as possible just in case
    
    // -- PUBLIC
    return {
        shim: true,
        
        type: "ClientLocation",
        
        lastPosition: null,
        
        getCurrentPosition: function(successCallback, errorCallback, options) {
            var self = this;
            if (!checkGoogleLoader(function() {
                self.getCurrentPosition(successCallback, errorCallback, options);
            })) return;
            
            if (google.loader.ClientLocation) {
                var cl = google.loader.ClientLocation;
                
                var position = {
                    latitude: cl.latitude,
                    longitude: cl.longitude,
                    altitude: null,
                    accuracy: 43000, // same as Gears accuracy over wifi?
                    altitudeAccuracy: null,
                    heading: null,
                    velocity: null,
                    timestamp: new Date(),
                    
                    // extra info that is outside of the bounds of the core API
                    address: {
                        city: cl.address.city,
                        country: cl.address.country,
                        country_code: cl.address.country_code,
                        region: cl.address.region
                    }
                };

                successCallback(position);
                
                this.lastPosition = position;
            } else if (typeof errorCallback == "function")  {
                errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."});
            }
        },
        
        watchPosition: function(successCallback, errorCallback, options) {
            this.getCurrentPosition(successCallback, errorCallback, options);
            
            var self = this;
            var watchId = setInterval(function() {
                self.getCurrentPosition(successCallback, errorCallback, options);
            }, 10000);
            
            return watchId;
        },
        
        clearWatch: function(watchId) {
            clearInterval(watchId);
        },
        
        getPermission: function(siteName, imageUrl, extraMessage) {
            // for now just say yes :)
            return true;
        }

    };
})();

// If you have Gears installed use that, else use Ajax ClientLocation
navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation : AjaxGeoLocation;

})();

function preventBubble( E )
{
	if( window.event ){
		window.event.cancelBubble = true;
		window.event.returnValue  = false;
	} else if( E && ( typeof E.stopPropagation != 'undefined' ) ) {
		E.stopPropagation();
	}
	else if( E && ( typeof E.preventBubble != 'undefined' ) ) {
		E.preventBubble();
	}
    
	if( E && ( typeof E.preventDefault != 'undefined' ) ) {
		E.preventDefault();
	}
}


function InfoBox(opts) {
	google.maps.OverlayView.call(this);
	this.map_ = opts.map;

	var me = this;
	/*
	this.boundsChangedListener_ =
		google.maps.event.addListener(this.map_, "bounds_changed", function() {
			return me.panMap.apply(me);
	});
	*/
}

InfoBox.prototype = new google.maps.OverlayView();

	
InfoBox.prototype.remove = function() {
	if (this.div_) {
		this.div_.parentNode.removeChild(this.div_);
		this.div_ = null;
	}
	if (this.contentdiv_) {
		this.contentdiv_.parentNode.removeChild(this.contentdiv_);
		this.contentdiv_ = null;
	}
	this.setMap( null );
};


InfoBox.prototype.close = function()
{
	this.remove();
};

InfoBox.prototype.set_size = function( size )
{
	this.width_ = size.width;
	this.height_ = size.height;
	if( this.div_ ) {
		this.div_.style.width = this.width_ + "px";
		this.div_.style.height = ( this.height_ + 8 ) + "px";
		this.panMap();
	}
};

InfoBox.prototype.set_content = function( content )
{
	this.content_ = content;
	if( this.contentdiv_ ) {
		this.contentdiv_.innerHTML = content;
		this.panMap();
	}
};

InfoBox.prototype.open = function( map, marker )
{
	this.latlng_ = marker.getPosition();
	this.setMap(this.map_);
	this.panMap();
}

InfoBox.prototype.draw = function() {
	// Creates the element if it doesn't exist already.
			this.createElement();
			if (!this.div_) return;

	// Calculate the DIV coordinates of two opposite corners of our bounds to
			// get the size and position of our Bar
			var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
			if (!pixPosition) return;

	// Now position our DIV based on the DIV coordinates of our bounds
	this.div_.style.width = this.width_ + "px";
	this.div_.style.left = ( ( pixPosition.x - this.width_ / 2 + 1) | 0 ) + "px";
	this.div_.style.height = this.height_ + "px";
	this.div_.style.top = (pixPosition.y - this.height_ - 43 ) + "px";
	this.div_.style.display = 'block';
	
	/*
	alert( pixPosition.x  + "\n" + pixPosition.y + "\n" +
		this.div_.style.left + "\n" + this.div_.style.width + "\n" +
		this.div_.style.top + "\n" + this.div_.style.height );
	*/
};

/* Creates the DIV representing this InfoBox in the floatPane.  If the panes
 * object, retrieved by calling get_panes, is null, remove the element from the
 * DOM.  If the div exists, but its parent is not the floatPane, move the div
 * to the new pane.
 * Called from within draw.  Alternatively, this can be called specifically on
 * a panes_changed event.
 */
InfoBox.prototype.createElement = function() {
	var panes = this.getPanes();
	var div = this.div_;
	if (!div) {
		// This does not handle changing panes.  You can set the map to be null and
		// then reset the map to move the div.
		div = this.div_ = document.createElement("div");
		div.style.position = "absolute";
		div.style.width = this.width_ + "px";
		div.style.height = ( this.height_ + 8 ) + "px";
		
		var outerDiv = document.createElement("div");
		outerDiv.style.border = "1px solid black";
		outerDiv.style.borderBottom = "0";
		outerDiv.style.backgroundColor = "#FFFFFF";
		outerDiv.style.height = this.height_ + "px";
		
		//var topDiv = document.createElement("div");
		//outerDiv.appendChild( topDiv );
		//topDiv.style.textAlign = "right";
		var closeImg = document.createElement("img");
		closeImg.style.width = "32px";
		closeImg.style.height = "32px";
		closeImg.style.cursor = "pointer";
		closeImg.style.position = "absolute";
		closeImg.style.top = "5px";
		closeImg.style.right = "5px";
		closeImg.style.zIndex = 10;
		closeImg.src = mrpSettings.resourceServer + "img/mobile/closebigger.gif";
		outerDiv.appendChild( closeImg );
		//topDiv.appendChild(closeImg);
		
		var contentDiv = document.createElement( "div" );
		this.contentdiv_ = contentDiv;
		contentDiv.style.padding = "5px";
		outerDiv.appendChild( contentDiv );
		if( this.content_ ) {
			contentDiv.innerHTML = this.content_;
		}
		//contentDiv.innerHTML = "<b>Hello World!</b>";
		
		var beakDiv = document.createElement( "div" );
		beakDiv.style.height = "8px";
			beakDiv.style.background = "url(" + mrpSettings.resourceServer + "img/mobile/gmap-beak-down.png) no-repeat center top";
			
		function removeInfoBox(ib) {
			return function() {
     					ib.setMap(null);
   					};
		}

	    google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));

		div.appendChild(outerDiv);
		div.appendChild(beakDiv);
		div.style.display = 'none';
		panes.floatPane.appendChild(div);
	} 
	else if (div.parentNode != panes.floatPane) {
		// The panes have changed.  Move the div.
		div.parentNode.removeChild(div);
		panes.floatPane.appendChild(div);
	} 
	else {
		// The panes have not changed, so no need to create or move the div.
	}
}

/* Pan the map to fit the InfoBox.
	*/
InfoBox.prototype.panMap = function() {
	// if we go beyond map, pan map
	var map = this.map_;
	var bounds = map.getBounds();
	if (!bounds) return;

	// The position of the infowindow
	var position = this.latlng_;
	 
	// The dimension of the infowindow
	var iwWidth = this.width_ + 20;
	var iwHeight = this.height_;
	 
	// The offset position of the infowindow
	var iwOffsetX = -( this.width_ / 2 ) | 0;
	var iwOffsetY = -this.height_;
	 
	// Padding on the infowindow
	var padX = 0;
	var padY = 110;
	 
	// The degrees per pixel
	var mapDiv = map.getDiv();
	var mapWidth = mapDiv.offsetWidth;
	var mapHeight = mapDiv.offsetHeight;
	var boundsSpan = bounds.toSpan();
	var longSpan = boundsSpan.lng();
	var latSpan = boundsSpan.lat();
	var degPixelX = longSpan / mapWidth;
	var degPixelY = latSpan / mapHeight;
	 
	// The bounds of the map
	var mapWestLng = bounds.getSouthWest().lng();
	var mapEastLng = bounds.getNorthEast().lng();
	var mapNorthLat = bounds.getNorthEast().lat();
	var mapSouthLat = bounds.getSouthWest().lat();
	 
	// The bounds of the infowindow
	var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
	var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
	var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
	var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;
	 
	// calculate center shift
	var shiftLng =
		(iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
		(iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
	var shiftLat =
		(iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
		(iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);
	 
	// The center of the map
	var center = map.getCenter();
	 
	// The new map center
	var centerX = center.lng() - shiftLng;
	var centerY = center.lat() - shiftLat;
	 
	// center the map to the new shifted center
	map.setCenter(new google.maps.LatLng(centerY, centerX));
	 
	// Remove the listener after panning is complete.
	//google.maps.event.removeListener(this.boundsChangedListener_);
	//this.boundsChangedListener_ = null;
};

function preventBubble( E )
{
	if( window.event ){
		window.event.cancelBubble = true;
		window.event.returnValue  = false;
	} else if( E && ( typeof E.stopPropagation != 'undefined' ) ) {
		E.stopPropagation();
	}
	else if( E && ( typeof E.preventBubble != 'undefined' ) ) {
		E.preventBubble();
	}
    
	if( E && ( typeof E.preventDefault != 'undefined' ) ) {
		E.preventDefault();
	}
}


function InfoBox(opts) {
	google.maps.OverlayView.call(this);
	this.map_ = opts.map;

	var me = this;
	/*
	this.boundsChangedListener_ =
		google.maps.event.addListener(this.map_, "bounds_changed", function() {
			return me.panMap.apply(me);
	});
	*/
}

InfoBox.prototype = new google.maps.OverlayView();

	
InfoBox.prototype.remove = function() {
	if (this.div_) {
		this.div_.parentNode.removeChild(this.div_);
		this.div_ = null;
	}
	if (this.contentdiv_) {
		this.contentdiv_.parentNode.removeChild(this.contentdiv_);
		this.contentdiv_ = null;
	}
	this.setMap( null );
};


InfoBox.prototype.close = function()
{
	this.remove();
};

InfoBox.prototype.set_size = function( size )
{
	this.width_ = size.width;
	this.height_ = size.height;
	if( this.div_ ) {
		this.div_.style.width = this.width_ + "px";
		this.div_.style.height = ( this.height_ + 8 ) + "px";
		this.panMap();
	}
};

InfoBox.prototype.set_content = function( content )
{
	this.content_ = content;
	if( this.contentdiv_ ) {
		this.contentdiv_.innerHTML = content;
		this.panMap();
	}
};

InfoBox.prototype.open = function( map, marker )
{
	this.latlng_ = marker.getPosition();
	this.setMap(this.map_);
	this.panMap();
}

InfoBox.prototype.draw = function() {
	// Creates the element if it doesn't exist already.
			this.createElement();
			if (!this.div_) return;

	// Calculate the DIV coordinates of two opposite corners of our bounds to
			// get the size and position of our Bar
			var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
			if (!pixPosition) return;

	// Now position our DIV based on the DIV coordinates of our bounds
	this.div_.style.width = this.width_ + "px";
	this.div_.style.left = ( ( pixPosition.x - this.width_ / 2 + 1) | 0 ) + "px";
	this.div_.style.height = this.height_ + "px";
	this.div_.style.top = (pixPosition.y - this.height_ - 43 ) + "px";
	this.div_.style.display = 'block';
	
	/*
	alert( pixPosition.x  + "\n" + pixPosition.y + "\n" +
		this.div_.style.left + "\n" + this.div_.style.width + "\n" +
		this.div_.style.top + "\n" + this.div_.style.height );
	*/
};

/* Creates the DIV representing this InfoBox in the floatPane.  If the panes
 * object, retrieved by calling get_panes, is null, remove the element from the
 * DOM.  If the div exists, but its parent is not the floatPane, move the div
 * to the new pane.
 * Called from within draw.  Alternatively, this can be called specifically on
 * a panes_changed event.
 */
InfoBox.prototype.createElement = function() {
	var panes = this.getPanes();
	var div = this.div_;
	if (!div) {
		// This does not handle changing panes.  You can set the map to be null and
		// then reset the map to move the div.
		div = this.div_ = document.createElement("div");
		div.style.position = "absolute";
		div.style.width = this.width_ + "px";
		div.style.height = ( this.height_ + 8 ) + "px";
		
		var outerDiv = document.createElement("div");
		outerDiv.style.border = "1px solid black";
		outerDiv.style.borderBottom = "0";
		outerDiv.style.backgroundColor = "#FFFFFF";
		outerDiv.style.height = this.height_ + "px";
		
		//var topDiv = document.createElement("div");
		//outerDiv.appendChild( topDiv );
		//topDiv.style.textAlign = "right";
		var closeImg = document.createElement("img");
		closeImg.style.width = "32px";
		closeImg.style.height = "32px";
		closeImg.style.cursor = "pointer";
		closeImg.style.position = "absolute";
		closeImg.style.top = "5px";
		closeImg.style.right = "5px";
		closeImg.style.zIndex = 10;
		closeImg.src = mrpSettings.resourceServer + "img/mobile/closebigger.gif";
		outerDiv.appendChild( closeImg );
		//topDiv.appendChild(closeImg);
		
		var contentDiv = document.createElement( "div" );
		this.contentdiv_ = contentDiv;
		contentDiv.style.padding = "5px";
		outerDiv.appendChild( contentDiv );
		if( this.content_ ) {
			contentDiv.innerHTML = this.content_;
		}
		//contentDiv.innerHTML = "<b>Hello World!</b>";
		
		var beakDiv = document.createElement( "div" );
		beakDiv.style.height = "8px";
			beakDiv.style.background = "url(" + mrpSettings.resourceServer + "img/mobile/gmap-beak-down.png) no-repeat center top";
			
		function removeInfoBox(ib) {
			return function() {
     					ib.setMap(null);
   					};
		}

	    google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));

		div.appendChild(outerDiv);
		div.appendChild(beakDiv);
		div.style.display = 'none';
		panes.floatPane.appendChild(div);
	} 
	else if (div.parentNode != panes.floatPane) {
		// The panes have changed.  Move the div.
		div.parentNode.removeChild(div);
		panes.floatPane.appendChild(div);
	} 
	else {
		// The panes have not changed, so no need to create or move the div.
	}
}

/* Pan the map to fit the InfoBox.
	*/
InfoBox.prototype.panMap = function() {
	// if we go beyond map, pan map
	var map = this.map_;
	var bounds = map.getBounds();
	if (!bounds) return;

	// The position of the infowindow
	var position = this.latlng_;
	 
	// The dimension of the infowindow
	var iwWidth = this.width_ + 20;
	var iwHeight = this.height_;
	 
	// The offset position of the infowindow
	var iwOffsetX = -( this.width_ / 2 ) | 0;
	var iwOffsetY = -this.height_;
	 
	// Padding on the infowindow
	var padX = 0;
	var padY = 110;
	 
	// The degrees per pixel
	var mapDiv = map.getDiv();
	var mapWidth = mapDiv.offsetWidth;
	var mapHeight = mapDiv.offsetHeight;
	var boundsSpan = bounds.toSpan();
	var longSpan = boundsSpan.lng();
	var latSpan = boundsSpan.lat();
	var degPixelX = longSpan / mapWidth;
	var degPixelY = latSpan / mapHeight;
	 
	// The bounds of the map
	var mapWestLng = bounds.getSouthWest().lng();
	var mapEastLng = bounds.getNorthEast().lng();
	var mapNorthLat = bounds.getNorthEast().lat();
	var mapSouthLat = bounds.getSouthWest().lat();
	 
	// The bounds of the infowindow
	var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
	var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
	var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
	var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;
	 
	// calculate center shift
	var shiftLng =
		(iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
		(iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
	var shiftLat =
		(iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
		(iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);
	 
	// The center of the map
	var center = map.getCenter();
	 
	// The new map center
	var centerX = center.lng() - shiftLng;
	var centerY = center.lat() - shiftLat;
	 
	// center the map to the new shifted center
	map.setCenter(new google.maps.LatLng(centerY, centerX));
	 
	// Remove the listener after panning is complete.
	//google.maps.event.removeListener(this.boundsChangedListener_);
	//this.boundsChangedListener_ = null;
};

