

var GdbConfiguration = {
	singleMarkZoomLevel: 15,
	showAllZoomLevel: 15,
	searchZoomMargin: 3,
	accWarnZoomLevel: 16,

	mapElementId: 'gdbgmap_map',
	keyElementId: 'gdbgmap_key',
	infoElementId: 'gdbgmap_info',
	statusElementId: 'gdbgmap_status',
	coordElementId: 'gdbgmap_coord',

	markListNormalClassName: '',
	markListHighlightClassName: 'selected',

	warningOnClassName: 'gdbgmap_warning_enabled',
	warningOffClassName: 'gdbgmap_warning_disabled',


	gdbUrl: '/apps/geodeticdatabase/index.html',
	gdbModePrm: 'mode',
	gdbSessionIdPrm: 'sessionid',
	gdbInfoPrms: { nextform: 'gmapmarkinfo', code: '$id', noframe: 1},
	gdbFoundMarkListPrms: { nextform: 'result' },
	gdbSavedMarkListPrms: { nextform: 'marklist' },
	gdbDownloadPrms: { nextform: 'download' },
	gdbGetSavedMarkPrms: { nextform: 'gmapsavedmark', noframe: 1 },
	gdbGetFoundMarkPrms: { nextform: 'gmapfoundmark', noframe: 1 },
	gdbSetFoundMarkPrms: { action: '+setfoundmarks', foundmarklist: '$foundmarks' },
	gdbSetSavedMarkPrms: { action: '+updatelist', listaction: 'clear+add', mark: '$savedmarks' },

	defaultLocation: [ -41.0, 175.0, 5, 'N'],
	markListsInStatus: false
};
//////////////////////////////////////////////////

var GDBGMAP_MARKTYPE_DEFAULT = 0;
var GDBGMAP_MARKTYPE_SELECTED = 1;
var GDBGMAP_MARKTYPE_HIGHLIGHT = 2;

var GDBGMAP_SEARCHTYPE_ID = 0;
var GDBGMAP_SEARCHTYPE_NAME = 1;
var GDBGMAP_SEARCHTYPE_ADDRESS = 2;

var GDBGMAP_ID_NONE = 0;
var GDBGMAP_ID_MARK = 1;
var GDBGMAP_ID_FOUND = 2;
var GDBGMAP_ID_SAVED = 3;

//////////////////////////////////////////////////
// GdbObject - base class for Gdb classes.  Purpose is to add a
// object id to simplify access objects from html javascript link
//


function GdbObject()
{
}

GdbObject.prototype.objectList = new Array();

GdbObject.prototype.Instantiate = function()
{
	if( this.gdbobjid == null )
	{ 
		this.gdbobjid = GdbObject.prototype.objectList.length;
		GdbObject.prototype.objectList.push( this );
	}
}

GdbObject.prototype.GdbObjectId = function()
{
	this.Instantiate();
	return this.gdbobjid;
}

GdbObject.prototype.HtmlInvoke = function( funcname )
{
	this.Instantiate();
	var invoke='GdbGetObject('+this.gdbobjid+').'+funcname+'(';
	var i;
	for( i = 1; i < arguments.length; i++ )
	{
		if( i > 1 ) invoke=invoke+',';
		invoke = invoke + arguments[i];
	}
	invoke = invoke+')'
	return invoke;
}

function GdbGetObject( id )
{
	return GdbObject.prototype.objectList[id];
}

function GdbUnloadObjects( id )
{
	var objlist = GdbObject.prototype.objectList;
	for( var i = 0; i < objlist.length; i++ ) 
	{
		if( objlist[i].Unload ) objlist[i].Unload();
	}
}

function GdbGmapUnload()
{
    GdbUnloadObjects();	
    GUnload();
}

//////////////////////////////////////////////////
//  Mark list - a list of marks used for each layer, search result 
//  set, and saved marks.  Provides the interface between the marks
//  returned from the LinzGdbMap object, and the marks displayed on
//  the map.

GdbMarkList.prototype = new GdbObject();

function GdbMarkList( id, gmap, options )
{
	this.id = id;
	this.gmap = gmap;
	this.map = gmap.map;
	this.markers = new Array();
	this.idlist = {};
	this.ndeleted = 0;
	this.html = null; 
	this.element_prefix = "lzmk_"+this.GdbObjectId()+"_";

	if( options == null ) options = {};
	this.visible = options.visible ? options.visible : true;
	this.marktype = options.marktype ? options.marktype : GDBGMAP_MARKTYPE_DEFAULT;

	this.updated = false;
	this.highlighted = null;
}


GdbMarkList.prototype.Length = function()
{
	return this.markers.length;
}

GdbMarkList.prototype.Count = function()
{
	return this.markers.length - this.ndeleted;
}

GdbMarkList.prototype.Marker = function( i )
{
	return i < this.markers.length ? this.markers[i] : null;
}

GdbMarkList.prototype.GetIndexById = function( id )
{
	return this.idlist[id];
}

GdbMarkList.prototype.GetMarkerById = function( id )
{
	var i = this.GetIndexById( id );
	return i == null ? null : this.markers[i];
}

GdbMarkList.prototype.Marks = function( markarray )
{
	if( markarray == null ) markarray = new Array();
	this.Apply( function(marker){ markarray.push( marker.linz.mark ); } );
	return markarray;
}

GdbMarkList.prototype.SetOnUpdate = function( handler )
{
	GEvent.addListener( this, "update", handler );
}

GdbMarkList.prototype.OnUpdate = function()
{
	if( ! this.updated ) return;
	this.html = '';
	GEvent.trigger( this, "update", this );
	this.updated = false;
}

