yahoo_app_id = (self.yahoo_app_id && yahoo_app_id) ? yahoo_app_id : 'test';
yahoo_init_url = 'http://api.maps.yahoo.com/ajaxymap?appid='+yahoo_app_id;
// The following line is commented because it returns an error, as of 5/28/08:
//document.writeln('<script type="text/javascript" src="'+yahoo_init_url+'"><'+'/'+'script>');


function InitializeGeocoder() {

	yahoo_base_url = 'http://api.maps.yahoo.com/ajax/geocode?appid='+yahoo_app_id+'&qt=3&qs='; // qt = query type?
	// if (self.YGeoCode) { YGeoCode.getPoint = function(d){ YahooGeocodeCallback(d) }; }
	YGeoCode = {}; YGeoCode.getPoint = function(d){ YahooGeocodeCallback(d) };
	extra_fields = ['address','city','state','zip','country','precision'];

	source_menu = document.getElementById('source') || null;
	type_menu = document.getElementById('input_type') || null;
	separator_menu = document.getElementById('separator') || null;
	extra_info_checkbox = document.getElementById('extra_info') || null;
	color_box = document.getElementById('add_color') || null;
	progress_indicator = document.getElementById('progress') || null;
	error_message_div = document.getElementById('error_message') || null;
	start_button = document.getElementById('start') || null;
	start_button_parent = (start_button) ? start_button.parentNode : null;
	start_button_onclick = (start_button) ? start_button.getAttribute('onclick') : '';


}

function DetectDataType(input_id) {
	if (!document.getElementById(input_id)) { return false; }
	if (!document.getElementById(input_id).value) { return false; }
	var first_row = '';
	var first_eol_position = document.getElementById(input_id).value.indexOf('\n');
	if (first_eol_position > 0) {
		first_row = document.getElementById(input_id).value.substring(0,first_eol_position);
	} else if (first_eol_position == 0) {
		var next_eol_position = document.getElementById(input_id).value.indexOf('\n',1);
		first_row = document.getElementById(input_id).value.substring(1,next_eol_position);
	}
	var detected_type;
	if (first_row.match(/(^|\t|,)(street|add?ress?e?1?|city|town|plaats|ville|state|province|zip|postal|post ?code|code ?postale?|airport)\b/i)) {
		detected_type = 'table';
	} else {
		detected_type = 'list';
	}
	for (i=0; i<type_menu.options.length; i++) {
		if (type_menu.options[i].value == detected_type) {
			type_menu.selectedIndex = i;
		}
	}

	return true;
}


function GeocodeMultiple(input_id,output_id) {

	// globals:
	input_textarea = document.getElementById(input_id) || null;
	results_textarea = document.getElementById(output_id) || null;
	source = (source_menu) ? source_menu.value : 'yahoo';
	input_type = (type_menu) ? type_menu.value : 'list';
	extra_info = (extra_info_checkbox.checked) ? true : false;
	added_color = (color_box && color_box.value.match(/\w/)) ? color_box.value : '';
	sep = ','; if (separator_menu && separator_menu.value) { sep = (separator_menu.value == 'tab') ? "\t" : separator_menu.value; }

	if (progress_indicator) { progress_indicator.innerHTML = ''; }
	if (error_message_div) { error_message_div.style.display = 'none'; error_message_div.innerHTML = ''; }

	if (!input_textarea || !results_textarea) { return false; }

	var input_text = input_textarea.value;
	input_text = input_text.replace(/(^\s+|\s+$)/g,""); // delete leading and trailing white space
	input_text = input_text.replace(/\r/,'\n'); // just in case there are weird line breaks
	input_lines = input_text.split(/\n/);
	input_locations = [];
	input_data = [];

	if (!input_text.match(/\w/)) { return false; }

	if (input_type == 'list' && input_lines[0].match(/(^|\t|,)(street|add?ress?e?1?|city|town|ville|plaats|state|province|zip|postal|post ?code|p\. ?code|code ?postale?|airport)\b/i)) {
		alert ('You\'ve selected "raw list" as your input type, but it looks like your data is in a structured table with column headers.  Please either remove the header row or switch to "tabular data" mode.');
		return false;
	} else if (input_type == 'table' && !input_lines[0].match(/(^|\t|,)(street|add?ress?e?1?|city|town|ville|plaats|state|province|zip|postal|post ?code|code ?postale?|airport)\b/i)) {
		alert ('You\'ve selected "tabular data" as your input type, but it looks like your data doesn\'t have a header row.  Please either add a header row or switch to "raw list" mode.');
		return false;
	}

	if (!source) { source = 'yahoo'; }

	if (input_type == 'table') { // tabular
		var result = ParseTabularAddresses();
		if (!result) { return false; }
	} else { // list
		var result = ParseListOfAddresses();
		if (!result) { return false; }
	}

	continue_geocoding = true;

	location_counter = 0;
	lookup_counter = 0;
	var has_coordinates_already = (input_data.length == 0) ? false : ((input_data[location_counter]['latitude'].match(/\d/) && input_data[location_counter]['latitude'] != 0) || (input_data[location_counter]['longitude'].match(/\d/) && input_data[location_counter]['longitude'] != 0)) ? true : false;
	if (source == 'yahoo') {
		yahoo_retries = 0;
		if (input_locations[location_counter].match(/\w\w/) && !has_coordinates_already) {
			YahooGeocode();
		} else {
			YahooGeocodeCallback(null);
		}

	}
}

