wa_account="transfermymember"; wa_location=111;
wa_pageName=location.pathname;  // you can customize the page name here
document.cookie='__support_check=1';wa_hp='http';
wa_rf=document.referrer;wa_sr=window.location.search;
wa_tz=new Date();if(location.href.substr(0,6).toLowerCase()=='https:')
wa_hp='https';wa_data='&an='+escape(navigator.appName)+ 
'&sr='+escape(wa_sr)+'&ck='+document.cookie.length+
'&rf='+escape(wa_rf)+'&sl='+escape(navigator.systemLanguage)+
'&av='+escape(navigator.appVersion)+'&l='+escape(navigator.language)+
'&pf='+escape(navigator.platform)+'&pg='+escape(wa_pageName);
wa_data=wa_data+'&cd='+
screen.colorDepth+'&rs='+escape(screen.width+ ' x '+screen.height)+
'&tz='+wa_tz.getTimezoneOffset()+'&je='+ navigator.javaEnabled();
wa_img=new Image();wa_img.src=wa_hp+'://loc1.hitsprocessor.com/statistics.asp'+
'?v=1&s='+wa_location+'&acct='+wa_account+wa_data+'&tks='+wa_tz.getTime();
document.getElementById('wa_u').src=wa_hp+'://loc1.hitsprocessor.com/track.js';


/***********************************************
* Bookmark site script- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
***********************************************/

/* Modified to support Opera */
function bookmarksite(title,url){
if (window.sidebar) // firefox
	window.sidebar.addPanel(title, url, "");
else if(window.opera && window.print){ // opera
	var elem = document.createElement('a');
	elem.setAttribute('href',url);
	elem.setAttribute('title',title);
	elem.setAttribute('rel','sidebar');
	elem.click();
} 
else if(document.all)// ie
	window.external.AddFavorite(url, title);
}




// -------------------------------------------------------------------------
//
//	SITE FUNCTIONS
//
// -------------------------------------------------------------------------
function refreshStates() {
	var countryID = $('countryID').value;
	var url = '/?view=common.listStates';
	var params = 'countryID=' + countryID;
	if (refreshStates.arguments[1]) { params = params + '&addAny=true';  }
	$('stateID').options.length = 0;
	$('stateID').options[0] = new Option("Please wait...","")
	if ($('progressBar1')) { $('progressBar1').innerHTML = "<IMG src='/images/indicator_arrows_white.gif' height='15' width='15' />" }
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) {
				states = originalRequest.responseText.split(',');
				var element = 0;
				while (element < states.length-1)
				 {
				  IDName = states[element].split(':');
				  stateID = IDName[0];
				  stateName = IDName[1];
				  $('stateID').options[element] = new Option(stateName, stateID);
				  element += 1;
				  }
				  $('progressBar1').innerHTML = "";
				  validationMarker("validationMarker1", 0);
			;}
	});
	if ($('countryID').value != 3) {
		$('currencyDDebit').innerHTML = "$";
		$('currencyUpfront').innerHTML = "$";
		$('currencyTransfer').innerHTML = "$";
		if ($('countryID').value == 1) { $('adPrice').innerHTML = "$15.95"  } else
		{  $('adPrice').innerHTML = "$15.30" }
	} else {
		$('currencyDDebit').innerHTML = "£";
		$('currencyUpfront').innerHTML = "£";
		$('currencyTransfer').innerHTML = "£";
		 $('adPrice').innerHTML = "£7.30"
	}
}



function refreshTowns() {
	var stateID = $('stateID').value;
	var url = '/?view=common.listTowns';
	var params = 'stateID=' + stateID;
	if (refreshTowns.arguments[1]) { params = params + '&addAny=true';  }
	$('townID').options.length = 0;
	$('townID').options[0] = new Option("Please wait...", "")
	if ($('progressBar2')) { $('progressBar2').innerHTML = "<IMG src='/images/indicator_arrows_white.gif' height='15' width='15'  />" }
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) {
				towns = originalRequest.responseText.split(',');
				var element = 0;
				while (element < towns.length-1)
				 {
				  IDName = towns[element].split(':');
				  townID = IDName[0];
				  townName = IDName[1];
				  $('townID').options[element] = new Option(titleCase(townName.toLowerCase()), townID);
				  element += 1;
				  }
				  $('progressBar2').innerHTML = "";
			;}
	});
}


