﻿// detect whether we have access to the xml request
var xmlhttp=false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
// JScript gives us Conditional compilation, we can cope with old IE versions.
// and security blocked creation of the objects.
 try {
  xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
 } catch (e) {
  try {
   xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (E) {
   xmlhttp = false;
  }
 }
@end @*/

// if we're using IE6, we need shimming for the combobox div

var IE6 = false /*@cc_on || @_jscript_version < 5.7 @*/;

if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
    try {
	    xmlhttp = new XMLHttpRequest();
    } catch (e) {
	    xmlhttp=false;
    }
}
if (!xmlhttp && window.createRequest) {
    try {
	    xmlhttp = window.createRequest();
    } catch (e) {
	    xmlhttp=false;
    }
}

if (!xmlhttp) {
    alert('Unfortunately your browser does not support functionality required to view this page.  Please update your browser to the latest version');
}

// Gets the position of an inline element (IE4+ NS6+/Mozilla only!)
function getElementPosition(el){
	for (var lx=0,ly=0;el!=null;
		lx+=el.offsetLeft,ly+=el.offsetTop,el=el.offsetParent);
	return {left:lx,top:ly}
}

// Creates a new town or postcode search box from the div element passed
// config - {
//      elementId (string): id of the div to be used as the postcode search box
//      inputClassName (string): the css class to be applied to the generated input element
//      inputName (string): the name of the form element generated
//      inputCssClass (string): the css class to be applied to the generated input field
//      jsonUrl (string): the url of the json to load
//      resultsContainerClassName (string): the css class name to be applied to the div containing the results
//      inputHeight (number): the height of the generated input
//      maxDropDownHeight (number): the maximum height of the drop down, if the number of items exceeds this, scrolling will be applied
//      showDropDownDelay (number): the delay in ms after typing has stopped to show the drop down
//      enableDisableFieldId (string): an optional field id to enable or disable based on whether the user has entered a vaid postcode
//      dataRoot (string): an optional string specifying the name of the variable within the returned json that holds the data
//      displayProperty (string): which property within the results should be displayed
//      valueProperty (string): which property within the results should be used for the selected value
//      emptyText (string): the text to display when no valid input has been set
//      initialValue (string): the initial value of the generated hidden field
//      initialText (string): the initial value to display in the generated input field
// }
function TownOrPostcodeLite(config) {
    var scope = this;
    
    this.config = config;
    
    // clear any content
    var containerDiv = document.getElementById(config.elementId);
    containerDiv.innerHTML = '';
    
    // set our default selected index
    this.selectedIndex = -1;
    
    // check to see if we have a value and some text, if we do set our value selected flag
    if (this.config.initialText && this.config.initialValue) {
        this.valueSelected = true;
    } else {
        if (config.enableDisableFieldId) {
            document.getElementById(config.enableDisableFieldId).disabled = true;
        }
    }
    
    // generate our inoput field and add it to our container
    this.input = document.createElement('input');
    this.input.className = this.config.inputCssClass;
    this.input.setAttribute('type', 'text');
    this.input.setAttribute('name', config.inputName);
    this.input.setAttribute('cssClass', config.inputClassName);
    this.input.setAttribute('autocomplete', 'off');
    this.input.value = this.config.initialText || this.config.emptyText;
    this.intervalId = null;
    // disable form submission when the emnter key is pressed
    this.input.onkeypress = function(e) {
        var evt = e || window.event;
        if (evt.keyCode == 13) {
            return false;
        }
    }
    this.input.onkeyup = function(e) {
        var evt = e || window.event;
        scope.hasFocus = true;
        scope.valueSelected = false;
        if (this.value.length > 2) {
            // allow the user to enter what appears to be a postcode
            if (!/\d/.test(this.value)) {
                keyCode = evt.keyCode;
                // check for arrow keys (not forgetting the weird keycodes safari gives back)
                if ((keyCode >= 37 && keyCode <= 40) || (keyCode >= 63232 && keyCode <= 63235)) {
                    // is it the up or down key?
                    if (keyCode == 38 || keyCode == 63233) {
                        // up key was pressed
                        if (scope.selectedIndex != 0) {
                            scope.setSelectedIndex(scope.selectedIndex - 1, scope);
                        }
                    } else if(keyCode == 40 || keyCode == 63232) {
                        // down key was pressed
                        if (scope.selectedIndex != scope.results.length - 1) {
                            scope.setSelectedIndex(scope.selectedIndex + 1, scope);
                        }
                    }
                } else {
                    if (keyCode != 13) {
                        if (scope.intervalId) {
                            clearInterval(scope.intervalId);
                        }
                        scope.intervalId = setInterval(function() { scope.search(scope); }, scope.config.showDropDownDelay);
                    } else {
                        scope.input.value = scope.selectedDiv.innerHTML;
                        scope.hiddenField.value = scope.selectedDiv.dataValue;
                        scope.valueSelected = true;
                        scope.selectedDiv = scope.selectedDiv;
                        scope.selectedIndex = scope.selectedDiv.itemIndex;
                        scope.hideSelection();
                    }
                }
            }
        }
    }
    this.input.onfocus = function() {
        if (this.value == scope.config.emptyText) {
            this.value = '';
        }
    }
    this.input.onblur = function() {
        if (!scope.resultsContainerHasFocus)
        {
			scope.hasFocus = false;
			scope.hideSelection();
        }
    }
    containerDiv.appendChild(this.input);
    // generate our hidden field to store the town id
    this.hiddenField = document.createElement('input');
    this.hiddenField.setAttribute('type', 'hidden');
    this.hiddenField.setAttribute('name', config.hiddenInputName);
    if (config.initialValue) {
        this.hiddenField.value = config.initialValue;
    }
    containerDiv.appendChild(this.hiddenField);
    
    // generate our div that will contain our results and add it to the document
    this.resultsContainer = document.createElement('div');
    this.resultsContainer.style.position = 'absolute';
    this.resultsContainer.style.visibility = 'hidden';
    this.resultsContainer.className = config.resultsContainerClassName;
	this.resultsContainer.onmouseover = function() {
		scope.resultsContainerHasFocus = true;
	}
	this.resultsContainer.onmouseout = function() {
		scope.resultsContainerHasFocus = false;		
	}
	if (IE6)
	{
		// create an iframe width 100% width / height, append to the results container
		this.resultsContainer.innerHTML = '<IFRAME id="IE6Iframe" style="LEFT: 0px; POSITION: absolute; TOP: 0px; width: 100%; height: 100%; z-index: 1;" src="javascript:false;" frameBorder="0" scrolling="no"></IFRAME><div id="IE6Div" style="LEFT: 0px; POSITION: absolute; TOP: 0px; z-index: 2; background-color: #FF0000"></div>';
		// create another div above the iframe - this is where we'll append our divs when we load them
		document.body.appendChild(this.resultsContainer);
		this.resultsDiv = document.getElementById('IE6Div');
		this.iframe = document.getElementById('IE6Iframe');
	} else {
		this.resultsDiv = this.resultsContainer;
		document.body.appendChild(this.resultsContainer);
	}
}