GdbMarkList.prototype._clear = function()
{
	var marker;
	while( marker = this.markers.pop() )
	{
		if( this.map ) this.map.removeOverlay( marker );
		this.updated = true;
	}
	this.ndeleted = 0;
	this.idlist = {};
}

GdbMarkList.prototype._removeMark = function(mark)
{
	var i = this.GetIndexById( mark.id );
	if( i == null ) return;
	var marker = this.Marker(i);
	if( marker )
	{
		if( this.map ) this.map.removeOverlay( marker );
		this.markers[i] = null;
		this.idlist[marker.linz.mark.id] = null;
		this.updated = true;
		this.ndeleted++;
		if( this.ndeleted == this.markers.length) this._clear();
	}
}

GdbMarkList.prototype.Clear = function()
{
	this._clear();
	this.OnUpdate();
}

GdbMarkList.prototype._addMark = function( mark )
{
	if( this.idlist[mark.id] ) return;
	var marker = this.CreateMarker( mark );
	this.markers.push( marker );
	if( this.map )  this.map.addOverlay( marker );
	if( ! this.visible ) marker.hide();
	this.idlist[mark.id] = this.markers.length-1;
	this.updated = true;
}

GdbMarkList.prototype.SetMark = function( mark )
{
	if( this.markers.length == 1 &&
            this.markers[0].linz.mark.id == mark.id ) return;
	this._clear();
	this.AddMark( mark );
}

GdbMarkList.prototype.AddMark = function( mark )
{
	this._addMark( mark );
	this.OnUpdate();
}

GdbMarkList.prototype.SetMarks = function( marks )
{
	this.AddMarks( marks, true );
}

GdbMarkList.prototype.AddMarks = function( marks, clear )
{
	if( clear ) this._clear();
	if( ! marks || marks.length < 1 ) return;
	for( var i = 0; i < marks.length; i++ )
	{
		this._addMark( marks[i] );
	}
	this.OnUpdate();
}

GdbMarkList.prototype.RemoveMark = function( mark )
{
	this._removeMark(mark);
	this.OnUpdate();
}

GdbMarkList.prototype.RemoveMarks = function( marks )
{
	if( ! marks || marks.length < 1 ) return;
	for( var i = 0; i < marks.length; i++ )
	{
		this._removeMark(marks[i]);
	}
	this.OnUpdate();
}

GdbMarkList.prototype.Apply = function( f )
{
	for( var i = 0; i < this.markers.length; i++ )
	{
		var marker = this.markers[i];
		if( marker != null ) f( this.markers[i] );
	}
}

GdbMarkList.prototype.SetVisible = function( visible )
{
	if( this.visible != visible )
	{
		this.visible = visible;
		if( visible ) this.Apply( function(marker){ marker.show(); } );
		else this.Apply( function(marker){ marker.hide(); } );
	}
}

GdbMarkList.prototype.HighlightMark = function( i )
{
	if( i == this.highlighted ) return;
	this.ClearHighlight();
	var marker = this.Marker(i);
	if( marker ) 
	{ 
		marker.setImage( marker.linz.highlight_image );
		if( marker.linz.elementid )
		{
			var el = document.getElementById( marker.linz.elementid );
			if( el ) el.className = this.gmap.markListHighlightClassName;
		}
	}
	this.highlighted = i;
}

GdbMarkList.prototype.ClearHighlight = function()
{
	var marker = null;
	if( this.highlighted != null )
	{
		marker = this.Marker( this.highlighted );
	}
	if( marker ) 
	{ 
		marker.setImage( marker.linz.normal_image );
		if( marker.linz.elementid )
		{
			var el = document.getElementById( marker.linz.elementid );
			if( el ) el.className = this.gmap.markListNormalClassName;
		}
	}
	this.highlighted = null;
}

GdbMarkList.prototype.MarkIds = function( separator, prefix )
{
	if( separator == null || separator == "" ) separator = "|";
	if( prefix == null ) prefix = "";
	var list = "";
	var sep = prefix;
	this.Apply( function(marker){ 
		list = list + sep + marker.linz.mark.id;
		sep = separator;
		} );
	return list;
}

function ZIndex( mark ) { return mark.linz.zindex; }

GdbMarkList.prototype.CreateMarker = function( mark )
{
	var layer = this.gmap.Layer( mark.layerid );
	var icon = layer.icon;
        var zindex = layer.zindex;
	
	if( this.marktype == GDBGMAP_MARKTYPE_SELECTED )
	{
		icon = layer.icon_selected;
		zindex = layer.zindex_selected;
	}
	else if (this.marktype == GDBGMAP_MARKTYPE_HIGHLIGHT )
	{
		icon = layer.icon_highlight;
		zindex = layer.zindex_highlight;
	}

        if( icon == null ) icon = G_DEFAULT_ICON;

	var marklatlon = new GLatLng( mark.y, mark.x );
	var title = mark.id + ": " + mark.name;
	var marker = new GMarker(
                   marklatlon,
                   {title: title,
                    icon: icon, 
                    zIndexProcess: ZIndex } );

	marker.linz = { 
		zindex: zindex,
		layer: layer,
		mark: mark,
		normal_image: icon.image,
		highlight_image: layer.icon_highlight.image
		};

	var gmap = this.gmap;

	GEvent.addListener(marker,"mouseover",function(){ gmap.SetStatusMessage( title ); } );
	GEvent.addListener(marker, "dblclick", function() { gmap.map.setCenter(  marklatlon, gmap.singleMarkZoomLevel ); } );
        GEvent.addListener(marker, "click", function() { gmap.HighlightMark( mark );} );

	return marker;
}


