/* =========================
| POSTCODE ANYWHERE UI
| Copyright, Andy Croxall (mitya@mitya.co.uk, www.mitya.co.uk)
|
| FOR DESCRIPTION, DEPENDENCIES, USAGE INFO AND EXAMPLE, VISIT WWW.MITYA.CO.UK/SCRIPTS
|
| NOTES
| - You can test this for free using the postocde WR26NJ.
========================= */


/* ----------------------
| CONFIG.
|
| - Usage
| 	- pathToPHPScript: declare path to PHP script (needed for this script to work) which queries PA web service
| 	- mode: set mode (drop-down or lightbox?)
| 	- fieldsToDataMap: map your field names (left) to data field names returned by web service (right)
| 	- mode1_secondsToWaitOnMouseOutBeforeHidingAddresses - if mode 1, seconds to wait between mouse out on addresses list and vanish
| 	- global CSS for addresses list
|
| - Stylistic
| 	- listCSS: property/value pairings of CSS to be applied to addresses list
| 	- listCSS_mode2Only: as above, but only if mode 2
| 	- mode1_appearMethod: either 'slide' or 'fade'
| 	- defaultLinkText: the text that will appear on the invoker link/button
|	- waitText: the text that will appear on the invoker link/button whilst a request is in process
---------------------- */

//usage config
var pathToPHPScript = '/Services/PHP/postcode_anywhere.inc.php';
var mode = location.search.indexOf('mode=2') == -1 ? 1 : 2;
var fieldsToDataMap = {
	name:           'Company',
	line1:			'Line1',
	line2:			'Line2',
	line3:			'Line3',
	city:           'PostTown',
	county:			'County',
    postcode:       'Postcode'
}

var mode1_secondsToWaitOnMouseOutBeforeHidingAddresses = 1.5;

//stylistic config
var listCSS = {overflow: 'auto', height: 200, width: 475, background: '#fff'};
var listCSS_mode2Only = {border: 'solid 1px #aaa'};
var mode1_appearMethod = 'fade';
var defaultLinkText = 'Find my address...';
var waitText = 'Please wait...';


/* ----------------------
| PREP:
---------------------- */

var instances = [];


/* ----------------------
| MAIN: off we go
---------------------- */