function refreshProviders() {

	var townID = $('townName').value // options[$('townID').selectedIndex].text;
	var url = '/?view=common.listProviders';
	var params = 'townName=' + townID;
	params = params + '&cid='+$('countryID').value;
	var element = 0;
	$('providerID').options.length = 0;
	$('providerID').options[0] = new Option("Please wait...", "")
	//if ($('validationMarker3')) { $('validationMarker3').innerHTML = "<IMG src='/images/indicator_arrows_white.gif' height='15' width='15'  />" }
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) {
				providers = originalRequest.responseText.split(',');
				element = 0;
				while (element <= providers.length)
				 {
				  IDName = providers[element].split(':');
				  providerID = IDName[0];
				  providerName = IDName[1];
				  $('providerID').options[element] = new Option(titleCase(providerName.toLowerCase()), providerID);
				  element += 1;
				  }
				 //$('validationMarker3').innerHTML = "";
			;}
	});

}

function populateNames() {
	$('countryName').value = $('countryID').options[$('countryID').selectedIndex].text;
	$('stateName').value = $('stateID').options[$('stateID').selectedIndex].text;
	if ($('providerID')) {$('providerName').value = $('providerID').options[$('providerID').selectedIndex].text; }
	return true;
}

function titleCase(text)
	{
		var original = text;
		var o_split = original.split(" ");
		//this probably isn't a complete list of words that shouldn't be capitalized
		var special_words = new Array('and', 'the', 'to', 'for', 'is', 'in', 'a', 'at', 'an', 'from', 'by', 'if', 'of','mc', 'dc');
		for (i=0;i<o_split.length;i++) {
			if (i == 0) {
				//always capitalize the first word
				o_split[i] = (o_split[i].substring(0,1)).toUpperCase() + o_split[i].substring(1);
			}
			else if(special_words.indexOf(o_split[i]) < 0) {
			  	o_split[i] = (o_split[i].substring(0,1)).toUpperCase() + o_split[i].substring(1);
			}
		}
		retval = o_split.join(' ');
		return retval;
	}

function changeLabelContent(label, content){

	$(label).innerHTML = content;
	return true;
}

function validationMarker(region, state) {
	if (state == 1) {
	$(region).innerHTML = "Please type a town name then select the matching location from the list." }
	else {
		$(region).innerHTML = " "
	}
}


function validateSellStep1() {

	if ($('countryID').value == "" && $('nationwide').checked == false) {
			$('countryID').focus();
			validationMarker("progressBar1", 1);
			return false;
		//Need a country
	} else validationMarker("progressBar1", 0);

	if ($('stateID').value == "0" && $('nationwide').checked == false) {   //Need a state
		$('stateID').focus();
		validationMarker("progressBar2", 1);
		return false;
	} else validationMarker("progressBar2", 0);


	if ($('townName').value.length == 0 && $('nationwide').checked == false) {    //Need a town
		$('townName').focus();
		validationMarker("validationMarker3", 1);
		return false;
	} else validationMarker("validationMarker3", 0);

	if ($('providerID').value == "0" && $('otherProvider').checked == false) { //Need to enter a provider name
		$('providerID').focus();
		validationMarker("validationMarker4", 1);
		return false;
	} else validationMarker("validationMarker4", 0);

	if ($('otherProvider').checked == true && $('providerNameOther').value == "") { //Need to enter a provider name
		$('providerID').focus();
		validationMarker("validationMarker7", 1);
		return false;
	} else validationMarker("validationMarker7", 0);

	if ( ($('DirectDebit').checked == true) && ($('directDebitAmount').value == ""  ||  !isNum($('directDebitAmount').value)))
		{ //Complete DDebit data
		$('directDebitAmount').focus();
		validationMarker("validationMarker5", 1);
		validationMarker("validationMarker6", 0);
		return false;
	} else { validationMarker("validationMarker5", 0); }

	if ( $('Upfront').checked && ($('contractPayoutAmount').value == "" || !isNum($('contractPayoutAmount').value))) { //Complete Payout data
		$('contractPayoutAmount').focus();
		validationMarker("validationMarker6", 1);
		validationMarker("validationMarker5", 0);
		return false;
	} else validationMarker("validationMarker6", 0);

	if ($('transferAmount').value < 0 || !isNum($('transferAmount').value)) {
		$('transferAmount').focus();
		validationMarker("validationMarker8", 1);
		validationMarker("validationMarker6", 0);
		return false;
	} else validationMarker("validationMarker8", 0);

	return true;

}

