function MGeocoder(MOptions) {
	this.self = this;
	MOptions = MOptions ? MOptions : {};
	this.parent = MOptions.container ? MOptions.container : null;
	this.width = MOptions.width ? MOptions.width : 300;
	this.height = MOptions.height ? MOptions.height : 260;
	this.gc = new GClientGeocoder();
	this.spIcons = Array();
	this.markers = Array();
	this.territoryId;
	this.territoryName;
	this.pMarkIndex = 0;	

	this.address;
	this.latlon;

};



MGeocoder.prototype.initialize = function() {
	this.container = document.createElement('DIV');
	this.parent.appendChild(this.container);

	this.container.style.border = '1px solid gray';
	this.container.style.background = '#ffffff';
	this.container.style.font = 'normal 10px verdana';
	this.createTitleBar();
	this.createIconBar();
	this.createSearchBar();
	this.createMap();
	this.createStatusBar();
	this.createMarkers();
};


//-------------



MGeocoder.prototype.createTitleBar = function() {
	var self = this.self;

	var topBar = document.createElement('DIV');
	this.container.appendChild(topBar);
	topBar.style.textAlign = 'center';

	this.titleBar = document.createElement('DIV');
	this.container.appendChild(this.titleBar);
	this.titleBar.style.border = '1px solid gray';
	this.titleBar.style.textAlign = 'center';
	this.titleBar.style.padding = '2px';
	this.titleBar.style.font = 'normal 12px verdana';
	this.titleBar.style.background = 'navy';
	this.titleBar.style.color = 'white';
};



MGeocoder.prototype.createIconBar = function() {
	var self = this.self;

	this.iconBar = document.createElement('DIV');
	this.container.appendChild(this.iconBar);
	this.iconBar.style.textAlign = 'center';
	this.iconBar.icons = Array();

	for (var n = 0 ; n < this.spIcons.length ; n++) {
		var icon = document.createElement('IMG');
		icon.src = '/images/' + this.spIcons[n].iconImage;
		icon.style.cursor = 'pointer';
		icon.style.margin = '2px';
		icon.style.padding = '2px';
		icon.style.border = '2px solid white';
		this.iconBar.appendChild(icon);
		icon.iconIndex = n;
//		icon.appendChild(icon);
		icon.onmouseover = function(){self.highlightIcon(this)};
		icon.onmouseout = function(){self.highlightIcon(null)};
		icon.onclick = function(){self.selectIcon(this)};
		this.iconBar.icons.push(icon);
	}
};


MGeocoder.prototype.highlightIcon = function(oIcon) {
	for (var n = 0 ; n < this.iconBar.icons.length ; n++) {
		if (!this.iconBar.icons[n].selected) {
			this.iconBar.icons[n].style.background = '';
		}
	}
	if (oIcon && !oIcon.selected) {
		oIcon.style.background = '#CCCCCC';
	}
};

MGeocoder.prototype.selectIcon = function(oIcon) {
	var self = this.self;
	this.hideMarkers();	
	
	for (var n = 0 ; n < this.iconBar.icons.length ; n++) {
		this.iconBar.icons[n].style.border = '2px solid white';
		this.iconBar.icons[n].style.background = '';
		this.iconBar.icons[n].selected = false;
		this.selectedIconIndex = null;
	}
	if (oIcon) {
		oIcon.style.border = '2px solid red';
		oIcon.selected = true;
		self.selectedIconIndex = oIcon.iconIndex;

		if (self.latlon) {
			var marker = self.markers[self.selectedIconIndex];
			marker.setLatLng(self.latlon);
			marker.show();
		}
		
	}
};




MGeocoder.prototype.createSearchBar = function() {
	var self = this.self;

	var topBar = document.createElement('DIV');
	this.container.appendChild(topBar);
	topBar.style.textAlign = 'center';

	var iTable = document.createElement('TABLE');
	topBar.appendChild(iTable);
//	iTable.setAttribute('width','100%');
	iTable.setAttribute('cellSpacing',0);
	iTable.setAttribute('cellPadding',1);

	var oTBody = document.createElement('TBODY');
	iTable.appendChild(oTBody);

	var oRow = document.createElement('TR');
	oTBody.appendChild(oRow);
	
	var oCell = document.createElement('TD');
	oRow.appendChild(oCell);
	oCell.innerHTML = 'Address: ';

	var oCell = document.createElement('TD');
	oRow.appendChild(oCell);
	this.adressInput = document.createElement('INPUT');
	oCell.appendChild(this.adressInput);
	this.adressInput.style.border = '1px solid gray';
	this.adressInput.style.width = '200px';
	this.adressInput.onkeydown = function(event){
		if (event.keyCode == 13) {
			self.geocodeAddress();
		}
	};
	oCell.style.overflow = 'visible';

	this.optionsDiv = document.createElement('DIV');
	oCell.appendChild(this.optionsDiv);

	this.optionsDiv.style.background = '#eeeeee';
	this.optionsDiv.style.border = '1px solid gray';
	this.optionsDiv.style.marginTop = '2px';
	this.optionsDiv.style.marginLeft = '5px';
	this.optionsDiv.style.padding = '3px';
	
	this.optionsDiv.style.display = 'none';
	this.optionsDiv.style.position = 'absolute';
	this.optionsDiv.style.zIndex = '10000';


	var oCell = document.createElement('TD');
	oRow.appendChild(oCell);
	var oButton = document.createElement('INPUT');
	oButton.type = 'button';
	oButton.value = 'Go';
	oCell.appendChild(oButton);
	oButton.style.border = '1px solid gray';
	oButton.onclick = function(){self.geocodeAddress()};
//-------------
};
	
