/***********************************************************************************************************/
/***********************************************************************************************************/
// ROUTE MODEL IN MEMORY - Route, Segment and Point objects plus map display logic
// Copyright 2007-2008 Collaborative Bike Map Project
/***********************************************************************************************************/
/***********************************************************************************************************/
// Segment boundary types (of point)...
var SEG_INTERIOR = "i";
var SEG_BOUNDARY = "b";

// Marker types...
var MARKER_INTERIOR = 1;
var MARKER_BOUNDARY = 2;
var MARKER_INTERIOR_SEL = 3;
var MARKER_BOUNDARY_SEL = 4;
var MARKER_INTERIOR_INACT = 5;
var MARKER_BOUNDARY_INACT = 6;
var MARKER_INTERIOR_INACT_SEL = 7;
var MARKER_BOUNDARY_INACT_SEL = 8;

// Segment bikeway types
var BWTYPE_ROAD = 1;
var BWTYPE_PATH = 2;
var BWTYPE_DUAL = 3;
var BWTYPE_TRAIL = 4;
var BWTYPE_NONE = 5;

// Road types
var RTYPE_BIKELANE = 1;
var RTYPE_SHOULDER = 2;
var RTYPE_WOL = 3;
var RTYPE_SQUEEZE = 4;
var RTYPE_INT = 5;
var RTYPE_NONE = 6;

// Comment categories
var COMCAT_INFO = 1;
var COMCAT_ALERT = 2;
var COMCAT_QUESTION = 3;
var COMCAT_ATTRACT = 4;
var COMCAT_BIKESHOP = 5;
var COMCAT_ADVONOTE = 6;

// Path types // not currently used
var PTYPE_PAVED = 1;
var PTYPE_UNPAVED = 2;
var PTYPE_PARTIAL = 3;
var PTYPE_NONE = 4;

// Generic types -- may have to allow for empty value, so zero isn't used here
var FLD_YES = 1;
var FLD_NO = 2;
var UNK = 20;

// One way values
var OW_NO = 1;
var OW_FORWARD = 2;
var OW_BACKWARD = 3;  

/***********************************************************************************************************/
/***********************************************************************************************************/
// Route object type
/***********************************************************************************************************/
/***********************************************************************************************************/
/* Route object type */
function Route() {
	this.id = null;         // null for new route        
	this.bzid = null;       // database id for this route - null for new route    // #server  
	this.name = null;         // #server
	this.len = null;          // #server
	this.desc = null;         // #server
	// this.bikeway = null;      // This doesn't appear to be used anywhere at the route level -- removed 4/19/09
	this.creator = null;      // #server (server generates)
	// this.createdate = null;   // #server (server generates)  // ADD THIS WHEN READY
	this.editdate = null;     // #server (server generates)
	this.minlat = null;       // #server
	this.maxlat = null;       // #server
	this.minlng = null;       // #server
	this.maxlng = null;       // #server
	this.minlatcode = null;      // southernmost panel at route's zoom level  #server
	this.maxlatcode = null;      // northernmost panel at route's zoom level  #server
	this.minlngcode = null;      // westernmost panel at route's zoom level #server
	this.maxlngcode = null;      // easternmost panel at route's zoom level #server
	this.zoom = ZOOM_MIN;        // #server - low numbers are farther out (0=whole world, 19=max zoom)
	this.pending_new_seg = 0;    // if next appended point should trigger new seg (betw curr last pnt and appended pnt)
	this.finished = 0;           // in these objects, 0=false, 1=true        // THIS ISN'T USED - what is it???
	this.pointlist = new LinkedList;     // linked list of points - the route object (not seg) OWNS points - part of SIMPLE MODEL
	this.seglist = new LinkedList;       // linked list of segments - part of SIMPLE MODEL
	this.polylines = [];         // drawn polylines (GPolyline objects) assoc'd w/route (may not be updated when rest of object is)
	this.visible = true;         // whether route should be drawn (in view mode) - not necessarily updated when rest of object is
	this.panels = [];            // panels that route belongs to (all have route's zoom level) -- CAUTION: creates circular reference
}
Route.prototype = Node;        // Inherit from Node class
                               // Don't need to explicitly call Node constructor since it takes no parameters