function validateSellStep3() {
	if ($('providerStreet').value == "" ) {
		$('providerStreet').focus();
		validationMarker("validationMarker1", 1);
		return false;
	} validationMarker("validationMarker1", 0);

	if ($('providerPhone').value == "" && $('providerURL').value == "") {
		$('providerPhone').focus();
		validationMarker("validationMarker2", 1);
		return false;
	} validationMarker("validationMarker2", 0);

	return true;

}


function validateSellStep4() {

	if ($('eclientEmail').value != ""){
		var url = '/?view=common.checkClient';
		var params = 'clientEmail=' + $('eclientEmail').value;
		params = params + "&password=" + $('eclientPassword').value;
		params = params + "&af=1";
		var ajax = new Ajax.Request(
				url,
				{method: 'post',
				parameters: params,
				onComplete: function(originalRequest) {
							if (originalRequest.responseText == 2) {
								document.frm_SellStep4.submit();
							} else validationMarker("validationMarker7", 1);

				}

		});
		return false;
	}

	if ($('clientFirstname').value == "" ) {
		$('clientFirstname').focus();
		validationMarker("validationMarker1", 1);
		return false;
	} validationMarker("validationMarker1", 0);

	if ($('clientSurname').value == "" ) {
		$('clientSurname').focus();
		validationMarker("validationMarker2", 1);
		return false;
	} validationMarker("validationMarker2", 0);


	if ($('clientPreferredName').value == "" ) {
		$('clientPreferredName').focus();
		validationMarker("validationMarker3", 1);
		return false;
	} validationMarker("validationMarker3", 0);


	if (emailCheck($('clientEmail').value) == false ) {
		$('clientEmail').focus();
		validationMarker("validationMarker4", 1);
		return false;
	} validationMarker("validationMarker4", 0);


	if ($('clientPhone').value == "" ) {
		$('clientPhone').focus();
		validationMarker("validationMarker5", 1);
		return false;
	} validationMarker("validationMarker5", 0);


	if ($('clientPassword').value == "" ) {
		$('clientPassword').focus();
		validationMarker("validationMarker6", 1);
		return false;
	} validationMarker("validationMarker6", 0);

	var url = '/?view=common.checkClient';
	var params = 'clientEmail=' + $('clientEmail').value;
	params = params + "&af=0"
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) {
						if (originalRequest.responseText == 0) {
							document.frm_SellStep4.submit();
						} else validationMarker("validationMarker4", 1);

			}

	});

	return true;

}

function validateSellStep6(SESSIONID) {
	if ($('agreeTerms').checked == false ) {
		validationMarker("validationMarker1", 1);
		return false;
	} validationMarker("validationMarker1", 0);

	var sendMarketing = 0
	if ($('sendMarketing').checked){
		sendMarketing = $('sendMarketing').value;
	}

	var url = '/?view=sell.step6';
	var params = 'sendMarketing=' + sendMarketing;
	var params = params + '&PHPSESSID=' + SESSIONID;
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) { 	window.setTimeout('nothing()', 2000); }

	});




	return true;
}


function validateBuyStep1(){
	if (jQuery('#countryID').val() == "") {
		jQuery('#countryID').focus();
		validationMarker("validationMarker1", 1);
		return false;
	} 
	
	if (jQuery('#search_townpc_input').val() == "") {
		jQuery('#search_townpc_input').focus();
		validationMarker("validationMarker2", 1);
		return false;
	} 	
	validationMarker("validationMarker1", 0);
	validationMarker("validationMarker2", 0);
	$('countryName').value = $('countryID').options[$('countryID').selectedIndex].text;
	return true;
}


function validateBuyStep4() {
	if ($('buyerFirstname').value == "" ) {
		$('buyerFirstname').focus();
		validationMarker("validationMarker1", 1);
		return false;
	} validationMarker("validationMarker1", 0);

	if ($('buyerLastname').value == "" ) {
		$('buyerLastname').focus();
		validationMarker("validationMarker2", 1);
		return false;
	} validationMarker("validationMarker2", 0);

	if ($('buyerPreferredName').value == "" ) {
		$('buyerPreferredName').focus();
		validationMarker("validationMarker3", 1);
		return false;
	} validationMarker("validationMarker3", 0);

	if ($('buyerEmailAddress').value == "" || emailCheck($('buyerEmailAddress').value) == false ) {
		$('buyerEmailAddress').focus();
		validationMarker("validationMarker4", 1);
		return false;
	} validationMarker("validationMarker4", 0);

	if ($('buyerAgreeTerms').checked == false ) {
		validationMarker("validationMarker5", 1);
		return false;
	} validationMarker("validationMarker5", 0);
return true;
}


