// Copyright 2006 Phillip Holmstrand 
var per = new Object();
var source,dest,start_line,gcObj,curRow,succCount,curTimeout,format,working,map,map_width,map_height,validate_span,geocode_button,geocoder_span,f_lat,f_lon,f_address,centerImg,smallImg,markers,gA;
var lat_name = "bg_lat", long_name = "bg_long", dist_name = "bg_distance";
var markerArray = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')
var colorArray = new Array('orange','blue','green','red','purple','yellow','grey');

function init() {
	source = dId("sourceData");
	dest = dId("destData");
	geocoder_span = dId("geocoder_status");
	geocode_button = dId("geocode_button");
	validate_span = dId("validate_status");
	per.dist_sel = dId("dist_sel").selectedIndex;
	per.dist_cb_status = dId("dist_cb").checked;
	per.field_cb_status = dId("field_cb").checked;
	addImages();
	var map_div = dId("mapDiv");
	try {
		map = new YMap(map_div);
		map.addPanControl();
		var zp = new YCoordPoint(5,30);
		zp.translate('right','bottom');
		map.addZoomLong(zp);
		map.addTypeControl();
		map.disableKeyControls();
//		yMapsZoomFix();
		YGeoCode.getMap = function(d){ endGeocode(d) };
	} catch (obj) {
		window.status = 'Map failed to load.';
	}
	getSize(dId("mapDiv"));
	toggleExample(0);
}

function simpleInit() {
	var map_div = dId("mapDiv");
	map = new YMap(map_div);
	map.addPanControl();
	map.addZoomLong();
	map.addTypeControl();
	map.disableKeyControls();
	map_width = parseInt(map_div.style.width);
	map_height = parseInt(map_div.style.height);
	addImages();
	getSize(dId("mapDiv"));
	if (!per['dist_cb_status']) {
		per.dist_sel = 0;
		per.dist_cb_status = false;
	}
	if (!per['field_cb_status']) {
		per.field_cb_status = false;
	}
	per.field_cb_status = true;
	if (per)
		doMap();
	else
		alert('Data load error, try reloading the page or rebuilding map.');
}

function yImg(ySize, yCoordPoint, src) {
	var yI = new YImage();
	yI.src = src;
	yI.size = ySize;
	yI.offsetSmartWindow = yCoordPoint;
	return yI;
}

function addImages() {
	centerImg = yImg(new YSize(30,33),new YCoordPoint(0,0),'/images/blue.png');
	smallImg = yImg(new YSize(9,9),new YCoordPoint(4,3),'/images/small_orange.gif');
	smallImgRed = yImg(new YSize(9,9),new YCoordPoint(4,3),'/images/small_blue.gif');
}

function getFormat() {
	var formatObj = document.geocodeForm.format;
	for (var i=0;i<formatObj.length;i++) if (formatObj[i].checked) formatValue = formatObj[i].value;
	if (formatValue == "\\t") formatValue = "\t";
	return formatValue;
}

function toggleExample(val) {
	obj = dId("example_toggle_anchor");
	if (getCookie("examples") == val) {
		setCookie("examples", 0, cookieDate);
	} else {
		setCookie("examples", 1, cookieDate);
		if (source && source.value.length == 0) loadExample();
	}
	if (getCookie("examples") == 1) {
		obj.innerHTML = "turn off example loading";
	} else {
		obj.innerHTML = "turn on example loading";
	}
}

function loadExample() {
	if (getCookie('examples') == 0) return;
	switch (getFormat()) {
		case '\t': loadURL('example_tab.txt', source); break;
		case '|': loadURL('example_bar.txt', source); break;
	}
}

function unValidateSource() {
	validate_span.innerHTML = '';
	per.columnNames = '';
}