MGeocoder.prototype.createMap = function() {
	var self = this.self;
	if (!this.map) {
		var mapDiv = document.createElement('DIV');
		mapDiv.style.height = this.height + 'px';
		this.container.appendChild(mapDiv);
		this.map = new GMap2(mapDiv);
		this.map.setCenter(app.centerPoint,app.zoom);
		this.map.addControl(new GSmallMapControl());
		this.map.addControl(new GMapTypeControl());
		this.map.enableScrollWheelZoom();
		

		GEvent.addListener(this.map,'click',function(ol,latlon,olLatlon){
			if (latlon) {
				self.geocode(latlon,true);
			}
		});


	}
};

MGeocoder.prototype.createMarkers = function() {
	for (var n = 0 ; n < this.spIcons.length ; n++) {
		var marker = this.createMarker(this.spIcons[n]);
		this.markers.push(marker);
		this.map.addOverlay(marker);
		marker.hide();
	}
};

MGeocoder.prototype.createMarker = function(spObj) {
	var self = this.self;
	var icon = spObj.icon;
	var title = spObj.name + ' : ' + spObj.description;
	var marker = new GMarker(this.map.getCenter(),{draggable:true,icon:icon,title:title});
	GEvent.addListener(marker,'dragend',function(){
		self.geocode(marker.getLatLng(),true);
	});
	return marker;
};

MGeocoder.prototype.hideMarkers = function() {
	for (var n = 0 ; n < this.markers.length ; n++) {
		this.markers[n].hide();
	}
};

MGeocoder.prototype.createStatusBar = function() {
	var self = this.self;

	this.statusBar = document.createElement('TABLE');
	this.container.appendChild(this.statusBar);
	this.statusBar.setAttribute('width','100%');
	this.statusBar.setAttribute('cellSpacing',0);
	this.statusBar.setAttribute('cellPadding',1);

	this.statusBar.style.display = 'none';
	this.statusBar.style.background = '#E9EC00';
	this.statusBar.style.padding = '3px';
	this.statusBar.style.font = 'normal 10px verdana';
	this.statusBar.style.borderTop = '1px solid black';

	var oTBody = document.createElement('TBODY');
	this.statusBar.appendChild(oTBody);

	var oRow = document.createElement('TR');
	oTBody.appendChild(oRow);
	
	var oCell = document.createElement('TD');
	oCell.style.width = '100px';
	oRow.appendChild(oCell);
	oCell.setAttribute('vAlign','top');
	oCell.innerHTML = 'Address: ';
	
	this.sbAddress = document.createElement('TD');
	oRow.appendChild(this.sbAddress);
	this.sbAddress.style.fontWeight = 'bold';
	this.sbAddress.setAttribute('align','center');

	var oCell = document.createElement('TD');
	oCell.style.width = '100px';
	oRow.appendChild(oCell);
	oCell.setAttribute('rowSpan',2);
	oCell.setAttribute('align','right');

	var oButton = document.createElement('INPUT');
	oButton.type = 'button';
	oButton.value = 'Clear';
	oCell.appendChild(oButton);
	oButton.style.border = '1px solid gray';
	oButton.style.width = '80px';
	oButton.onclick = function(){self.clearAddress()};

	var oButton = document.createElement('INPUT');
	oButton.type = 'button';
	oButton.value = 'Save';
	oCell.appendChild(oButton);
	oButton.style.border = '1px solid gray';
	oButton.style.width = '80px';
	oButton.onclick = function(){self.setAddress()};

//----------
	var oRow = document.createElement('TR');
	oTBody.appendChild(oRow);
	
	var oCell = document.createElement('TD');
	oRow.appendChild(oCell);
	oCell.setAttribute('vAlign','top');
	oCell.innerHTML = 'Lat/Lon: ';
	
	this.sbLatLon = document.createElement('TD');
	oRow.appendChild(this.sbLatLon);
	this.sbLatLon.style.fontWeight = 'bold';
	this.sbLatLon.setAttribute('align','center');



};