GdbMarkList.prototype.ClickListMark = function( i )
{
	var marker = this.Marker(i);
	if( marker ) this.gmap.HighlightMark( marker.linz.mark );
}

GdbMarkList.prototype.Html = function()
{
	if( this.html ) return this.html;
	var html = '<div class="gdbgmap_mark_list">';
	for( var i = 0; i < this.Length(); i++ )
	{
		var marker = this.Marker(i);
		if( marker == null ) continue;
		var title = marker.getTitle();
		if( marker.linz.elementid == null )
		{
			marker.linz.elementid = this.element_prefix+i;
		}

		html = html + '<p ' +
			'id="' + marker.linz.elementid + '" ' +
			'class="'+this.gmap.markListNormalClassName+'" ' +
			'onmouseover="'+this.HtmlInvoke('HighlightMark',i)+'" ' +
			'onmouseout="'+this.HtmlInvoke('ClearHighlight')+'" ' +
			'onclick="'+this.HtmlInvoke('ClickListMark',i)+'" ' +
			'>' + 
			title +
			'</p>';
	}
	html = html+"</div>";
	this.html = html;
	return html;
}

//////////////////////////////////////////////////
//  GdbInfoText: object for managing content of the info window in 
//  different modes.

GdbInfoText.prototype = new GdbObject();

function GdbInfoText( id, gmap  )
{
	this.id = id;
	this.gmap = gmap;
	this.text = null;
}

GdbInfoText.prototype.Text = function()
{
	if( this.text == null ) this.OnListUpdate();
	return this.text;
}

GdbInfoText.prototype.SetText  = function( text )
{
	if( this.text == text ) return;
	this.text = text;
	GEvent.trigger(this,"update",this);
}

GdbInfoText.prototype.SetOnUpdate = function( handler )
{
	GEvent.addListener(this,"update",handler);
}

GdbInfoText.prototype.LinkToList  = function( marklist )
{
	var info = this;
	marklist.SetOnUpdate( function(marklist){info.OnListUpdate();} );
}

GdbInfoText.prototype.MakeLink = function( label, func )
{
	return '<p class="gdbgmap_applink">' + 
                       '<a href="javascript:' +
			this.HtmlInvoke(func) +
			'">' + label + '</a></p>';
}

GdbInfoText.prototype.OnListUpdate  = function()
{
}

////////////////////////////////////////
//  Mark details

GdbMarkDetailInfo.prototype = new GdbInfoText();

function GdbMarkDetailInfo( id, gmap, marklist )
{
	this.base = GdbInfoText;
	this.base(id, gmap );
	this.marklist = marklist;
	this.LinkToList( marklist );
}

GdbMarkDetailInfo.prototype.OnListUpdate = function()
{
	this.SetText('');
	var marker = this.marklist.Marker(0);
	if( marker == null ) return;
	var url = gmap.GdbUrl( { id: '='+marker.linz.mark.id }, gmap.gdbInfoPrms );
        var info = this;
	LinzGetUrl( url, function(text){ info.SetText( text ); } );
}


////////////////////////////////////////

GdbMarkDetailHeader.prototype = new GdbInfoText();

function GdbMarkDetailHeader( id, gmap, highlightlist, savedlist )
{
	this.base = GdbInfoText;
	this.base(id, gmap );
	this.LinkToList( highlightlist );
	this.LinkToList( savedlist );
	this.highlightlist = highlightlist;
	this.savedlist = savedlist;
}

GdbMarkDetailHeader.prototype.SaveMark = function()
{
	var marker = this.highlightlist.Marker(0);
	if( marker ) this.savedlist.AddMark( marker.linz.mark );
}

GdbMarkDetailHeader.prototype.UnsaveMark = function()
{
	var marker = this.highlightlist.Marker(0);
	if( marker ) this.savedlist.RemoveMark( marker.linz.mark );
}

GdbMarkDetailHeader.prototype.OnListUpdate = function()
{
	var id = this.highlightlist.MarkIds();
	if( id == '' ) { this.SetText(''); return; }
	var i = this.savedlist.GetIndexById(id);
	var func = (i == null) ? 'SaveMark' : 'UnsaveMark';
	var label =  (i == null) ? "Save " + id  + " for download" : "Remove " + id + " from saved marks";

	var savelink = this.MakeLink(label,func);

	this.SetText( savelink );
}

////////////////////////////////////////////////////////////////

GdbFoundListInfo.prototype = new GdbInfoText();

function GdbFoundListInfo( id, gmap, foundlist, savedlist )
{
	this.base = GdbInfoText;
	this.base(id, gmap );
	this.LinkToList( foundlist );
	this.LinkToList( savedlist );
	this.foundlist = foundlist;
	this.savedlist = savedlist;
}

GdbFoundListInfo.prototype.SaveMarks = function()
{
	this.savedlist.AddMarks( this.foundlist.Marks() );
}

GdbFoundListInfo.prototype.UnsaveMarks = function()
{
	this.savedlist.RemoveMarks( this.foundlist.Marks() );
}

GdbFoundListInfo.prototype.ListFoundMarks = function( marklist )
{
	this.gmap.GdbPage( this.gmap.gdbFoundMarkListPrms );
}

GdbFoundListInfo.prototype.OnListUpdate = function()
{
	var text = '';
	if( this.foundlist.Count() >  0 ) 
	{
		var text = '<p class="gdbgmap_title">Search Results (' + this.foundlist.Count() + ')</p>';
		var add = false;
		for( var i = 0; i < this.foundlist.Length(); i++ )
		{
			var marker = this.foundlist.Marker(i);
			if( marker != null && this.savedlist.GetIndexById(marker.linz.mark.id) == null )
			{
				add = true;
				break;
			}
		}
		var func = add ? 'SaveMarks' : 'UnsaveMarks';
		var label =  add ? "Save results for download" : "Remove results from saved marks";
	
		text = text + this.MakeLink(label,func);
		text = text + this.MakeLink('Detailed list','ListFoundMarks');
		text = text + this.foundlist.Html();
	}
	
	this.SetText( text );
}