TownOrPostcodeLite.prototype.search = function(scope) {
    clearInterval(scope.intervalId);
    if (scope.hasFocus) {
        scope.selectedIndex = -1;
        // remove any existing elements
        scope.resultsDiv.innerHTML = '';
        xmlhttp.open("POST", scope.config.jsonUrl,true);
        xmlhttp.onreadystatechange=function() {
            if (xmlhttp.readyState==4) {
                if (scope.config.dataRoot) {
                    scope.results = eval( '(' + xmlhttp.responseText + ')' )[scope.config.dataRoot];
                } else {
                    scope.results = eval( '(' + xmlhttp.responseText + ')' );
                }
                scope.showResults();
            }
        }
        xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlhttp.send('query=' + encodeURI(scope.input.value));
    }
}

TownOrPostcodeLite.prototype.showResults = function(results) {
    var scope = this;
    var inputPosition = getElementPosition(this.input);
    height = 0;
	width = 0;
    this.resultsContainer.style.top = (inputPosition.top + this.input.offsetHeight) + 'px';
    this.resultsContainer.style.left = inputPosition.left + 'px';
    this.resultsContainer.style.visibility = 'visible';
    for(i = 0; i < scope.results.length; i++) {
        div = document.createElement('div');
        div.innerHTML = scope.results[i][scope.config.displayProperty];
        div.dataValue = scope.results[i][scope.config.valueProperty];
        div.className = scope.config.itemClassName;
        div.itemIndex = i;
        div.id = 'ComboItem_' + i;
        div.offSetHeight = height;
        div.onmouseover = function() {
            scope.setSelectedIndex(this.itemIndex, scope);
        }
        div.onmousedown = function() {
            scope.input.value = this.innerHTML;
            scope.hiddenField.value = this.dataValue;
            scope.valueSelected = true;
            scope.selectedDiv = this;
            scope.selectedIndex = this.itemIndex;
			scope.hideSelection();
        }
        scope.resultsDiv.appendChild(div);
        height += div.offsetHeight;
		width = Math.max(width, div.offsetWidth);
    }
    if (height > this.config.maxDropDownHeight) {
        scope.resultsContainer.style.height = this.config.maxDropDownHeight + 'px';
    } else {
        scope.resultsContainer.style.height = (height + 20) + 'px';
    }
	if (IE6)
	{
		scope.iframe.style.height = (height + 20) + 'px';
	}
}