MGeocoder.prototype.geocodeAddress = function() {
	if (this.adressInput.value) {
		this.geocode(this.adressInput.value);
	}
	else {
		alert('Please enter a location to search');
	}
};




MGeocoder.prototype.setTerritotyInfo = function(id,name,spType) {
	this.territoryId = id;
	this.territoryName = name;
	spType = spType ? spType : 1;

	this.selectedIconIndex = spType-1;
	var icon = this.iconBar.icons[this.selectedIconIndex];
	this.selectIcon(icon);

	this.address = null;
	this.latlon = null;

	if (this.territoryId) {
		var poly = app.pSelector.getSelectorPolyByTerritoryId(this.territoryId);
		if (poly.territoryBounds) {
			var z = this.map.getBoundsZoomLevel(poly.territoryBounds);
			z = z < 9 ? z : 8;
			this.map.setCenter(poly.territoryBounds.getCenter(), z);
		}
		else {
			this.map.setCenter(app.centerPoint,app.zoom);
		}
		if (poly.servicePoint) {
			this.address = poly.servicePoint.getTitle();
			this.latlon = poly.servicePoint.getLatLng();
			var marker = this.markers[this.selectedIconIndex];
			marker.setLatLng(this.latlon);
			marker.show();
			this.sbAddress.innerHTML = poly.servicePoint.getTitle();
			this.sbLatLon.innerHTML = poly.servicePoint.getLatLng().lat().toFixed(6) + ',' + poly.servicePoint.getLatLng().lng().toFixed(6);
			this.statusBar.style.display = '';
		}

	
		
		this.titleBar.innerHTML = 'Set service point for territory "' + this.territoryName + '"';
		this.titleBar.innerHTML += '<br><small>';
		this.titleBar.innerHTML += 'Click on the map or enter an address to search';
		this.titleBar.innerHTML += '</small>';
		
		
		if (this.overlay) {
			this.map.removeOverlay(this.overlay);
			this.overlay = null;
		}
		this.overlay = app.pSelector.tlc.createOverlay(app.pSelector.tlc.overlayTheme);

		var fid = app.pSelector.getFranchiseId();

		this.overlay.getTileLayer().getTileUrl = function (a,b) {
			var url = '/cgi-bin/getFranchiseTile.pl?fid=' + fid + '&x=' + a.x + '&y=' + a.y + '&z=' + b + '&r=' + Math.random();
	//GLog.write(url)
			return url;
		};
		
		
		this.map.addOverlay(this.overlay);
	
	
	}
};

MGeocoder.prototype.reset = function() {
	this.hideMarkers();
	this.map.checkResize();
	this.map.setMapType(G_NORMAL_MAP);
	this.sbAddress.innerHTML = '';
	this.sbLatLon.innerHTML = '';
	this.hideMultiRes();
	this.statusBar.style.display = 'none';
	this.address = null;
	this.latlon = null;


};

MGeocoder.prototype.geocode = function(query,useMaxAccuracy) {
	var self = this.self;
	if (query) {
		this.gc.reset();
		this.gc.getLocations(query,function(response){self.addAddressToMap(response,useMaxAccuracy)});
	}
};

