
// Region : consists of two latitude and two longitude values, from which the corner markers
//  and the polygon and the singlePoint are derived.

// A region is modelled by two arrays, one for latitude and one for longitude.
// Each array has two elements, which contain either floats or empty.
//	lat, lon.
// The order that the elements are specified is unimportant. (eg [ 155, 160 ] or [ 160, 155 ] )

// map markers and the polygon and the singlePoint are derived from these variables.

// An empty string; mostly used for lat & lon fields
var empty = "";

Region=function () {
	// specify the edges of the region as two values each of latitude and longitude:
	this.lat=[empty,empty];
	this.lon=[empty,empty];

	// an array of marker objects for the corners, based on the lat and lon values.
	this.m=[[null,null],[null,null]];

	// a polygon built from the four corners.
	this.polygon=null;

	// a single point (NOTE:  at least one of polygon and singlePoint will be null).
	this.singlePoint=null;
}

// try and find the center of the region.  If region is not fully specified, have a go.
// returns a 2 element array of latitude and longitude.  may contain null for either element.
Region.prototype.getCenter=function() {
	var latCenter;
	var lonCenter;
	var onePoint=this.isOnePoint();

	if ( onePoint ) {
		latCenter = onePoint[0];
		lonCenter = onePoint[1];
	} else {
		if ( this.lat[0]==empty || this.lat[1]==empty ) {
			if ( this.lat[0]==empty ) { latCenter=this.lat[1]; } else { latCenter=this.lat[0]; }
		} else {
			latCenter=this.lat[0]*1 + (this.lat[1]-this.lat[0])/2.0;
//			report.say("this.lat[0]: "+this.lat[0]);
//			report.say("this.lat[1]: "+this.lat[1]);
//			report.say("latCenter: "+latCenter);
		}
		if ( this.lon[0]==empty || this.lon[1]==empty ) {
			if ( this.lon[0]==empty ) { lonCenter=this.lon[1]; } else { lonCenter=this.lon[0]; }
		} else {
			lonCenter=this.lon[0]*1 + (this.lon[1]-this.lon[0])/2.0;
		}
	}
	return [ latCenter, lonCenter ];
}

Region.prototype.reportmarkers=function() {
	var msg="<BR>Markers: ";
	for ( i in [0,1] ) {
		msg += "<BR> (i="+i+") ";
		for ( j in [0,1] ) {
			msg += "<BR>   (j="+j+") <BR>";
			if ( this.m[i][j] == null ) {
				msg+=" Null ";
			} else {
				var marker=this.m[i][j];
				msg+=" ilat: "+ marker.ilat;
				msg+=" ilon: "+ marker.ilon;
			}
		}
	}
	return msg;
}
Region.prototype.report=function() {
	var msg="lat[0]: "+this.lat[0]
		+" lat[1]: "+this.lat[1]
		+" lon[0]: "+this.lon[0]
		+" lon[1]: "+this.lon[1]
		+".";
	msg+=this.reportmarkers();
	return msg;
}
Region.prototype.clear=function(){
	// clear data model
	this.lat=[empty,empty];
	this.lon=[empty,empty];
	this.m=[[null,null],[null,null]];
	this.polygon=null;
	this.singlePoint=null;

	// clear input boxes
	this.resetInput();
	// clear markers and polygon from map
	map.clearOverlays();
	// but keep the extents overlay..
	//displayProductExtents(productMenu.selectedIndex);
	displayProductExtents(prod.selectedIndex);

//	report.say("region cleared. "+this.report());
	report.clear();
	info.clear();
	info.say("<br><br>");
}