function validateAdminLogin(){
	if ($('username').value == ""){
			$('username').focus();
			return false;
	}
	if ($('password').value == "") {
			$('password').focus();
			return false;
	}
	return true;
}

function validateAdminEditOffer() {

	if ($('providerType').value == 'Other' && $('providerOtherText').value == "" ){
			$('providerOtherText').focus();
			validationMarker("validationMarker1", 1);
			return false;
	}
	if ($('providerName').value == "") {
			$('providerName').focus();
			validationMarker("validationMarker2", 1);
			return false;
	}
	if ($('countryID').value == "") {
			$('countryID').focus();
			validationMarker("validationMarker3", 1);
			return false;
	}
	
	if ($('nationwide').checked == true)
	{ 
		return true;
	}
	else 
	{
		if ($('providerStreet').value == "" || $('providerTown').value == "") 
		{
			$('providerStreet').focus();
			validationMarker("validationMarker4", 1);
			return false;
		}
	}
	return true;
}

function validateAdminEditClient() {
	return true
}


function adminGoEdit()
{
	$('view').value = "manage.editOffer";
	$('frm_viewOffer').submit();

}


function adminGoDelete()
{
	$('view').value = "manage.deleteOffer";
	if (confirm('Are you sure?  This will PERMANTENTLY remove the advertisement from the database.  The client will not be informed.')) {
		$('frm_viewOffer').submit();
	}

}


function adminGoApprove()
{
	$('view').value = "manage.approveOffer";
	if (confirm('Are you sure?  This will publish the advertisement live and send a confirmation email to the client.')) {
		$('frm_viewOffer').submit();
	}


}


function adminGoSuspend()
{
	$('view').value = "manage.suspendOffer";
	if (confirm('Are you sure?  This will unpublish the advertisement, you can re-activated it.')) {
		$('frm_viewOffer').submit();
	}
}

function adminGoReactivate()
{
	$('view').value = "manage.reactivateOffer";
	$('frm_viewOffer').submit();
}

function adminGoUnarchive()
{
	$('view').value = "manage.reactivateArchivedOffer";
	$('frm_viewOffer').submit();
}


function sendFeedback() {
	if ($('feedback').value == "") {
		$('feedback').focus();
		return false;
	}
	var url = "/?view=common.sendFeedback";
	var params = 'feedback=' + $('feedback').value;
	params = params + '&email=' + $('email').value;
	$('control').innerHTML = "<IMG src='/images/indicator_arrows_black.gif' height='15' width='15'  /> SENDING...";
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) {
				$('feedback').value= "MESSAGE SENT.  Thank you."
				$('control').innerHTML = "<input type='button' name='btn_Feedback' id='btn_Feedback' onClick='sendFeedback();' value='send' />";

			;  }
	});

	return true;
}


function recoverPassword(fieldname) {
	if ($(fieldname).value == "") {
		$(fieldname).focus();
		return false;
	}
	var url = "/?view=common.password";
	var params = 'username=' + $(fieldname).value;
	$('notes').innerHTML = "<IMG src='/images/indicator_arrows_black.gif' height='15' width='15'  /> requesting...";
	var ajax = new Ajax.Request(
			url,
			{method: 'post',
			parameters: params,
			onComplete: function(originalRequest) {
				if (originalRequest.responseText == 1) {
					$('notes').innerHTML = "Your password has been emailed to you.";}
				else {
					$('notes').innerHTML = "Your password was not sent. Please check your username.";
				}

			;  }
	});

	return true;

}



var numb = '0123456789.';
var lwr = "abcdefghijklmnopqrstuvwxyz -'";
var upr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ -'";

function isValid(parm,val) {
  if (parm == "") return false;
  for (i=0; i<parm.length; i++) {
    if (val.indexOf(parm.charAt(i),0) == -1) return false;
  }
  return true;
}

function isNum(parm) {return isValid(parm,numb);}
function isLower(parm) {return isValid(parm,lwr);}
function isUpper(parm) {return isValid(parm,upr);}
function isAlpha(parm) {return isValid(parm,lwr+upr);}
function isAlphanum(parm) {return isValid(parm,lwr+upr+numb);}


function nothing() {
	return true
}

function checkTA() {
	if (!$('agreeTerms').checked) { 
			alert("Please tick the box under 'Terms of use'");
			return false;
		}
	return true;
}