////////////////////////////////////////////////////////////////

GdbSavedListInfo.prototype = new GdbInfoText();

function GdbSavedListInfo( id, gmap, savedlist )
{
	this.base = GdbInfoText;
	this.base(id, gmap );
	this.LinkToList( savedlist );
	this.savedlist = savedlist;
}

GdbSavedListInfo.prototype.SaveVisibleMarks = function()
{
	this.gmap.SaveVisibleMarks();
}

GdbSavedListInfo.prototype.Clear = function()
{
	this.savedlist.Clear();
}

GdbSavedListInfo.prototype.ListMarks = function()
{
	this.gmap.GdbPage( this.gmap.gdbSavedMarkListPrms );
}

GdbSavedListInfo.prototype.Download = function()
{
	this.gmap.GdbPage( this.gmap.gdbDownloadPrms );
}

GdbSavedListInfo.prototype.OnListUpdate = function()
{
	var count = this.savedlist.Count();
	var text = '<p class="gdbgmap_title">Saved marks (' + count + ')</p>';
        text = text + this.MakeLink('Save all visible marks','SaveVisibleMarks');
	if( count > 0 ) 
	{
		text = text + this.MakeLink('Empty saved mark list','Clear');
		text = text + this.MakeLink('Detailed list','ListMarks');
		text = text + this.MakeLink('Download saved marks','Download');
	}
	text = text + this.savedlist.Html();
	this.SetText( text);
}

////////////////////////////////////////////////////////////////

 

GdbGmap.prototype = new GdbObject();

GdbGmap.prototype.ValidOption =
{
	mapElementId:1,
	keyElementId:1,
	infoElementId:1,
	statusElementId:1,
	coordElementId:1,
	debugElementId:1,
	accWarnElementId:1,
	zoomWarnElementId:1,
	markListHighlightClassName:1,
	markListNormalClassName:1,
	warningOnClassName:1,
	warningOffClassName:1,
	statusCookie:1,
	gdbUrl:1,
	gdbSessionId:1,
	gdbMode:1,
	startLocDef:1
};

function GdbGmap( options  )
{
    this.Instantiate();

    this.valid = false;
    this.index_loaded = false;
    this.infomode = GDBGMAP_ID_NONE;
    this.pendingInfoMode = null;
    this.startLocation = null;
    this.gdbSessionId = '';
    this.gdbMode = '';

    for( var p in GdbConfiguration ) { this[p] = GdbConfiguration[p]; };

    if( options )
    {
	for( var p in options ){ if( this.ValidOption[p] ) this[p] = options[p]; }
    };

    this.SetStatusFromCookie();
    this.SetStartLocationFromDefinition();

    this.CreateGoogleMap();
    if( ! this.map ) return;

    this.CreateLinzGdbMap();
    if( ! this.index ) return;

    this.LinkIndex();
    this.LinkMap();

    this.LoadIndex();

    this.SetupMarkLists();

    // Set the initial default location so that the middle zoom control returns 
    // to this view even if start with different extents.
    this.SetMapLocation( this.defaultLocation );
    if( this.startLocation ) this.SetMapLocation( this.startLocation );

    this.valid = true;

}

GdbGmap.prototype.SetupMarkLists = function()
{
	var gmap = this;

	var display = this.pendingDisplayMarkList;
	if( display == null ) display = GDBGMAP_ID_NONE;

	this.foundmarks = new GdbMarkList( GDBGMAP_ID_FOUND, this, { marktype: GDBGMAP_MARKTYPE_SELECTED, visible: display == GDBGMAP_ID_FOUND } );
	this.savedmarks = new GdbMarkList( GDBGMAP_ID_SAVED, this, { marktype: GDBGMAP_MARKTYPE_SELECTED, visible: display == GDBGMAP_ID_SAVED } );
	this.highlightmark = new GdbMarkList( GDBGMAP_ID_MARK, this, { marktype: GDBGMAP_MARKTYPE_HIGHLIGHT, visible: true } );

	this.foundlisthtml = new GdbFoundListInfo( GDBGMAP_ID_FOUND, this, this.foundmarks, this.savedmarks );

	this.savedlisthtml = new GdbSavedListInfo( GDBGMAP_ID_SAVED, this, this.savedmarks );

	this.highlightinfo = new GdbMarkDetailInfo( GDBGMAP_ID_MARK, this, this.highlightmark );
	this.highlightheader = new GdbMarkDetailHeader( GDBGMAP_ID_MARK, this, this.highlightmark, this.savedmarks );

	this.foundlisthtml.SetOnUpdate( function(info){ gmap.OnUpdateInfo(info); });
	this.savedlisthtml.SetOnUpdate( function(info){ gmap.OnUpdateInfo(info); });
	this.highlightinfo.SetOnUpdate( function(info){ gmap.OnUpdateInfo(info); });
	this.highlightheader.SetOnUpdate( function(info){ gmap.OnUpdateInfo(info); });

	if( this.pendingHighlightMark != null ) this.LoadMarkList( this.highlightmark, this.pendingHighlightMark );
	if( this.pendingFoundMarks != null ) this.LoadMarkList( this.foundmarks, this.pendingFoundMarks );
	if( this.pendingSavedMarks != null ) this.LoadMarkList( this.savedmarks, this.pendingSavedMarks );

	if( this.pendingInfoMode != null ) this.SetInfoMode( this.pendingInfoMode );

	this.GetGdbMarks( this.gdbGetSavedMarkPrms, this.savedmarks );
	this.GetGdbMarks( this.gdbGetFoundMarkPrms, this.foundmarks );
}