function validateSource() {
	format = getFormat();
	source.value = source.value.trim();
	if (source.value.length < 5) {
		alert('Check your source data, make sure its populated correctly. Look at the example if you are having trouble.');
		return 0;
	}
	var lineArray = source.value.split('\n');

	for (var i=0;i<lineArray.length;i++) {
		var line = lineArray[i].trim();
		if (line.substr(0,1) != '#') {
			per.columnNames = line.split(formatValue);
			start_line = i+1;
			break;
		}
	}
	
	if (per.columnNames.toString().indexOf(lat_name) != -1 || per.columnNames.toString().indexOf(long_name) != -1 || per.columnNames.toString().indexOf(dist_name) != -1){
		alert('Validation Error: You cannot have columns named \"' + lat_name + '\" or \"' + long_name + '\" or \"' + dist_name + '\" as these are used by the geocoder, please check your column names and re-validate.');
		per.columnNames = '';
		return 0;
	}
	
	per.dataRS = new Array();
	for (var r=start_line;r<lineArray.length;r++) {
		var row = lineArray[r].split(formatValue);
		per.dataRS[r-start_line] = new Array();
		for (var c=0;c<row.length;c++) {
			per.dataRS[r-start_line][c] = row[c].trim();
		}
	}

	if (per.dataRS.length > 500) {
		if (!confirm("Warning: Geocoding datasets larger than 500 at one time is not recommended, if you have a large set of data to geocode try to process it in 500 address chunks. Do you want to continue anyway?")) {
			per.columnNames = '';
			return 0;
		}
	}

	per.address_col = populateSelect(dId('address_sel'), per.columnNames, 'address');
	per.city_col = populateSelect(dId('city_sel'), per.columnNames, 'city');
	per.state_col = populateSelect(dId('state_sel'), per.columnNames, 'state');
	per.state_col = per.state_col >= 0 ? per.state_col : per.state_col = populateSelect(dId("state_sel"), per.columnNames, "province");
	per.zip_col = populateSelect(dId('zip_sel'), per.columnNames, 'zip');
	per.desc_col = populateSelect(dId('desc_sel'), per.columnNames, 'description');
	per.group_col = populateSelect(dId('group_sel'), per.columnNames, 'group');
	per.title_col = populateSelect(dId('title_sel'), per.columnNames, 'title');
	per.title_col = per.title_col >= 0 ? per.title_col : populateSelect(dId('title_sel'), per.columnNames, 'name');
	per.descURL_col = populateSelect(dId('descURL_sel'), per.columnNames, 'url');
	per.descIMG_col = populateSelect(dId('descIMG_sel'), per.columnNames, 'image');
	per.descIMG_col = per.descIMG_col >= 0 ? per.descIMG_col : populateSelect(dId('descIMG_sel'), per.columnNames, 'img');
	
	per.color_col = null;
	for (i=0;i<per.columnNames.length;i++) {
		if (per.columnNames[i].toLowerCase().indexOf("color") != -1) {
			per.color_col = i;
			break;
		}
	}
	
	validate_span.innerHTML = "Done: " + per.columnNames.length + " columns, " + per.dataRS.length + " rows";
}

function doGeocode() {
	if (!per.columnNames) {
		alert('You need to validate the source first, check Step #3.');
		return 0;
	} else if (per.address_col < 0 && per.city_col < 0 && per.state_col < 0 && per.zip_col < 0) {
		alert('No columns that can be geocoded are selected, check Step #4.');
		return 0;
	} else if (working) {
		if (confirm('Are you sure you want to stop the current geocoding processs?'))
			return stopGeocode();
		else
			return 0;
	}

	per.desc_col = rS(dId("desc_sel"));

	if (per.desc_col == -1 || per.desc_col.toString().split('\t').length > 1) {
		per.desc_col = '';
		var selCol = '\t' + per.columnNames[per.title_col] + '\t' + per.columnNames[per.descIMG_col] + '\t' + per.columnNames[per.descURL_col] + '\t' + per.columnNames[per.address_col] + '\t' + per.columnNames[per.address_col] + '\t' + per.columnNames[per.city_col] + '\t' + per.columnNames[per.state_col] + '\t' + per.columnNames[per.zip_col] + '\t' + per.columnNames[per.group_col] + '\t' + (per.color_col ? per.columnNames[per.color_col] : '') + '\t';
		for (var i=0;i<per.columnNames.length;i++)  {
			if (selCol.indexOf('\t' + per.columnNames[i] + '\t') == -1) {
				per.desc_col = per.desc_col + '\t' + i;
			}
		}
		per.desc_col = per.desc_col.trim();
	}

	var lineArray = source.value.split('\n');
	per.mapRS = new Array();
	working = 1;
	curRow = 0;
	succCount = 0;
	geocode_button.value = 'Stop Geocoder';
	dest.value = '';
	for (var c=0;c<per.columnNames.length;c++) dest.value += per.columnNames[c].trim() + format;
	dest.value += lat_name + format + long_name + format;
	dest.value += per.dist_cb_status ? format + dist_name : '';
	startRow(curRow);
}

