﻿/*
Waypoint Quick Entry - v01.71 2010-03-07
(c) 2010, Prime Suspect Software

Greasemonkey user script: see http://greasemonkey.mozdev.org

DESCRIPTION OF SCRIPT

* v01.71 2010-06-29 Preliminary fix for site changes.

* v01.70 2010-03-07 Added auto update notification. Removed no longer
	needed site-fix code.

* v01.60 2010-01-27 Fix for site not supplying initial coordinates
	when updating or deleting an existing waypoint.

* v01.50 2010-01-22 Update for site changes. 

* v01.40 2008-07-24 Fix to accommodate site changes.

* v01.30 Added coordinate paste-box.

* v01.20 Fix to accomodate gc.com bug that adds an extra "/" to 
	the URL of the waypoint entry page.

* v01.10 Auto-focus to the waypoint entry field after clicking.

* v01.00 Initial release.

// ==UserScript==
// @name           GC Waypoint Quick Entry
// @description    (v01.71) GC Waypoint Quick Entry
// @namespace      http://gmscripts.locusprime.net/
// @include        http://www.geocaching.com/hide/wptlist.aspx?*
// @include        http://www.geocaching.com//hide/wptlist.aspx?*
// @include        http://www.geocaching.com/seek/cache_details.aspx?*
// @include        http://www.geocaching.com/hide/report.aspx?*
// @include        http://*.geocaching.com/admin/review.aspx*
// @require        VrChk.js
// ==/UserScript==

*/

