/* An InfoBox is like an info window, but it displays
 * under the marker, opens quicker, and has flexible styling.
 * @param {GLatLng} latlng Point to place bar at
 * @param {Map} map The map on which to display this InfoBox.
 * @param {Object} opts Passes configuration options - content,
 *   offsetVertical, offsetHorizontal, className, height, width
 */
function InfoBox() {
	google.maps.OverlayView.call(this);
}


/* InfoBox extends GOverlay class from the Google Maps API
 */
InfoBox.prototype = new google.maps.OverlayView();

InfoBox.prototype.open = function(opts) {
	this.latlng_ = opts.latlng;
	this.map_ = opts.map;
	this.html_ = opts.html;
	this.offsetVertical_ = -240;
	this.offsetHorizontal_ = -35;
	this.height_ = 228;
	this.width_ = 227;
	this.number = opts.number || false;
	this.show = opts.show || false;
	var me = this;
	this.boundsChangedListener_ =
	google.maps.event.addListener(this.map_, "bounds_changed", function() {
		return me.panMap.apply(me);
	});
	this.setMap(this.map_);
}

/* Creates the DIV representing this InfoBox
 */
InfoBox.prototype.remove = function() {
	if (this.div_) {
		this.div_.parentNode.removeChild(this.div_);
		this.div_ = null;
	}
};

/* Redraw the Bar based on the current projection and zoom level
 */
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.offsetHorizontal_) + "px";
	this.div_.style.height = this.height_ + "px";
	this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
	this.div_.style.display = 'block';
	this.div_.className = 'infoWindowWebcam';
		
	if (this.number) {	
		this.span_.style.left = (pixPosition.x + this.offsetHorizontal_ + 28) + "px";
		this.span_.style.top = (pixPosition.y + this.offsetVertical_ + 212) + "px";
		this.span_.style.display = 'block';
		this.span_.style.position = 'absolute';
		this.span_.style.color = '#ffffff';
		this.span_.style.width = '15px';
		this.span_.style.height = '15px';
		this.span_.className = 'number';
		this.span_.style.textAlign = 'center';
	}
	
};

/* Creates the DIV representing this InfoBox in the floatPane.  If the panes
 * object, retrieved by calling getPanes, 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_;
	var span = this.span_;
	
	if (this.number) {	
		if (!span) {
			var span = this.span_ = document.createElement("span");
			span.innerHTML = '0';
			span.className = 'number';
			panes.floatPane.appendChild(span);
		}
	}
  
	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.border = "0px none";
		div.style.position = "absolute";
		//div.style.background = "url('http://gmaps-samples.googlecode.com/svn/trunk/images/blueinfowindow.gif')";
		div.style.width = this.width_ + "px";
		div.style.height = this.height_ + "px";
		var contentDiv = document.createElement("div");
		contentDiv.className='inner';
		contentDiv.innerHTML = this.html_;

		//var topDiv = document.createElement("div");
		//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.right = "7px";
		closeImg.style.top = "2px";
		closeImg.src = "http://gmaps-samples.googlecode.com/svn/trunk/images/closebigger.gif";
		contentDiv.appendChild(closeImg);

		function removeInfoBox(ib) {
			return function() {
				ib.setMap(null);
			};
		}

		google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));

		//div.appendChild(topDiv);
		div.appendChild(contentDiv);
		div.style.display = 'none';
		panes.floatPane.appendChild(div);
		
		this.panMap();
	} 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_;
	var iwHeight = this.height_;

	// The offset position of the infowindow
	var iwOffsetX = this.offsetHorizontal_;
	var iwOffsetY = this.offsetVertical_;

	// Padding on the infowindow
	var padX = 0;
	var padY = 0;

	// 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
	// TODO: NOT WORK ZOOM & MOVE
	map.setCenter(new google.maps.LatLng(centerY, centerX));

	// Remove the listener after panning is complete.
	google.maps.event.removeListener(this.boundsChangedListener_);
	this.boundsChangedListener_ = null;
};