/****************************************************************/
// Method to redraw (or draw) the entire route.  It will redraw 
// existing points or polylines if already drawn.
// It determines and sets markertype for each point.  
// Inputs: active - Whether route is active (open)     
/****************************************************************/
Route.prototype.redrawRoute = function (active) {
	if (this.pointlist != null) {
		var pntarray = this.pointlist.toArray();        // create array from pointlist
		redrawSpecPoints (pntarray, active);                // redraw all points in route
		this.redrawPolylines (true, active);           // redraw all polylines in route
	}
}

/*****************************************************************************/
/* ROUTE cleanup method.  This cleans up constituent doubly linked lists (pointlist, seglist) so 
   garbage collection succeeds. */
/*****************************************************************************/
Route.prototype.cleanup = function() {
	if (this.pointlist != null) {
		this.pointlist.removeAll();
		//this.pointlist = null;
	}
	if (this.seglist != null) {
		this.seglist.removeAll();
		//this.seglist = null;
	}
}

/*****************************************************************************/
/* Erase polylines for this route   */
/*****************************************************************************/
Route.prototype.erasePolylines = function() {
	var overlay, i;
	// Remove all polylines for this route
	for (i in this.polylines) {
		overlay = this.polylines[i];
		if (overlay != null) {
			if (overlay.getVertexCount() > 1)       // ??? had to add this due to change in the API -- 9/07
				Map.removeOverlay (overlay);        // remove prior polyline //
		}
	}
	this.polylines = [];        // clear array
}


/****************************************************************/
// Draw/redraw clickable polylines per specified point array.
// Inputs:
//    rte - Route
//    everyflag - Set to true to draw a separate polyline for every segment.
//                Set to false to use as few polylines as possible (default).
//    active - Whether current route is active (open) - affects line appearance
/****************************************************************/
Route.prototype.redrawPolylines = function (everyflag, active) {
	var latlnglist;
	var seg, color, prevcolor, i, quit, width;
	var firstpoint, lastpoint;
	var prevselected, selected;
	var opacity;
	
	//debugger;
	
	// Set default everyflag parm
	if (everyflag == undefined) 
		everyflag = false;

	// Remove old polylines for this route
	this.erasePolylines();

	// Prepare to loop
	seg = this.seglist.firstnode;
	if (seg != null) {           // if we have any segments
		prevcolor = null;
		prevselected = false;
		firstpoint = seg.firstpoint;
		quit = false;

		// Loop through segments.  If this segment has new color or selection status, draw previous segments' polyline
		// (otherwise we wait until all done with same-look segments, which will be drawn together as one polyline)
		// firstpoint and lastpoint are first and last point of set of segments we are drawing as one polyline
		while (!quit) {
			 
			if (seg != null) {
				color = seg.getColor();
				selected = (seg == SelectedSegment) ? true : false;
			}
			if (prevcolor != null && (prevcolor != color || selected != prevselected || everyflag || seg == null)) {   
				       // if not at start of route AND (line style changed OR do every segment OR done looping through segments)...

				// Draw previous polyline...
				if (firstpoint != lastpoint) {          // if not zero-length segment
					// latlnglist = getLatLngList (this, firstpoint, lastpoint);
					if (!active) {
						width = POLYLINE_WIDTH_INACTIVE;
						opacity = POLYLINE_OPACITY_INACTIVE;
					}
					else if (prevselected) {
						width = POLYLINE_WIDTH_SELECTED;
						opacity = POLYLINE_OPACITY_SELECTED;
					}
					else {
						width = POLYLINE_WIDTH_DEFAULT;
						opacity = POLYLINE_OPACITY_DEFAULT;
					}
					// Draw polyline (possibly double), set up event handlers, push overlay(s) into this.polylines					
					this.drawPolyline (firstpoint, lastpoint, prevcolor, width, opacity);	
					//overlay = new GPolyline (latlnglist, prevcolor, width, POLYLINE_OPACITY_DEFAULT);
					//Map.addOverlay (overlay);
					//this.polylines.push (overlay);
					
					// Set up listener for polyline click event
					//MapEv.setHandler (overlay, "GPolyline", 'click', [overlay, firstpoint, lastpoint]);
				}
				// Start new polyline...
				if (seg != null)                     // if not at end of route
					firstpoint = seg.firstpoint;     // start with new firstpoint
			}
			if (seg != null) {                   // if not done looping yet
				prevcolor = color;               // remember color
				prevselected = selected;         // remember selection status
				lastpoint = seg.lastpoint;       // update lastpoint
				seg = seg.next;                  // loop again
			}
			else
				quit = true;                     // Stop drawing
		}	
	}
}