palookup = function(params) {

	var thiss = this;
	var paie = 'Postcode lookup initialisation error\n\n';


	/* ----------------------
	| CHECK FIELD: Check params is an object and that passed field identifier relates to field. If not, complain and exit.
	---------------------- */

	if (typeof params != 'object') {
		alert(paie+'palookup() expected an object of parameters. '+(typeof params)+' Passed.');
		return false;
	}
	var idCheckerPattern = /^\w+$/;
	this.field = idCheckerPattern.test(params.field) ? $('#'+params.field) : ($(params.field).length == 1 ? $(params.field) : false);
	if (!this.field) {
		alert(paie+'Could not find a form field relating to the field identifier passed to palookup()');
		return false;
	}


	/* ----------------------
	| BUILD INVOKER: if field OK, build lookup link/button (as preferred). Position it as a child of body but absolutely
	| positioned so it sits next to field. Style it with extra CSS, if passed.
	---------------------- */

	this.lookupLinkOrBut = document.createElement(!params.button ? 'a' : 'button');

	with($(this.lookupLinkOrBut)) {

		addClass('paLookupInvoker');

		if (!params.button) {
			attr('href', 'javascript:void(0);');
			get(0).appendChild(document.createTextNode(defaultLinkText));
		} else
			html(defaultLinkText);

		if (params.absolute)
			css({
				position:	'absolute',
				left:		this.field.offset().left + parseInt(this.field.css('width')) + 15,
				top:		this.field.offset().top + 1
			});

		if (typeof params.cssObj == 'object') css(params.cssObj);
		if (typeof params.cssClass == 'string') addClass(params.cssClass);

	}

	params.absolute ? $(document.body).append(this.lookupLinkOrBut) : this.field.after(this.lookupLinkOrBut);


	/* ----------------------
	| when lookup link clicked, send request assuming postcode entered. REGEXP to ensure postcode is valid, though obviously PA
	| does this server-side too.
	---------------------- */

	$(this.lookupLinkOrBut).click(function() {

		if ($(this).html() == defaultLinkText) {

			/* ----------------------
			| PREP - store entered postcode, comaplin if nothing entered, update link to say 'please wait' until AJAX response,
			| then do AJAX request.
			| For site demo, allow postcode WR26NJ only.
			---------------------- */

			var postcode = thiss.field.val().replace(/ /g, '');
			/*if (postcode != 'WR26NJ') {
				alert("For the purposes of this demo, you can enter only the postcode WR26NJ. For any other postcode, you'd need a paid Postcode Anywhere account.");
				return false;
			}*/
			origLinkCol = $(this).css('color');
			thiss.updateLink(true);
			if (!postcode) {
				alert("You didn't enter a postcode to look up");
				thiss.updateLink();
				return false;
			} else {

				/* ----------------------
				| AJAX REQUEST 1 - get preview of addresses matching submitted postcode
				---------------------- */

				$.getJSON(
					pathToPHPScript+'?rand='+Math.floor(Math.random()*10000),
					{postcode: postcode},
					function(json) {

						/* ----------------------
						| Process JSON response. Iterate over object, break each address into array then insert into master array
						| with parts comma-sep. If WS returns an error, alert it out.
						---------------------- */

						if (json[0].Error) {
							alert('Postcode lookup error:\n\n'+json[0].Cause+' '+json[0].Resolution);
							return false;
						} //else postcode was valid so off we go...

						var formattedAddresses = [];
						var addressPartsStorer = [];

						for(var j in json) {
							var thisAddressParts = [];
							for(var i in json[j]) {
								if (i != 'Id') thisAddressParts.push(json[j][i]);
							}
							formattedAddresses.push("<a href='javascript:void(0);' id='address"+json[j].Id+"'>"+thisAddressParts.join(', ')+"</a>");
						}


						/* ----------------------
						| Output via lightbox dialog (if mode == 1), with each address as a link. Clicking one of these links calls
						| populateForm() (see below) or faux <select> under field (if mode == 2).
						---------------------- */

						var addressesString = formattedAddresses.join('');


						/* ----------------------
						| Mode 1
						---------------------- */
						if (mode == 1) {
							$('#addressesList').remove(); //clean up from any prev lookup
							var div = document.createElement('div');

							//build and position fake drop-down <div>
							with($(div)) {
								attr('id', 'addressesList');
								html(addressesString);
								css(listCSS);
								css({
									position:	'absolute',
									display:	'none',
									left:		thiss.field.offset().left,
									top:		(thiss.field.offset().top + parseInt($(thiss.field).get(0).offsetHeight)) - 1,
									//try to make border match border of field we're appearing under. FF can't read computed border
									//on inputs, so use #777
									border:		'solid 1px '+(thiss.field.css('borderColor') ? thiss.field.css('borderColor') : '#777')
								});
								if (mode1_appearMethod == 'slide') {
									children().hide();
									css('height', 0);
								}

								//onmouseout, wait a sec then, if no re-hover, hide <div>
								mouseout(function(e) {
							        if ($(e.relatedTarget).parents('#addressesList').length == 0 && !$(e.relatedTarget).is('#addressesList'))
							            to = setTimeout(function() {
							            	$('#addressesList').fadeOut('normal', mode1_appearMethod == 'slide' ? function() {
							            		$(this).children().hide();
							            		$(this).css('height', 0);
							            		thiss.updateLink();
						            		} : null);
							            	clearTimeout(to);
							            	to = null;
							        	}, mode1_secondsToWaitOnMouseOutBeforeHidingAddresses * 1000);
							    });
								mouseover(function() {
									try { clearTimeout(to); to = null; } catch(e) {}
								});
							}

							//append to document and bring it in
							document.body.appendChild(div);
							if (mode1_appearMethod == 'slide')
								$('#addressesList').animate({height: listCSS.height}, 150, null, function() {
									$(this).children().fadeIn();
								});
							else {
								with($('#addressesList')) {
									css('height', listCSS.height);
									fadeIn();
								}
							}

						/* ----------------------
						| Mode 2
						---------------------- */

						} else if (mode == 2) {
							lbdialog({
								content:	"<div id='addressesList' style='margin: 0 auto'>"+addressesString+'</div>',
								css:		{height: listCSS.height + 70, width: listCSS.width + 30},
								OKButton:	{text: 'cancel'}
							});
							with($('#addressesList')) { css(listCSS); css(listCSS_mode2Only); }
						}


						/* ----------------------
						| Style/give functionality to links. When one clicked, do 2nd AJAX request (get full form of clicked address).
						---------------------- */

						with($('#addressesList a')) {

							css({display: 'block', width: '100%', padding: 6, borderBottom: 'solid 1px #bbb', textDecoration: 'none'});
							live('mouseover', function() {
								$(this).css({background: '#eee', textDecoration: 'underline'});
							});
							live('mouseout', function() {
								$(this).css({background: 'none', textDecoration: 'none'});
							});
							live('click', function() {
								var clickedAddressID = $(this).attr('id').match(/^address(.+)$/)[1];


								/* ----------------------
								| AJAX REQUST 2: Send address ID of clicked address out to PA's "get address by ID" WS. When parts
								| returned, populate form and return lookup link to live status. If error, complain and exit.
								---------------------- */

								$.getJSON(
									pathToPHPScript+'?by=address_id&rand='+Math.floor(Math.random()*10000),
									{address_id: clickedAddressID},
									function(json) {
										if (json[0].Error) {
											alert('Postcode lookup error:\n\n'+json[0].Cause+' '+json[0].Resolution);
											return false;
										}
										for(var e in fieldsToDataMap) {
											if ($('input[name='+e+']').length > 0)
												$('input[name='+e+']').val(json[0][fieldsToDataMap[e]]);                                            
										}
										mode == 1 ? $('#addressesList').fadeOut() : hidelightbox();

										/* ----------------------
										| Done. Return link to live status and do callback, if passed.
										---------------------- */

										thiss.updateLink();
										if (typeof params.callback == 'function') params.callback(json);


									}
								)

							});
						}

					});

				}

			}

		return false; //don't let this click be construed by other JS as a call to do something else, e.g. submit a form

	});

}


/* ----------------------
| UTILITY:	Set up utility func for updating lookup link and initiate and also set up custom dialog func if one set in config
---------------------- */

palookup.prototype.updateLink = function(disabled) {
	with($(this.lookupLinkOrBut)) {
		text(!disabled ? defaultLinkText : waitText);
		css({color: !disabled ? origLinkCol : '#888', textDecoration: 'none'});
		attr('disabled', !disabled ? false : true);
	};
}
