;(function(){

	/**
	 * 가상 키보드 객체 배열 변수
	 * @see	모든 가상 키보드에 접근하기 위한 클로져(closure) 변수
	 */
	var keyboard = [] ;

	/**
	 * 한국어 키보드 표현
	 */
	var couple = {
		q: 'ㅂ' , w: 'ㅈ' , e: 'ㄷ' , r: 'ㄱ' , t: 'ㅅ' , y: 'ㅛ' , u: 'ㅕ' , i: 'ㅑ' , o: 'ㅐ' , p: 'ㅔ' ,
		a: 'ㅁ' , s: 'ㄴ' , d: 'ㅇ' , f: 'ㄹ' , g: 'ㅎ' , h: 'ㅗ' , j: 'ㅓ' , k: 'ㅏ' , l: 'ㅣ' ,
		z: 'ㅋ' , x: 'ㅌ' , c: 'ㅊ' , v: 'ㅍ' , b: 'ㅠ' , n: 'ㅜ' , m: 'ㅡ' ,
		Q: 'ㅂ' , W: 'ㅈ' , E: 'ㄷ' , R: 'ㄱ' , T: 'ㅅ' , Y: 'ㅛ' , U: 'ㅕ' , I: 'ㅑ' , O: 'ㅐ' , P: 'ㅔ' ,
		A: 'ㅁ' , S: 'ㄴ' , D: 'ㅇ' , F: 'ㄹ' , G: 'ㅎ' , H: 'ㅗ' , J: 'ㅓ' , K: 'ㅏ' , L: 'ㅣ' ,
		Z: 'ㅋ' , X: 'ㅌ' , C: 'ㅊ' , V: 'ㅍ' , B: 'ㅠ' , N: 'ㅜ' , M: 'ㅡ' ,
		1: '!' , 2: '@' , 3: '#' , 4: '$' , 5: '%' , 6: '^' , 7: '&' , 8: '*' , 9: '(' , 0: ')'
	} ;

	var control = {
		backspace: '<a href="javascript:void(0)" class="backspace">←</a>' ,
		clear: '<a href="javascript:void(0)" class="clear">Clear</a>' ,
		close: '<a href="javascript:void(0)" class="close">Close</a>' ,
		submit: '<a href="javascript:void(0)" class="submit">Submit</a>'
	} ;

	/**
	 * 인수로 전달된 배열의 원소를 버튼(HTML)으로 배치하여 반환한다.
	 * @param	{Array}		key		버튼 문자 배열
	 * @param	{String}	hangule	한글 출력 여부
	 * @return	{String}	버튼 배치(HTML)
	 */
	function allocate ( key , hangule )
	{
		var button = '' , i ;
		for ( i in key )
		{
			if ( key[i] === ' ' )
				button += '<br>' ;
			else if ( hangule === true && typeof couple[key[i]] === 'string' )
				button += '<button class="couple"><b>' + key[i] + '</b><u>' + couple[key[i]] + '</u></button>' ;
			else
				button += '<button><b>' + key[i] + '</b></button>' ;
		}
		return button ;
	}

	/**
	 * 가상 키보드 레이어 내의 버튼을 랜덤하게 재배치 한다.
	 * @param	{jQuery}	$button	버튼
	 * @see		button 태그의 text 교체 방식으로 진행된다.
	 */
	function random ( $button )
	{
		var temp , j , i ;
		for ( i = 0 ; i < $button.length ; i ++ )
		{
			j = i ;
			while( j === i )
				j = Math.floor ( Math.random () * $button.length ) ;
			temp = $button.eq(j).html();
			$button.eq(j).html($button.eq(i).html());
			$button.eq(i).html(temp);
		}
	}

	/**
	 * jQuery 확장
	 */
	$.fn.extend({

		/**
		 * 가상 키보드 사용
		 * @param	{JSON}	option	키보드 설정
		 * @see		다음과 같은 항목을 설정 할 수 있다.
		 * 			id: 가상 키보드 레이어 아이디
		 * 			class: 가상 키보드 CSS 클래스
		 * 			key: 키(key 값을 객체로 전달 할 경우, 탭 형태로 출력된다)
		 * 			random: 랜덤 배열 여부
		 * 			hangule: 한글 표기 여부
		 *			position: 가상 키보드 출력 위치
		 *			control: 컨트롤 버튼 출력 여부 및 순서
		 */
		keyboard: function(option){

			// 키보드 사용 대상 객체가 없는 경우 무시한다.
			if ( this.size() === 0 )
				return ;

			// 현재 가상 키보드 고유번호
			var uid = keyboard.length ;

			// 기본 옵션 설정
			var basic = {
				id: 'ssKeyboard' + uid ,
				class: 'ssKeyboard',
				key: {'영소':'1234567890 qwertyuiop asdfghjkl zxcvbnm', '영대': '1234567890 QWERTYUIOP ASDFGHJKL ZXCVBNM', '특수': '`!@#$%^&*() +-=_~[]{}<> *\\|\'";:,./?'},		// 객체 방식으로 설정된 경우에는 탭으로 표현.
				random: false ,
				hangule: true ,
				position: {side: 'bottom', offset:{top: 0, left: 0}} ,
				control: ['backspace', 'clear', 'close', 'submit']
			} ;
			option = $.extend(basic, option);

			// 가상 키보드 레이어 생성 및 버튼 배치 / 이벤트 핸들러
			keyboard[uid] = $('<div id="' + option.id + '" class="' + option.class + '"></div>');
			if ( typeof option.key === 'string' )
			{
				option.key = option.key.split('');
				keyboard[uid].append(allocate ( option.key , option.hangule ));
			}
			else
			{
				var tab = '' , i ;
				for ( i in option.key )
				{
					option.key[i] = option.key[i].split('');
					keyboard[uid].append('<div tab="' + i + '" style="display:none;">' + allocate ( option.key[i] , option.hangule ) + '</div>');
					tab += '<li>' + i + '</li>';
				}
				var $ul = $('<ul>' + tab + '</ul>') ;
			}
			keyboard[uid].on('click','button',function(){
				keyboard[uid].data('input').val(keyboard[uid].data('input').val() + $(this).children('b').text()) ;
			});

			// 컨트롤 배치
			var $control = $('<div class="control"></div>') ;
			if ( $ul )
				$control.prepend($ul);
			if ( option.control !== undefined )
			{
				for ( i = 0 ; i < option.control.length ; i ++ )
					if ( control[option.control[i]] !== undefined )
						$control.append(control[option.control[i]]) ;
			}

			// 컨트롤 이벤트 핸들러
			$control.find('.close').click(function(){
				keyboard[uid].hide();
			});
			$control.find('.clear').click(function(){
				keyboard[uid].data('input').val('');
			});
			$control.find('.submit').click(function(){
				$(this).siblings('.close').click();
				keyboard[uid].data('input').closest('form').submit();
			});
			$control.find('.backspace').click(function(){
				keyboard[uid].data('input').val(keyboard[uid].data('input').val().slice(0, -1));
			});
			$control.find('li').click(function(){
				keyboard[uid].children(':not(:first)').hide();
				keyboard[uid].children('[tab="' + $(this).text() + '"]').show();
				$(this).siblings('*').removeClass('on');
				$(this).closest('li').addClass('on');
			}).eq(0).trigger('click');

			// 전역 배치
			keyboard[uid].prepend($control);
			$('body').append(keyboard[uid]);

			// 입력 폼 이벤트 핸들러
			this.each(function(){
				var $obj = $(this);
				$obj.bind('focusin',function(e){

					// 버튼 랜덤 처리
					if(option.random === true)
					{
						if ( option.key.length )
							random ( keyboard[uid].find('button') ) ;
						else
							for(var i in option.key)
								random ( keyboard[uid].children('[tab="' + i + '"]').children('button') ) ;
					}

					// 다른 레이어 숨김
					for ( var i in keyboard )
						keyboard[i].hide();

					// 노출 위치 조정
					var pos = $obj.position() ;
					pos.position = 'absolute' ;
					switch ( option.position.side )
					{
						case 'top' :
							pos.top -= keyboard[uid].outerHeight() ;
							break ;
						case 'left' :
							pos.left -= keyboard[uid].outerWidth() ;
							break ;
						case 'right' :
							pos.left += $obj.outerWidth() ;
							break ;
						case 'bottom' :
							pos.top += $obj.outerHeight() ;
							break ;
					}
					if ( option.position.offset !== undefined )
					{
						pos.top += isFinite ( option.position.offset.top ) ? option.position.offset.top : 0 ;
						pos.left += isFinite ( option.position.offset.left ) ? option.position.offset.left : 0 ;
					}
					keyboard[uid].css(pos).show() ;

					// 객체 할당
					keyboard[uid].data('input',$obj) ;
				});
			});
		}
	});

})();