/*global USS411, document, window, XMLHttpRequest, ActiveXObject */

/*jslint nomen: false, regexp:false, plusplus:false, white:false, onevar:false, eqeqeq:true  */
/**
 * This method extends the string object to strip html
 * @author ALW
 * @method
 */
String.prototype.stripHTML = function () {
    var matchTag = /<(?:.|\s)*?>/g;
	return this.replace(matchTag, '');
};

/**
 * Used for creating an autosuggest drop down box
 * @author ALW
 * @namespace USS411.dynamic
 * @class AutoSuggest
 * @param {Object} _textbox HTML Text Element to attach to 
 * @param {Object} _provider Instance of Class to provide suggestions 
 */
USS411.dynamic.AutoSuggest = function (_textbox, _provider) {
	/* This will set all the defaults */
	this.cur = -1; 
    this.dropdown = null; 
    this.provider = _provider;
    this.textbox = _textbox;
	this.query = null;
	this.cssClassName = 'dyn-drop-down';
	this.suggestLimit = 14;
	this.lenBeforeSuggest = 2;
};

/**
 * Method to hide dropdown
 * @method hideList
 */
USS411.dynamic.AutoSuggest.prototype.hideList = function () {
    this.dropdown.style.visibility = 'hidden';
	this.cur = -1;
			
};

/**
 * This will attached to 'selected' class name to the appropriate
 * element and remove all others
 * @method highlightSuggestion
 * @param {Object} _sNode The HTML list container
 */
USS411.dynamic.AutoSuggest.prototype.highlightSuggestion = function (_sNode) {
    for (var i = 0, l = this.dropdown.childNodes.length; i < l; i++) {
        var _node = this.dropdown.childNodes[i];
        if (_node === _sNode) {
            _node.className = 'selected';
        } else if (_node.className === 'selected') {
            _node.className = '';
        }
    }
};

/**
 * This creates the structure for the drop down and 
 * attach mouse events
 * @method createDropDown
 */
USS411.dynamic.AutoSuggest.prototype.createDropDown = function () {
    this.dropdown = document.createElement('ul');
    this.dropdown.className = this.cssClassName;
    this.dropdown.style.visibility = 'hidden';
    this.dropdown.style.minWidth = this.textbox.offsetWidth + 'px';
    this.dropdown.style.left = this.getLeft() + 'px';
    this.dropdown.style.top = (this.getTop() + this.textbox.offsetHeight) + 'px';
    document.body.appendChild(this.dropdown);
    var _that = this; //use to pass this reference to events
    this.dropdown.onmousedown = this.dropdown.onmouseup = this.dropdown.onmouseover = function (_event) {
        var _theEvent = _event || window.event;
        var _target = _theEvent.target || _theEvent.srcElement;
		if (_theEvent.type === 'mousedown') {
            _that.textbox.value = _target.innerHTML.stripHTML();
            _that.hideList();
        } else if (_theEvent.type === 'mouseover') {
            _that.highlightSuggestion(_target);
        } else {
			_that.textbox.focus();
        }
    };
};


/**
 * This is used to find the LEFT postion of the DOM Element passed
 * @method getLeft
 */
USS411.dynamic.AutoSuggest.prototype.getLeft = function () {
    var _node = this.textbox;
    var _posLeft = 0;
	while (_node != null && _node.tagName !== ('BODY')) {
        _posLeft += _node.offsetLeft;
        _node = _node.offsetParent;
	}
    return _posLeft;
};

/**
 * This is used to get the TOP position of the DOM Element passed
 * @method getTop
 */
USS411.dynamic.AutoSuggest.prototype.getTop = function () {
    var _node = this.textbox;
    var _posTop = 0;
    while (_node != null && _node.tagName !== ('BODY')) {
        _posTop += _node.offsetTop;
        _node = _node.offsetParent;
    }
    return _posTop;
};

/**
 * This iterates through the suggestion array and create the elements
 * for the list. It then positions and shows the list
 * @method showSuggestions
 * @param {Array} _suggestArray Array of suggestion passed by the provider
 */