function CheckMultiple2(frm, name) {
				for (var i=0; i < frm.length; i++)
				{
					fldObj = frm.elements[i];
					fldId = fldObj.id;
					if (fldId) {
						var fieldnamecheck=fldObj.id.indexOf(name);
						if (fieldnamecheck != -1) {
							if (fldObj.checked) {
								return true;
							}
						}
					}
				}
				return false;
			}
		function CheckForm2(f) {
			if (f.email.value == "") {
				alert("Please enter your email address.");
				f.email.focus();
				return false;
			}
		
			var fname = "CustomFields_1_2";
			var fld = document.getElementById(fname);
			if (fld.value == "") {
				alert("Please enter a value for field First Name");
				fld.focus();
				return false;
			}
		
				return true;
			};
			
function selectOffers(type){

	jQuery("#offersTable").find('input:checkbox').attr("checked", ""); 

	switch (type) {
	case 'active':
		jQuery("tr[active='1']").find('input:checkbox').attr("checked", "checked"); 		
		break;
	case 'archived':
		jQuery("tr[archived='1']").find('input:checkbox').attr("checked", "checked"); 
		break;
	case 'suspended':
		jQuery("tr[suspended='Yes']").find('input:checkbox').attr("checked", "checked");
		break;
	case 'paid':
		jQuery("tr[paid='1']").find('input:checkbox').attr("checked", "checked");
		break;
	case 'unpaid':
		jQuery("tr[paid='0']").find('input:checkbox').attr("checked", "checked");
		break;
	case 'expired':
		jQuery("tr[expired='1']").find('input:checkbox').attr("checked", "checked");
		break;				
	case 'none':
		jQuery("#offersTable").find('input:checkbox').attr("checked", ""); 
		break;
}

return true;

}


function changeOfferState(action){ 

	var url = "/?view=manage.ajaxupdateoffers";
	var data = jQuery("input:checkbox").serializeArray();
	json = {};

	jQuery("#loadStatus").html("Processing...");	
	for (i in data) {
		json[data[i].name] = data[i].value
	} 
	jQuery.post(url, 
		{ data: json, 
		  action: action
		},
		function(response){
			jQuery("#loadStatus").html("Finished.");
		} 
	);		
}


// -------------------------------------------------------------------------
//
//	MAPPING FUNCTIONS
//
// -------------------------------------------------------------------------

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Latitude/longitude spherical geodesy formulae & scripts (c) Chris Veness 2002-2009            */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/*
 * Use Haversine formula to calculate distance (in km) between two points specified by 
 * latitude/longitude (in numeric degrees)
 *
 * from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine",
 *       Sky and Telescope, vol 68, no 2, 1984
 *       http://www.census.gov/cgi-bin/geo/gisfaq?Q5.1
 *
 * example usage from form:
 *   result.value = LatLon.distHaversine(lat1.value.parseDeg(), long1.value.parseDeg(), 
 *                                       lat2.value.parseDeg(), long2.value.parseDeg());
 * where lat1, long1, lat2, long2, and result are form fields
 */
LatLon.distHaversine = function(lat1, lon1, lat2, lon2) {
  var R = 6371; // earth's mean radius in km
  var dLat = (lat2-lat1).toRad();
  var dLon = (lon2-lon1).toRad();
  lat1 = lat1.toRad(), lat2 = lat2.toRad();

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.cos(lat1) * Math.cos(lat2) * 
          Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  return d;
}


/*
 * Use Law of Cosines to calculate distance (in km) between two points specified by latitude/longitude 
 * (in numeric degrees).
 */
LatLon.distCosineLaw = function(lat1, lon1, lat2, lon2) {
  var R = 6371; // earth's mean radius in km
  var d = Math.acos(Math.sin(lat1.toRad())*Math.sin(lat2.toRad()) +
                    Math.cos(lat1.toRad())*Math.cos(lat2.toRad())*Math.cos((lon2-lon1).toRad())) * R;
  return d;
}


/*
 * calculate (initial) bearing between two points
 *   see http://williams.best.vwh.net/avform.htm#Crs
 */
LatLon.bearing = function(lat1, lon1, lat2, lon2) {
  lat1 = lat1.toRad(); lat2 = lat2.toRad();
  var dLon = (lon2-lon1).toRad();

  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1)*Math.sin(lat2) -
          Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  return Math.atan2(y, x).toBrng();
}


/*
 * calculate midpoint of great circle line between p1 & p2.
 *   see http://mathforum.org/library/drmath/view/51822.html for derivation
 */