function ParseListOfAddresses() { // input_locations[] and input_lines[] are global
	for (j=0; j<input_lines.length; j++) {
		input_locations.push(input_lines[j]);
	}
	if (input_lines.length < 1) { return false; }

	// Prepare results box for output
	if (!results_textarea.value.match(/\w/)) {
		//results_textarea.value = results_textarea.value + 'latitude'+sep+'longitude'+sep+'name'+sep+'desc';
		if (extra_info) {
			for (var j=0; j<extra_fields.length; j++) {
				results_textarea.value = results_textarea.value + sep+qd(extra_fields[j].replace(/(^\s*|\s*$)/g,''));
			}
		}
		results_textarea.value = results_textarea.value + '\n';
	}
	return true;
}



function YahooGeocode() {
	var loc = input_locations[location_counter].replace(/\t/g,', ');
	yahoo_geocode_script = new JSONscriptRequest( yahoo_base_url + URIEscape_Lite(loc) );
	yahoo_geocode_script.buildScriptTag(); // Build the dynamic script tag
	yahoo_geocode_script.addScriptTag(); // Add the script tag to the page
	lookup_counter += 1;
}

function GoogleGeocode() {
	var loc = input_locations[location_counter].replace(/\t/g,', ');
	google_geocode_script = new JSONscriptRequest( google_base_url + URIEscape_Lite(loc) );
	google_geocode_script.buildScriptTag(); // Build the dynamic script tag
	google_geocode_script.addScriptTag(); // Add the script tag to the page
	lookup_counter += 1;
}

function YahooGeocodeCallback(data) {
	var d= {};
	var try_again = false;
	if (data) {
		if (data && data.GeoAddress) {
			d['gv_name'] = data.GeoAddress.replace(/\t/g,"  ");
		}
		if (data && data.GeoPoint && data.GeoPoint.Lat) {
			d['latitude'] = data.GeoPoint.Lat.toString();
			d['longitude'] = data.GeoPoint.Lon.toString();

		} else {
			d['latitude'] = '0';
			d['longitude'] = '0';
			d['precision'] = 'Yahoo: not found';
		}
		yahoo_geocode_script.removeScriptTag();
	}

	if (try_again && yahoo_retries < 2) { // don't do more than 3 lookups total
		yahoo_retries += 1;
	} else {
		OutputRow(d);
		location_counter += 1;
		yahoo_retries = 0;
	}

	if (location_counter < input_locations.length && (!yahoo_limit || lookup_counter < yahoo_limit) && continue_geocoding) {
		var has_coordinates_already = (input_data.length == 0) ? false : ((input_data[location_counter]['latitude'].match(/\d/) && input_data[location_counter]['latitude'] != 0) || (input_data[location_counter]['longitude'].match(/\d/) && input_data[location_counter]['longitude'] != 0)) ? true : false;
		if (input_locations[location_counter].match(/\w\w/) && !has_coordinates_already) {
			window.setTimeout("YahooGeocode()",1000*yahoo_delay);
		} else {
			YahooGeocodeCallback(null);
		}
	} else if (location_counter < input_locations.length && yahoo_limit && lookup_counter >= yahoo_limit) {

		var msg = "Sorry, you're only allowed to send "+yahoo_limit+" addresses at once to the Yahoo! geocoder with this form.  To do more, follow the instructions to save this form to your computer and use it locally.";
		alert (msg);
	} else if (location_counter == input_locations.length) { // all done, no limit issues

	}
}

