/*
Infomation
==========================================================================================
jQuery Plugin
	Name       : jquery.ajaxComboBox
	Version    : 3.5.3
	Update     : 2010-07-18
	Author     : sutara_lumpur
	Author-URI : http://d.hatena.ne.jp/sutara_lumpur/20090124/1232781879
	License    : MIT License (http://www.opensource.org/licenses/mit-license.php)
	Based-on   : Uses code and techniques from following libraries...
		* jquery.suggest 1.1
			Author     : Peter Vulgaris
			Author-URI : http://www.vulgarisoip.com/
==========================================================================================

Contents
==========================================================================================
	01. ComboBox????????
	02. ComboBox???????????
	03. ????????
	04. ????????
	05. ComboBox????? - ???
	06. ComboBox????? - Ajax??
	07. ComboBox????? - ???????
	08. ComboBox????? - ???????
	09. ComboBox????? - ??????
	10. ??????
==========================================================================================
*/
(function($) {
	$.ajaxComboBox = function(area_pack, source, options, msg) {

		//================================================================================
		// 01. ComboBox????????
		//--------------------------------------------------------------------------------
		var num       = 0; //????????????
		var box_width = $(area_pack).width();

		//************************************************************
		// ComboBox??????
		//************************************************************
		var $add_area = $('<div></div>')
			.addClass(options.p_add_cls);

		if(options.package){
			var $add_btn = $('<img />')
				.attr({
					'alt'   : msg['add_btn'],
					'title' : msg['add_title'],
					'src'   : options.p_add_img1
				})
				.mouseover(function (ev){
					$(ev.target).attr('src',options.p_add_img2);
				})
				.mouseout(function (ev){
					$(ev.target).attr('src',options.p_add_img1);
				})
				.click(function (){
					addPack(area_pack);
				})
				.appendTo($add_area);
		}

		//????Box??????
		if(options.init_val === false){
			addPack(area_pack);
		}else{
			for(i=0; options.init_val.length > i ;i++){
				addPack(area_pack);
			}
			options.init_val = false;
		}

		//================================================================================
		// 02. ComboBox???????????
		//--------------------------------------------------------------------------------
		//************************************************************
		//ComboBox???
		//************************************************************
		function delPack(box){
			var past_id = $(area_pack).find('input[type=text]').eq(0).attr('id');
			$(box).parent().parent().remove();

			var new_id = $(area_pack).find('input[type=text]').eq(0).attr('id');
			$('label[for=' + past_id + ']').attr('for', new_id);

			delBtnShowHide();
		}

		//************************************************************
		//???????????????
		//************************************************************
		function delBtnShowHide(){
			var box_cls_name = '#' + $(area_pack).attr('id') + ' .'+ options.p_area_cls;

			if($(box_cls_name).length == 1){
				$(box_cls_name + ' .' + options.p_del_cls).css('visibility','hidden');
			} else {
				$(box_cls_name + ' .' + options.p_del_cls).css('visibility','visible');
			}
		}

		//************************************************************
		//ComboBox???
		//************************************************************
		function addPack(btn){
			num++;

			var $pack = $('<div></div>')
				.addClass(options.p_area_cls);

			var $box = $('<div></div>');

			var $del_area = $('<div></div>')
				.addClass(options.p_del_cls);

			var del_btn = $('<img />')
				.attr({
					'alt'   : msg['del_btn'],
					'title' : msg['del_title'],
					'src'   : options.p_del_img1
				})
				.mouseover(function (ev){
					$(ev.target).attr('src',options.p_del_img2);
				})
				.mouseout(function (ev){

					$(ev.target).attr('src',options.p_del_img1);
				})
				.click(function(ev){
					delPack(ev.target);
				})
				.appendTo($del_area);

			var $clear = $('<div style="clear:both"></div>');

			if(options.package){
				$box.addClass(options.p_acbox_cls);
				$pack
					.append($box)
					.append($del_area)
					.append($clear);

				$(area_pack)
					.append($pack)
					.append($add_area);

				$box.width(box_width);
				$(area_pack).width(
					box_width + $del_area.width()
				);
				$add_area.css('margin-left', $box.width());
			} else {
				$pack.append($box);
				$(area_pack).append($pack);
				$box.width($(area_pack).width());
			}

			//?????ComboBox???????????
			individual($box);

			delBtnShowHide();
		}

		//************************************************************
		//?????ComboBox?????
		//************************************************************
		function individual(area_combobox){
		
			//Ajax???????????????
			$.ajaxSetup({cache: false});
			
			//================================================================================
			// 03. ????????
			//--------------------------------------------------------------------------------
			//**********************************************
			//??????
			//**********************************************
			var show_hide        = false; //??????????????????????
			var timer_show_hide  = false; //??????????????????????????
			var timer_delay      = false; //hold timeout ID for suggestion result_area to appear
			var timer_val_change = false; //??????(????????????????)
			var type_suggest     = false; //????????false=>?? / true=>??
			var page_num_all     = 1;     //????????????????
			var page_num_suggest = 1;     //????????????????
			var max_all          = 1;     //?????????????
			var max_suggest      = 1;     //?????????????
			var now_loading      = false; //Ajax????????????
			var reserve_btn      = false; //????????????????????
			var reserve_click    = false; //?????????????????????mousedown???
			var $xhr             = false; //XMLHttp?????????
			var key_paging       = false; //????????????
			var key_select       = false; //????????????
			var prev_value       = '';    //ComboBox??????

			//????
			var size_navi        = null;  //???????(????????)
			var size_results     = null;  //???????(???????)
			var size_li          = null;  //???????(????????)
			var size_left        = null;  //???????(??????)
			var select_field;             //?????????????????
			if(options.sub_info){
				if(options.show_field && !options.hide_field){
					select_field = options.field + ',' + options.show_field;
				} else {
					select_field = '*';
				}
			} else {
				select_field = options.field;
				options.hide_field = '';
			}
			if(options.select_only && select_field != '*'){
				select_field += ',' + options.primary_key;
			}

			//??????????????????????????
			var primary_key = (options.select_only)
				? options.primary_key
				: '';

			//**********************************************
			//?????
			//**********************************************
			$(area_combobox).addClass(options.combo_class);

			var $table = $('<table cellspacing="1"><tbody><tr><th></th><td></td></tr></tbody></table>')
				.addClass(options.table_class);


			var $input = $('<input />')
				.attr({
					'type'         : 'text',
					'autocomplete' : 'off'
				})
				.addClass(options.input_class);
			if(options.cake_rule){
				//-----------------------------------
				//CakePHP??name,id?????
				//-----------------------------------
				var field_camel = toCakeCamelCase(options.cake_field);

				if(options.package){
					//?????
					$input.attr({
						'name' : 'data[' + options.cake_model + '][' + options.cake_field + '][' + (num - 1) + ']',
						'id'   : options.cake_model + field_camel + (num - 1)
					});
				} else {
					//??
					$input.attr({
						'name' : 'data[' + options.cake_model + '][' + options.cake_field + ']',
						'id'   : options.cake_model + field_camel
					});
				}
			} else {
				//-----------------------------------
				//???name,id?????
				//-----------------------------------
				$input.attr({
					'name' : options.input_prefix + num,
					'id'   : options.input_prefix + num
				});
			}


			var $obj_th = $table.children('tbody').children('tr').children('th');

			var $button = $table.children('tbody').children('tr').children('td');
			/*$button.append('<img />');*/

			var $result_area = $('<div></div>')
				.addClass(options.re_area_class);

			var $navi = $('<div></div>')
				.addClass(options.navi_class);

			var $results = $('<ul></ul>')
				.addClass(options.results_class);

			//????
			var $attached_tbl = $('<div></div>')
				.addClass(options.sub_info_class);

			//"??????"??????
			var $hidden = $('<input type="hidden" />')
				.attr({
					'name': $input.attr('name'),
					'id'  : $input.attr('name') + '_hidden'
				})
				.val('');

			//????title?????
			btnAttrDefault();

			//**********************************************
			//????????
			//**********************************************

			$obj_th.append($input);

			$result_area.append($results);

			$(area_combobox)
				.append($table)
				.append($result_area);

			//????????hidden???
			if(options.select_only) $(area_combobox).append($hidden);

			//?????????????
			$input.width(
				$(area_combobox).width() -
				$button.children('img').width() -
				parseInt($obj_th.css('padding-left')) -
				parseInt($obj_th.css('padding-right')) -
				parseInt($button.css('padding-left')) -
				parseInt($button.css('padding-right')) -
				parseInt($button.css('border-left-width')) -
				parseInt($button.css('border-right-width')) -
				parseInt($table.css('border-left-width')) -
				parseInt($table.css('border-right-width')) -
				3 //?????"border-spacing:1px?3"??

				//IE8??'border-spacing'??????????????
				// - (parseInt($table.css('border-spacing')) * 3)
			);

			//ComboBox???????
			setInitVal();

			//================================================================================
			// 04. ????????
			//--------------------------------------------------------------------------------
			//**********************************************
			//???????
			//**********************************************
			$button.mouseup(function(ev) {
				if($result_area.css('display') == 'none') {
					clearInterval(timer_val_change);
					
					type_suggest = false;
					suggest();
					
					$input.focus();
				} else {
					hideResult();
				}
				ev.stopPropagation();
			});
			$button.mouseover(function() {
				reserve_btn = true;
				if (now_loading) return;
				$button
					.addClass(options.btn_on_class)
					.removeClass(options.btn_out_class);
			});
			$button.mouseout(function() {
				reserve_btn = false;
				if (now_loading) return;
				$button
					.addClass(options.btn_out_class)
					.removeClass(options.btn_on_class);
			});
			//???mouseout???
			$button.mouseout();

			//**********************************************
			//?????????
			//**********************************************
			//???(????????)
			if ($.browser.mozilla || $.browser.opera) {
				$input.keypress(processKey);
			}else{
				$input.keydown(processKey);
			}
			$input.focus(function() {
				show_hide = true;
				checkValChange();
			});
			$input.blur(function(ev) {
				//?????????
				clearTimeout(timer_val_change);

				//???????
				show_hide = false;

				//????????????
				checkShowHide();

				//?????????
				btnAttrDefault();
			});
			$input.mousedown(function(ev) {
				reserve_click = true;

				//???????????
				clearTimeout(timer_show_hide);

				ev.stopPropagation();
			});
			$input.mouseup(function(ev) {
				$input.focus();
				reserve_click = false;
				ev.stopPropagation();
			});

			//**********************************************
			//?????
			//**********************************************
			$navi.mousedown(function(ev) {
				reserve_click = true;

				//???????????
				clearTimeout(timer_show_hide);

				ev.stopPropagation();
			});
			$navi.mouseup(function(ev) {
				$input.focus();
				reserve_click = false;
				ev.stopPropagation();
			});

			//**********************************************
			//????
			//**********************************************
			$attached_tbl.mousedown(function(ev) {
				reserve_click = true;

				//???????????
				clearTimeout(timer_show_hide);
				ev.stopPropagation();
			});
			$attached_tbl.mouseup(function(ev) {
				$input.focus();
				reserve_click = false;
				ev.stopPropagation();
			});

			//**********************************************
			//body??
			//**********************************************
			$('body').mouseup(function() {
				//???????????
				clearTimeout(timer_show_hide);

				//???????
				show_hide = false;
				hideResult();
			});

			//================================================================================
			// 05. ComboBox????? - ???
			//--------------------------------------------------------------------------------
			//**********************************************
			//CakePHP??????????UpperCamelCase?
			//**********************************************
			// @param text str ???????
			function toCakeCamelCase(str){
				return str.replace(
					/^.|_./g,
					function(match){
						return match
							.replace(/_(.)/, '$1')
							.toUpperCase();
					}
				);
			}

			//**********************************************
			//ComboBox???????
			//**********************************************
			function setInitVal(){
				if(options.init_val === false) return;

				if(options.select_only){
					//------------------------------------------
					//???????????
					//------------------------------------------
					//hidden?????
					$hidden.val(options.init_val[num - 1]);

					//?????????????
					var init_val_data = '';
					var $xhr2 = $.get(
						options.init_src,
						{
							'q_word'      : options.init_val[num - 1],
							'field'       : options.field,
							'primary_key' : options.primary_key,
							'db_table'    : options.db_table
						},
						function(data){
							$input.val(data);
							prev_value = data;

							//????
							$button.attr('title',msg['select_ok']);
							$button.children('img').attr({
								'src'   : options.select_ok_img,
								'alt'   : msg['get_all_alt'],
								'title' : msg['select_ok']
							});
						}
					);
				} else {
					//------------------------------------------
					//?????????????????
					//------------------------------------------
					prev_value = options.init_val[num - 1];
					$input.val(options.init_val[num - 1]);
				}
			}

			//**********************************************
			//??????????????????
			//**********************************************
			//??????????????????????
			//
			// @param boolean enforce ???????????????????
			function scrollWindow(enforce) {

				//------------------------------------------
				//?????????
				//------------------------------------------
				var $current_result = getCurrentResult();

				var target_top = ($current_result && !enforce)
					? $current_result.offset().top
					: $table.offset().top;

				var target_size;
				if(options.sub_info){
					var $tbl = $attached_tbl.children('table:visible');
					target_size =
						$tbl.height() +
						parseInt($tbl.css('border-top-width'), 10) +
						parseInt($tbl.css('border-bottom-width'), 10);

				} else {
					setSizeLi();
					target_size = size_li;
				}

				var client_height = document.documentElement.clientHeight;

				var scroll_top = (document.documentElement.scrollTop > 0)
					? document.documentElement.scrollTop
					: document.body.scrollTop;

				var scroll_bottom = scroll_top + client_height - target_size;

				//------------------------------------------
				//???????
				//------------------------------------------
				var gap;
				if ($current_result.length) {
					if(target_top < scroll_top || target_size > client_height) {
						//???????
						//???????????????????????????????
						gap = target_top - scroll_top;

					} else if (target_top > scroll_bottom) {
						//???????
						gap = target_top - scroll_bottom;

					} else {
						//???????????
						return;
					}

				} else if (target_top < scroll_top) {
					gap = target_top - scroll_top;
				}
				window.scrollBy(0, gap);
			}
			//**********************************************
			//????title????
			//**********************************************
			//??? & ??????????
			function btnAttrDefault() {

				if(options.select_only){

					if($input.val() != ''){
						if($hidden.val() != ''){
							
							if(typeof(options.fnselectOK)=='function') options.fnselectOK.call(this,$hidden.val());
														
							//????
							/*$button.attr('title',msg['select_ok']);
							$button.children('img').attr({
								'src'   : options.select_ok_img,
								'alt'   : msg['get_all_alt'],
								'title' : msg['select_ok']
							});
							return;*/
						} else {
							
							if(typeof(options.fnselectERR)=='function') options.fnselectERR.call(this,$hidden.val());
							
							//????
							/*$button.attr('title',msg['select_ng']);
							$button.children('img').attr({
								'src'   : options.select_ng_img,
								'alt'   : msg['get_all_alt'],
								'title' : msg['select_ng']
							});*/
							return;
						}
					} else {
						//??????????
						
						if(typeof(options.fnUnSelect)=='function') options.fnUnSelect.call(this);
						
						$hidden.val('');
					}
				}
				//????
				$button.attr('title',msg['get_all_btn']);
				$button.children('img').attr({
					'src'   : options.button_img,
					'alt'   : msg['get_all_alt'],
					'title' : msg['get_all_btn']
				});
			}
			//???
			function btnAttrClose() {
				$button.attr('title',msg['close_btn']);
				$button.children('img').attr({
					'src'   : options.load_img,
					'alt'   : msg['close_alt'],
					'title' : msg['close_btn']
				});
			}
			//????
			function btnAttrLoad() {
				$button.attr('title',msg['loading']);
				$button.children('img').attr({
					'src'   : options.load_img,
					'alt'   : msg['loading_alt'],
					'title' : msg['loading']
				});
			}

			//**********************************************
			//??????????????
			//**********************************************
			function checkValChange() {
				timer_val_change = setTimeout(isChange,500);

				function isChange() {
					now_value = $input.val();

					if(now_value != prev_value) {

						//???????
						if(options.select_only){
							$hidden.val('');
							btnAttrDefault();
						}
						//?????????
						page_num_suggest = 1;
						
						type_suggest = true;
						suggest();
					}
					prev_value = now_value;

					//????????????
					checkValChange();
				}
			}

			//**********************************************
			//????????????????
			//**********************************************
			function checkShowHide() {
				timer_show_hide = setTimeout(function() {
					if (show_hide == false && reserve_click == false){
						hideResult();
					}
				},500);
			}

			//**********************************************
			//????????
			//**********************************************
			function processKey(e) {
				if (
					(/27$|38$|40$|^9$/.test(e.keyCode) && $result_area.is(':visible')) ||
					(/^37$|39$|13$|^9$/.test(e.keyCode) && getCurrentResult()) ||
					/40$/.test(e.keyCode)
				) {
					if (e.preventDefault)  e.preventDefault();
					if (e.stopPropagation) e.stopPropagation();

					e.cancelBubble = true;
					e.returnValue  = false;

					switch(e.keyCode) {
						case 37: // left
							if (e.shiftKey) firstPage();
							else            prevPage();
							break;

						case 38: // up
							key_select = true;
							prevResult();
							break;

						case 39: // right
							if (e.shiftKey) lastPage();
							else            nextPage();
							break;

						case 40: // down
							if (!$result_area.is(':visible') && !getCurrentResult()){
								type_suggest = false;
								suggest();
							} else {
								key_select = true;
								nextResult();
							}
							break;

						case 9:  // tab
							key_paging = true;
							hideResult();
							break;

						case 13: // return
							selectCurrentResult();
							break;

						case 27: //	escape
							key_paging = true;
							hideResult();
							break;
					}

				} else {
					checkValChange();
				}
			}

			//**********************************************
			//???????????
			//**********************************************
			function setLoadImg() {
				now_loading = true;
				btnAttrLoad();
			}
			function clearLoadImg() {
				$button.children('img').attr('src' , options.button_img);
				now_loading = false;
				if(reserve_btn) $button.mouseover(); else $button.mouseout();
			}

			//================================================================================
			// 06. ComboBox????? - Ajax??
			//--------------------------------------------------------------------------------
			//**********************************************
			//Ajax???
			//**********************************************
			function abortAjax() {
				if ($xhr){
					//jQuery1.4.3??????IE7????????????
					if($.browser.msie && $.browser.version == '7.0') return;
					$xhr.abort();
					$xhr = false;
					clearLoadImg();
				}
			}

			//**********************************************
			//Ajax??
			//**********************************************
			function suggest(){
				var q_word         = (type_suggest) ? $.trim($input.val()) : '';
				var which_page_num = (type_suggest) ? page_num_suggest : page_num_all;

				if (type_suggest && q_word.length < options.minchars){ 
					hideResult();
					
				} else {
					//Ajax????????
					abortAjax();

					//??????
					$attached_tbl.children('table').css('display','none');

					setLoadImg();

					//???Ajax????????
					$xhr = $.getJSON(
						options.source,
						{
							'q_word'      : q_word,
							'page_num'    : which_page_num,
							'per_page'    : options.per_page,
							'field'       : options.field,
							'show_field'  : options.show_field,
							'hide_field'  : options.hide_field,
							'select_field': select_field,
							'order_field' : options.order_field,
							'order_by'    : options.order_by,
							'primary_key' : primary_key,
							'db_table'    : options.db_table
						},
						function(json_data, status){
							//???Ajax????????????????????????????
							//??????json_data??????????
							if(!json_data || status != 'success'){
								hideResult();
								return;
							}
							if(!json_data.candidate){
								//???????????????
								hideResult();
							} else {
								//????1???????????????????????
								if(json_data.cnt > json_data.cnt_page){
									setNavi(json_data.cnt, json_data.cnt_page, which_page_num);
								} else {
									$navi.css('display','none');
								}

								//?????(arr_candidate)
								var arr_candidate = [];
								$.each(json_data.candidate, function(i,obj){
									var nq_word=q_word.replace(/[-\s]+/ig,'[-\s]+').replace(/[сc]+/ig,'[сc]+').replace(/[аa]+/ig,'[аa]+');
									arr_candidate[i] = obj.replace(
										new RegExp(nq_word, 'ig'),
										function(q_word) {
											return '<span class="' + options.match_class + '">' + q_word + '</span>';
										}
									);
								});

								//????(arr_attached)
								var arr_attached = [];
								if(json_data.attached){
									$.each(json_data.attached,function(i,obj){
										arr_attached[i] = obj;
									});
								} else {
									arr_attached = false;
								}

								//??????(arr_primary_key)
								var arr_primary_key = [];
								if(json_data.primary_key){
									$.each(json_data.primary_key,function(i,obj){
										arr_primary_key[i] = obj;
									});
								} else {
									arr_primary_key = false;
								}
								displayItems(arr_candidate, arr_attached, arr_primary_key);
							}
							clearLoadImg();
							selectFirstResult();
						}
					);
				}
			}
				
			//================================================================================
			// 07. ComboBox????? - ???????
			//--------------------------------------------------------------------------------

			//**********************************************
			//???????
			//**********************************************
			// @param integer cnt         DB??????????
			// @param integer page_num    ??????????????????
			function setNavi(cnt, cnt_page, page_num) {

				var num_page_top = options.per_page * (page_num - 1) + 1;
				var num_page_end = num_page_top + cnt_page - 1;

				//var cnt_result = msg['page_info']
				var cnt_result = msg['page_info']
					.replace('cnt'          , cnt)
					.replace('num_page_top' , num_page_top)
					.replace('num_page_end' , num_page_end);

				$navi.text(cnt_result);

				var navi_p = $('<p></p>'); //??????????????
				var max    = Math.ceil(cnt / options.per_page); //?????

				//????
				if (type_suggest) {
					max_suggest = max;
				}else{
					max_all = max;
				}

				//????????????????
				var left  = page_num - Math.ceil ((options.navi_num - 1) / 2);
				var right = page_num + Math.floor((options.navi_num - 1) / 2);

				//????????????left,right???
				while(left < 1){ left ++;right++; }
				while(right > max){ right--; }
				while((right-left < options.navi_num - 1) && left > 1){ left--; }

				//----------------------------------------------
				//??????????

				//?<< ??????
				if(page_num == 1) {
					if(!options.navi_simple){
						$('<span></span>')
							.text('<< ')
							.addClass('page_end')
							.appendTo(navi_p);
					}
					$('<span></span>')
						.text(msg['prev'])
						.addClass('page_end')
						.appendTo(navi_p);
				} else {
					if(!options.navi_simple){
						$('<a></a>')
							.attr({'href':'javascript:void(0)','class':'navi_first'})
							.text('<< ')
							.attr('title', msg['first_title'])
							.appendTo(navi_p);
					}
					$('<a></a>')
						.attr({'href':'javascript:void(0)','class':'navi_prev'})
						.text(msg['prev'])
						.attr('title', msg['prev_title'])
						.appendTo(navi_p);
				}

				//????????????
				for (i = left; i <= right; i++)
				{
					//?????????<span>???(?????)
					var num_link = (i == page_num) ? '<span class="current">'+i+'</span>' : i;

					$('<a></a>')
						.attr({'href':'javascript:void(0)','class':'navi_page'})
						.html(num_link)
						.appendTo(navi_p);
				}

				//???X? >>????
				if(page_num == max) {
					$('<span></span>')
						.text(msg['next'])
						.addClass('page_end')
						.appendTo(navi_p);
					if(!options.navi_simple){
						$('<span></span>')
							.text(max + ' >>')
							.addClass('page_end')
							.appendTo(navi_p);
					}
				} else {
					$('<a></a>')
						.attr({'href':'javascript:void(0)','class':'navi_next'})
						.text(msg['next'])
						.attr('title', msg['next_title'])
						.appendTo(navi_p);
					if(!options.navi_simple){
						$('<a></a>')
							.attr({'href':'javascript:void(0)','class':'navi_last'})
							.text(max + ' >>')
							.attr('title', msg['last_title'])
							.appendTo(navi_p);
					}
				}

				//??????????????????????????????
				if (max > 1) {
					$navi.append(navi_p).show();

					//----------------------------------------------
					//????????????????

					//?<< 1??????
					$('.navi_first').mouseup(function(ev) {
						$input.focus();
						ev.preventDefault();
						firstPage();
					});

					//?< ????????
					$('.navi_prev').mouseup(function(ev) {
						$input.focus();
						ev.preventDefault();
						prevPage();
					});

					//??????????????
					$('.navi_page').mouseup(function(ev) {
						$input.focus();
						ev.preventDefault();

						if(!type_suggest){
							page_num_all = parseInt($(this).text(), 10);
						}else{
							page_num_suggest = parseInt($(this).text(), 10);
						}
						suggest();
					});

					//??? >??????
					$('.navi_next').mouseup(function(ev) {
						$input.focus();
						ev.preventDefault();
						nextPage();
					});

					//?max >>??????
					$('.navi_last').mouseup(function(ev) {
						$input.focus();
						ev.preventDefault();
						lastPage();
					});
				}
			}

			//**********************************************
			//???????
			//**********************************************
			//1?????
			function firstPage() {
				if(!type_suggest) {
					if (page_num_all > 1) {
						page_num_all = 1;
						suggest();
					}
				}else{
					if (page_num_suggest > 1) {
						page_num_suggest = 1;
						suggest();
					}
				}
			}
			//??????
			function prevPage() {
				if(!type_suggest){
					if (page_num_all > 1) {
						page_num_all--;
						suggest();
					}
				}else{
					if (page_num_suggest > 1) {
						page_num_suggest--;
						suggest();
					}
				}
			}
			//??????
			function nextPage() {
				if(!type_suggest){
					if (page_num_all < max_all) {
						page_num_all++;
						suggest();
					}
				} else {
					if (page_num_suggest < max_suggest) {
						page_num_suggest++;
						suggest();
					}
				}
			}
			//???????
			function lastPage() {
				if(!type_suggest){
					if (page_num_all < max_all) {
						page_num_all = max_all;
						suggest();
					}
				}else{
					if (page_num_suggest < max_suggest) {
						page_num_suggest = max_suggest;
						suggest();
					}
				}
			}

			//================================================================================
			// 08. ComboBox????? - ???????
			//--------------------------------------------------------------------------------
			//**********************************************
			//?????<ul>?????
			//**********************************************
			// @params array arr_candidate   DB?????????????
			// @params array arr_attached    ???????
			// @params array arr_primary_key ??????
			//
			//arr_candidate???????<li>???????
			//????????????????
			function displayItems(arr_candidate, arr_attached, arr_primary_key) {

				if (arr_candidate.length == 0) {
					hideResult();
					return;
				}

				//?????????????
				$results.empty();
				$attached_tbl.empty();

				for (var i = 0; i < arr_candidate.length; i++) {

					//?????
					var $li = $('<li>' + arr_candidate[i] + '</li>');

					//??????
					if(options.select_only){
						$li.attr('id', arr_primary_key[i]);
					}

					$results.append($li);

					//????????????
					if(arr_attached){
						var $tbl = $('<table><tbody></tbody></table>');

						for (var j=0; j < arr_attached[i].length; j++) {

							//th????????
							if(options.sub_as[arr_attached[i][j][0]] != null){
								var th_name = options.sub_as[arr_attached[i][j][0]];
							} else {
								var th_name =  arr_attached[i][j][0];
							}

							var $tr = $('<tr></tr>');
							$tr.append('<th>' + th_name + '</th>');
							$tr.append('<td>' + arr_attached[i][j][1] + '</td>');
							$tbl.children('tbody').append($tr);
						}
						$attached_tbl.append($tbl);
					}
				}
				//?????
				if(arr_attached) $attached_tbl.insertAfter($results);
				
				var dop_offset=100;
				if($.browser.msie && parseFloat($.browser.version)<7) {dop_offset=$(area_combobox).offset().left/3}
				
				$result_area
					.show()
					.width(
						$table.width() + 220 +
						parseInt($table.css('border-left-width')) +
						parseInt($table.css('border-right-width'))
					).css({left:(options.isrel?0:$(area_combobox).offset().left-dop_offset)+'px'});

				$results
					.children('li')
					.mouseover(function() {

						//Firefox????????????????????????
						//???????????????????????????
						if (key_select) {
							key_select = false;
							return;
						}

						//???????
						setSubInfo(this);

						$results.children('li').removeClass(options.select_class);
						$(this).addClass(options.select_class);
					})
					.mousedown(function(e) {
						reserve_click = true;

						//???????????
						clearTimeout(timer_show_hide);
						//ev.stopPropagation();
					})
					.mouseup(function(e) {
						reserve_click = false;

						//Firefox????????????????????????
						//???????????????????????????
						if (key_select) {
							key_select = false;
							return;
						}
						e.preventDefault();
						e.stopPropagation();
						selectCurrentResult();
					});

				//????title????(???)
				btnAttrClose();
			}

			//**********************************************
			//????????
			//**********************************************
			//???????????
			// @return object current_result ???????????????(<li>??)
			function getCurrentResult() {

				if (!$result_area.is(':visible')) return false;

				var $current_result = $results.children('li.' + options.select_class);

				if (!$current_result.length) $current_result = false;

				return $current_result;
			}
			//?????????????
			function selectCurrentResult() {

				//???????????????
				scrollWindow(true);

				var $current_result = getCurrentResult();

				if ($current_result) {
					$input.val($current_result.text());
					hideResult();

					//added
					prev_value = $input.val();

					//??????
					if(options.select_only){
						$hidden.val($current_result.attr('id'));
						btnAttrDefault();
					}
				}
				$input.focus();  //?????????????????
				$input.change(); //????????????????????
			}
			//?????????
			function nextResult() {
				var $current_result = getCurrentResult();

				if ($current_result) {

					//???????
					setSubInfo($current_result.next());

					$current_result
						.removeClass(options.select_class)
						.next()
							.addClass(options.select_class);
				}else{
					//???????
					setSubInfo($results.children('li:first-child'), 0);

					$results.children('li:first-child').addClass(options.select_class);
				}
				//???????????????
				scrollWindow();
			}
			//?????????
			function prevResult() {
				var $current_result = getCurrentResult();

				if ($current_result) {

					//???????
					setSubInfo($current_result.prev());

					$current_result
						.removeClass(options.select_class)
						.prev()
							.addClass(options.select_class);
				}else{
					//???????
					setSubInfo(
						$results.children('li:last-child'),
						($results.children('li').length - 1)
					);

					$results.children('li:last-child').addClass(options.select_class);
				}
				//???????????????
				scrollWindow();
			}
			//????????
			function hideResult() {

				if (key_paging) {
					//???????????????
					scrollWindow(true);
					key_paging = false;
				}

				$result_area.hide();

				//??????
				$attached_tbl.children('table')
					.css('display','none');

				//Ajax????????
				abortAjax();

				//????title?????
				btnAttrDefault();
			}
			//?????1??????????????
			function selectFirstResult() {
				$results.children('li:first-child').addClass(options.select_class);

				//???????
				setSubInfo($results.children('li:first-child'));

				//???????????????
				scrollWindow(true);
			}

			//================================================================================
			// 09. ComboBox????? - ??????
			//--------------------------------------------------------------------------------
			//**********************************************
			//?????????????????????
			//**********************************************
			function setSizeResults(){
				if(size_navi == null){
					size_navi =
						$navi.height() +
						parseInt($navi.css('border-top-width'), 10) +
						parseInt($navi.css('border-bottom-width'), 10) +
						parseInt($navi.css('padding-top'), 10) +
						parseInt($navi.css('padding-bottom'), 10);
				}
			}
			function setSizeNavi(){
				if(size_results == null){
					size_results = parseInt($results.css('border-top-width'), 10);
				}
			}
			function setSizeLi(){
				if(size_li == null){
					$obj = $results.children('li:first');
					size_li =
						$obj.height() +
						parseInt($obj.css('border-top-width'), 10) +
						parseInt($obj.css('border-bottom-width'), 10) +
						parseInt($obj.css('padding-top'), 10) +
						parseInt($obj.css('padding-bottom'), 10);
				}
			}
			function setSizeLeft(){
				if(size_left == null){
					size_left =
						$results.width() +
						parseInt($results.css('padding-left'), 10) +
						parseInt($results.css('padding-right'), 10) +
						parseInt($results.css('border-left-width'), 10) +
						parseInt($results.css('border-right-width'), 10);
				}
			}

			//**********************************************
			//???????
			//**********************************************
			// @paramas object  obj   ?????????????<li>??
			// @paramas integer n_idx ????<li>???(0~)
			function setSubInfo(obj, n_idx){

				//????????????????????
				if(!options.sub_info) return;

				//???????????????
				//???????????????????
				setSizeNavi();
				setSizeResults();
				setSizeLi();
				setSizeLeft();

				//???<li>?????
				if(n_idx == null){
					n_idx = $results.children('li').index(obj);
				}

				//??????????
				$attached_tbl.children('table').css('display','none');

				//??????????????????????
				if(n_idx > -1){

					var t_top = 0;
					if($navi.css('display') != 'none') t_top += size_navi;
					t_top += (size_results + size_li * n_idx);
					var t_left = size_left;

					//Firefox?????border-collapse:collapse;??????
					//??1px,??1px????????????
					//??>http://www.nk0206.com/life/2009/10/bordercollapse2.html
					if($.browser.mozilla) {
						t_top  ++;
						t_left ++;
					}
					t_top  += 'px';
					t_left += 'px';
					
					$attached_tbl.children('table:eq(' + n_idx + ')').css({
						'position': 'absolute',
						'top'     : t_top,
						'left'    : t_left,
						'display' : ($.browser.msie) ? 'block' : 'table' //for IE7
					});
				}
			}
		}
	};

	//================================================================================
	// 10. ??????
	//--------------------------------------------------------------------------------
	$.fn.ajaxComboBox = function(source, options) {
		if (!source) return;

		//************************************************************
		//?????
		//************************************************************
		options = $.extend({
			//????
			source         : source,
			db_table       : 'tbl',                    //????DB??????
			img_dir        : 'acbox/img/',             //?????????
			field          : 'name',                   //?????????????
			minchars       : 1,                        //?????????????????????
			per_page       : 10,                       //????1??????????
			navi_num       : 5,                        //?????????????????
			navi_simple    : false,                    //?????????????????????
			init_val       : false,                    //ComboBox????(???????)
			init_src       : 'acbox/php/initval.php',  //???????????????????
			input_prefix   : $(this).attr('id') + '_', //?????????name??????
			mini           : false,                    //ComboBox????????????????
			lang           : 'en',                     //?????(?????????)
			
			//????
			sub_info       : false, //??????????????
			sub_as         : {},    //??????????????
			show_field     : '',    //????????????(???????????)
			hide_field     : '',    //??????????????(???????????)
			
			isrel		   : 0,

			//??????
			select_only    : false, //??????????????
			primary_key    : 'id'   //????????hidden????????
		}, options);
		
		//2?????(????????????????)
		options = $.extend({
			order_field    : options.field,            //ORDER BY(SQL) ??????????
			order_by       : 'ASC',                    //ORDER BY(SQL) ???????????????

			//?????
			package       : false,                            //?????????????????
			p_del_img1     : options.img_dir + 'del_out.png',  //?????(??????)
			p_del_img2     : options.img_dir + 'del_over.png', //?????(???????)
			p_add_img1     : options.img_dir + 'add_out.png',  //?????(??????)
			p_add_img2     : options.img_dir + 'add_over.png', //?????(???????)

			//CakePHP??
			cake_rule      : false, //ComboBox?name????CakePHP?????????????
			cake_model     : options.db_table, //???????????????????????
			cake_field     : options.field,    //?????????????????????????
			
			//--------------------------
			// ????????
			//--------------------------
			//???????
			p_area_cls     : 'box_area'  + ((options.mini)?'_mini':''), //ComboBox + ?????
			p_acbox_cls    : 'combo_box' + ((options.mini)?'_mini':''), //ComboBox
			p_add_cls      : 'add_area'  + ((options.mini)?'_mini':''), //?????
			p_del_cls      : 'del_area'  + ((options.mini)?'_mini':''), //?????

			//ComboBox??
			combo_class    : 'ac_combobox_area' + ((options.mini)?'_mini':''), //ComboBox?????<div>
			table_class    : 'ac_table'         + ((options.mini)?'_mini':''), //ComboBox?<table>
			input_class    : 'ac_input'         + ((options.mini)?'_mini':''), //????????
			button_class   : 'ac_button'        + ((options.mini)?'_mini':''), //????CSS???
			btn_on_class   : 'ac_btn_on'        + ((options.mini)?'_mini':''), //???(mover?)
			btn_out_class  : 'ac_btn_out'       + ((options.mini)?'_mini':''), //???(mout?)
			re_area_class  : 'ac_result_area'   + ((options.mini)?'_mini':''), //??????<div>
			navi_class     : 'ac_navi'          + ((options.mini)?'_mini':''), //????????<div>
			results_class  : 'ac_results'       + ((options.mini)?'_mini':''), //???????<ul>
			select_class   : 'ac_over'          + ((options.mini)?'_mini':''), //????<li>
			match_class    : 'ac_match'         + ((options.mini)?'_mini':''), //??????<span>
			sub_info_class : 'ac_attached'      + ((options.mini)?'_mini':''), //????

			//????
			button_img     : options.img_dir + 'combobox_button' + ((options.mini)?'_mini':'') + '.png',
			load_img       : options.img_dir + 'ajax-loader'     + ((options.mini)?'_mini':'') + '.gif',
			select_ok_img  : options.img_dir + 'select_ok'       + ((options.mini)?'_mini':'') + '.png',
			select_ng_img  : options.img_dir + 'select_ng'       + ((options.mini)?'_mini':'') + '.png'
		}, options);

		//************************************************************
		//????????????
		//************************************************************
		switch (options.lang){
		
			//???
			case 'ja':
				var msg = {
					'add_btn'     : '?????',
					'add_title'   : '????????????',
					'del_btn'     : '?????',
					'del_title'   : '????????????',
					'next'        : '??',
					'next_title'  : '??'+options.per_page+'? (???)',
					'prev'        : '??',
					'prev_title'  : '??'+options.per_page+'? (???)',
					'first_title' : '??????? (Shift + ???)',
					'last_title'  : '??????? (Shift + ???)',
					'get_all_btn' : '???? (???)',
					'get_all_alt' : '??:???',
					'close_btn'   : '??? (Tab??)',
					'close_alt'   : '??:???',
					'loading'     : '????...',
					'loading_alt' : '??:????...',
					'page_info'   : 'num_page_top - num_page_end ? (? cnt ?)',
					'select_ng'   : '?? : ???????????????',
					'select_ok'   : 'OK : ???????????'
				};
				break;

			//??
			case 'en':
				var msg = {
					'add_btn'     : 'Add button',
					'add_title'   : 'add a box',
					'del_btn'     : 'Del button',
					'del_title'   : 'delete a box',
					'next'        : 'Следующая',
					'next_title'  : 'Следующая '+options.per_page+'',
					'prev'        : 'Предыдущая',
					'prev_title'  : 'Предыдущая'+options.per_page+'',
					'first_title' : 'Первая',
					'last_title'  : 'Последняя',
					'get_all_btn' : 'Все',
					'get_all_alt' : '',
					'close_btn'   : 'Закрыть',
					'close_alt'   : 'Закрыть',
					'loading'     : 'загрузка...',
					'loading_alt' : '(загрузка)',
					'page_info'   : 'num_page_top - num_page_end из cnt',
					'select_ng'   : 'Attention : Please choose from among the list.',
					'select_ok'   : 'OK : Correctly selected.'
				};
				break;

			//????? (Joaquin G. de la Zerda??????)
			case 'es':
				var msg = {
					'add_btn'     : 'Agregar boton',
					'add_title'   : 'Agregar una opcion',
					'del_btn'     : 'Borrar boton',
					'del_title'   : 'Borrar una opcion',
					'next'        : 'Siguiente',
					'next_title'  : 'Proximas '+options.per_page+' (tecla derecha)',
					'prev'        : 'Anterior',
					'prev_title'  : 'Anteriores '+options.per_page+' (tecla izquierda)',
					'first_title' : 'Primera (Shift + Left)',
					'last_title'  : 'Ultima (Shift + Right)',
					'get_all_btn' : 'Ver todos (tecla abajo)',
					'get_all_alt' : '(boton)',
					'close_btn'   : 'Cerrar (tecla TAB)',
					'close_alt'   : '(boton)',
					'loading'     : 'Cargando...',
					'loading_alt' : '(Cargando)',
					'page_info'   : 'num_page_top - num_page_end de cnt',
					'select_ng'   : 'Atencion: Elija una opcion de la lista.',
					'select_ok'   : 'OK: Correctamente seleccionado.'
				};
				break;

			default:
		}
		this.each(function() {
			new $.ajaxComboBox(this, source, options, msg);
		});
		return this;
	};
})(jQuery);