/******************************************************************************/
// Draw polyline (really up to two polylines if double color used). 
// Set up event handler(s), and push overlay(s) onto this.polylines[] array.
/*******************************************************************************/
Route.prototype.drawPolyline = function (firstpoint, lastpoint, color, totalwidth, opacity) {
	var colorvalues = new Array (2);
	var latlnglists = new Array (2);
	var widths = new Array (2);
	var offsets = new Array (2);
	// var overlays = new Array (2);
	var overlay;
	var n, i, j;
	
	//debugger;

	colorvalues[0] = ColorsObject.getColorValue1 (color);
	colorvalues[1] = ColorsObject.getColorValue2 (color);
	
	// If two-color line, set up for both 1st & 2nd polylines
	if (colorvalues[1]) {
		switch (totalwidth) {
			case 6:
				widths[0] = 3;
				widths[1] = 2;
				offsets[0] = 1.5;
				offsets[1] = -1.5;
				break;
			case 5:
				widths[0] = 3;
				widths[1] = 2;
				offsets[0] = 1.5;
				offsets[1] = -1.0;
				break;
			case 4:
				widths[0] = 2;
				widths[1] = 2;
				offsets[0] = 1.0;
				offsets[1] = -1.0;
				break;				
			default:
				widths[0] = totalwidth/2;
				widths[1] = totalwidth - widths[0];      // not sure what this will do
				offsets[0] = totalwidth/4;
				offsets[1] = -offsets[0];
				break;
		}
		latlnglists[0] = getLatLngLists (firstpoint, lastpoint, offsets[0]);
		latlnglists[1] = getLatLngLists (firstpoint, lastpoint, offsets[1]);
		n = 2;
	}
	// else just set up for 1 polyline
	else {
		latlnglists[0] = getLatLngLists (firstpoint, lastpoint, 0);
		widths[0] = totalwidth;
		n = 1;
	}
	
	// Draw & record polylines, define event handler for each 
	for (i=0; i<n; i++) {
		for (j=0; j<latlnglists[i].length; j++) {		
			overlay = new GPolyline (latlnglists[i][j], colorvalues[i], widths[i], opacity);   // use actual 
			Map.addOverlay (overlay);
			this.polylines.push (overlay);
			// Set up listener for polyline click event
			MapEv.setHandler (overlay, "GPolyline", 'click', [overlay, firstpoint, lastpoint]);
		}
	}
}


/******************************************************************************/
// Build COMPLEX MODEL from SIMPLE MODEL for the route.  Using SIMPLE MODEL data,
// Fill in COMPLEX MODEL fields. 
/*******************************************************************************/
Route.prototype.buildComplexModel = function () {
	var pnt, seg;
	var pnt_of_seg;      // index of point within its segment
	
	// Complex model fields are:
	//    Segment.firstpoint
	//    Segment.lastpoint
	//    Segment.span
	//    Point.segbefore
	
	// If no points, do nothing
	if (this.pointlist.length == 0) {
	}
	
	// If single point route
	else if (this.pointlist.length == 1) {
		pnt = this.pointlist.firstnode;
		seg = this.seglist.firstnode;
		seg.firstpoint = seg.lastpoint = pnt;
		seg.span = 0;
		pnt.segbefore = null;
	}
	
	// Multi-point route
	else {	
		seg = null;
		pnt = this.pointlist.firstnode;
		pnt_of_seg = 0;
		while (pnt != null) {
			pnt.segbefore = seg;
			if ((pnt.boundtype == SEG_BOUNDARY && pnt.segbefore == pnt.segafter) ||
				(pnt.boundtype != SEG_BOUNDARY && pnt.segbefore != pnt.segafter)) {
				alert ("For point id " + pnt.id + ", boundary type = " + pnt.boundtype + " but segbefore/segafter values are inconsistent!");
			}			
			if (pnt.boundtype == SEG_BOUNDARY) {
				if (seg != null) {							// if not first point in entire list 
					seg.lastpoint = pnt;					// set segment info for segment ending here
					seg.span = pnt_of_seg;
				}
				seg = pnt.segafter;							 // go to new segment
				if (pnt.next != null) {                      // if not last point in entire list
					seg.firstpoint = pnt;                    // set segment info for segment starting here
					pnt_of_seg = 0;							 // reset index of point within its segment
				}
			}
			pnt = pnt.next;
			pnt_of_seg++;      // 0-based - index of point within its segment
		}
	}
	
	/* // Loop through route points
    while (pnt != null) {		// if boundary point (first point always must be)
        if (pnt.boundtype == SEG_BOUNDARY) {
			curr_seg = pnt.segafter;         // update current segment
			if (curr_seg != null) {          // if new segment exists (not last point of multi-point route)
				curr_seg.firstpoint = pnt;   // set segment info
				curr_seg.span = 0;           // initialize span
				if (this.pointlist.length == 1) {     // if only one point in route (and thus segment)
					curr_seg.lastpoint = pnt;      // segment's first and last point are the same point
				}
			}
			if (prev_seg != null) {          // if there's a previous segment
				prev_seg.lastpoint = pnt;    // update segment info
				prev_seg.span = span + 1;    // finalize span
			}
			pnt.segbefore = prev_seg;        // segbefore set in COMPLEX MODEL, not SIMPLE MODEL
			span = 0;                        // reset
		}
		else {           // else interior point
			// pnt.segafter = curr_seg;         // not set for interior points in SIMPLE MODEL, so we must set this here
			pnt.segbefore = curr_seg;        // segbefore = segafter for interior points
			span++;                          // increment span
		}
		prev_seg = curr_seg;                 // update previous segment 
		// Loop again
		pnt = pnt.next;
	}   */
}