TownOrPostcodeLite.prototype.hideSelection = function() {
    validValue = false;
    // check to see if we have any digits - if we do assume the user has entered a postcode
    if (/\d/.test(this.input.value)) {
        postcode = IsPostcode(this.input.value);
        if (postcode) {
            this.input.value = postcode;
            this.hiddenField.value = postcode;
            validValue = true;
            if (this.config.onValueSelected != null) {
                this.config.onValueSelected();
            }
        } else {
            this.input.value = this.config.emptyText;
            this.hiddenField.value = '';
            alert('The postcode you have entered does not appear to be valid.  Please check and try again');
        }
    } else {
        this.resultsContainer.style.visibility = 'hidden';
        // force a selection if we have already loaded our data
        if (this.results && this.results.length > 0 && !this.valueSelected) {
            if (this.input.value.toLowerCase() == this.results[0][this.config.displayProperty].toLowerCase()) {
                this.input.value = this.results[0][this.config.displayProperty];
                this.hiddenField.value = this.results[0][this.config.valueProperty];
                if (this.config.onValueSelected != null) {
                    this.config.onValueSelected();
                }
                validValue = true;
            } else {
                this.hiddenField.value = '';
                this.input.value = this.config.emptyText;
            }
        } else if (!this.valueSelected) {
            this.hiddenField.value = '';
            this.input.value = this.config.emptyText;
        } else if (this.valueSelected) {
            validValue = true;
            if (this.config.onValueSelected != null) {
                this.config.onValueSelected();
            }
        }

    }
    if (this.config.enableDisableFieldId) {
        document.getElementById(this.config.enableDisableFieldId).disabled = !validValue;
    }
}

TownOrPostcodeLite.prototype.setSelectedValue = function(dataId, dataValue) {
    this.input.value = dataValue;
    this.hiddenField.value = dataId;
}

TownOrPostcodeLite.prototype.getSelectedValue = function() {
    return this.hiddenField.value;
}

TownOrPostcodeLite.prototype.setSelectedIndex = function(index, scope) {
    if (scope.selectedDiv) {
        scope.selectedDiv.className = this.config.itemClassName;
    }
    scope.selectedDiv = document.getElementById('ComboItem_' + index);
    if (scope.selectedDiv) {
        scope.selectedDiv.className = this.config.selectedItemClassName;
        scope.selectedIndex = index;
        var containerHeight = scope.resultsContainer.clientHeight - 20;
        if ((scope.selectedDiv.offSetHeight - scope.resultsContainer.scrollTop) > containerHeight) {
            scope.resultsContainer.scrollTop = scope.selectedDiv.offSetHeight - containerHeight;
        } else if ((scope.selectedDiv.offSetHeight - scope.resultsContainer.scrollTop) < 0) {
            scope.resultsContainer.scrollTop = scope.selectedDiv.offSetHeight;
        }
        //document.getElementById('DebugValue').value = scope.selectedDiv.offsetTop + "," + scope.resultsContainer.scrollTop;
    }
}