(function () {
	var YL = YAHOO.lang,
		YUD = YAHOO.util.Dom,
		YUE = YAHOO.util.Event,
		get = YUD.get;
	AE.namespace('AE.widget.intelligentSearch');
	AE.widget.intelligentSearch = function () {
		this.inputEl = null;
		this.jsonData = [];
		this.selectedOption = [-1, '', ''];
		this.config = {};
		this._defConfig = {
			url: '',
			inputElId: '',
			listCssClass: 'intelligentList',
			listCssStyle: 'left:0px;top:0px;width:200px;height:auto;z-index:100',
			keyWordClass: '',
			listItemNum: 10,
			requestDelay: 0.15,
			enableResultCount: 1,
			enableCatShow: 1,
			returnVarName: 'intelSearchData',
			isNeedSubmit: true
		};
		this.init = function (userConfig) {
			this.config = YL.merge(this._defConfig, userConfig);
			this.inputEl = get(this.config.inputElId);
			this.UIController = YL.merge(this.UIController, {});
			this.requestHander = YL.merge(this.requestHander, {});
			this.dataParser = YL.merge(this.dataParser, {});
			this.UIController.init(this);
			this.onInit.fire();
			if (window.location.href.indexOf('chinasuppliers') != -1) {
				this.config.enableCatShow = 0;
			}
		};
		this.initOnActive = function () {
			if (this.requestHander.requestCount == 0 && !this.dataParser.isInit) {
				this.requestHander.init(this);
				this.dataParser.init(this);
				this.UIController.initEvts();
				this.onActive.fire();
				return true;
			}
			return false;
		};
		this.onInit = new YAHOO.util.CustomEvent('onInit', this);
		this.onActive = new YAHOO.util.CustomEvent('onActive', this);
		this.onRequestSent = new YAHOO.util.CustomEvent('onRequestSent', this);
		this.onRequestFailure = new YAHOO.util.CustomEvent('onRequestFailure', this);
		this.onRequestSuccess = new YAHOO.util.CustomEvent('onRequestSuccess', this);
		this.onListDisplay = new YAHOO.util.CustomEvent('onListDisplay', this);
		this.onListDisplayed = new YAHOO.util.CustomEvent('onListDisplayed', this);
		this.onListHide = new YAHOO.util.CustomEvent('onListHide', this);
		this.onListHidden = new YAHOO.util.CustomEvent('onListHidden', this);
		this.onOptionClick = new YAHOO.util.CustomEvent('onOptionClick', this);
		this.onOptionMouseDown = new YAHOO.util.CustomEvent('onOptionMouseDown', this);
		this.onInputKeyDown = new YAHOO.util.CustomEvent('onInputKeyDown', this);
	};
	AE.widget.intelligentSearch.prototype = {
		requestHander: {
			_parent: null,
			_timer: null,
			_processor: null,
			_isLoading: false,
			disabled: false,
			requestCount: 0,
			previousQuery: '',
			returnDataLength: 0,
			init: function (scope) {
				this._parent = scope;
			},
			send: function () {
				var _self = this,
					P = this._parent,
					config = P.config;
				var inputEl = P.dataParser.HTMLElements.inputEl;
				if (this.disabled || this._isLoading) {
					return;
				};
				this._isLoading = true;
				this._timer = setTimeout(function () {
					var inputVal = inputEl.value.toLowerCase().replace(/^\s+/, '').replace(/\s{2,}/g, ' ');
					if (YAHOO.lang.trim(inputVal) == '') {
						P.UIController.hideList();
						_self._isLoading = false;
						return;
					}
					P.onRequestSent.fire();
					_self.requestCount++;
					_self._processor = YAHOO.util.Get.script(_self._buildURL(inputVal, inputEl.form), {
						onSuccess: _self._onSuccess,
						scope: _self,
						charset: 'iso-8859-1',
						data: inputVal,
						insertBefore: P.inputEl
					});
					_self._isLoading = false;
				}, config.requestDelay * 1000);
			},
			_onSuccess: function (o) {
				var P = this._parent;
				P.jsonData = eval('window.' + P.config.returnVarName);
				if (!YL.isArray(P.jsonData) || P.jsonData.length == 0 || YAHOO.lang.trim(P.inputEl.value) == '') {
					this.returnDataLength = 0;
					P.UIController.hideList();
				} else {
					P.dataParser.update(P);
					P.UIController.displayList();
					P.onRequestSuccess.fire();
				}
				P.selectedOption[2] = o.data;
				P.jsonData = null;
				o.purge();
			},
			_buildURL: function (searchStr, f) {
				var P = this._parent,
					config = P.config,
					param = '',
					baseUrl = config.url;
				if (baseUrl.indexOf('?') != -1) {
					var urlArray = baseUrl.split('?');
					baseUrl = urlArray[0];
					param = '&' + urlArray[1];
				}
				return (baseUrl + '?keyword=' + encodeURIComponent(searchStr) + '&' + 'searchType=' + (config.enableCatShow == 1 ? ( !! f.IndexArea ? f.IndexArea.value : '') : '') + '&' + 'varname=' + config.returnVarName + '&' + '__number=' + config.enableResultCount + '&' + 'time=' + (new Date()).getTime() + param);
			}
		},
		dataParser: {
			_parent: null,
			isInit: false,
			HTMLElements: {
				docEl: document,
				inputEl: null,
				listBox: null,
				iframeMask: null,
				showBtn: null,
				hideBtn: null,
				optionList: []
			},
			init: function (scope) {
				var P = scope,
					config = P.config,
					inputEl = P.inputEl,
					els = this.HTMLElements;
				this._parent = P;
				els.inputEl = inputEl;
				els.iframeMask = this._insertHTMLAfter(els.inputEl, this._buildHTML(config.listCssClass, config.listItemNum));
				els.listBox = YUD.getNextSibling(els.iframeMask);
				this._initHTMLElements(els.listBox);
				this._formatHTML();
				this.isInit = true;
			},
			update: function (parentScope) {
				var P = this._parent,
					config = P.config,
					els = this.HTMLElements,
					optionList = els.optionList,
					jsonData = P.jsonData,
					tempData = [];
				if (!this.isInit) {
					this.init(parentScope)
				};
				for (var i = 0, l = jsonData.length; i < l; i++) {
					if ( !! jsonData[i].cat) {
						for (j = 0, k = jsonData[i].cat.length; j < k; j++) {
							tempData.push({
								keywords: jsonData[i].keywords,
								cat: jsonData[i].cat[j]
							});
						}
						tempData.push({
							keywords: jsonData[i].keywords
						});
					} else {
						tempData.push(jsonData[i]);
					}
				}
				P.requestHander.returnDataLength = tempData.length;
				for (i = 0, l = optionList.length; i < l; i++) {
					var option = optionList[i],
						numHtml = '',
						txtHtml = '';
					var inputVal = els.inputEl.value.toLowerCase().replace(/^\s+/, '').replace(/\s{2,}/g, ' ');
					if (i < tempData.length) {
						if (config.keyWordClass != '') {
							txtHtml = '<span class="js_key">' + this._boldKeyWords(tempData[i].keywords, inputVal, config.keyWordClass) + '</span>';
						} else {
							txtHtml = '<span class="js_key">' + tempData[i].keywords + '</span>';
						}
						if (config.enableCatShow == 1) {
							option.removeAttribute('catid');
							if ( !! tempData[i].cat) {
								for (var item in tempData[i].cat) {
									if (tempData[i].cat.hasOwnProperty(item)) {
										txtHtml += '<span class="cat" style="font-weight:bold;"> in ' + tempData[i].cat[item] + '</span>';
										option.setAttribute('catid', item);
									}
								}
							}
						}
						if (config.enableResultCount == 1 && tempData[i].count) {
							numHtml = '<span class="s">' + tempData[i].count + '</span>';
						}
						option.innerHTML = numHtml + txtHtml;
						YUD.setStyle(option, 'display', '');
					} else {
						YUD.setStyle(option, 'display', 'none');
					}
					option = null;
				}
				tempData = null;
			},
			_buildHTML: function (skinClass, itemNum) {
				var html = '<iframe frameborder="0" src="about:blank" scrolling="no" class="intelligentIframeMask" style="visibility:hidden;"></iframe>' + '<div class="' + skinClass + '" style="visibility:hidden;">' + '<div class="showSearchSuggestion" style="display:none;">Search Suggestions</div>' + '<div><div class="intelligentListTitle"><span>Hide</span>Search Suggestions</div>';
				for (var i = 0; i < itemNum; i++) {
					html += '<p id="listItem' + i + '">&nbsp;</p>';
				};
				html += '</div></div>';
				return html;
			},
			_insertHTMLAfter: function (el, html) {
				if (el.insertAdjacentHTML) {
					el.insertAdjacentHTML('AfterEnd', html);
				} else {
					var range = el.ownerDocument.createRange(),
						frag;
					range.setStartAfter(el);
					frag = range.createContextualFragment(html);
					el.parentNode.insertBefore(frag, el.nextSibling)
				}
				return el.nextSibling;
			},
			_initHTMLElements: function (container) {
				var els = this.HTMLElements,
					optionList = [];
				els.showBtn = container.firstChild;
				els.hideBtn = YUD.getFirstChild(YUD.getNextSibling(els.showBtn));
				optionList = container.getElementsByTagName('p');
				for (var i = 0, j = optionList.length; i < j; i++) {
					var option = optionList[i];
				}
				els.optionList = optionList;
			},
			_formatHTML: function () {
				var P = this._parent,
					config = P.config,
					els = this.HTMLElements;
				var listBox = els.listBox,
					ifmMask = els.iframeMask,
					hideBtn = els.hideBtn;
				if (!config.listCssStyle || config.listCssStyle == '') {
					return;
				}
				config.listCssStyle = config.listCssStyle.replace(/\s/ig, '');
				var styles = config.listCssStyle.split('\;');
				for (var i = 0; i < styles.length; i++) {
					var styleItem = styles[i].split('\:'),
						styleName = styleItem[0],
						styleValue = styleItem[1];
					if (!styleName) continue;
					switch (styleName.toLowerCase()) {
					case 'z-index':
						YUD.setStyle(listBox, styleName, styleValue);
						YUD.setStyle(ifmMask, 'z-index', YUD.getStyle(listBox, 'z-index') - 1);
						break;
					case 'top':
					case 'left':
					case 'width':
					case 'height':
						YUD.setStyle([listBox, ifmMask], styleName, styleValue);
						break;
					default:
						YUD.setStyle(listBox, styleName, styleValue);
					}
				}
				listBox.orgWidth = listBox.clientWidth + 'px';
			},
			_boldKeyWords: function (str, keyWord, css) {
				if (!keyWord) return str;
				return str.replace(keyWord, '<span class="' + css + '">' + keyWord + '</span>');
			}
		},
		UIController: {
			_els: {},
			_parent: null,
			_currentListItemIndex: -1,
			isOptionBoxOpen: false,
			isOptionListOpen: true,
			init: function (scope) {
				this._parent = scope;
				var inputEl = get(scope.config.inputElId);
				YUE.on(inputEl, 'click', this._inputElOnClick, this);
				YUE.on(inputEl, 'keydown', this._inputElOnKeydown, this);
			},
			initEvts: function () {
				if (!this._parent || !this._parent.dataParser.isInit) {
					return;
				}
				this._els = this._parent.dataParser.HTMLElements;
				this.bindListeners(this._evtsMap);
			},
			_evtsMap: [
				['docEl', 'click', '_documentOnClick'],
				['inputEl', 'keyup', '_inputElOnKeyup'],
				['inputEl', 'paste', '_inputElOnKeyup'],
				['showBtn', 'click', '_showBtnOnClick'],
				['hideBtn', 'click', '_hideBtnOnClick'],
				['optionList', 'click', '_optionOnClick'],
				['optionList', 'mouseover', '_optionOnMouseover'],
				['optionList', 'mousedown', '_optionOnMousedown']
			],
			bindListeners: function (evtsMap) {
				for (var i = 0; i < evtsMap.length; i++) {
					var evtDef = evtsMap[i];
					var el = evtDef[0],
						evt = evtDef[1],
						fname = evtDef[2];
					YUE.on(this._els[el], evt, this[fname], this);
				}
			},
			_inputElOnKeyup: function (e, scope) {
				scope._parent.requestHander.send();
			},
			_inputElOnKeydown: function (e, scope) {
				var P = scope._parent,
					f = this.form,
					opts = scope._els.optionList,
					opt = null,
					catid = '';
				P.initOnActive();
				scope._parent.onInputKeyDown.fire(e.keyCode);
				P.requestHander.disabled = false;
				if (scope.isOptionListOpen) {
					scope.moveListItem(e.keyCode);
					if (e.keyCode == 13 && scope._currentListItemIndex != -1) {
						opt = opts[scope._currentListItemIndex];
						catid = opt.getAttribute('catid');
						if ( !! catid) {
							YUE.stopEvent(e);
							window.location = f.action + '?' + scope.param(f, {
								CatId: catid
							});
						}
					}
				}
			},
			_inputElOnClick: function (e, scope) {
				YUE.stopEvent(e);
				var P = scope._parent,
					initStatus = P.initOnActive();
				if (scope._els.inputEl.value != P.selectedOption[2]) P.requestHander.send();
				else {
					if (scope._els.inputEl.value != '') scope.displayList();
				}
			},
			_documentOnClick: function (e, scope) {
				if (scope.isOptionBoxOpen) {
					scope.hideList();
				}
			},
			_showBtnOnClick: function (e, scope) {
				YUE.stopEvent(e);
				YUD.setStyle(scope._els.hideBtn, 'display', '');
				YUD.setStyle(YUD.getNextSibling(this), 'display', '');
				YUD.setStyle(this, 'display', 'none');
				scope.displayList(scope._els.listBox.orgWidth);
				scope.isOptionListOpen = true;
			},
			_hideBtnOnClick: function (e, scope) {
				YUE.stopEvent(e);
				YUD.setStyle(scope._els.showBtn, 'display', '');
				YUD.setStyle(this.parentNode, 'display', 'none');
				YUD.setStyle(this, 'display', 'none');
				scope.isOptionListOpen = false;
				scope.hideList('auto');
			},
			_optionOnClick: function (e, scope) {
				var config = scope._parent.config,
					f = scope._els.inputEl.form,
					catid = this.getAttribute('catid');
				scope._parent.onOptionClick.fire(this);
				YUE.stopEvent(e);
				if (config.isNeedSubmit == true) {
					if ( !! catid) {
						window.location = f.action + '?' + scope.param(f, {
							CatId: catid
						});
					} else {
						scope.submitSelect(f);
					}
				}
				scope.hideList();
			},
			_optionOnMouseover: function (e, scope) {
				var inx = this.id.replace('listItem', '');
				YUE.stopEvent(e);
				scope.transListItem(inx);
				scope.setListItemIndex(inx);
			},
			_optionOnMousedown: function (e, scope) {
				var inx = this.id.replace('listItem', '');
				scope._parent.selectedOption[0] = inx;
				scope.setInputElValue(scope._els.optionList[inx]);
				scope._parent.onOptionMouseDown.fire(this);
			},
			displayList: function (w) {
				var els = this._els;
				if ( !! w) {
					YUD.setStyle(els.listBox, 'width', w);
				}
				this.syncMaskWH();
				if (this.isOptionBoxOpen) {
					return;
				}
				this._parent.onListDisplay.fire();
				YUD.setStyle([els.listBox, els.iframeMask], 'visibility', 'visible');
				this.isOptionBoxOpen = true;
				this._parent.onListDisplayed.fire();
			},
			hideList: function (w) {
				var els = this._els;
				if ( !! w) {
					YUD.setStyle(els.listBox, 'width', w);
				}
				if (!this.isOptionBoxOpen) {
					return;
				}
				this._parent.onListHide.fire();
				YUD.setStyle([els.listBox, els.iframeMask], 'visibility', 'hidden');
				YUD.removeClass(els.optionList, 'current');
				this.isOptionBoxOpen = false;
				if (this._currentListItemIndex >= 0) YUD.removeClass(this._els.optionList[this._currentListItemIndex], 'current');
				this._currentListItemIndex = -1;
				this._parent.onListHidden.fire();
				this._parent.requestHander.disabled = false;
			},
			moveListItem: function (kCode) {
				var optionList = this._els.optionList;
				var inx = this._currentListItemIndex;
				var dLen = this._parent.requestHander.returnDataLength;
				if (dLen <= 0 || this._els.inputEl.value == '' || (kCode != 38 && kCode != 40)) {
					return;
				}
				if (kCode == 38) {
					inx--;
					if (inx < -1) inx = dLen - 1;
				} else if (kCode == 40) {
					inx++;
					if (inx >= dLen) inx = -1;
				}
				this.transListItem(inx);
				this.setListItemIndex(inx);
				this._parent.selectedOption[0] = inx;
				this.setInputElValue(inx >= 0 ? optionList[inx] : null);
			},
			transListItem: function (nextInx) {
				var prevInx = this._currentListItemIndex;
				if (prevInx >= 0) {
					YUD.removeClass(this._els.optionList[prevInx], 'current');
				}
				if (nextInx >= 0) YUD.addClass(this._els.optionList[nextInx], 'current');
			},
			param: function (f, ext) {
				var ps = {},
					qar = [],
					fels = f.elements,
					qr = '';
				for (var i = 0, l = fels.length; i < l; i++) {
					if (!fels[i].name) continue;
					ps[fels[i].name] = encodeURIComponent(fels[i].value).replace(/%20/g, '+');
				}
				ps = YL.merge(ps, ext);
				for (var p in ps) {
					if (ps.hasOwnProperty(p)) {
						qar.push(p + '=' + ps[p]);
					}
				}
				qr = qar.join('&');
				ps = null;
				qar = null;
				return qr;
			},
			submitSelect: function (f) {
				if (this._els.inputEl.value.replace(/\s/g, '') != '') {
					f.submit();
				}
			},
			setListItemIndex: function (inx) {
				this._currentListItemIndex = parseInt(inx);
			},
			setInputElValue: function (option) {
				if (option != null) {
					var _self = this,
						val = '',
						key = YUD.getElementsByClassName('js_key', 'span', option);
					if (key.length == 1) {
						val = key[0].innerText || key[0].textContent;
					}
					this._parent.selectedOption[1] = val + ( !! option.getAttribute('catid') ? ('^' + option.getAttribute('catid')) : '');
				} else {
					var val = this._parent.selectedOption[2];
				}
				this._parent.requestHander.disabled = true;
				this._els.inputEl.value = val;
			},
			syncMaskWH: function () {
				var listBox = this._els.listBox;
				var ifmMask = this._els.iframeMask;
				YUD.setStyle(ifmMask, 'width', listBox.offsetWidth + 'px');
				YUD.setStyle(ifmMask, 'height', listBox.offsetHeight + 'px');
			}
		}
	};
}());