// update variables as neccessary, and redraw the web-page.
Region.prototype.resetMarkers=function(){
	// report.say("resetMarkers:  "+this.report());
	// report.say("resetMarkers:");
	for (ilat in this.lat) {
	  if (this.lat[ilat]==empty) {
		// report.say("lat "+ilat+":  "+"Null");
	  } else {
		// report.say("lat "+ilat+":  "+this.lat[ilat]);
		for ( ilon in this.lon) {
			if (this.lon[ilon]==empty) {
				// report.say("lon "+ilon+":  "+"Null");
			} else {
				// report.say("lon "+ilon+":  "+this.lon[ilon]);
				if (this.m[ilat][ilon]) {
					// report.say("setting latlon ","blue");
//					report.say(this.lat[ilat],"green");
//					report.say(this.lon[ilon],"green");
//					report.say(this.m[ilat][ilon].ilat);
//					report.say(this.m[ilat][ilon].getLatLng().x);
//					report.say(this.m[ilat][ilon].getLatLng().y);
					this.m[ilat][ilon].setLatLng(
						new GLatLng(this.lat[ilat],this.lon[ilon]));
//					report.say("done ","blue");
				} else {
					// report.say("creating new marker ","magenta");
					this.m[ilat][ilon]=regionCorner.makeMarker(this,ilat,ilon);
				}
			}
		}
	  }
	}	
	this.buildPolygon();
}
Region.prototype.resetInput=function(){
	maplon[0].value=region.lon[0];
	maplon[1].value=region.lon[1];
	maplat[0].value=region.lat[0];
	maplat[1].value=region.lat[1];
}
Region.prototype.buildPolygon=function(){

	if(this.polygon) {map.removeOverlay(this.polygon);}
	region.insidePoly=false;

	if ( this.m[0][0]==null || this.m[0][1]==null 
		|| this.m[1][0]==null || this.m[1][1]==null ) {
		this.polygon=null;
		return;
	} 
	// Polygon mode closing polygon
	var points=[
		 	this.m[0][0].getLatLng(), 
			this.m[1][0].getLatLng(),
			this.m[1][1].getLatLng(),
			this.m[0][1].getLatLng(),
			this.m[0][0].getLatLng()
		 ];
	points=[
		 	this.m[0][0].getLatLng(), 
			this.m[0][1].getLatLng(),
			this.m[1][1].getLatLng(),
			this.m[1][0].getLatLng(),
			this.m[0][0].getLatLng()
		 ];
	this.polygon = new GPolygon(points, lineColor, lineWeight, lineOpacity, fillColor, fillOpacity, {clickable:false});
	this.area = this.polygon.getArea()/(1000*1000);
	var unit = " km&sup2;";
//	var mno = marker.content;
	info.clear();
	info.say( "Area selected:<br> " + this.area.toFixed(3) + "  " + unit);

	//this.polygon.draggable=true;
	GEvent.addListener(this.polygon, "mouseover", function() {
		region.insidePoly=true;
	});
	GEvent.addListener(this.polygon, "mouseout", function() {
		region.insidePoly=false;
	});
	// the following have now effect:
	GEvent.addListener(this.polygon, "click", function() {
		report.error("click inside polygon!");
	});
	GEvent.addListener(this.polygon, "drag", function() {
		report.error("moving polygon!");
	});
//	report.say( listObjectMembers(this.polygon) );
	map.addOverlay(this.polygon);
}

// namespace for dealing with corners of a region:
var regionCorner={};
// return a visible marker on the map representing one of the corners of a specific region
// the returned object is a GMarker, but with ilat and ilon properties added.
regionCorner.makeMarker=function(region, ilat, ilon) {

	// return null object if indexes are invalid:
	if ( ilat < 0 || ilat > 1 || ilon < 0 || ilon > 1 ) { 
		return {};
	}
	// return null object if either of latitude or longitude is not yet defined
	if ( (region.lat[ilat]==empty) || (region.lon[ilon]==empty)) {
		return {};
	}
	
	var point={y: region.lat[ilat], x:region.lon[ilon]};
	var marker=new gmarker.newMarker(point);

	marker.ilat=ilat;
	marker.ilon=ilon;
	marker.region=region;
	
	regionCorner.addEventListeners(marker);

	return marker;
}
regionCorner.addEventListeners=function(marker) {
    GEvent.addListener(marker, "mouseover", function() {
        showTooltip(marker);
    });
 
    GEvent.addListener(marker, "mouseout", function() {
        tooltip.style.display = "none";
    });

    // Drag listener
    GEvent.addListener(marker, "drag", function() {
        tooltip.style.display= "none";
        regionCorner.move(marker);
    });
}