/***********************************************************************************************************/
/***********************************************************************************************************/
/* Segment object type */
/***********************************************************************************************************/
/***********************************************************************************************************/
function Segment() {
	this.id = null;
	this.bzid = null;       // database id for this segment - null for new segment    // #server
	this.name = null;                   // #server
	this.len = null;                    // #server
	this.numlanes = null;               // #server
	this.desc = null;                   // #server
	this.zoom = ZOOM_MIN;               // #server
	this.dir = OW_NO;                   // #server
	this.bikeway = BWTYPE_ROAD;              // #server
	this.roadtype = RTYPE_WOL;               // #server
	this.skill = UNK;                        // #server
	/////// --> this.hide = FLD_NO;         // #server -- BUT IMPLEMENT THIS LATER
	this.minlat = null;       // new - use is TBD - #server
	this.maxlat = null;       // new - use is TBD - #server
	this.minlng = null;       // new - use is TBD - #server
	this.maxlng = null;       // new - use is TBD - #server
	// REMOVED: this.opp_roadtype = null;
	// REMOVED: this.opp_skill = null;
	// REMOVED: this.use_opp = false;
	// this.pathtype = null;
	this.sidewalk = UNK;               // #server
	this.speed = null;                 // #server   
	this.route = null;
	// Note: Because of SIMPLE MODEL limitations, only a one-point route can have a one-point segment
	// COMPLEX MODEL fields...
	this.firstpoint = null;     // First point of segment -- COMPLEX MODEL ONLY
	this.lastpoint = null;      // Last point of segment -- COMPLEX MODEL ONLY
	this.span = 0;          // # of gaps between pts (number of pts minus 1) -- COMPLEX MODEL ONLY
	                        //Set to zero if route has only one point. 
	// End of COMPLEX MODEL fields       // NOTE: Inherited next/prev elements are part of SIMPLE MODEL
	// this.getColor = getColor;    
	this.visible = true;         // whether segment should be drawn (in view mode) - not necessarily updated when route is
}
Segment.prototype = Node;        // Inherit from Node class