// ------------------------Version Checking------------------------ //
fCheckScriptVersion('e18b0e65-95b8-42ce-aca1-086b5b5e17c0', '01.71');
// ------------------------Version Checking------------------------ //

	thisURL = document.location + '';
	
	//  If waypoint entry page.
	if (thisURL.match(/\/wptlist/))  {
	
		var e_WaypointEdit_ShortDescription = 
				document.getElementById("ctl00_ContentBody_WaypointEdit_ShortDescription");
		e_WaypointEdit_ShortDescription.style.width = '100%';
		// e_WaypointEdit_ShortDescription.style.height = '120px';
		e_WaypointEdit_ShortDescription.style.height = '8em';
		
		
		var typeList = document.getElementById("ctl00_ContentBody_WaypointEdit_WptTypeList");
		
		if (typeList) {
		
			//  Get form table.
			var frmDL = typeList.parentNode;
			while(frmDL.nodeName != 'DL') {
				frmDL = frmDL.parentNode;  
			}
			
			//  Add new DT and DD to list.
			var qeDT = document.createElement('DT');
			// qeDT.id = 'qeDT';
			// insertAheadOf(qeDT, frmDL.childNodes[1]);
			// qeDT.appendChild(document.createTextNode('Quick Entry:'));
			
			var qeDD = document.createElement('DD');
			// qeDD.id = 'qeDD';
			// insertAfter(qeDD, qeDT);
			
			
			//  Populate cell.
			qeDD.appendChild(document.createTextNode('['));
			qeLink = document.createElement("a");
			qeLink.id = 'qeLink_Parking';
			qeLink.title = 'Click for Parking Location';
			qeLink.href = 'javascript:void(0)';
			qeLink.addEventListener("click", qeClicked, true);
			qeLink.setAttribute('idnum', -2);
			qeLink.appendChild(document.createTextNode('\u00a0Parking\u00a0'));
			qeDD.appendChild(qeLink);
			qeDD.appendChild(document.createTextNode('] ['));
			for (var i = 1; i <= 9; i++) {
				qeLink = document.createElement("a");
				qeLink.id = 'qeLink' + i;
				qeLink.title = 'Click for Stage ' + i;
				qeLink.href = 'javascript:void(0)';
				qeLink.addEventListener("click", qeClicked, true);
				qeLink.setAttribute('idnum', i);
				qeLink.appendChild(document.createTextNode('\u00a0' + i + '\u00a0'));
				qeDD.appendChild(qeLink);
				qeDD.appendChild(document.createTextNode('] ['));
			}
			qeLink = document.createElement("a");
			qeLink.id = 'qeLink_Final';
			qeLink.title = 'Click for Final Stage';
			qeLink.href = 'javascript:void(0)';
			qeLink.addEventListener("click", qeClicked, true);
			qeLink.setAttribute('idnum', -1);
			qeLink.appendChild(document.createTextNode('\u00a0Final\u00a0'));
			qeDD.appendChild(qeLink);
			qeDD.appendChild(document.createTextNode(']'));
		}
		
		//  Add waypoint id to Add Waypoint URL. 
		var wp = UrlParm('wp');
		AddWaypointToLink(wp, false);
		
		//  Determine waypoint entry type.
		var coorTab = document.getElementsByName("ctl00$ContentBody$WaypointEdit$Coordinates")[0];
		var WptEntryType = coorTab.value;
					
		//  Locate table holding coordinate entry fields.
		coorTab = fUpGenToType(coorTab, 'TABLE')
				
		//  Add new column to table.
		var ctCell = coorTab.rows[0].insertCell(coorTab.rows[0].cells.length);
		ctCell.rowSpan = 5;
		
		//  Create text area, and add to new cell.
		coorBox = document.createElement("textarea");
		coorBox.rows = 2;
		coorBox.cols = 23;
		coorBox.id = "coorBox";
		ctCell.appendChild(coorBox);	
		ctCell.appendChild(document.createElement("br"));
		
		//  Get hemisphere defaults.
		var nsDefault = GM_getValue("nsSelect", 1);
		var weDefault = GM_getValue("weSelect", -1);
		
		//  Add hemisphere selectors.
		var nsSelect = document.createElement("select");
		nsSelect.id = "nsSelect";
		var nsOption = document.createElement("option");
		nsOption.value = 1;
		nsOption.appendChild(document.createTextNode("N"));
		nsSelect.appendChild(nsOption);
		nsOption.selected = (nsOption.value == nsDefault);
		var nsOption = document.createElement("option");
		nsOption.value = -1;
		nsOption.appendChild(document.createTextNode("S"));
		nsSelect.appendChild(nsOption);
		nsOption.selected = (nsOption.value == nsDefault);
		ctCell.appendChild(nsSelect);
		nsSelect.addEventListener("change", nsweChange, true);
		
		var weSelect = document.createElement("select");
		weSelect.id = "weSelect";
		var weOption = document.createElement("option");
		weOption.value = -1;
		weOption.appendChild(document.createTextNode("W"));
		weSelect.appendChild(weOption);
		weOption.selected = (weOption.value == weDefault);
		var weOption = document.createElement("option");
		weOption.value = 1;
		weOption.appendChild(document.createTextNode("E"));
		weSelect.appendChild(weOption);
		weOption.selected = (weOption.value == weDefault);
		ctCell.appendChild(weSelect);
		weSelect.addEventListener("change", nsweChange, true);
		
		//  Add button.
		ctButton = document.createElement("input");
		ctButton.id = 'ctButton';
		ctButton.type = 'button';
		ctButton.name = 'ctButton';
		ctButton.value = 'Add Coordinates';
		ctCell.appendChild(ctButton);
		ctButton.addEventListener('click', ctButtonClicked, false);

		
	//  If cache page.
	} else if (thisURL.match(/\/cache_details/))  {

		http://www.geocaching.com/seek/cupload.aspx
		var xPathSearch = "//a[contains(@href, '\.geocaching\.com\/seek\/cupload\.aspx')]";
		var upList = document.evaluate(
				xPathSearch, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		var ic = upList.snapshotLength;
		if (ic > 0) {
			upLink = upList.snapshotItem(0);
			CacheIdNum = UrlParm('id', false, upLink.href);
		
			// Get Waypoint ID.
			var WaypointId = IDToWpt(CacheIdNum);

			//  Add waypoint id to Add Waypoint URL.
			AddWaypointToLink(WaypointId, true);
		} else {
			return;
		}
		
	//  If cache edit page.
	} else if (thisURL.match(/\/report/))  {
			
		//  Get attribute link.
		var xPathSearch = "//a[contains(@href, 'attributes.aspx')]";
		var atList = document.evaluate(
				xPathSearch,
				document,
				null,
				XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
				null);
		var ic = atList.snapshotLength;
		//  Extract id number.
		if (ic > 0) {
			ThisLink = atList.snapshotItem(0);
			var idNum = UrlParm('WptID', true, ThisLink.href);
			//  Convert to waypoint id.
			wp = IDToWpt(idNum);
			//  Add waypoint id to Add Waypoint URL.
			AddWaypointToLink(wp, true);
		}
		
	}

	
//  ---------------------- Functions ----------------------  //

	
	
	//  Process Quick Entry click.
	function qeClicked() {
		var wp = UrlParm('wp');
		var idnum = this.getAttribute('idnum') - 0;
		var e_eqName = document.getElementById("ctl00_ContentBody_WaypointEdit_Name");
		var e_eqLookup = document.getElementById("ctl00_ContentBody_WaypointEdit_WptCode");
		var e_eqPrefix = document.getElementById("ctl00_ContentBody_WaypointEdit_PrefixCode");
		if (idnum == -2) {
			SetTypeDropdown(217);
			e_eqName.value = wp + ' Parking';
			e_eqLookup.value = 'PARKNG';
			e_eqPrefix.value = 'PK';
			SetViewOpt(0);
		} else if (idnum == -1) {
			SetTypeDropdown(220);
			e_eqName.value = wp + ' Final';
			e_eqLookup.value = 'FINAL';
			e_eqPrefix.value = 'FN';
			SetViewOpt(2);
		} else if (idnum > 0) {
			SetTypeDropdown(219);
			e_eqName.value = wp + ' Stage ' + idnum;
			e_eqLookup.value = 'STAGE' + idnum;
			e_eqPrefix.value = 'S' + idnum;
			SetViewOpt(2);
		}
		ns = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates:_selectNorthSouth");
		if (ns) { ns.focus(); }
	}

	
	//  Pass code to set the waypoint type dropdown.
	function SetTypeDropdown(optid) {
		//	List of type codes:
		//		217	Parking Area
		//		218	Question to Answer
		//		219	Stages of a Multicache
		//		220	Final Location
		//		221	Trailhead
		//		452	Reference Point
		for (i = 1; i < typeList.length; i++) {
			if (typeList.options[i].value == optid) {
				typeList.selectedIndex = i;
			}
		}
	}

	
	//  Set view type (0 = Show All; 1 = Hide Coords; 2 = Hide All)
	function SetViewOpt(optid) {
		var e_ViewMethod = document.getElementById("ctl00_ContentBody_WaypointEdit_ViewMethod_" + optid);
		e_ViewMethod.checked = true;
	}

	//  Store default dropdown values.
	function nsweChange() {
		GM_setValue(this.id, this.value)
	}

	//  Coordinate button clicked.
	function ctButtonClicked() {
		var cs = coorBox.value;
		var nums = new Array();
		var j = -1;
		var dig = false;
		for (var i = 0; i < cs.length; i++) {
			c = cs.substr(i,1);
			if (c.match(/\d/)) {
				if (!dig) {
					j++;
					nums[j]='';
					dig = true;
				}
				nums[j] += c;
			} else {
				dig = false;
			}
		}
		
		var selectNorthSouth = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates:_selectNorthSouth");
		var selectEastWest = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates:_selectEastWest");
		var LatDegs = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLatDegs");
		var LonDegs = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLongDegs");
		
		selectNorthSouth.value = nsSelect.value;
		selectEastWest.value = weSelect.value;		
		
		//  Type 0: Decimal Degrees (DegDec)
		if (WptEntryType == 0) {
			if (nums.length < 4) {
				alert('Not enough numeric data elements.');
			} else {
				LatDegs.value = nums[0] + '.' + nums[1];
				LonDegs.value = nums[2] + '.' + nums[3];
			}
			
		//  Type 1: Degrees and minutes (MinDec)
		} else if (WptEntryType == 1) {
			if (nums.length < 6) {
				alert('Not enough numeric data elements.');
			} else {
				var LatMins = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLatMins");
				var LonMins = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLongMins");
				LatDegs.value = nums[0];
				LatMins.value = nums[1] + '.' + nums[2];
				LonDegs.value = nums[3];
				LonMins.value = nums[4] + '.' + nums[5];
			}
			
		//  Type 2: Degrees, minutes, seconds (DMS)
		} else if (WptEntryType == 2) {
			if (nums.length < 8) {
				alert('Not enough numeric data elements.');
			} else {
				var LatMins = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLatMins");
				var LatSecs = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLatSecs");
				var LonMins = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLongMins");
				var LonSecs = document.getElementById("ctl00_ContentBody_WaypointEdit_Coordinates__inputLongSecs");
				LatDegs.value = nums[0];
				LatMins.value = nums[1];
				LatSecs.value = nums[2] + '.' + nums[3];
				LonDegs.value = nums[4];
				LonMins.value = nums[5];		
				LonSecs.value = nums[6] + '.' + nums[7];		
			}
		}
		
	}
	
	//  Append waypoint id to all links to Add Waypoint page.
	function AddWaypointToLink(wp, newPage) {
		//  Get list of additional waypoint links.
		var xPathSearch = "//a[contains(@href, '/wptlist.aspx?')]";
		var awList = document.evaluate(
				xPathSearch,
				document,
				null,
				XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
				null);
		var ic = awList.snapshotLength;
		
		//  Append waypoint ID to the URL.
		if (ic > 0) {		
			for (var i = 0; i < ic; i++) {
				var ThisLink = awList.snapshotItem(i);
				ThisLink.href += '&wp=' + wp;
				if (newPage) {	ThisLink.target = '_blank'; }
			}
		}	
	}

	
	//  Returns a URL parameter.
	//    ParmName - Parameter name to look for.
	//    IgnoreCase - (optional) *false, true. Ignore parmeter name case.
	//    UrlString - (optional) String to search. If omitted, document URL is used.
	function UrlParm(ParmName, IgnoreCase, UrlString) {
		var RegRslt, sc = '', RtnVal = '';
		if (IgnoreCase) {sc = 'i'}
		if(UrlString) {
			var PageUrl = UrlString;
		} else {
			PageUrl = document.location + '';
		}
		var ParmString = PageUrl.substring(PageUrl.indexOf('?') + 1);
		var RegEx1 = new RegExp('(^|&)' + ParmName + '=(.*?)(&|#|$)', sc);
		RegRslt = RegEx1.exec(ParmString);
		if (RegRslt) {RtnVal = RegRslt[2]}
		return RtnVal;
	}

	
	//  Convert ID number to waypoint.
	function IDToWpt(idNum) {
		var BASE_GC = "0123456789ABCDEFGHJKMNPQRTVWXYZ";
		var BASE_31 = "0123456789ABCDEFGHIJKLMNOPQRSTU";
		var WptWork, Wpt;
		idNum = idNum - 0;
		if (idNum <= 65535) {
			Wpt = idNum.toString(16);
			Wpt = 'GC' + Wpt.toUpperCase();
		} else {
			idNum = idNum + 411120;
			WptWork = idNum.toString(31);
			WptWork = WptWork.toUpperCase();
			Wpt = 'GC';
			for (var i = 0; i < WptWork.length; i++) {
				Wpt += BASE_GC.substr(BASE_31.indexOf(WptWork.substr(i, 1)), 1);
			}
		}
		return Wpt;
	}

	
	
	//	Insert element after an existing element.
	function insertAfter(newElement, anchorElement) {
		anchorElement.parentNode.insertBefore(newElement, anchorElement.nextSibling);
	}

	//  Insert element aheadd of an existing element.
	function insertAheadOf(newElement, anchorElement) {
		anchorElement.parentNode.insertBefore(newElement, anchorElement);
	}


	//  Remove element and everything below it.
	function removeNode(element) {
		element.parentNode.removeChild(element);
	}


	//  Move up the DOM tree a specific number of generations.
	function fUpGen(gNode, g) {
		var gNode;
		var g;
		for (var i = 0; i < g; i++) {
			gNode = gNode.parentNode;
		}
		return gNode;
	}

	//  Move up the DOM tree until a specific DOM type is reached.
	function fUpGenToType(gNode, gType) {
		var gNode;
		var gType = gType.toUpperCase();
		while (gNode.nodeName.toUpperCase() != gType) {
			gNode = gNode.parentNode;
		}
		return gNode;
	}
		
	