function GoogleGeocodeCallback(data) {
	var d = {};
	var try_again = false;
	if (data) {
		var xml_string = json2xml(data);
		if (data.Status && data.Status.code && data.Status.code == 200) {
			d['latitude'] = data.Placemark[0].Point.coordinates[1].toString();
			d['longitude'] = data.Placemark[0].Point.coordinates[0].toString();
			d['gv_name'] = data.name.replace(/\t/g,"  ");
			d['gv_desc'] = tag_to_string(xml_string,'address').replace(/, (USA?|United States)$/,'');
			d['address'] = tag_to_string(xml_string,'ThoroughfareName');
			d['city'] = tag_to_string(xml_string,'LocalityName');
			d['state'] = tag_to_string(xml_string,'AdministrativeAreaName');
			d['zip'] = tag_to_string(xml_string,'PostalCodeNumber');
			d['country'] = tag_to_string(xml_string,'CountryNameCode');
			var acc = tag_to_string(xml_string,'Accuracy'); d['precision'] = google_precision[acc];
		} else if (data.Status && data.Status.code) {
			d['gv_name'] = data.name.replace(/\t/g,"  ");
			d['precision'] = 'Google error: '+google_status[data.Status.code];
			d['latitude'] = 0;
			d['longitude'] = 0;
		} else {
			// trouble!
		}
		google_geocode_script.removeScriptTag();
	}
	if (try_again && yahoo_retries < 2) { // don't do more than 3 lookups total
		google_retries += 1;
	} else {
		OutputRow(d);
		location_counter += 1;
		google_retries = 0;
	}

	if (location_counter < input_locations.length && (!google_limit || lookup_counter < google_limit) && continue_geocoding) {
		var has_coordinates_already = (input_data.length == 0) ? false : ((input_data[location_counter]['latitude'].match(/\d/) && input_data[location_counter]['latitude'] != 0) || (input_data[location_counter]['longitude'].match(/\d/) && input_data[location_counter]['longitude'] != 0)) ? true : false;
		if (input_locations[location_counter].match(/\w\w/) && !has_coordinates_already) {
			window.setTimeout("GoogleGeocode()",1000*google_delay);
		} else {
			GoogleGeocodeCallback(null);
		}
	} else if (location_counter < input_locations.length && google_limit && lookup_counter >= google_limit) {

		var msg = "Sorry, you're only allowed to send "+google_limit+" addresses at once to the Google geocoder with this form.  To do more, either use Yahoo (for North American addresses) or follow the instructions to save this form to your computer and use it locally.";
		alert (msg);
	} else if (location_counter == input_locations.length) { // all done, no limit issues

	}
}