/*****************************************************************************/
/* Get segment color based on type info */
/*****************************************************************************/
Segment.prototype.getColor = function () {

	var cc = CC_INVALID;
	// Filter modes: FILTER_STANDARD, FILTER_SIDEWALK, FILTER_GOODROADS, FILTER_ALL	
	
	// Filter mode = FILTER_STANDARD - show paths, bikeable roads, dual bikeways, standalone trails
	if (FilterMode == FILTER_STANDARD) {	 
		if (this.bikeway == BWTYPE_PATH)
			cc = CC_GREEN;
		else if (this.bikeway == BWTYPE_ROAD)			
			cc = CC_BLUE;
		else if (this.bikeway == BWTYPE_DUAL)
			cc = CC_PURPLE;
		else if (this.bikeway == BWTYPE_TRAIL)
			cc = CC_LTGREEN;
	}
	
	// Filter mode = FILTER_STANDARD_SW
	else if (FilterMode == FILTER_STANDARD_SW) {       // same as FILTER_STANDARD but show sidewalks
		if (this.bikeway == BWTYPE_PATH)
			cc = CC_GREEN;
		else if (this.bikeway == BWTYPE_ROAD) {
			if (this.sidewalk == FLD_YES)
				cc = CC_MAGENTA;
			else
				cc = CC_BLUE;		
		}
		else if (this.bikeway == BWTYPE_DUAL)
			cc = CC_PURPLE;
		else if (this.bikeway == BWTYPE_TRAIL)
			cc = CC_LTGREEN;
		else {
			if (this.sidewalk == FLD_YES)
				cc = CC_BROWN;
		}
	}
	
	// Filter mode = FILTER_GOODROADS
	else if (FilterMode == FILTER_GOODROADS) {       // show road bikeways and trails, no sidepaths
		if (this.bikeway == BWTYPE_ROAD || this.bikeway == BWTYPE_DUAL)
			cc = CC_BLUE;
		else if (this.bikeway == BWTYPE_TRAIL)
			cc = CC_LTGREEN;
	}

	// Filter mode = FILTER_PATHS
	else if (FilterMode == FILTER_PATHS) {       // show road bikeways and trails, no sidepaths
		if (this.bikeway == BWTYPE_PATH || this.bikeway == BWTYPE_DUAL)
			cc = CC_GREEN;
		else if (this.bikeway == BWTYPE_TRAIL)
			cc = CC_LTGREEN;
	}
	
	// Filter mode = FILTER_ALL
	else if (FilterMode == FILTER_ALL) {       // show everything
		// alert ("Filter All -- this.sidewalk = " + this.sidewalk);
		if (this.bikeway == BWTYPE_PATH)
			cc = CC_GREEN;
		else if (this.bikeway == BWTYPE_ROAD) {
			if (this.sidewalk == FLD_YES)
				cc = CC_MAGENTA;
			else
				cc = CC_BLUE;		
		}
		else if (this.bikeway == BWTYPE_DUAL)
			cc = CC_PURPLE;
		else if (this.bikeway == BWTYPE_TRAIL)
			cc = CC_LTGREEN;
		else {
			if (this.sidewalk == FLD_YES)
				cc = CC_BROWN;
			else
				cc = CC_RED;
		}
	}
	
	return cc;
}



/*************************************************************************************************/
/* Set segment values to residual values - last used values for last created or selected segment */
/*************************************************************************************************/
Segment.prototype.remember = function () {
	if (SegmentMemory != null) {
		this.bikeway = SegmentMemory.bikeway;
		this.roadtype = SegmentMemory.roadtype;
		this.skill = SegmentMemory.skill;
		this.sidewalk = SegmentMemory.sidewalk;
		this.speed = SegmentMemory.speed;
	}
}

/*************************************************************************************************/
/* Save segment values as residual values - last used values for last created or selected segment */
/*************************************************************************************************/
Segment.prototype.memorize = function () {
	if (SegmentMemory == null) { 
		SegmentMemory = new Segment;
	}
	SegmentMemory.bikeway = this.bikeway;
	SegmentMemory.roadtype = this.roadtype;
	SegmentMemory.skill = this.skill;
	SegmentMemory.sidewalk = this.sidewalk;
	SegmentMemory.speed = this.speed;
}


/***********************************************************************************************************/
/***********************************************************************************************************/
/* Point object type */
/***********************************************************************************************************/
/***********************************************************************************************************/
function Point(lat, lng) {
	this.id = null;
	this.bzid = null;       // database id for this point - null for new point     // #server
	this.lat = lat;              // #server
	this.lng = lng;              // #server
	this.heading = null;		 // #server
	this.isnotepnt = false;      // #server (may be implicit on server, i.e. if note exists, once supported)
	this.notecat = null;         // TBD 
	this.pntnote = null;         // TBD
	// REMOVED: this.opp_pntnote = null;
	// REMOVED: this.use_opp = false;
	this.intid = null;           // #server
	this.route = null;         
	this.segafter = null;   // seg following this point (SIMPLE MODEL); if 1-point route, set to only segment
							// Only a 1-point route can have a one-point segment
	this.boundtype = null;   // "i" or "b" (SIMPLE MODEL);  
							 // next/prev elements (from Node) are also part of SIMPLE MODEL
	// COMPLEX MODEL Fields...
	this.segbefore = null;  // used in COMPLEX MODEL only. Segment before this point (null if start of route) - 
							//     even set for interior points.  Not set if only 1 point in route.
	// END OF COMPLEX MODEL Fields
	// Fields indicating current display information for this point...							 
	this.marker = null;      // drawn marker (GMarker object) associated with point 
							 // (not necessarily updated when rest of object is, but updated whenever marker is redrawn)
	this.markertype = null;    // type of drawn marker (MARKER_INTERIOR, etc.) - Updated when this.marker is updated
	this.visible = true;       // whether point is displayed (view mode) - Not necessarily updated when rest of object is
	//this.drawPoint = drawPoint;    // method to draw marker at this point
	//this.erasePoint = erasePoint;   // method to remove marker from screen (without deleting point in data structure)
	//this.redrawPoint = redrawPoint;    // method to erase and redraw marker at this point
}
Point.prototype = Node;        // Inherit from Node class