LatLon.midPoint = function(lat1, lon1, lat2, lon2) {
  lat1 = lat1.toRad(); 
  lat2 = lat2.toRad();
  var dLon = (lon2-lon1).toRad();

  var Bx = Math.cos(lat2) * Math.cos(dLon);
  var By = Math.cos(lat2) * Math.sin(dLon);

  lat3 = Math.atan2(Math.sin(lat1)+Math.sin(lat2),
                    Math.sqrt((Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx) + By*By ) );
  lon3 = lon1.toRad() + Math.atan2(By, Math.cos(lat1) + Bx);

  if (isNaN(lat3) || isNaN(lon3)) return null;
  return new LatLon(lat3.toDeg(), lon3.toDeg());
}


/*
 * calculate destination point given start point, initial bearing (deg) and distance (km)
 *   see http://williams.best.vwh.net/avform.htm#LL
 */
LatLon.prototype.destPoint = function(brng, d) {
  var R = 6371; // earth's mean radius in km
  var lat1 = this.lat.toRad(), lon1 = this.lon.toRad();
  brng = brng.toRad();

  var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) + 
                        Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng) );
  var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), 
                               Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
  lon2 = (lon2+Math.PI)%(2*Math.PI) - Math.PI;  // normalise to -180...+180

  if (isNaN(lat2) || isNaN(lon2)) return null;
  return new LatLon(lat2.toDeg(), lon2.toDeg());
}


/*
 * calculate final bearing arriving at destination point given start point, initial bearing and distance
 */
LatLon.prototype.finalBrng = function(brng, d) {
  var p1 = this, p2 = p1.destPoint(brng, d);
  // get reverse bearing point 2 to point 1
  var rev = LatLon.bearing(p2.lat, p2.lon, p1.lat, p1.lon);
  // & reverse it by adding 180Â°
  var brng = (rev + 180) % 360;
  return brng;
}


/*
 * calculate distance, bearing, destination point on rhumb line
 *   see http://williams.best.vwh.net/avform.htm#Rhumb
 */
LatLon.distRhumb = function(lat1, lon1, lat2, lon2) {
  var R = 6371; // earth's mean radius in km
  var dLat = (lat2-lat1).toRad(), dLon = Math.abs(lon2-lon1).toRad();
  var dPhi = Math.log(Math.tan(lat2.toRad()/2+Math.PI/4)/Math.tan(lat1.toRad()/2+Math.PI/4));
  var q = (Math.abs(dLat) > 1e-10) ? dLat/dPhi : Math.cos(lat1.toRad());
  // if dLon over 180Â° take shorter rhumb across 180Â° meridian:
  if (dLon > Math.PI) dLon = 2*Math.PI - dLon;
  var d = Math.sqrt(dLat*dLat + q*q*dLon*dLon); 
  return d * R;
}


LatLon.brngRhumb = function(lat1, lon1, lat2, lon2) {
  var dLon = (lon2-lon1).toRad();
  var dPhi = Math.log(Math.tan(lat2.toRad()/2+Math.PI/4)/Math.tan(lat1.toRad()/2+Math.PI/4));
  if (Math.abs(dLon) > Math.PI) dLon = dLon>0 ? -(2*Math.PI-dLon) : (2*Math.PI+dLon);
  return Math.atan2(dLon, dPhi).toBrng();
}


LatLon.prototype.destPointRhumb = function(brng, dist) {
  var R = 6371; // earth's mean radius in km
  var d = parseFloat(dist)/R;  // d = angular distance covered on earth's surface
  var lat1 = this.lat.toRad(), lon1 = this.lon.toRad();
  brng = brng.toRad();

  var lat2 = lat1 + d*Math.cos(brng);
  var dLat = lat2-lat1;
  var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
  var q = (Math.abs(dLat) > 1e-10) ? dLat/dPhi : Math.cos(lat1);
  var dLon = d*Math.sin(brng)/q;
  // check for some daft bugger going past the pole
  if (Math.abs(lat2) > Math.PI/2) lat2 = lat2>0 ? Math.PI-lat2 : -(Math.PI-lat2);
  lon2 = (lon1+dLon+Math.PI)%(2*Math.PI) - Math.PI;
 
  if (isNaN(lat2) || isNaN(lon2)) return null;
  return new LatLon(lat2.toDeg(), lon2.toDeg());
}


/*
 * construct a LatLon object: arguments in numeric degrees
 *
 * note all LatLong methods expect & return numeric degrees (for lat/long & for bearings)
 */
function LatLon(lat, lon) {
  this.lat = lat;
  this.lon = lon;
}


/*
 * represent point {lat, lon} in standard representation
 */