USS411.dynamic.AutoSuggest.prototype.showSuggestions = function (_suggestArray) {
	if (this.textbox.value.length > this.lenBeforeSuggest) {
		var _element = null;
		var _limit = (this.suggestLimit < _suggestArray.length) ? this.suggestLimit : _suggestArray.length;
		this.dropdown.innerHTML = '';
		var _myQ = this.query.toLowerCase();
		var _myRegEx = new RegExp(_myQ, 'i');
		for (var i = 0; i < _limit; i++) {
			_element = document.createElement('li');
			var _newString = _suggestArray[i].replace(_myRegEx, '<strong>' + _myQ + '</strong>');
			_element.innerHTML = _newString;
			this.dropdown.appendChild(_element);
		}
		this.dropdown.style.left = this.getLeft() + 'px';
		this.dropdown.style.top = (this.getTop() + this.textbox.offsetHeight) + 'px';
		this.dropdown.style.visibility = 'visible';
	} else {
		this.hideList();
	}
};

/**
 * This will create a selection in the textbox based on what
 * the user has entered. This allows for prefill and the
 * user to continue typing
 * @method aelectRange
 * @param {Object} _start
 * @param {Object} _length
 */
USS411.dynamic.AutoSuggest.prototype.selectRange = function ( _start, _length) {
    if (this.textbox.createTextRange) {
        var _selectRange = this.textbox.createTextRange();
        _selectRange.moveStart('character', _start);
        _selectRange.moveEnd('character', _length - this.textbox.value.length);
        _selectRange.select();
    } else if (this.textbox.setSelectionRange) {
        this.textbox.setSelectionRange(_start, _length);
    }
    this.textbox.focus();
};

/**
 * This will method checks for the ability to select and if exists
 * will call the selectRange method
 * @method typeAhead
 * @param {Object} _suggestion
 * @param {Object} _typeAhead
 */
USS411.dynamic.AutoSuggest.prototype.typeAhead = function (_suggestion, _typeAhead) {
    if (this.textbox.createTextRange || this.textbox.setSelectionRange) {
        var _len = this.textbox.value.length;
        this.textbox.value = _suggestion;
        this.selectRange(_len, _suggestion.length);
    }
};

/**
 * This checks the array provided by the provider and prefill and/or
 * show suggestions
 * @method autoSuggest
 * @param {Array} _suggestArray Array provided by provider
 * @param {Boolean} _typeAhead Whether or not to prefill text box 
 */
USS411.dynamic.AutoSuggest.prototype.autoSuggest = function (_suggestArray, _typeAhead) {
	this.query = this.textbox.value;
	if (_suggestArray.length > 0) {
        if (_typeAhead) {
            this.typeAhead(_suggestArray[0]);
        }
        this.showSuggestions(_suggestArray);
    } else {
		this.noMoreSuggestions = true;  //this is to stop the ajax from searching when no results
        this.hideList();
    }
};


/**
 * Handles keyup event
 * @method handleKeyUp
 * @param {Event} _event
 */
USS411.dynamic.AutoSuggest.prototype.handleKeyUp = function (_event) {
    var _keyCode = _event.keyCode;
    if (_keyCode === 8 || _keyCode === 46) {
		this.noMoreSuggestions = false;
        this.provider.requestSuggestions(this, false);
    } else if (_keyCode < 32 || (_keyCode >= 33 && _keyCode <= 46) || (_keyCode >= 112 && _keyCode <= 123)) {
        //ignore
    } else {
        //autoSuggest
        if (!this.noMoreSuggestions) {
			this.provider.requestSuggestions(this, false);
		}
    }
};

/**
 * Handles Key Down Event
 * @method handleKeyDown
 * @param {Event} _event
 */
USS411.dynamic.AutoSuggest.prototype.handleKeyDown = function (_event) {
	switch (_event.keyCode) {
        case 38: //up arrow
            this.previousSuggestion();
            break;
        case 40: //down arrow
            this.nextSuggestion();
            break;
        case 13: //enter
            this.hideList();
			//return false;
    }
};

/**
 * Handles Kepress and is used to stop form from submiting on enter
 * @method handleKeyPress
 * @param {Event} _event
 */
USS411.dynamic.AutoSuggest.prototype.handleKeyPress = function (_event) {
    var _keyCode = _event.keyCode;
    if (_keyCode === 13) {
		//return false;
	}
};