GdbGmap.prototype.CreateGoogleMap = function()
{    
    this.map = null;
    var el = document.getElementById( this.mapElementId );
    if( ! el ) return;
    var map = new GMap2(el);

     // Add controls like Normal Google Maps
     map.enableScrollWheelZoom();
     map.enableContinuousZoom();
     map.addControl(new GLargeMapControl());
     map.addControl(new GMapTypeControl());
     map.addControl(new GScaleControl());

     var omc = new GOverviewMapControl();
     map.addControl(omc);
     omc.hide();
     this.map = map;
}
GdbGmap.prototype.LinkMap = function()
{
    var gmap = this;
    // GEvent.addListener(this.map, "movestart", function() { gmap.ClearView();} );
    GEvent.addListener(this.map, "moveend", function(){ gmap.SetMapView();} );
    if( this.coordElementId )
    {
	var el = document.getElementById( this.coordElementId );
        if( el ){ 
           GEvent.addListener(this.map, "mousemove", function( latlon ){
               el.innerHTML = CoordRepresentation( latlon );
               });
           }
    }
}

GdbGmap.prototype.SetMapLocation = function( loc )
{
    var map = this.map;
    if( ! map ) { this.startLocation=loc; return; }
    var type = G_NORMAL_MAP;
    if( loc[3] == 'S' ) type= G_SATELLITE_MAP;
    if( loc[3] == 'H' ) type = G_HYBRID_MAP;
    this.map.setCenter( new GLatLng(Number(loc[0]),Number(loc[1])),Number(loc[2]),type);
}

GdbGmap.prototype.GetMapLocation = function()
{
    var type = 'N';
    var map = this.map;
    var center = this.map.getCenter();
    var zoom = this.map.getZoom();
    var mapType = this.map.getCurrentMapType();
    if( mapType ) mapType = mapType.getUrlArg();
    var type = 'N';
    if( mapType == G_SATELLITE_MAP.getUrlArg() ) type = 'S';
    if( mapType == G_HYBRID_MAP.getUrlArg() ) type = 'H';
    return [ center.lat(), center.lng(), zoom, type ];
}


GdbGmap.prototype.CreateLinzGdbMap = function()
{
    var index = new LinzGdbMap();
    this.index =  index;
}

GdbGmap.prototype.LinkIndex = function()
{
    var gmap = this;
    this.index.onindexloaded = function(){ gmap.OnIndexLoaded(); };
    this.index.ondrawmark = function ( mark ){ gmap.DrawMark( mark ); };
    this.index.onviewset = function (){ gmap.ViewSet(); };
    this.index.onviewcomplete = function (){ gmap.ViewComplete(); };
}

GdbGmap.prototype.LoadIndex = function()
{
	this.index.LoadIndex();
}

GdbGmap.prototype.Unload = function()
{
    this.WriteStatusToCookie();

    if( this.index )
    {
    this.index.onindexloaded = null;
    this.index.ondrawmark = null;
    this.index.onviewset = null;
    this.index.onviewcomplete = null;
    }

    GEvent.clearListeners( this.map, "moveend");
    GEvent.clearListeners( this.map, "mousemove");

    this.foundmarks.Clear();
    this.savedmarks.Clear();
    this.highlightmark.Clear();
    this.ClearLoadedMarks();
}

function CoordRepresentation( latlon )
{
    return latlon.lat().toFixed(5) + " " + latlon.lng().toFixed(5);
}

GdbGmap.prototype.SetStatusMessage = function( statusMessage )
{
    if( ! this.statusElementId ) return;
    var el = document.getElementById( this.statusElementId );
    if( el ) el.innerHTML = statusMessage;
}

GdbGmap.prototype.ClearLoadedMarks = function()
{
	var layers = this.index.Layers();
	if( ! layers ) return;
	layers.Apply( function(layer){ layer.markers.Clear(); } );
}

GdbGmap.prototype.SetMapView = function()
{
	var map = this.map;
	if( ! map.isLoaded() ) return;

        this.SetStatusMessage("loading ... ");

        this.ClearLoadedMarks();

        var mapBounds = map.getBounds();
	var zoomLevel = map.getZoom();
        var LL = mapBounds.getSouthWest();
        var UR = mapBounds.getNorthEast();
        var showAll = zoomLevel >= this.showAllZoomLevel;
	this.index.SetView( LL.lng(),UR.lng(),LL.lat(),UR.lat(), showAll);

        if( this.zoomWarnElementId )
	{
		var el = document.getElementById( this.zoomWarnElementId );
		if( el ) el.className = this.index.toomany ? 
                           this.warningOnClassName : this.warningOffClassName;
        }

        if( this.accWarnElementId )
	{
		var el = document.getElementById( this.accWarnElementId );
		if( el ) el.className = zoomLevel >= this.accWarnZoomLevel ? 
                           this.warningOnClassName : this.warningOffClassName;
        }
}

GdbGmap.prototype.DrawMark = function( mark )
{
	this.Layer( mark.layerid ).markers.AddMark( mark );
}

GdbGmap.prototype.OnIndexLoaded = function()
{
	this.SetupLayers();
	if( this.keyElementId ) this.SetupLayerKey();
	this.index_loaded = true;
	if( this.pending_index_functions != null )
	{
		while( this.pending_index_functions.length > 0 )
		{
			var f = this.pending_index_functions.shift();
			f();
		}
	}
	this.DoPendingSearch();
}

