
/**************************************************************************
***************************************************************************
** OBJECT AND FUNCTIONS FOR HANDLING EVENTS ON GOOGLE OBJECTS
***************************************************************************
**************************************************************************/
// Copyright 2007-2008 Collaborative Bike Map Project

/****************************************************************************
// Object that defines the event handler and other properties
// for each event on a Google object.  Use setHandler() to
// set up a listener function which calls the handler.
****************************************************************************/
function MapEvents () {
	this.GMap2_click =		{fnobj:null, fn:mapClick,		argct:2};		// parms = overlay, glatlng			
	this.GMarker_click =	{fnobj:null, fn:pointClick,		argct:0};
	this.GMarker_dragend =	{fnobj:null, fn:pointDrag,		argct:0};
	this.GPolyline_click =	{fnobj:null, fn:polylineClick,	argct:0};
	this.GMap2_moveend =	{fnobj:null, fn:mapPan,			argct:0};
	this.GMap2_zoomend =	{fnobj:null, fn:mapPan,			argct:0};       // for zoom, parms = oldLevel, newLevel
}

/****************************************************************************
// setHandler() method
// This sets the handler for a particular GEvent event, based on the
//   function bindings set in the MapEvents object.
// Inputs: 
//   obj - Google API object the event is triggered by
//   objname - Name of the Google API object in obj (e.g. 'GMarker')
//   eventname - Name of the event (e.g. 'dragend' or 'click)
//   parmarray - Array of arguments to be passed to the designated handler routine.  These
//      are passed verbatim by the event listener (the nested closure routine) to the event handler, 
//      in addition to (after) Goodle-defined arguments defined for the listener that we want to use 
//      (argct from MapEvents indicates the number of Google-defined arges we want to use). 
****************************************************************************/
MapEvents.prototype.setHandler = function (obj, objname, eventname, parmarray) {
	var i;
	var keyname = objname + '_' + eventname;      // build key into MapEvents object
	var optional_args = [];
	var mapev = this;                             // can't use "this" in event handlers because it points to event object
	for (i=0; i<arguments.length; i++) {
		optional_args[i] = arguments[i+3];
	}
	
	// Define nested event listener function based on argct...
	// Do it this non-elegant way because it's clearer, limits logic within each
	// listener and avoids possible pitfalls of using "arguments" object
	switch (this[keyname].argct) { 			
		case 3:
			GEvent.addListener (obj, eventname, function (parm0, parm1, parm2) { 
				var ar = [(parm0 || null), (parm1 || null), (parm2 || null)];
				mapev[keyname].fn.apply (mapev[keyname].fnobj, ar.concat (parmarray));     
			});
			break;			
		case 2:
			GEvent.addListener (obj, eventname, function (parm0, parm1) {
				var ar = [(parm0 || null), (parm1 || null)];
				mapev[keyname].fn.apply (mapev[keyname].fnobj, ar.concat (parmarray));      
			});
			break;			
		case 1:
			GEvent.addListener (obj, eventname, function (parm0) {
				var ar = [(parm0 || null)];
				mapev[keyname].fn.apply (mapev[keyname].fnobj, ar.concat (parmarray));       
			});
			break;			
		case 0:
			GEvent.addListener (obj, eventname, function () {
				mapev[keyname].fn.apply (mapev[keyname].fnobj, parmarray);        
			});			
			break;		
		default:
			alert ('Error: MapEvents.argct is out of range (' + this[keyname].argct + ')');
	}
}


/***********************************************************************************************************/
/***********************************************************************************************************/
// Non-member functions - Event handlers for major events
/***********************************************************************************************************/
/***********************************************************************************************************/

/******************************************/
/* Procedure that handles map click event */
/******************************************/
function mapClick (overlay, glatlng) {    
	//debugger;
	if (overlay == null) {
		var gmarker, leftdiv;
		var lat = roundLatLng (glatlng.lat());
		var lng = roundLatLng (glatlng.lng());
		var pnt;     //, redrawpoint1, redrawpoint2;

		if (OpenRoute != null) {
			// Determine situation for checkAndSaveOnNext() 
			if (CurrMode == MODE_APPEND) situation = SIT_PNT_APP;
			else if (CurrMode == MODE_INSERT_AFTER)	situation = SIT_PNT_INS_AFTER;
			else if (CurrMode == MODE_INSERT_BEFORE) situation = SIT_PNT_INS_BEFORE;
			else if (CurrMode == MODE_NEW) situation = SIT_PNT_NEW;

			// Check which fields need to be checked, save fields if checks pass
			if (FldInfo.checkAndSaveOnNext (situation, null)) {      // do the check & save
				// Add point if seg & point data on the screen is okay
				addPoint (lat, lng);                    // Update underlying data model
			}
		}
	}
}