LatLon.prototype.toString = function() {
  return this.lat.toLat() + ', ' + this.lon.toLon();
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend String object with method for parsing degrees or lat/long values to numeric degrees
//
// this is very flexible on formats, allowing signed decimal degrees, or deg-min-sec suffixed by 
// compass direction (NSEW). A variety of separators are accepted (eg 3Âº 37' 09"W) or fixed-width 
// format without separators (eg 0033709W). Seconds and minutes may be omitted. (Minimal validation 
// is done).

String.prototype.parseDeg = function() {
  if (!isNaN(this)) return Number(this);                 // signed decimal degrees without NSEW

  var degLL = this.replace(/^-/,'').replace(/[NSEW]/i,'');  // strip off any sign or compass dir'n
  var dms = degLL.split(/[^0-9.]+/);                     // split out separate d/m/s
  for (var i in dms) if (dms[i]=='') dms.splice(i,1);    // remove empty elements (see note below)
  switch (dms.length) {                                  // convert to decimal degrees...
    case 3:                                              // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; break;
    case 2:                                              // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; break;
    case 1:                                              // decimal or non-separated dddmmss
      if (/[NS]/i.test(this)) degLL = '0' + degLL;       // - normalise N/S to 3-digit degrees
      var deg = dms[0].slice(0,3)/1 + dms[0].slice(3,5)/60 + dms[0].slice(5)/3600; break;
    default: return NaN;
  }
  if (/^-/.test(this) || /[WS]/i.test(this)) deg = -deg; // take '-', west and south as -ve
  return deg;
}
// note: whitespace at start/end will split() into empty elements (except in IE)


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for converting degrees/radians

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}

Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
  return this * 180 / Math.PI;
}

Number.prototype.toBrng = function() {  // convert radians to degrees (as bearing: 0...360)
  return (this.toDeg()+360) % 360;
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for presenting bearings & lat/longs

Number.prototype.toDMS = function() {  // convert numeric degrees to deg/min/sec
  var d = Math.abs(this);  // (unsigned result ready for appending compass dir'n)
  d += 1/7200;  // add Â½ second for rounding
  var deg = Math.floor(d);
  var min = Math.floor((d-deg)*60);
  var sec = Math.floor((d-deg-min/60)*3600);
  // add leading zeros if required
  if (deg<100) deg = '0' + deg; if (deg<10) deg = '0' + deg;
  if (min<10) min = '0' + min;
  if (sec<10) sec = '0' + sec;
  return deg + '\u00B0' + min + '\u2032' + sec + '\u2033';
}

Number.prototype.toLat = function() {  // convert numeric degrees to deg/min/sec latitude
  return this.toDMS().slice(1) + (this<0 ? 'S' : 'N');  // knock off initial '0' for lat!
}

Number.prototype.toLon = function() {  // convert numeric degrees to deg/min/sec longitude
  return this.toDMS() + (this>0 ? 'E' : 'W');
}

Number.prototype.toPrecision = function(fig) {  // override toPrecision method with one which displays 
  if (this == 0) return 0;                      // trailing zeros in place of exponential notation
  var scale = Math.ceil(Math.log(this)*Math.LOG10E);
  var mult = Math.pow(10, fig-scale);
  return Math.round(this*mult)/mult;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

function initialise(lat, long, range) {
    var latlng = new google.maps.LatLng(lat, long);
    var myOptions = {
      zoom: 11,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
	  disableDefaultUI: true
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    var centrePoint = new LatLon(parseFloat(lat), parseFloat(long));
	points = regionZone(centrePoint, range);
	var regions = Array();
	var range = Array();
	for (i = 0; i < points.length; i++) {
        point = new google.maps.LatLng(points[i].lat, points[i].lon),
        range.push(point);
    }

	new Ajax.Request('/?view=common.getAdsByRegion',
	  {
	    method:'post',
	    parameters: {minLat: points[0].lat, maxLat: points[2].lat, minLon: points[0].lon, maxLon: points[2].lon},
	    onSuccess: function(transport){
	      var response = transport.responseText.evalJSON(true) || "no response text";
	      drawAdMarkers(response);
	    },
	    onFailure: function(){ alert('Something went wrong...') }
	  });


}


function regionZone(centrePoint, x){
	var points = Array();
	var d = Math.sqrt((x*x)+(x*x));
	var r = 315;
	var startPoint = centrePoint.destPoint(r, parseFloat(d));
	var nextPoint = startPoint;
	r = 90;
	points.push(startPoint);
	for (i = 0; i < 3; i++){
		nextPoint = nextPoint.destPoint(r, x*2);
		points.push(nextPoint);
		r += 90;
	}
	
	return points;
} 

function drawAdMarkers(dataset) {
	for(i=0; i < dataset.offers.length; i++)	
	{
		var offer = dataset.offers[i];
		var latlong = new google.maps.LatLng(offer.providerLat, offer.providerLon);
		var titleString = offer.providerName+", "+ offer.amount +", "+ offer.remaining;
		var marker = new google.maps.Marker({
		      position: latlong, 
		      map: map, 
		      title: titleString,
		      zIndex: parseInt(offer.offerID)
		});

		google.maps.event.addListener(marker, 'click', function() {
			var offerUrl = '/?view=buy.step3&offerID='+this.zIndex;
			window.location = offerUrl;
		});
   
	}
	return true;
}


function codeAddress(locationString) {
    var address = locationString;
    geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) 
      {
        alert(results[0].geometry.location); 
      }
      });
}