function stopGeocode() {
	working = 0;
	geocoder_span.innerHTML = "Geocoded: " + succCount + "/" + (per.dataRS.length) + " records.";
	geocode_button.value = 'Run Geocoder';
	doMap();
}

function startRow(r) {
	if (!working) return 0;
	geocoder_span.innerHTML = 'Processing: ' + (r+1) + '/' + per.dataRS.length;
	per.mapRS[r] = new Object();
	var rowData = per.dataRS[r];
	var rM = per.mapRS[r];
	
	rM['a'] = per.address_col >= 0 ? rowData[per.address_col] : '';
	rM['c'] = per.city_col >= 0 ? rowData[per.city_col] : '';
	rM['s'] = per.state_col >= 0 ? rowData[per.state_col] : '';
	rM['z'] = per.zip_col >= 0 ? rowData[per.zip_col] : '';
	rM['t'] = per.title_col >= 0 ? rowData[per.title_col] : '';
	rM['u'] = per.descURL_col >= 0 ? rowData[per.descURL_col] : '';
	rM['i'] = per.descIMG_col >= 0 ? rowData[per.descIMG_col] : '';	
	rM['cl'] = per.color_col ? rowData[per.color_col] : null;
	rM['g'] = per.group_col >= 0 ? rowData[per.group_col] : '';	
	
	rM['d'] = '';
	if (per.desc_col.toString().indexOf('\t') != -1) {
		var descArray = per.desc_col.split('\t');
		for (var i=0;i<descArray.length;i++) {
			if (rowData[descArray[i].trim()] && rowData[descArray[i].trim()].trim().length) 
				rM['d'] += '<div>' + (per.field_cb_status ? '<span class="l">' + per.columnNames[descArray[i]] + ':</span>&nbsp;' : '') + rowData[descArray[i].trim()] + '</div>'; 
		}
	} else {
		rM['d'] = per.desc_col >= 0 && rowData[per.desc_col] ? rowData[per.desc_col] : '';
		rM['d'] = rM['d'].length > 0 ? '<div>' + (per.field_cb_status ? '<span class="l">' + per.columnNames[per.desc_col] + ':</span>&nbsp;' : '') + rM['d'] + '</div>' : '';
	}

	dest.value += '\n';	
	
	for (var c=0;c<rowData.length;c++) dest.value += rowData[c] + format;
	
	curRow = r;
	var gcURL = baseURL + '&qs=' + escape(rM['a']);
	gcURL = rM['c'] && rM['c'].length > 0 ? gcURL + '%2C' + escape(rM['c']) : gcURL;
	gcURL = rM['s'] && rM['s'].length > 0 ? gcURL + '%2C' + escape(rM['s']) : gcURL;
	gcURL = rM['z'] && rM['z'].length > 0 ? gcURL + '%2C' + escape(rM['z']) : gcURL;
	gcObj = new JSONscriptRequest(gcURL);
	gcObj.buildScriptTag();
	gcObj.addScriptTag();
	curTimeout = setTimeout("endGeocode(null)", 8000);
}

function endGeocode(data) {
	clearTimeout(curTimeout);
	var lat, lon;
	var rM = per.mapRS[curRow];
	gcObj.removeScriptTag();
	delete gcObj;
	if (data && data.GeoPoint && data.GeoPoint.Lat) {
		lat = parseFloat(data.GeoPoint.Lat);
		lon = parseFloat(data.GeoPoint.Lon);
		succCount++;
	} else {
		lat = 0;
		lon = 0;
	}
	rM['lt'] = lat;
	rM['ln'] = lon;
	
	if (!rM['z']) rM['z'] = '';

	rM['l'] = rM['a'] && rM['a'].length ? rM['a'] + '<br>' : rM['a'];
	rM['l'] = rM['c'] && rM['c'].length ? rM['l'] + rM['c'] : rM['l'];
	rM['l'] = rM['s'] && rM['s'].length && rM['c'].length ? rM['l'] + ', ' + rM['s'] : rM['l'] + rM['s'].trim();
	rM['l'] = ((rM['s'] && rM['s'].length) || rM['c'].length) && rM['z'] && rM['z'].length ? rM['l'] + ' ' + rM['z'] : rM['l'] + ' ' + rM['z'];
	rM['l'] = "<div>" + rM['l'] + "</div>";

	dest.value = dest.value + lat + format + lon;

	if (per.dist_cb_status && per.mapRS[0]['lt']) {
		var dist = distance(parseFloat(per.mapRS[0]['lt']), parseFloat(per.mapRS[0]['ln']), rM['lt'], rM['ln']).toFixed(2);

		if (dist != 0) {
			var dist_label = per.dist_sel ? '&nbsp;km' : '&nbsp;mi';
			rM['d'] = rM['d'] + '<div><span class="l">Distance:</span>&nbsp;' + addCommas(dist) + dist_label + '</div>';
			dest.value = dest.value + format + dist;
		} else dest.value += format + 0;
	} else {
		f_address = null;
	}
	
	curRow++;
	if (curRow < per.dataRS.length) {		
		startRow(curRow);
	} else {
		stopGeocode();
	}
}