/****************************************************************
// Handle click on a point's marker 
// Input: pnt - Point for this marker
***************************************************************/
function pointClick (pnt) {
	if (pnt != null) {				 // just to be absolutely safe!
		var rte = pnt.route;		// get route object (might not be OpenRoute)
		if (rte == OpenRoute) {		// if route is open for editing
			if (FldInfo.checkAndSaveOnNext (SIT_PNT_NAV, pnt)) {    // check/save fields for old point
				selectPoint (pnt, true, false);          // select added point, redraw route accordingly
			}
		}
	}
}	


/******************************************************************************/
// Handle move of specified point after its marker has been dragged. 
// Update data model and form fields;  redraw markers & polylines as appropriate.
// New lat & lng can be determined from the GMarker object (stored in the point object).
// Select the moved point unless the previously selected point has invalid field data, 
// in which case move the point but don't select it.
// Inputs: 
//     pnt - Point that was moved
/*******************************************************************************/
function pointDrag (pnt) {
	var prevpnt;
	
	if (pnt != null) {       // just to be absolutely safe!  
	
		// If new point selected, check old point fields -- but what to do if check fails???
		// if (FldInfo.checkAndSaveOnNext (SIT_PNT_NAV, pnt)) {
		
		var gmarker = pnt.marker;    // get point's GMarker object
		var rte = pnt.route;         // get route object (might not be OpenRoute)
		
		if (rte == OpenRoute) {   // if route is open for editing		
			// Update point lat & lng
			var updated_glatlng = gmarker.getPoint();         // get lat/lng after drag
			pnt.lat = roundLatLng (updated_glatlng.lat());    // update data model...
			pnt.lng = roundLatLng (updated_glatlng.lng());	  	
			
			// If new point selected, check (and save) old point fields 
			if (FldInfo.checkAndSaveOnNext (SIT_PNT_NAV, pnt)) {						
				// If check succeeds, select moved point (don't redraw yet)
				prevpnt = selectPoint (pnt, false);           // select added point (don't redraw)
			}
			else {  // else check fails - even though we moved a point, keep the old point selected
				prevpnt = pnt;
			}
			
			// Redraw and update fields as necessary
			if (prevpnt != pnt)        // if new selected point 
				redrawSpecPoints (new Array (pnt, prevpnt), true);		// redraw markers as needed
			else                                     // else not new selected point 
				FldInfo.setLatLngFields ();          // refresh lat & lng fields to match SelectedPoint	
				       // (doesn't hurt anything if moved point isn't selected due to check failure)	
				
			// Redraw polylines		
			rte.redrawPolylines(true, true);	// redraw polylines
		}
	}
}

/******************************************************************************/
// Handle polyline click event.  This is called from the event procedure.
/*******************************************************************************/
function polylineClick (overlay, firstpoint, lastpoint) {
	var rte;
	var s, p;
	rte = firstpoint.route;
	var segbef, segaft;

	// Case where clicked route is the open route - select the clicked segment
	if (rte == OpenRoute) {
		seg1 = firstpoint.segafter;         // determine selected segment
		seg2 = lastpoint.segbefore;
		if (seg1 != seg2) {                 // if this is a multi-segment polyline (though it shouldn't be)
			// can't determine selected segment, so don't change selected segment or selected point
		}
		else if (seg1 == SelectedSegment) {          // if clicked segment already selected
			// Segment already selected - don't change selected segment or selected point
		}
		else {                 // else select the clicked on segment 
			newselectedpoint = seg1.firstpoint;
			// If new point selected, check old point fields
			if (FldInfo.checkAndSaveOnNext (SIT_PNT_NAV, newselectedpoint)) {	
				selectPoint (newselectedpoint, true, false);    // if check passed, select new point & segment and redraw
			}
		}
	}

	// If there is no open route (aside from empty route), select the entire clicked route (not for edit)
	else if (CurrMode == MODE_NEW) {
		
	}

	// Case where clicked route is not the current route - select the clicked route
	else if (rte != SelectedRoute) {
		
	}
}



/********************************************************************************
// Handle map pan
*********************************************************************************/
function mapPan () {

	var mapbounds = Map.getBounds();
	var nelatlng = mapbounds.getNorthEast();
	var swlatlng = mapbounds.getSouthWest();
	var maxlat = roundLatLng (nelatlng.lat());
	var minlat = roundLatLng (swlatlng.lat());	
	var minlng = roundLatLng (swlatlng.lng());
	var maxlng = roundLatLng (nelatlng.lng());

	// JSC removed only for presenting as demo
	// dumpText ("Map moveend event");
	// dumpText ("Max lat = " + maxlat + ", min lat = " + minlat + ", max lng = " + maxlng + ", min lng = " + minlng);
	// dumpText ("Lat span = " + (maxlat - minlat) + ", lng span = " + (maxlng - minlng));
	// dumpText ("Zoom level = " + Map.getZoom());
	
	
}


/********************************************************************************
// Handle map zoom
*********************************************************************************/
function mapZoom (oldzoom, newzoom) {
	dumpText ("Map movezoom event");
	dumpText ("Old/new zoom level = " + oldzoom + ", " + newzoom);
}