/**
 * Used to navigate to next selection in list
 * @method nextSuggestion
 */
USS411.dynamic.AutoSuggest.prototype.nextSuggestion = function () {
    var _listNodes = this.dropdown.childNodes;
	if (_listNodes.length > 0 && this.cur < _listNodes.length - 1) {
        var _node = _listNodes[++this.cur];
        this.highlightSuggestion(_node);
        this.textbox.value = _node.innerHTML.stripHTML();
    }
};

/**
 * Used to navigate to previous suggestion in list
 * @method previousSuggestion
 */
USS411.dynamic.AutoSuggest.prototype.previousSuggestion = function () {
    var _listNodes = this.dropdown.childNodes;
    if (_listNodes.length > 0 && this.cur > 0) {
        var _node = _listNodes[--this.cur];
        this.highlightSuggestion(_node);
		this.textbox.value = _node.innerHTML.stripHTML();
    }
};

USS411.dynamic.AutoSuggest.prototype.attachEvent = function (obj, type, fn) {
	var that, newFn;
	newFn = function () {
		fn.apply(that, arguments);
	};
	if (window.event) {
		obj.attachEvent('on'+type, newFn);
	} else {
		obj.addEventListener(type, newFn, false);
	}
};

/**
 * This initializes the object by attaching the events on the
 * textbox and creates the dropdown box
 * @method init
 */
USS411.dynamic.AutoSuggest.prototype.init = function () {
    var _that = this;
	if (this.textbox.setAttribute) {
		this.textbox.setAttribute('autocomplete','off');
	}
    this.textbox.onkeyup = function(_event){
		if (!_event) {
            _event = window.event;
        }
		//if (_that.textbox.value.length > (_that.lenBeforeSuggest)) {
			_that.handleKeyUp(_event);
		//}
    };
    this.textbox.onkeydown = function (_event) {
    	if (!_event) {
            _event = window.event;
        }
		//if (_that.textbox.value.length > _that.lenBeforeSuggest) {
			_that.handleKeyDown(_event);
		//}
    };
	this.textbox.onkeypress = function (_event) {
		if (!_event) {
            _event = window.event;
        }
        return _that.handleKeyPress(_event);
	};
    this.textbox.onblur = function () {
        _that.hideList();
    };
    this.createDropDown();
};

/**
 * City State Suggestion Provider
 * @author ALW
 * @namespace USS411.util
 * @class cityStateProvider
 */
USS411.util.cityStateProvider = function () {
	this.ajaxURL = '/cityStateList.html';
};

/**
 * Creates and makes the AJAX call
 * @method ajaxCall
 */
USS411.util.cityStateProvider.prototype.ajaxCall = function () {
	var _xmlhttp;
	var _that = this;
	/*Creates the request object*/
	if (window.XMLHttpRequest) { 
		_xmlhttp = new XMLHttpRequest();
  	} else if (window.ActiveXObject) {
		/* For later than  IE7 */
  		_xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  	} else {
		return false;
	}
	_xmlhttp.onreadystatechange = function () {
		if(_xmlhttp.readyState === 4) {
			_that.createArray(_xmlhttp.responseText);
		} else if (_that.asControl.textbox.value.length > _that.asControl.lenBeforeSuggest) {
			_that.asControl.dropdown.style.visibility = 'visible';
			_that.asControl.dropdown.innerHTML = '<li>Searching...</li>';
		}
	};
	_xmlhttp.open('GET', this.ajaxURL + '?prefix=' + encodeURI(this.asControl.textbox.value.toLowerCase()), true);
	_xmlhttp.send(null);
};

/**
 * Creates the array
 * @param {Object} _responsetext
 */
USS411.util.cityStateProvider.prototype.createArray = function (_responsetext) {
	var _jsonObj = {};
	if (_responsetext.isJSON()) {
		_jsonObj = _responsetext.evalJSON();
	}
	this.cityState = _jsonObj || [];
	this.returnSuggestions();
};

/**
 * Analizes the suggestion array, if what the user has entered is at 
 * the begining of the value then add it to the array to create the
 * list 
 * @method returnSuggestions
 */