GdbGmap.prototype.WithIndex = function( f )
{
	if( this.index_loaded ) { f(); return; }
	if( this.pending_index_functions == null ) this.pending_index_functions = new Array();
	this.pending_index_functions.push(f);
}

GdbGmap.prototype.ViewSet = function()
{
	this.UpdateLayerKey();
}

GdbGmap.prototype.ViewComplete = function()
{

        this.SetStatusMessage("");
}

GdbGmap.prototype.Layers = function()
{
	return this.index.Layers();
}

GdbGmap.prototype.Layer = function(id)
{
	return this.index.Layers().Layer(id);
}

GdbGmap.prototype.SetupLayers = function()
{
	var layers = this.index.Layers();
	var icons = GdbLayerIcons();
	var zindex = layers.Length()+1;
	var zindexsel = 2*layers.Length()+1;

	for( var i = 0; i < layers.Length(); i++ )
	{
            var layer = layers.Layer(i);
	    for( var ic = 0; ic < icons.length; ic++ )
	    {
		if( icons[i].code == layer.code )
		{
			layer.icon = icons[i].icon;
			layer.icon_selected = icons[i].icon_selected;
			layer.icon_highlight = icons[i].icon_highlight;
                }
            }
            layer.zindex = zindex  - i;
            layer.zindex_selected = zindexsel - i;
            layer.zindex_highlight = zindexsel+1;
	    layer.markers = new GdbMarkList(GDBGMAP_ID_NONE,this)
        }
	var dl = this.disabledLayers;
	if( dl )
	{
		for( var i = 0; i < dl.length; i++ )
		{
			var layer = layers.LayerFromCode(dl[i]);
			if( layer) layer.markers.SetVisible(false);
		}
	}
}

GdbGmap.prototype.ShowLayer = function( id, show )
{
	this.Layer(id).markers.SetVisible(show);
}

GdbGmap.prototype.SetupLayerKey = function()
{
    var keyElement = document.getElementById( this.keyElementId );
    if( ! keyElement ) return;

    var html = '<table class="gdbgmap_layertable">'+"\n";
    var mapid = this.id;
    var gmap = this;
    this.Layers().Apply(
      function( layer ) {
        layer.elementid = "gdblayer_" + layer.id;
	var checked = layer.markers.visible ? "checked" : "";
	var onclick = gmap.HtmlInvoke('ShowLayer',layer.id,'this.checked');
	html = html + '<tr class="gdbgmap_layerrow_active" id="' + layer.elementid +'">' + 
                      '<td class="gdbgmap_layericon"><img src="'+layer.icon.image+'" alt="Layer '+layer.code + ' icon"></td>' +
                      '<td class="gdbgmap_layercheckbox"><input type="checkbox" onclick="'+onclick+'" ' + checked + ' ></td>' +
		      '<td class="gdbgmap_layername">' + layer.name + '</td>' + "\n";
         });
    html = html + "</table>\n";
    keyElement.innerHTML = html;
}

GdbGmap.prototype.UpdateLayerKey = function()
{
    // Coded this way to ensure that don't show low orders active and higher orders
    // inactive
  
    var layers = this.Layers();
    var classname = "gdbgmap_layerrow_inactive";
    for( i = layers.Length()-1; i >= 0; i-- )
    {
	  var layer = layers.Layer(i);
          if( layer.active ) classname = 'gdbgmap_layerrow_active';
          if( ! layer.elementid ) continue;
          var el = document.getElementById( layer.elementid );
          if( ! el ) continue;
          el.className = classname;
    }
}


GdbGmap.prototype.LoadFoundMarks = function( marks, sstatus )
{
        this.SetStatusMessage(sstatus);
	if( marks.length == 0 ) 
	{
		this.ShowMiscInfo(sstatus);
		return;
	}

	var infoMode = marks.length == 1 ? GDBGMAP_ID_MARK :GDBGMAP_ID_FOUND;
	
	if( marks.length == 1 ) this.highlightmark.SetMark( marks[0] );
        this.SetInfoMode( infoMode );
	this.foundmarks.SetMarks( marks );

	this.ZoomToMarks( this.foundmarks );
}

GdbGmap.prototype.HighlightMark = function( mark )
{
	this.highlightmark.SetMark( mark );
	
	var marker = this.highlightmark.Marker(0);
	if( ! this.map.getBounds().containsLatLng( marker.getLatLng() ) )
	{
		this.ZoomToMarks( this.highlightmark );
	}
	this.SetInfoMode( GDBGMAP_ID_MARK );
}

GdbGmap.prototype.ZoomToMarks = function( marklist )
{
        if( ! marklist || marklist.Count() < 1 ) return;

	var bounds = new GLatLngBounds();
	marklist.Apply( function( marker ) 
	{
		bounds.extend( marker.getLatLng() );
	});
	var zoomLevel = this.map.getBoundsZoomLevel( bounds )-1;
	if( marklist.Count() == 1 ) zoomLevel = this.singleMarkZoomLevel;
	if( (! this.map.getBounds().containsBounds( bounds )) ||
	    this.map.getZoom() < zoomLevel - this.searchZoomMargin )
		this.map.setCenter( bounds.getCenter(), zoomLevel );
}