/*****************************************************************************/
/* Redraw marker for this point                      */
// Method 1: Call this.marker.setImage (Iconset.redsquare.image)
// Method 2: Call Map.removeOverlay, then this.drawPoint() with desired icon
// Method 3: Somehow change icon on the fly???
// Future: Provide parameter to indicate which method to use.
// Inputs: active - Whether route is active (open) or not
/*****************************************************************************/
Point.prototype.redrawPoint = function (active) {
	var newmarkertype;
	//dumpText ("At start of redrawPoint()");

	if (active) {
		if (this.boundtype == SEG_INTERIOR) 	
			newmarkertype = (SelectedPoint == this) ? MARKER_INTERIOR_SEL : MARKER_INTERIOR;
		else
			newmarkertype = (SelectedPoint == this) ? MARKER_BOUNDARY_SEL : MARKER_BOUNDARY;
	}
	else {
		if (this.boundtype == SEG_INTERIOR) 	
			newmarkertype = (SelectedPoint == this) ? MARKER_INTERIOR_INACT_SEL : MARKER_INTERIOR_INACT;
		else
			newmarkertype = (SelectedPoint == this) ? MARKER_BOUNDARY_INACT_SEL : MARKER_BOUNDARY_INACT;
	}

	// if new marker type is different, redraw it
	if (this.markertype != newmarkertype) {
		this.erasePoint();
		this.drawPoint (active);
		//dumpText ("At end of redrawPoint()");
	}
}


/*****************************************************************************/
/* Remove marker for this point   */
/*****************************************************************************/
Point.prototype.erasePoint = function () {
	if (this.marker != null) {
		Map.removeOverlay (this.marker);
		this.marker = this.markertype = null;
	}
}