regionCorner.move=function(marker) {
        var point=marker.getLatLng();
	report.clear();
//      report.say( "Lat: "+point.y+" Lng: "+point.x );
//      report.say( "ilat: "+marker.ilat+" ilon: "+marker.ilon );
	
	marker.region.lat[marker.ilat]=point.y.toFixed(3);
	marker.region.lon[marker.ilon]=point.x.toFixed(3);
	marker.region.resetInput();
	region.resetMarkers();
//	report.say( marker.region.report(),"green" );
}

// ============================================
// respond to a change in the value of any of the lat/lon input entry boxes.
// In the case of an incorrect value, the value gets set to empty
//  theid is the HTML id of the entry box.
//  latlon is a string, either 'lat' or 'lon', i is either 0 or 1.
function latlonInputChange(theid,latlon,i) {
	report.clear();
	// report.say("latlonInputChange","red");
	var val=empty;
        var txtInput=document.getElementById(theid);
        var txt=txtInput.value;

        if (txt==empty) { 
//              report.error( "Blank input was ignored for "+theid);
		region.resetInput();
        } else {
                var val=parseFloat(txt);
                if ( isNaN(val) ) { 
                        report.error(txt+" is not a number, and was ignored for "+theid);
			region.resetInput();
                } else {
			region[latlon][i]=val;
		}
	}
	region.resetMarkers();

	// Put the ".say" call(s) after the ".error" calls, because ".error" clears the report:
//	report.say("latlonInputChange("+theid+","+latlon+","+i+")","red");
//	report.say(region.report(),"green");
}

function mapLeftClick(overlay, point) {
	report.clear();
//	report.say("map click");
	if(point) {
		var lat=point.y.toFixed(3);
		var lon=point.x.toFixed(3);
//		report.say( lon+" "+lat);
		// try and find a un-defined lat/lon values, set one if found.
		if ( region.lat[0]==empty ) {
//			report.say( ".. lat[0] undefined");
			region.lat[0]=lat;
		} else if ( region.lat[1]==empty ) {
//			report.say( ".. lat[1] undefined");
			region.lat[1]=lat;
		} else {
//			report.say( ".. both lat edges are already defined. (doing nothing)");
		}
		if ( region.lon[0]==empty ) {
//			report.say( ".. lon[0] undefined");
			region.lon[0]=lon;
		} else if ( region.lon[1]==empty ) {
//			report.say( ".. lon[1] undefined");
			region.lon[1]=lon;
		} else {
//			report.say( ".. both lon edges are already defined. (doing nothing)");
		}
		region.resetMarkers();
		region.resetInput();	
	}
}

// decide whether the user has specified a single point.
// returns the point as [ lat , lon ] if it is, returns false otherwise
Region.prototype.isOnePoint=function() {
	result=false;
	var lat0set=(region.lat[0]!=empty);
	var lat1set=(region.lat[1]!=empty);
	var lon0set=(region.lon[0]!=empty);
	var lon1set=(region.lon[1]!=empty);
	var lat;
	var lon;
	var unset = "Unset";
	// report.say("isOnePoint:  unset = ["+unset+"]","blue");

	// report.say("isOnePoint:  lat0 = ["+region.lat[0]+"]","blue");
	// report.say("isOnePoint:  lon0 = ["+region.lon[0]+"]","blue");
	// report.say("isOnePoint:  lat1 = ["+region.lat[1]+"]","blue");
	// report.say("isOnePoint:  lon1 = ["+region.lon[1]+"]","blue");

	if ( lat0set && !lat1set ) {
		lat=region.lat[0];
	} else if ( !lat0set && lat1set ) {
		lat=region.lat[1];
	} else {
		lat = unset;
	}
	// report.say("isOnePoint:  lat = ["+lat+"]","blue");

	if ( lon0set && !lon1set ) {
		lon=region.lon[0];
	} else if ( !lon0set && lon1set ) {
		lon=region.lon[1];
	} else {
		lon = unset;
	}
	// report.say("isOnePoint:  lon = ["+lon+"]","blue");

	if ( lat != unset && lon != unset ) {
		result=[lat,lon];
		// report.say("isOnePoint:  True","blue");
	} else {
		// report.say("isOnePoint:  False","blue");
	}

	// report.say("isOnePoint:  result = ["+result+"]","blue");
	return result;
}