GdbGmap.prototype.DoSearch = function( type, searchString )
{
	if( ! this.index_loaded )
	{
		this.pendingSearch = { type: type, searchString: searchString };
		return;
	}
	if( type == GDBGMAP_SEARCHTYPE_ADDRESS )
	{
		this.SearchAddress( searchString );
		return;
	}
	this.ShowMiscInfo("searching ...");
	this.foundmarks.Clear();
	this.highlightmark.Clear();
	var gmap = this;
	var func = function(marks,sstatus){ 
            gmap.LoadFoundMarks( marks, sstatus );
	    };
	if( type == GDBGMAP_SEARCHTYPE_NAME )
	{
		searchString = searchString.replace(/\b(so|dp)(\d+)/ig,"$1 $2");
		this.index.SearchNames( searchString, func );
	}
	else
	{
		this.index.SearchId( searchString, func );
	}
}

GdbGmap.prototype.DoPendingSearch = function()
{
	var pendingSearch = this.pendingSearch;
	this.pendingSearch = null;
	if( pendingSearch )
	{
		this.DoSearch( pendingSearch.type, pendingSearch.searchString );
	}
}

GdbGmap.prototype.SearchAddress = function( addressString )
{
	addressString = addressString + ", nz";
	if( this.geocoder == null ) this.geocoder = new GClientGeocoder();
	if( this.geocoder == null ) 
	{
		this.ShowMiscInfo("Address searching is currently unavailable");
		return;
	}
	var gmap = this;
	this.geocoder.getLatLng( addressString, function(point){ gmap.ShowAddress(point); } );
}

GdbGmap.prototype.ShowAddress = function( point )
{
	if( point == null ) { this.ShowMiscInfo("Cannot find address"); return; }
	this.map.setCenter( point, this.singleMarkZoomLevel );
}

/////////////////////////////////////////////////////////////////////////
//  Info window functions
//

GdbGmap.prototype.OnUpdateInfo = function( info )
{
	if( this.infomode == info.id ) this.UpdateInfo();	
}

GdbGmap.prototype.SetInfoMode = function( mode )
{
	if( this.infomode != mode )
	{
		this.infomode=mode;
		this.UpdateInfo();

		if( mode == GDBGMAP_ID_FOUND || mode == GDBGMAP_ID_SAVED )
		{
			this.DisplayMarkList( mode );
		}
	}
}

GdbGmap.prototype.DisplayMarkList = function( mode, zoom )
{
	if( this.savedmarks == null || this.foundmarks == null )
	{
		this.pendingDisplayMarkList = mode;
		return;
	}
	if( zoom == null ) zoom = true;
	if( mode == GDBGMAP_ID_FOUND )
	{
		this.savedmarks.SetVisible( false );
		this.foundmarks.SetVisible( true );
		if( zoom ) this.ZoomToMarks( this.foundmarks );
	}
	if( mode == GDBGMAP_ID_SAVED )
	{
		this.foundmarks.SetVisible( false );
		this.savedmarks.SetVisible( true );
		if( zoom ) this.ZoomToMarks( this.savedmarks );
	}
}

GdbGmap.prototype.DisplayFoundMarks = function()
{
	this.SetInfoMode( GDBGMAP_ID_FOUND );
}

GdbGmap.prototype.DisplaySavedMarks = function()
{
	this.SetInfoMode( GDBGMAP_ID_SAVED );
}

GdbGmap.prototype.UpdateInfo = function()
{
	if( this.foundlisthtml == null ||
		this.savedlisthtml == null ||
		this.highlightheader == null ||
		this.highlightinfo == null )
	{
		this.pendingInfoMode = this.infomode;
		this.infomode = GDBGMAP_ID_NONE;
	}
 
	switch( this.infomode )
	{
	case GDBGMAP_ID_FOUND: this.SetInfoText( this.foundlisthtml.Text() ); break;
	case GDBGMAP_ID_SAVED: this.SetInfoText( this.savedlisthtml.Text() ); break;
	case GDBGMAP_ID_MARK: this.SetInfoText( this.highlightheader.Text() + this.highlightinfo.Text() ); break;
	default: this.SetInfoText('');
	}
}

GdbGmap.prototype.ShowMiscInfo = function( text )
{
	this.infomode = GDBGMAP_ID_NONE;
	this.SetInfoText( text );
}

GdbGmap.prototype.SetInfoText = function( text )
{
        this.infoView++;
	if( ! this.infoElementId ) return;
	var el = document.getElementById( this.infoElementId );
	if( el ) el.innerHTML = text;
}

//===========================================================================
// Functions for saved marks

GdbGmap.prototype.SaveVisibleMarks = function()
{
	var marks = new Array();
	this.Layers().Apply( function(layer) {
		if( layer.markers.visible ) { layer.markers.Marks( marks ); }
		} );
	if( this.foundmarks.visible ) this.foundmarks.Marks(marks);
	if( this.highlightmark.visible ) this.highlightmark.Marks(marks);
	this.savedmarks.AddMarks( marks );
}

GdbGmap.prototype.ClearSavedMarks = function( )
{
	this.savedmarks.Clear();
}


//===========================================================================
// Functions for retrieving GDB found and saved mark lists..

GdbGmap.prototype.GetGdbMarks = function( prms, list )
{
	
	var url = this.GdbUrl( prms );
	var gmap = this;
	LinzGetUrl( url, function(text){ gmap.HandleGdbMarks(text,list); } );
}

GdbGmap.prototype.HandleGdbMarks = function( text, list )
{
	var idstring = text.match(/(found|saved)marks\=(.*)/);
	if( idstring == null ) return;
	
	var foundlist = idstring[2];
	this.LoadMarkList( list, foundlist );
}

GdbGmap.prototype.LoadMarkList = function( list, markidtext )
{
	var gmap = this;
	if( markidtext != null && markidtext.match(/\w/)  )
	{
		this.WithIndex( function(){
			gmap.index.SearchId( markidtext, function(marks,sstatus){
				list.SetMarks(marks)
				});
			});
	}
	else
	{
		list.Clear();
	}
}