function getMarker(r) {
	if (per.dist_cb_status && !r) {
		return (per.mapRS.length > 26 ? smallImgRed : centerImg)
	} else if (per.group_col && per.group_col != -1) {
		var u=0
		for (;u<gA.length;u++) {
			if (gA[u] == per.mapRS[r]['g']) 
				break;
		}
		if (u <= 5) 
			gA[u] = per.mapRS[r]['g'];
		else {
			u = 6;
			gA[6] = 'Others';
		}
		if (gA.length <= colorArray.length) {
			per.mapRS[r]['clr'] = colorArray[u];
			return (per.mapRS.length > 26 ? yImg(new YSize(9,9),new YCoordPoint(4,3),'/images/small_' + colorArray[u] + '.gif') : yImg(new YSize(30,33),new YCoordPoint(0,0),'/images/' + colorArray[u] + '.png'));
		}
		return (per.mapRS.length > 26 ? smallImg : null);
	} else {
		return (per.mapRS.length > 26 ? smallImg : null)
	}
}

function doMap() {
	var c;
	
	gA = new Array();
	
	if (!map) {
		alert('Hmmm, appears the map is not loaded. Try refreshing your browser.');
		return 0;
	}

	if (per.dist_cb_status) {
		f_lat = per.mapRS[0]['lt'];
		f_lon = per.mapRS[0]['ln'];	
		f_address = per.mapRS[0]['l'];		
		
		if (f_lat == 0 || f_lon == 0) {
			alert('Looks like first address did not geocode properly. The rest of the geocoded points will still plot but distance will not be calculated. Check your data and try again.');
		}
	}
	map.removeMarkersAll();
	markers = new Array();
	c = 0;
	
	per.view_sel = per.view_sel || 0;
	switch (per.view_sel) {
		case 0: map.setMapType(YAHOO_MAP_REG); break;
		case 1: map.setMapType(YAHOO_MAP_SAT); break;
		case 2: map.setMapType(YAHOO_MAP_HYB); break;
	}

	per.max_lat = null;
	per.max_lon = null;
	per.min_lat = null;
	per.min_lon = null;
	per.max_dist_lat = null;
	per.max_dist_lon = null;
	for (var r=0;r<per.mapRS.length;r++) {
		if (per.mapRS[r][lat_name] != 0 && c < 200 && (per.mapRS[r]['lt'] != 0 && per.mapRS[r]['ln'] != 0)) {
			var rM = per.mapRS[r];
			per.max_lat = (rM['lt'] > per.max_lat || !per.max_lat) ? rM['lt'] : per.max_lat;
			per.max_lon = (rM['ln'] > per.max_lon || !per.max_lon) ? rM['ln'] : per.max_lon;
			per.min_lat = (rM['lt'] < per.min_lat || !per.min_lat) ? rM['lt'] : per.min_lat;
			per.min_lon = (rM['ln'] < per.min_lon || !per.min_lon) ? rM['ln'] : per.min_lon;
			if (f_lat != 0 && f_lon != 0) {
				per.max_dist_lat = (Math.abs(rM['lt']-f_lat) > per.max_dist_lat || !per.max_dist_lat) ? Math.abs(rM['lt']-f_lat) : per.max_dist_lat;
				per.max_dist_lon = (Math.abs(rM['ln']-f_lon) > per.max_dist_lon || !per.max_dist_lon) ? Math.abs(rM['ln']-f_lon) : per.max_dist_lon;
			}
			try {
				var marker = createMapMarker( new YMarker(new YGeoPoint(rM['lt'], rM['ln']), getMarker(r), "yM_" + c), rM['t'], rM['d'], rM['u'], rM['i'], rM['l'], (f_address != rM['l'] ? f_address : null), rM['lt'], rM['ln']);
				if (rM['clr']) marker.setSmartWindowColor(rM['clr']);
				if (per.mapRS.length <= 26 && !dest) marker.addLabel('<div style="font-size:16px;margin-top:2px;margin-left:5px;">' + markerArray[r] + '</div>');
				map.addOverlay(marker);
			} catch (check) {
//				alert('Failed to create: ' + rM['l'] + ' please contact pholmstr' + '@' + 'gmail.com with example data.');
			}
			if (dId("tabRow_" + c)) {
				markers[c] = new Object();
				markers[c]['marker'] = marker;
				markers[c]['Lat'] = rM['lt'];
				markers[c]['Lon'] = rM['ln'];
				dId("tabRow_" + c).href = "javascript:openPanWin(" + c + ");";
			}
			c++;
		}
	}
	if (!per.dist_cb_status || true) {
		var lat_size = per.max_lat - per.min_lat;
		var lon_size = per.max_lon - per.min_lon;

		f_lat = per.min_lat + (lat_size/2);
		f_lon = per.min_lon + (lon_size/2);
	} else {
		var lat_size = per.max_dist_lat*2;
		var lon_size = per.max_dist_lon*2;
	}
	var startPoint = new YGeoPoint(f_lat,f_lon);
	var startZoom = 19;
	for (var i=0;i<zooms.length;i++) {
		var zoomArray = zooms[i].split(',');
		if (zoomArray[0] * map_height > lat_size && zoomArray[1] * map_width > lon_size) {
			startZoom = i+1;
			break;
		}
	}
	if (gA.length > 1) {
		var leg = dId("legDiv");
		leg.style.display = 'block';
		for (var i=0;i<gA.length;i++) {
			leg.innerHTML += '<span style="white-space:nowrap;margin:4px;"><img src="/images/small_' + colorArray[i] + '.gif">&nbsp;' + gA[i] + '</span>';
		}
	}
	map.drawZoomAndCenter(startPoint, startZoom);
}