// -------------------------------------------------------------------------
//
//	EMAIL FUNCTIONS
//
// -------------------------------------------------------------------------


function emailCheck (emailStr) {

/* The following variable tells the rest of the function whether or not
to verify that the address ends in a two-letter country or well-known
TLD.  1 means check it, 0 means don't. */

var checkTLD=1;

/* The following is the list of known TLDs that an e-mail address must end with. */

var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

/* The following pattern is used to check if the entered e-mail address
fits the user@domain format.  It also is used to separate the username
from the domain. */

var emailPat=/^(.+)@(.+)$/;

/* The following string represents the pattern for matching all special
characters.  We don't want to allow special characters in the address.
These characters include ( ) < > @ , ; : \ " . [ ] */

var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

/* The following string represents the range of characters allowed in a
username or domainname.  It really states which chars aren't allowed.*/

var validChars="\[^\\s" + specialChars + "\]";

/* The following pattern applies if the "user" is a quoted string (in
which case, there are no rules about which characters are allowed
and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
is a legal e-mail address. */

var quotedUser="(\"[^\"]*\")";

/* The following pattern applies for domains that are IP addresses,
rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
e-mail address. NOTE: The square brackets are required. */

var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

/* The following string represents an atom (basically a series of non-special characters.) */

var atom=validChars + '+';

/* The following string represents one word in the typical username.
For example, in john.doe@somewhere.com, john and doe are words.
Basically, a word is either an atom or quoted string. */

var word="(" + atom + "|" + quotedUser + ")";

// The following pattern describes the structure of the user

var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

/* The following pattern describes the structure of a normal symbolic
domain, as opposed to ipDomainPat, shown above. */

var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

/* Finally, let's start trying to figure out if the supplied address is valid. */

/* Begin with the coarse pattern to simply break up user@domain into
different pieces that are easy to analyze. */

var matchArray=emailStr.match(emailPat);

if (matchArray==null) {

/* Too many/few @'s or something; basically, this address doesn't
even fit the general mould of a valid e-mail address. */

//alert("Email address seems incorrect (check @ and .'s)");
return false;
}
var user=matchArray[1];
var domain=matchArray[2];

// Start by checking that only basic ASCII characters are in the strings (0-127).

for (i=0; i<user.length; i++) {
if (user.charCodeAt(i)>127) {
alert("Ths username contains invalid characters.");
return false;
   }
}
for (i=0; i<domain.length; i++) {
if (domain.charCodeAt(i)>127) {
alert("Ths domain name contains invalid characters.");
return false;
   }
}

// See if "user" is valid

if (user.match(userPat)==null) {

// user is not valid

alert("The username doesn't seem to be valid.");
return false;
}

/* if the e-mail address is at an IP address (as opposed to a symbolic
host name) make sure the IP address is valid. */

var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {

// this is an IP address

for (var i=1;i<=4;i++) {
if (IPArray[i]>255) {
alert("Destination IP address is invalid!");
return false;
   }
}
return true;
}

// Domain is symbolic name.  Check if it's valid.

var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (i=0;i<len;i++) {
if (domArr[i].search(atomPat)==-1) {
alert("The domain name does not seem to be valid.");
return false;
   }
}

/* domain name seems valid, but now make sure that it ends in a
known top-level domain (like com, edu, gov) or a two-letter word,
representing country (uk, nl), and that there's a hostname preceding
the domain or country. */

if (checkTLD && domArr[domArr.length-1].length!=2 &&
domArr[domArr.length-1].search(knownDomsPat)==-1) {
alert("The address must end in a well-known domain or two letter " + "country.");
return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
alert("This address is missing a hostname!");
return false;
}

// If we've gotten this far, everything's valid!
return true;
}

//  End -->