// Function to create a GDB url taking a list of objects each of which
// may define parameters with values "=xxx", sets the value of the 
// parameter, "$xxx" substituted with a set value, "+xxx" concatenates
// with value, anything else, just sets the value.

GdbGmap.prototype.GdbUrl = function()
{
	var gdbPrms = {};
	var values = {};
	gdbPrms[this.gdbModePrm] = this.gdbMode;
	for( var i = 0; i < arguments.length; i++ )
	{
		for( var p in arguments[i] )
		{
			var v = arguments[i][p];
			if( v == null ) v = '';
			if( v.length > 0 && v.charAt(0) == '=')
			{
				values[p]=v.substr(1);
				continue;
			}
			if( v.length > 0 && v.charAt(0) == '$')
			{
				v = values[v.substr(1)];
			}
			if( gdbPrms[p] != null && gdbPrms[p].length > 0 && gdbPrms[p].charAt(0) == '+' )
			{
				v = gdbPrms[p] + v;
			}
			gdbPrms[p] = v;
		}
	}
	gdbPrms[this.gdbSessionIdPrm] = this.gdbSessionId;
	var url = this.gdbUrl;
	var link = "?";
	for( var p in gdbPrms )
	{
		url = url + link + p + '=' + gdbPrms[p];
		link='&';
	}
	return url;
}

// Jump to another page in the GDB.  Need to set saved and found mark
// lists to reflect any updates in this page.

GdbGmap.prototype.GdbPage = function( params )
{
	var values = {
		savedmarks: '='+this.savedmarks.MarkIds(),
		foundmarks: '='+this.foundmarks.MarkIds()
		}
	var url = this.GdbUrl( values, params, this.gdbSetFoundMarkPrms, this.gdbSetSavedMarkPrms );
	this.WriteStatusToCookie();
        window.location = url;
}

//===========================================================================
// Get and set current map status ..

GdbGmap.prototype.GetStatus = function()
{
	if( ! this.index_loaded ) return '';

	// Map settings
	var loc = 'loc:' + this.GetMapLocation().join('|');

	// Selected layers
	var layers = '';
	this.Layers().Apply( function(layer){ 
		if( ! layer.markers.visible ) layers = layers + '|' + layer.code;;
		});
	layers = layers.replace(/^\|/,';lyr:');

	// Current array of found marks
	var found = '';
	var saved = '';
	if( this.markListsInStatus ) 
	{
		found = this.foundmarks.MarkIds('|',';fnd:'); 
		saved = this.savedmarks.MarkIds('|',';sav:'); 
	}

	// Current highlighted mark
        var highlight = this.highlightmark.MarkIds();
	if( highlight != '' ) highlight = ';hlt:'+highlight;

	// Current info mode
	var infomode = ';inf:'+this.infomode;
	var mstatus =  loc + layers + infomode + saved + found + highlight;
	return mstatus;
}

GdbGmap.prototype.SetStatus = function( statusString, options )
{
	if( options == null ) options = {};
	var settings = statusString.split(';');
	this.pendingFoundMarks = null;
	this.pendingSavedMarks = null;
	this.pendingHighlightMark = null;
	for( var i = 0; i < settings.length; i++ )
	{
		var name = settings[i].substr(0,4);
		var value  = settings[i].substr(4);
		switch(name)
		{
		case 'loc:': this.SetMapLocation( value.split('|')); break;
		case 'lyr:': this.disabledLayers = value.split('|'); break;
		case 'fnd:': this.pendingFoundMarks = value; break;
		case 'sav:': this.pendingSavedMarks = value; break;
		case 'hlt:': this.pendingHighlightMark = value; break;
		case 'inf:': this.SetInfoMode( Number(value) ); break;
		}
	}
	if( this.pendingHighlightMark != null && this.highlightmark != null  ) 
	{ 
		this.LoadMarkList( this.highlightmark, this.pendingHighlightMark );
	}
	if( ! this.markListsInStatus )
	{
		this.pendingFoundMarks = null;
		this.pendingSavedMarks = null;
	}
	if ( this.pendingFoundMarks != null && this.foundmarks != null ) 
	{
		this.LoadMarkList( this.foundmarks, this.pendingFoundMarks );
	}
	if ( this.pendingSavedMarks != null && this.savedmarks != null ) 
	{
		this.LoadMarkList( this.savedmarks, this.pendingSavedMarks );
	}
}

GdbGmap.prototype.SetStartLocationFromDefinition = function( )
{
	if( ! this.startLocDef ) return;
	var loc = this.startLocDef.match(/(\-\d+[\.\d]*)\,(\d+[\.\d]*)(?:\,(\d+))?/);
	if( loc )
	{
		loc.shift();
		if( ! loc[2] ) loc[2] = this.singleMarkZoomLevel; 
		this.SetMapLocation(loc);
	}
}

GdbGmap.prototype.SetStatusFromCookie = function( options )
{
	if( ! this.statusCookie ) return;
	if( ! document || ! document.cookie ) return;
	var cookies = document.cookie.split(";");
	if( ! cookies ) return;
	for( var i = 0; i < cookies.length; i++ )
	{
		cbits = cookies[i].replace(/\s/g,'').split('=');
		if( cbits[0] == this.statusCookie )
		{ 
			var status = unescape(cbits[1]);
			this.SetStatus( status, options );
			break;
		}
	}
}

GdbGmap.prototype.WriteStatusToCookie = function()
{
	if( this.statusCookie )
	{
		document.cookie = this.statusCookie+"="+escape(this.GetStatus());
	}
}