/*****************************************************************************/
/* Draw marker for this point */
/*****************************************************************************/
Point.prototype.drawPoint = function (active) {
	var markeroptions, markertype;
	var pnt = this;
	var glatlng = new GLatLng (pnt.lat, pnt.lng);

	if (active) {
		if (this.boundtype == SEG_INTERIOR) {
			if (SelectedPoint == pnt) {
				markeroptions = {icon:Iconset.interior_sel, draggable:true, bouncy:false, dragCrossMove:false}
				markertype = MARKER_INTERIOR_SEL;
			}
			else {
				markeroptions = {icon:Iconset.interior, draggable:true, bouncy:false, dragCrossMove:false}
				markertype = MARKER_INTERIOR;
			}
		}
		else {
			if (SelectedPoint == pnt) {
				markeroptions = {icon:Iconset.boundary_sel, draggable:true, bouncy:false, dragCrossMove:false}
				markertype = MARKER_BOUNDARY_SEL;
			}
			else {
				markeroptions = {icon:Iconset.boundary, draggable:true, bouncy:false, dragCrossMove:false}
				markertype = MARKER_BOUNDARY;
			}
		}
	}

	else {    // inactive
		if (this.boundtype == SEG_INTERIOR) {
			if (SelectedPoint == pnt) {
				markeroptions = {icon:Iconset.interior_inact_sel, draggable:false, bouncy:false, dragCrossMove:false}
				markertype = MARKER_INTERIOR_INACT_SEL;
			}
			else {
				markeroptions = {icon:Iconset.interior_inact, draggable:false, bouncy:false, dragCrossMove:false}
				markertype = MARKER_INTERIOR_INACT;
			}
		}
		else {
			if (SelectedPoint == pnt) {
				markeroptions = {icon:Iconset.boundary_inact_sel, draggable:false, bouncy:false, dragCrossMove:false}
				markertype = MARKER_BOUNDARY_INACT_SEL;
			}
			else {
				markeroptions = {icon:Iconset.boundary_inact, draggable:false, bouncy:false, dragCrossMove:false}
				markertype = MARKER_BOUNDARY_INACT;
			}
		}
	}

	var gmarker = new GMarker (glatlng, markeroptions);       // Create marker
	Map.addOverlay(gmarker);							      // Draw marker
	pnt.marker = gmarker;                                     // save marker with point
	pnt.markertype = markertype;                              // save marker type with point
	if (pnt.route == OpenRoute) {                             // allow dragging only if open route
		gmarker.enableDragging();         
	}

	/******** Set up event listener to handle marker click event   */
	MapEv.setHandler (gmarker, "GMarker", 'click', [pnt]);
	/* GEvent.addListener(gmarker, 'click', function() {       // BEWARE - Closure! 
		if (pnt != null) {       // just to be absolutely safe! (pnt = this, kept in closure)
			var rte = pnt.route;     // get route object (might not be OpenRoute at execution time)
			if (rte == OpenRoute) {   // if route is open for editing
				selectPoint (pnt, true, false);           // select added point, redraw route accordingly
			}
		}
	}); */

	/******** Set up event listener to handle drag-end event */
	MapEv.setHandler (gmarker, "GMarker", 'dragend', [pnt]);
	/* GEvent.addListener (gmarker, 'dragend', function() {      // BEWARE - Closure!
		// debugger;
		if (pnt != null) {       // just to be absolutely safe! (pnt = this, kept in closure)
			var rte = pnt.route;     // get route object (might not be OpenRoute at execution time)
			if (rte == OpenRoute) {   // if route is open for editing
				var updated_glatlng = gmarker.getPoint();         // get lat/lng after drag
				pnt.lat = roundLatLng (updated_glatlng.lat());                  // update date model
				pnt.lng = roundLatLng (updated_glatlng.lng());		
				var prevpnt = selectPoint (pnt, false);           // select added point (don't redraw)
				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
				rte.redrawPolylines(true, true);						// redraw polyline
				
			}
		}
	}); */
}

/*****************************************************************************/
/* Check if point is part of the specified segment.  Requires complex model fields already set. */
/*****************************************************************************/
Point.prototype.checkIfOnSegment = function (seg) {
	var result = false;
	if (seg != null) {
		if (this.segafter == seg || this.segbefore == seg)      // requires complex model
			result = false;
	}
	return result;
}

/***********************************************************************************************************/
/***********************************************************************************************************/
// Non-member functions
/***********************************************************************************************************/
/***********************************************************************************************************/

/*******************************************************************
* Redisplay markers for Points specified via input array of Point objects.
* Markers are only redrawn if they are different from existing markers.
* Inputs:
*   points - Array of Point objects indicating points to be redrawn
*   active - Whether points are part of active (open) route or not
********************************************************************/
function redrawSpecPoints (points, active) {
	var p;

	for (p in points) {
		if (points[p] != null)             // safety check
			points[p].redrawPoint(active);
	}
}

/**********************************************************************
* Identify new current segment if a given point were to be made current.  
* This routine does not actually change SelectedSegment or SelectedPoint.
* Inputs:
*   pnt - Point to consider as new current point
* Return value:
*   Segment containing or starting at the specified point, or null for null input.
***********************************************************************/
function getCurrSegForPnt (pnt) {
	var newseg;

	if (pnt == null) {             // handle null case
		seg = null;
	}
	else {
		if (pnt.segafter != null)       // if there's segment starting here
			seg = pnt.segafter;         // use it
		else                            // else last point of route: use segment ending here
			seg = pnt.segbefore;
	}
	return (seg);
}


/**********************************************************************
* MIGHT NOT BE USED.  NOT GUARANTEED TO BE USED IN EVERY CASE, SO BEWARE.
* Identify new current point if a given segment were to be made current.  
* This routine does not actually change SelectedSegment or SelectedPoint.
* Inputs:
*   seg - Segment to consider as new current segment
* Return value:
*   First point of the specified segment, or null for null input.
***********************************************************************/
function getCurrPntForSeg (seg) {
	var newpnt;

	if (seg == null)              // handle null case
		pnt = null;
	else                          // else use first point of segment
		pnt = seg.firstpoint;
	return (pnt);
}