function OutputRow(d) {
	if (!input_lines[location_counter].match(/\w/)) {
		results_textarea.value = results_textarea.value + '\n';

	} else {
		if (!d['gv_desc'] && d['gv_name'] && self.input_field_index && input_field_index['name'] != null) { d['gv_desc'] = d['gv_name']; }
		d['gv_desc'] = (d['gv_desc'] == '' || d['gv_desc'] == null) ? '-' : d['gv_desc'];
		d['gv_name'] = (d['gv_name'] == '' || d['gv_name'] == null) ? '-' : d['gv_name'];
		if (input_type == 'table') {
			var row = new Array;
			var lat = (input_data[location_counter]['latitude'] != '' && input_data[location_counter]['latitude'] != 0) ? input_data[location_counter]['latitude'] : d['latitude'];
			var lon = (input_data[location_counter]['longitude'] != '' && input_data[location_counter]['longitude'] != 0) ? input_data[location_counter]['longitude'] : d['longitude'];
			if (input_field_index['latitude'] == null) { row.push(qd(lat)); }
			if (input_field_index['longitude'] == null) { row.push(qd(lon)); }
			var parts = SmartSplit(input_lines[location_counter],input_delimiter);
			for (var j=0; j<input_fields.length; j++) {
				if (input_fields[j].match(/^(lati?|latt?itude)\b/i)) {
					row.push(qd(lat));
				} else if (input_fields[j].match(/^(long?|lng|long?t?itude)\b/i)) {
					row.push(qd(lon));
				} else {
					var p = (parts[j]) ? parts[j].replace(/(^\s*|\s*$)/g,'') : '';
					if ((!p || p == '') && d[input_fields[j]]) { p = d[input_fields[j]]; } // replace missing data
					if (input_fields[j].match(/^(colou?re?|couleur)\b/i) && p == '' && added_color != '') { p = added_color; }
					row.push(qd(p));
				}
			}
			if (extra_info) {
				for (var j=0; j<extra_fields.length; j++) {
					if (input_field_index[extra_fields[j]] == null) {
						var e = (d[extra_fields[j]]) ? d[extra_fields[j]].replace(/(^\s*|\s*$)/g,'') : '';
						row.push(qd(e));
					}
				}
			}
			if (input_field_index['name'] == null) { row.push(qd(d['gv_name'])); }
			if (input_field_index['desc'] == null) { row.push(qd(d['gv_desc'])); }
			if (input_field_index['color'] == null) { row.push(qd(added_color)); }
			results_textarea.value = results_textarea.value +row.join(sep) + '\n';
		} else {
//
// outputs ***
//

		var getcode = qd(d['gv_name']);

		getcode = getcode.replace(/[\w\W]*,/g, "");
		getcode = getcode.replace(/"/g ,"");

		//the incident location icon
		var icon = getOffenseIcon(getcode);

		//create and add incident to map
		var point = new GLatLng(qd(d['latitude']),qd(d['longitude']));

		var marker = new GMarker(point,icon);
		//var marker = new GMarker(point);


		//add location to incidents array
		//incidents.push(marker)

		//add bubble to marker
		GEvent.addListener(marker, "click", function() {
			//map.bubble.show(i,v,rec.id,marker,true)
			marker.openInfoWindowHtml("Address = <b>" + qd(d['gv_name']) + "</b>");});

		map.addOverlay(marker);




			results_textarea.value = results_textarea.value + qd(d['latitude'])+sep+qd(d['longitude'])+sep+qd(d['gv_name']);

			if (extra_info) {
				for (var j=0; j<extra_fields.length; j++) {
					var e = (d[extra_fields[j]]) ? d[extra_fields[j]].replace(/(^\s*|\s*$)/g,'') : '';
					results_textarea.value = results_textarea.value +sep+qd(e);
				}
			}

			results_textarea.value = results_textarea.value + '\n';
		}
	}
	results_textarea.scrollTop = results_textarea.scrollHeight;

	if (progress_indicator) { progress_indicator.innerHTML = '('+(location_counter+1)+' of '+input_locations.length+' lines processed)'; }
}


//
// begin map stuff
//

function getOffenseIcon(code) {
if (code == "925" || code == "PKG"){
	var icon = new GIcon();
	icon.image = code + ".png";
	icon.shadow = "/images/icon_shadow.png";
	icon.iconSize = new GSize(15, 13);
	icon.shadowSize = new GSize(20, 34);
	icon.iconAnchor = new GPoint(20, 34);
	icon.infoWindowAnchor = new GPoint(0, 0);
	return icon;
	}
else {
	var icon = new GIcon();
	icon.image = "default.png";
	icon.shadow = "/images/icon_shadow.png";
	icon.iconSize = new GSize(20, 34);
	icon.shadowSize = new GSize(20, 34);
	icon.iconAnchor = new GPoint(20, 34);
	icon.infoWindowAnchor = new GPoint(0, 0);
	return icon;
	}


}   //endfunc getoffensecode



//
// end map stuff
//

function tag_to_string(xml_text,tag_name) { // read tags out of an XML string
	var pattern = new RegExp('<'+tag_name+'>\\s*([^<]*)\\s*<\/'+tag_name+'>','i');
	var m = pattern.exec(xml_text);
	m = (m) ? m[1] : '';
	return (m)
}

function qd(text) { // qd = quote delimiters
	if (text == undefined) { return ''; }
	text = text.toString();
	if (text == '') { return ''; }
	var dl = (sep) ? sep : ',';
	var pattern = (dl == '|') ? '\\'+dl : dl;
	if (text.toString().match(pattern)) {
		return '"'+text.replace(/(^\s*|\s*$)/g,'')+'"';
	} else {
		return text.replace(/(^\s*|\s*$)/g,'');
	}
}

function SmartSplit(text,dl) {
	var pattern = new RegExp('(^|'+dl+')\\s*"(.*?)"\\s*(?='+dl+'|$)','g');
	text = text.replace(pattern,
		function (complete_match,dl1,cell_contents) {
			return (dl1+cell_contents.replace(/,/g,'{delimiter}'));
		}
	);
	var parts = text.split(dl);
	for (i=0; i<parts.length; i++) {
		parts[i] = parts[i].replace(/\{delimiter\}/g,dl);
		parts[i] = parts[i].replace(/(^\s+|\s+$)/g,'');
	}
	return parts;
}

function URIEscape(text) {
	text = escape(text);
	text = text.replace(/\//g,"%2F");
	text = text.replace(/\?/g,"%3F");
	text = text.replace(/=/g,"%3D");
	text = text.replace(/&/g,"%26");
	text = text.replace(/@/g,"%40");
	return (text);
}
function URIEscape_Lite(text) {
	text = text.replace(/\//g,"%2F");
	text = text.replace(/\?/g,"%3F");
	text = text.replace(/=/g,"%3D");
	text = text.replace(/&/g,"%26");
	text = text.replace(/@/g,"%40");
	text = text.replace(/\#/g,"%23");
	return (text);
}


function JSONscriptRequest(fullUrl) {
	// REST request path
	this.fullUrl = fullUrl;
	// Keep IE from caching requests
	this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
	// Get the DOM location to put the script tag
	this.headLoc = document.getElementsByTagName("head").item(0);
	// Generate a unique script tag id
	this.scriptId = 'YJscriptId' + JSONscriptRequest.scriptCounter++;
}

// Static script ID counter
JSONscriptRequest.scriptCounter = 1;

// buildScriptTag method
//
JSONscriptRequest.prototype.buildScriptTag = function () {

	// Create the script tag
	this.scriptObj = document.createElement("script");

	// Add script object attributes
	this.scriptObj.setAttribute("type", "text/javascript");
	this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
	this.scriptObj.setAttribute("id", this.scriptId);
}

// removeScriptTag method
//
JSONscriptRequest.prototype.removeScriptTag = function () {
	// Destroy the script tag
	this.headLoc.removeChild(this.scriptObj);
}

// addScriptTag method
//
JSONscriptRequest.prototype.addScriptTag = function () {
	// Create the script tag
	this.headLoc.appendChild(this.scriptObj);
}


function json2xml(o, tab) {
	var toXml = function(v, name, ind) {
		var xml = "";
		if (v instanceof Array) {
			for (var i=0, n=v.length; i<n; i++)
				xml += ind + toXml(v[i], name, ind+"\t") + '\n';
		}
		else if (typeof(v) == "object") {
			var hasChild = false;
			xml += ind + "<" + name;
			for (var m in v) {
				if (m.charAt(0) == "@")
					xml += " " + m.substr(1) + "=\"" + v[m].toString() + "\"";
				else
					hasChild = true;
			}
			xml += hasChild ? ">" : "/>";
			if (hasChild) {
				for (var m in v) {
					if (m == "#text")
						xml += v[m];
					else if (m == "#cdata")
						xml += "<![CDATA[" + v[m] + "]]>";
					else if (m.charAt(0) != "@")
						xml += toXml(v[m], m, ind+"\t");
				}
				xml += (xml.charAt(xml.length-1)=='\n'?ind:"") + "</" + name + ">";
			}
		}
		else {
			xml += ind + "<" + name + ">" + v.toString() +  "</" + name + ">";
		}
		return xml;
	}, xml="";
	for (var m in o)
		xml += toXml(o[m], m, "");
	return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
}