MGeocoder.prototype.addAddressToMap = function(response,useMaxAccuracy) {
	if (!response || response.Status.code != 200) {
		switch (response.Status.code) {
			case G_GEO_SUCCESS: break;
			case G_GEO_BAD_REQUEST: alert("Error: " + response.Status.code + ' - A directions request could not be successfully parsed.'); break;
			case G_GEO_SERVER_ERROR: alert("Error: " + response.Status.code + ' - A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'); break;
			case G_GEO_MISSING_QUERY: alert("Error: " + response.Status.code + ' - The HTTP q parameter was either missing or had no value. For geocoding requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.'); break;
			case G_GEO_MISSING_ADDRESS: alert("Error: " + response.Status.code + ' - Synonym for G_GEO_MISSING_QUERY.'); break;
			case G_GEO_UNKNOWN_ADDRESS: alert("Error: " + response.Status.code + ' - No corresponding geographic location could be found for the specified address. This may be due to the fact that the address is relatively new, or it may be incorrect.'); break;
			case G_GEO_UNAVAILABLE_ADDRESS: alert("Error: " + response.Status.code + ' - The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.'); break;
			case G_GEO_UNKNOWN_DIRECTIONS: alert("Error: " + response.Status.code + ' - The GDirections object could not compute directions between the points mentioned in the query. This is usually because there is no route available between the two points, or because we do not have data for routing in that region.'); break;
			case G_GEO_BAD_KEY: alert("Error: " + response.Status.code + ' - The given key is either invalid or does not match the domain for which it was given.'); break;
			case G_GEO_TOO_MANY_QUERIES: alert("Error: " + response.Status.code + ' - The given key has gone over the requests limit in the 24 hour period.'); break;
			default: alert("Unknown Error"  + response.Status.code);
		}
	} 
	else {
		this.response = response;
		if (response.Placemark.length == 1 || useMaxAccuracy) {
			this.gotoPlacemark(0);
		}
		else if (response.Placemark.length > 1) {

			this.optionsDiv.innerHTML = '';
			var html = '<div class="titleDiv">Multiple choices found</div>';

			// Header
			var oDiv = document.createElement('DIV');
			oDiv.innerHTML = 'Multiple choices found';
			oDiv.style.borderBottom = '1px solid black';
			oDiv.style.marginBottom = '2px';
			oDiv.style.textAlign = 'center';
			this.optionsDiv.appendChild(oDiv);
			
			for (var n = 0 ; n < response.Placemark.length ; n++ ) {
				var linkDiv = this.createChoiceLink(n);
				this.optionsDiv.appendChild(linkDiv);
			}

			// Footer			
			var oDiv = document.createElement('DIV');
			oDiv.style.borderTop = '1px solid black';
			oDiv.style.marginTop = '2px';
			oDiv.style.cursor = 'pointer';
			oDiv.style.textAlign = 'center';
			oDiv.style.color = 'blue';
			oDiv.onclick     = function(){self.hideMultiRes()};
			oDiv.innerHTML = 'None of these';
			this.optionsDiv.appendChild(oDiv);
			
			this.optionsDiv.style.display = '';
		}
	}
};

MGeocoder.prototype.createChoiceLink = function(ix) {
	var self = this.self;
	var pMark = this.response.Placemark[ix];
	var oLink = document.createElement('DIV');
	oLink.style.cursor = 'pointer';
	oLink.style.color = 'blue';

	oLink.onmouseover = function(){this.style.color ='#FF9A00'};
	oLink.onmouseout  = function(){this.style.color = 'blue'};
	oLink.onclick     = function(){self.gotoPlacemark(ix)};
	oLink.innerHTML = pMark.address + ' [' + pMark.AddressDetails.Accuracy + ']';
	return oLink;
};

MGeocoder.prototype.hideMultiRes = function() {
	this.optionsDiv.style.display = 'none';
};

MGeocoder.prototype.gotoPlacemark = function(ix) {
	this.hideMultiRes();
	this.pMarkIndex = ix;

	var pMark = this.response.Placemark[ix];
	this.latlon = new GLatLng(pMark.Point.coordinates[1],	pMark.Point.coordinates[0]);
	this.address = pMark.address;
	

	var SW = new GLatLng(pMark.ExtendedData.LatLonBox.south,pMark.ExtendedData.LatLonBox.west);
	var NE = new GLatLng(pMark.ExtendedData.LatLonBox.north,pMark.ExtendedData.LatLonBox.east);
	var bounds = new GLatLngBounds(SW,NE);


	this.hideMarkers();	
	var marker = this.markers[this.selectedIconIndex];
	marker.setLatLng(this.latlon);
	marker.show();

	this.map.panTo(this.latlon);

	if (this.map.getBoundsZoomLevel(bounds) > this.map.getZoom()) {
		this.map.setCenter(bounds.getCenter(), this.map.getBoundsZoomLevel(bounds)); 
	}

	this.sbAddress.innerHTML = this.address;
	this.sbLatLon.innerHTML = this.latlon.lat().toFixed(6) + ',' + this.latlon.lng().toFixed(6);
	this.statusBar.style.display = '';

};




MGeocoder.prototype.setAddress = function() {
	if (typeof this.onAddressResolved == 'function') {
		var lat = '';
		var lon = '';
		var spType = '';
		var address = '';
		if (this.latlon) {
			var address = this.address;
			var lat = this.latlon.lat().toFixed(6);
			var lon = this.latlon.lng().toFixed(6);
			var spType = this.spIcons[this.selectedIconIndex].value;
		}

		this.onAddressResolved(
				this.territoryId,
				address,
				lat,
				lon,
				spType
			);
	}
};



MGeocoder.prototype.clearAddress = function() {
	this.address = null;
	this.latlon = null;
	this.sbAddress.innerHTML = '';
	this.sbLatLon.innerHTML = '';
	var marker = this.markers[this.selectedIconIndex];
	marker.hide();
};


MGeocoder.prototype.setSelectedIconIndex = function(val) {
	for (var n = 0 ; n < this.spIcons.length ; n++ ) {
		if (this.spIcons[n].value == val) {
			this.selectedIconIndex = n;
		}
	}
};