function openPanWin(c) {
	window.scrollTo(0,0);
	if (!markers[c]['Lat']) return;
	map.drawZoomAndCenter(new YGeoPoint(markers[c]['Lat'],markers[c]['Lon']), map.getZoomLevel());
//	map.panToLatLon(markers[c]['Lat'],markers[c]['Lon']);
	return openPointWin(markers[c]['marker']);
}

function kmlSubmit() {
	dId("kmlData").value = makeKML(per.mapRS);
	if (dId("kmlData").value.length)
		document.kmlSubmitForm.submit();
}

function jsonSubmit() {
	if (!per.mapRS) {
		alert('You need to validate your data and run the geocoder first, check steps above.');
		return 0;		
	}
	
	if (per.mapRS.length > 200) {
		alert("The map only supports showing up to 200 points, currently " + per.mapRS.length + " are in your source data. Please reduce the number of points in your source data and try again.");
		return 0;
	}

	var map_title = prompt('Enter in a title for your map:','');
	if (map_title == null) return null;
	var map_description = prompt('Enter in a short description for your map, try to be as descriptive as possible in 50 words or less (or just click the "OK" button if you don\'t want a description.):','');
	if (map_description == null) return null;
	per.map_title = map_title;
	per.map_description = map_description;
	delete per.dataRS;
	dId("jsonData").value = JSON.stringify(per);
	document.jsonSubmitForm.submit();
}

function distance(lat1, long1, lat2, long2) {
	if (per.dist_sel) {
		R = 6378.137;
	} else {
		R = 3963.19059;
	}
	dist = R*Math.acos(Math.cos(radians(90-lat1))*Math.cos(radians(90-lat2))+Math.sin(radians(90-lat1))*Math.sin(radians(90-lat2))*Math.cos(radians(long1-long2)));
	return Math.abs(dist); 
}

function radians(degrees) {
	return degrees * 0.0174532925;
}