USS411.util.cityStateProvider.prototype.returnSuggestions = function () {
	var _suggestArray = [];
    var _textboxValue = this.asControl.textbox.value.toLowerCase();
    if (_textboxValue.length > 0) {
		for (var i = 0, l = this.cityState.length; i < l; i++) {
            if (this.cityState[i].toLowerCase().indexOf(_textboxValue) === 0) {
                _suggestArray.push(this.cityState[i]);
            }
        }
		this.asControl.autoSuggest(_suggestArray, this.typeAhead);
    }	
};

/**
 * This is called from the AutoSuggest Class and provides 
 * City/State suggestions via AJAX call
 * @method requestSuggestions
 * @param {Object} _asControl The autu suggest class that has been passed
 * @param {Boolean} _typeAhead Whether or not to prefill
 */
USS411.util.cityStateProvider.prototype.requestSuggestions = function(_asControl, _typeAhead){
	this.asControl = _asControl;
	this.typeAhead = _typeAhead;
	this.ajaxCall();
};

/**
 * This class handles filtering autosuggest. It borrows methods from AutoSuggest
 * @author ALW
 * @namespace USS411.dynamic
 * @class AutoFilter
 * @see USS411.dynamic.AutoSuggest
 */
USS411.dynamic.AutoFilter = function(){
	USS411.dynamic.AutoSuggest.apply(this, arguments);
	this.singleResult = false;
	this.lenBeforeSuggest = 0;
    
};

USS411.dynamic.AutoFilter.prototype = new USS411.dynamic.AutoSuggest();

USS411.dynamic.AutoFilter.prototype.constructor = USS411.dynamic.AutoFilter;

/**
 * This checks the array provided by the provider and prefill and/or
 * show suggestions. if there is one suggestion, prepop and hide list
 * @method autoSuggest
 * @param {Array} _suggestArray Array provided by provider
 * @param {Boolean} _typeAhead Whether or not to prefill text box 
 */
USS411.dynamic.AutoFilter.prototype.autoSuggest = function (_suggestArray, _typeAhead) {
	this.query = this.textbox.value;
	if (_suggestArray.length > 1) {
        if (_typeAhead) {
            this.typeAhead(_suggestArray[0]);
        }
        this.showSuggestions(_suggestArray);
    } else if (_suggestArray.length === 1 && (this.evKeyCode !== 8 && this.evKeyCode !== 46)) {
        this.hideList();
		this.textbox.value = _suggestArray[0];
		this.singleResult = true;
    } else if (_suggestArray.length < 1 && (this.evKeyCode !== 8 && this.evKeyCode !== 46)){
		this.textbox.value = this.textbox.value.substr(0, this.textbox.value.length - 1);
	}
};

/**
 * Handles keyup event
 * @method handleKeyUp
 * @param {Event} _event
 */
USS411.dynamic.AutoFilter.prototype.handleKeyUp = function (_event) {
    this.evKeyCode = _event.keyCode;
	if (this.evKeyCode === 8 || this.evKeyCode === 46) {
		this.provider.requestSuggestions(this, false);
	} else if (this.evKeyCode === 13) {
		this.textbox.form.submit();	
	} else if (this.evKeyCode < 32 || (this.evKeyCode >= 33 && this.evKeyCode <= 46) || (this.evKeyCode >= 112 && this.evKeyCode <= 123)) {
        //ignore
	} else {
        //autoSuggest
        this.provider.requestSuggestions(this, false);
    }
};

/**
 * This initializes the object by attaching the events on the
 * textbox and creates the dropdown box
 * @method init
 */
USS411.dynamic.AutoFilter.prototype.init = function () {
    var _that = this;
	this.textbox.setAttribute('autocomplete', 'off');
	if (this.textbox.setAttribute) {
		this.textbox.setAttribute('autocomplete','off');
	}
    this.textbox.onkeyup = function(_event){
        if (!_event) {
            _event = window.event;
        }
			_that.handleKeyUp(_event);
	};
    this.textbox.onkeydown = function (_event) {
    	if (!_event) {
            _event = window.event;
        }
		
			_that.handleKeyDown(_event);
		
    };
	this.textbox.onkeypress = function (_event) {
		if (!_event) {
            _event = window.event;
        }
        return _that.handleKeyPress(_event);
	};
    this.textbox.onblur = function () {
        _that.hideList();
    };
    this.createDropDown();
};
