/**********************************************************************************
 * hone_view.js
 * 
 * Hone 프레임워크의 뷰와 관련된 부분이 포함되어 있는 스크립트 파일
 * 'Hone.view' 라는 네임스페이스를 사용하고 있음
 * 
 * @author 조만희
 **********************************************************************************/


// jQuery.getScript("js/ext/flexigrid.pack.js");

/*=============================================================
 * 
 * GridView 구현
 * 
 =============================================================*/

Hone.view.GridView = function (model, controller, targetId) {
	this._model = model;
	this._controller = controller;
	this._targetId = targetId;
	
	this._model.getRecordSet(this._targetId).setRecord = function () {
		
	};
};

Hone.view.GridView.headerRedraw = function (recordSetId, columns) {
	$("div.hDivBox th", $("#" + recordSetId).parent().parent()).each(function () {
		var headerAlign = columns[$(this).attr("axis").substr(3)].headerAlign;
		$(this).attr("align", headerAlign);
		$(this).attr("valign", "middle");
		$(">div", $(this)).each(function () {
			$(this).css({
				"text-align" : headerAlign
			});
		});
	});
	
	/*
	 * 헤더와는 관계가 없으나, paging 사용 시 처리를 위하여 기술함.
	 */
	var grid = Hone.view.GridView.getGrid(recordSetId);
	
	var pDiv = $(".pDiv", grid);
	if (pDiv) {
		$(".pcontrol input[type=text]", pDiv).css({
			width : "30px",
			"text-align" : "right"
		});
	}//end if
};

Hone.view.GridView.removeHeaderOverEvent = function (recordSetId) {
	var grid = Hone.view.GridView.getGrid(recordSetId);
	
	var hDiv = $(".hDiv", grid);
	if (hDiv) {
		$("thead tr:first th", hDiv).each(function () {
			// TODO mouseover 이벤트를 제거하면 click 이벤트까지 제거된다.. 이부분 해결해야함!
			$(this).unbind("mouseover");
		});
	}//end if
};

Hone.view.GridView.redraw = function (recordSetId, recordSetMetadata) {
	var grid = Hone.view.GridView.getGrid(recordSetId);
	var recordSet = Hone.model.PageContext.getRecordSet(recordSetId);
	
	/*
	 * 그리드의 헤더 디스플레이 여부를 변경하기 위한 코드 입니다.
	 */
	if (!recordSetMetadata.displayHeader) {
		$(".hDiv", grid).hide();
		$(".cDrag", grid).hide();
	}//end if
	
	/*
	 * 그리드의 바디 디스플레이 여부를 변경하기 위한 코드 입니다.
	 */
	if (!recordSetMetadata.displayBody) {
		$(".bDiv", grid).hide();
		return;
	}//end if
	
	/*
	 * 페이지 관련된 부분이 있다면, 해당 이벤트 및 기타 등등을 변경하기 위한 코드 입니다.
	 * 
	 * 2009.01.07 - Helexis
	 */
	var pDiv = $(".pDiv", grid);
	if (pDiv.size() > 0) {
		Hone.view.GridView.pageNavRedraw(pDiv, recordSet, recordSetMetadata);
	}//end if
	
	var rows = Hone.model.RecordSet.getDataRows(recordSet);
	
	/*
	 * 이하 부분은 inline-edit를 구현하기 위한 코드입니다.
	 * 
	 * 2008.11.25 - Helexis
	 */
	$("table#" + recordSetId + " tbody tr").each(function (recordIdx) {
		var record = recordSet.getRecord(recordIdx);
		var recordId = record.id;
		
		var row = Hone.model.Record.getDataRow(recordSetMetadata.columns, record.cell);
		
		$("td > div", $(this)).each(function (idx) {
			var target = $(this);
			
			/*
			 * 현재 레코드의 셀에 대한 메타 정보를 가져옴.
			 * 
			 * idx의 경우에는 선택된 셀의 인덱스이므로,
			 * axis의 인덱스 형태로 변환하기 위해
			 * 레코드 셋의 컬럼 갯수로 나눈 나머지를 사용함.
			 */
			var axis = $("div.hDiv div.hDivBox table thead tr th:nth-child(" + (idx + 1) + ")", grid).attr("axis");
			
			if (!axis) {
				return this;
			}//end if
			
			var index = axis.substr(3);
			var column = recordSetMetadata.columns[index];
			
			$(target).css({
				"text-align" : column.align
			});
			
			/*
			 * 컬럼 정보가 editable이 false이면 수정하지 않도록 한다.
			 * 
			 * editable이 false이면, 컬럼에 코드가 바인딩된 경우에는,
			 * 코드가 아니라, 코드 값을 보여주도록 수정.
			 * 
			 * 2008.12.05 - Helexis
			 */
			if (!column.editable) {
				
				if (column.code) {
					var codeObj = Hone.model.PageContext.codeContext[column.code + "_id"];
					var codeId = $(target).html();
					var codeValue = codeObj[codeId];
					
					/*
					 * 컬럼 렌더링 우선순위에 따라 렌더링한다.
					 * 
					 * 1. 렌더러가 설정되어 있는 경우, 렌더러를 최우선 적용한다.
					 * 2. 렌더러가 없는 경우, 템플릿을 적용한다.
					 * 3. 렌더러와 템플릿이 없는 경우, 그냥 디스플레이 한다.
					 */
					if (column.renderer) {
						target.html(column.renderer({
							rows : rows, 
							rowIndex : recordIdx,
							row : row, 
							columnId : column.name, 
							columnValue : codeValue
						}));
					} else if (Hone.Utils.hasText(column.template)) {
						Hone.view.GridView.applyTemplate(target, record.cell, recordSetMetadata.columns, column);
					} else {
						$(target).html(codeValue);
					}//end if else
					
				} else {
					
					/*
					 * 컬럼 렌더링 우선순위에 따라 렌더링한다.
					 * 
					 * 1. 렌더러가 설정되어 있는 경우, 렌더러를 최우선 적용한다.
					 * 2. 렌더러가 없는 경우, 템플릿을 적용한다.
					 * 3. 렌더러와 템플릿이 없는 경우, 그냥 디스플레이 한다.
					 */
					if (column.renderer) {
						target.html(column.renderer({
							rows : rows, 
							rowIndex : recordIdx,
							row : row, 
							columnId : column.name, 
							columnValue : row[column.name]
						}));
					} else if (Hone.Utils.hasText(column.template)) {
						Hone.view.GridView.applyTemplate(target, record.cell, recordSetMetadata.columns, column);
					}//end if
					
				}//end if
				
				return this;
			}//end if
			
			switch (column.type) {
			case "date" :
				target.bind("click", function (event) {
					/*
					 * INPUT에 이벤트가 중복적으로 적용되는 것을 막기 위해 사용한다.
					 */
					var targetNodeName = event.target.nodeName;
					if (!targetNodeName || targetNodeName.toUpperCase() == "INPUT") {
						return;
					}//end if
					// TODO mask 적용 검토...
					var inputId = recordId + "_" + axis;
					var input = $("<input type=\"text\" id=\"" + inputId + "\" value=\"" + target.html() + "\" readonly=\"readonly\"/>").css({
						position : "relative",
						left : "-3px",
						width : "100%",
						"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/calendar.png)",
						"background-repeat" : "no-repeat",
						"background-position" : "center right"
					});
					
					input.attr("cal", "Y");
					
					var prevValue = $("<input type=\"text\" value=\"" + target.html() + "\"/>").hide();
					
					target.html(input);
					
					input.bind("click", function () {
						input.attr("cal", "Y");
						input.focus();
					});
					
					input.bind("blur keydown", function (e) {
						if (e.type == "blur" && input.attr("cal") == "Y") {
							return;
						}//end if
						
						if (e.type == "keydown" && e.keyCode != Hone.view.Key.ENTER && e.keyCode != Hone.view.Key.ESC) {
							return;
						}//end if
						var value = input.val();
						target.html(value);
						/*
						 * 수정된 내용을 ServiceContext에도 반영함
						 */
						record.cell[index] = value;
						if (Hone.model.RecordStatus.INSERTED != record.status && value != prevValue.val()) {
							record.status = Hone.model.RecordStatus.UPDATED;
							prevValue.val(value);
							/*
							 * 수정된 레코드는 별도 표시
							 */
							target.parent().css({
								"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/dirty.png)",
								"background-repeat" : "no-repeat",
								"background-position" : "top left"
							});
							
						}//end if
					});
					
					if($.datepick) {//외부DatePicker라이브러리 사용시
						$("#" + inputId).datepick({
							"dateFormat" : "yy-mm-dd",
							"onSelect" : function () {
								input.attr("cal", "N");
								input.focus();
							},
							"onClose" : function () {
								input.attr("cal", "N");
								input.focus();
							}
						});					
					}
					else {
						$("#" + inputId).datepicker($.extend(Hone.view.Form.datepickerInitConfig, {
							"dateFormat" : "yy-mm-dd",
							"onSelect" : function () {
								input.attr("cal", "N");
								input.focus();
							},
							"onClose" : function () {
								input.attr("cal", "N");
								input.focus();
							}
						}));
					}
					
					input.focus();
					
					return false;
				});
				break;
			case "combo" :
				
				/*
				 * 콤보박스 자체를 나타내는 변수
				 */
				var selectList = $("select", target.parent());
				
				/*
				 * 콤보박스가 없을 경우, 생성해서 추가해 준다.
				 */
				if (selectList) {
					selectList = $("<select></select>").css({
						width : "100%"
					});
					
					var comboValueObj = Hone.model.PageContext.codeContext[column.code + "_id"];
					
					var oldId = $(target).html();
					var matchId, matchValue;
					
					$.each(comboValueObj, function (name, objValue) {
						selectList.append("<option value=\"" + name + "\">" + objValue + "</option>");
						if (name == oldId) {
							matchId = name;
							matchValue = objValue;
						}//end if
					});
					
					$(selectList).val(matchId);
					
					target.empty().append(selectList);
					
					var selectInputValue = $("<input type=\"hidden\" value=\"" + matchId + "\"/>");
					target.append(selectInputValue);
					
					$(selectList).change(function (e) {
						var value = $(this).val();
						var prevValue = selectInputValue;
						
						/*
						 * 수정된 내용을 ServiceContext에도 반영함
						 */
						record.cell[index] = value;
						if (Hone.model.RecordStatus.INSERTED != record.status && value != prevValue.val()) {
							record.status = Hone.model.RecordStatus.UPDATED;
							prevValue.val(value);
							/*
							 * 수정된 레코드는 별도 표시
							 */
							target.parent().css({
								"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/dirty.png)",
								"background-repeat" : "no-repeat",
								"background-position" : "top left"
							});
							
						}//end if
					});
				}//end if
				
				break;
			case "multiSelect" :
				// TODO multi-select 가능한 combobox 추가
				break;
			case "radio" :
				// TODO multi-select 가능한 combobox 추가
				
				/*
				 * 콤보박스 자체를 나타내는 변수
				 */
				var radioDiv = $("div:has(input[type=radio])", target.parent());
				
				/*
				 * 콤보박스가 없을 경우, 생성해서 추가해 준다.
				 */
				if (radioDiv) {
					
					radioDiv = $("<div></div>");
					target.empty().append(radioDiv);
					
					var radioInputValue = $("<input type=\"hidden\"/>");
					target.append(radioInputValue);
					
					var comboValueObj = Hone.model.PageContext.codeContext[column.code + "_id"];
					
					var oldId = $(target).html();
					var matchId, matchValue;
					
					$.each(comboValueObj, function (name, objValue) {
						if (name == oldId) {
							matchId = name;
							matchValue = objValue;
						}//end if
						var radio = $("<input type=\"checkbox\" value=\"" + name + "\"" + (name == matchId ? " checked" : "") + "/>");
						radioDiv.append(radio).append(objValue + "<br/>");

						$(radio).click(function (e) {
							var value = $(this).val();
							var prevValue = radioInputValue;
							
							/*
							 * 수정된 내용을 ServiceContext에도 반영함
							 */
							record.cell[index] = value;
							if (Hone.model.RecordStatus.INSERTED != record.status && value != prevValue.val()) {
								record.status = Hone.model.RecordStatus.UPDATED;
								prevValue.val(value);
								/*
								 * 수정된 레코드는 별도 표시
								 */
								target.parent().css({
									"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/dirty.png)",
									"background-repeat" : "no-repeat",
									"background-position" : "top left"
								});
								
							}//end if
						});
						
					});
					
					radioInputValue.val(matchId);
					
				}//end if
				
				break;
			default :
				var prevValue = $("<input type=\"hidden\" value=\"" + target.html() + "\"/>");
			
				/*
				 * 컬럼 렌더링 우선순위에 따라 렌더링한다.
				 * 
				 * 1. 렌더러가 설정되어 있는 경우, 렌더러를 최우선 적용한다.
				 * 2. 렌더러가 없는 경우, 템플릿을 적용한다.
				 * 3. 렌더러와 템플릿이 없는 경우, 그냥 디스플레이 한다.
				 */
				if (column.renderer) {
					target.html(column.renderer({
						rows : rows, 
						rowIndex : recordIdx,
						row : row, 
						columnId : column.name, 
						columnValue : row[column.name]
					}));
				} else if (Hone.Utils.hasText(column.template)) {
					Hone.view.GridView.applyTemplate(target, record.cell, recordSetMetadata.columns, column);
				}//end if
				
				target.bind("click", function (event) {
					/*
					 * INPUT에 이벤트가 중복적으로 적용되는 것을 막기 위해 사용한다.
					 */
					var targetNodeName = event.target.nodeName;
					if (!targetNodeName || targetNodeName.toUpperCase() == "INPUT") {
						return;
					}//end if
					// TODO mask 적용 검토...
					var input = $("<input type=\"text\"/>").css({
						position : "relative",
						left : "-3px",
						width : "100%",
						"text-align" : column.type == "number" ? "right" : "left"
					});
					
//					if (column.mask) {
//						if (column.type == "number") {
//							input.setMask({
//								mask : column.mask,
//								type : "reverse"
//							}).val(prevValue.val());
//						} else {
//							input.setMask(column.mask).val(prevValue.val());
//						}//end if else
//					} else {
//						input.val(prevValue.val());
//					}//end if else
					
					input.val(prevValue.val());
					
					target.html(input);
					
					input.bind("blur keydown", function (e) {
						if (e.type == "keydown" && e.keyCode != Hone.view.Key.ENTER && e.keyCode != Hone.view.Key.ESC) {
							return;
						}//end if
						var maskedValue = input.val();
						var value = maskedValue;
//						var value = column.mask ? input.unmaskedVal() : maskedValue;
						
						/*
						 * validation check.
						 * 값이 올바르지 않으면, 값을 지우고 포커스를 준다.
						 * 
						 * validation check의 우선순위는 다음과 같다.
						 * 
						 *  1) validator 호출
						 *  2) validator가 없을 경우, min & max validation
						 *  3) min & max 도 없을 경우, skip
						 *  
						 * 2008.12.11 - Helexis
						 */
						if (column.validator) {
							if (!column.validator.call(this, value, maskedValue)) {
								input.addClass("invalid");
								alert(column.message);
								input.focus();
								return;
							}//end if
							input.removeClass("invalid");
						} else if (column.min || column.max) {
							if (column.min && column.min > value) {
								input.addClass("invalid");
								alert(column.message);
								input.focus();
								return;
							}//end if
							if (column.max && column.max < value) {
								input.addClass("invalid");
								alert(column.message);
								input.focus();
								return;
							}//end if
							input.removeClass("invalid");
						}//end if
						
						if (column.renderer) {
							target.html(column.renderer({
								rows : rows, 
								rowIndex : recordIdx,
								row : row, 
								columnId : column.name, 
								columnValue : row[column.name],
								maskedValue : maskedValue
							}));
						} else if (Hone.Utils.hasText(column.template)) {
							Hone.view.GridView.applyTemplate(target, record.cell, recordSetMetadata.columns, column);
						} else {
							target.html(maskedValue);
						}//end if
						
						/*
						 * 수정된 내용을 ServiceContext에도 반영함
						 */
						record.cell[index] = value;
						if (Hone.model.RecordStatus.INSERTED != record.status && value != prevValue.val()) {
							record.status = Hone.model.RecordStatus.UPDATED;
							prevValue.val(value);
							/*
							 * 수정된 레코드는 별도 표시
							 */
							target.parent().css({
								"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/dirty.png)",
								"background-repeat" : "no-repeat",
								"background-position" : "top left"
							});
							
						}//end if
					});
					input.focus();
					
					return false;
				});
				break;
			}//end switch case
			
			
			return this;
		});
	});
};

/**
 * 주어진 target에 대해 column의 속성을 분석하여 template을 적용합니다.
 * 
 * @param target {Object} 템플릿 적용 대상 객체
 * @param cell {Array} 레코드 내 셀 정보를 포함하는 배열 객체
 * @param columns {Array} 컬럼 메타 정보를 포함하는 배열
 * @param column {Hone.model.Column} 대상 컬럼 객체
 */
Hone.view.GridView.applyTemplate = function (target, cell, columns, column) {
	/*
	 * jQuery의 template 플러그인을 사용하도록 변경하였음.
	 * 
	 * 2008.12.28 - Helexis
	 */
	var model = {};
	
	$.each(columns, function (i, col) {
		model[col.name] = cell[i];
	});
	
	var template = $.template(column.template);
	
	target.html(template, model);	
};


/**
 * 페이지 네비게이션에 대한 부분을 HONE 요구사항에 맞도록 변경합니다.
 * 
 * @param pageNavDiv {Object} 페이지 네비게이션 디비전
 * @param recordSet {Hone.model.RecordSet} 해당 레코드 셋 객체
 * @param recordSetMetadata {Hone.model.RecrodSetMetadata} 해당 레코드 셋 객체의 메타데이터 객체
 */
Hone.view.GridView.pageNavRedraw = function (pageNavDiv, recordSet, recordSetMetadata) {
	var searchControlId = recordSetMetadata.searchControlId;

	if (!Hone.Utils.hasText(searchControlId)) {
		alert("<hone:table> 태그의 searchControlId 속성 값이 지정되지 않아 페이징 기능을 사용할 수 없습니다.");
		return;
	}//end if
	
	if (!Hone.model.PageContext.getControl(searchControlId)) {
		alert("<hone:table> 태그의 searchControlId 속성 값이 잘못 지정되어 페이징 기능을 사용할 수 없습니다.");
		return;
	}//end if
	
	var pFirst = $(".pFirst", pageNavDiv);
	var pPrev = $(".pPrev", pageNavDiv);
	var pNext = $(".pNext", pageNavDiv);
	var pLast = $(".pLast", pageNavDiv);
	var pReload = $(".pReload", pageNavDiv);
	
	var pControl = $(".pcontrol input[type=text]", pageNavDiv).css({
		width : "30px",
		"text-align" : "right"
	});
	
	/*
	 * 이벤트를 클리어하지 않으면, 지속적으로 이벤트가 쌓여서 한꺼번에 동작한다.
	 * 
	 * 2009.01.07 - Helexis
	 */
	pFirst.unbind();
	pPrev.unbind();
	pNext.unbind();
	pLast.unbind();
	pReload.unbind();
	pControl.unbind();
	
	var totalRecordCount = recordSetMetadata.totalRecordCount;
	var volumePerPage = recordSetMetadata.volumePerPage;
	
	var firstPage = 1;
	var lastPage = Math.floor(totalRecordCount / volumePerPage) + (((totalRecordCount % volumePerPage) == 0) ? 0 : 1);
	
	pFirst.click(function () {
		if (recordSetMetadata.currentPage != 1) {
			recordSetMetadata.currentPage = 1;
			Hone.model.PageContext.getControl(searchControlId).eventHandler.call(this, null, true);
			Hone.model.PageContext.navigation.history = true;
		}//end if
	});
	
	pPrev.click(function () {
		if (recordSetMetadata.currentPage > 1) {
			recordSetMetadata.currentPage--;
			Hone.model.PageContext.getControl(searchControlId).eventHandler.call(this, null, true);
			Hone.model.PageContext.navigation.history = true;
		}//end if
	});
	
	pNext.click(function () {
		if (recordSetMetadata.currentPage < lastPage) {
			recordSetMetadata.currentPage++;
			Hone.model.PageContext.getControl(searchControlId).eventHandler.call(this, null, true);
			Hone.model.PageContext.navigation.history = true;
		}//end if
	});
	
	pLast.click(function () {
		if (recordSetMetadata.currentPage != lastPage) {
			recordSetMetadata.currentPage = lastPage;
			Hone.model.PageContext.getControl(searchControlId).eventHandler.call(this, null, true);
			Hone.model.PageContext.navigation.history = true;
		}//end if
	});
	
	pReload.click(function () {
		Hone.model.PageContext.getControl(searchControlId).eventHandler.call(this, null, true);
		Hone.model.PageContext.navigation.history = true;
	});
	
	pControl.bind("keydown", function (e) {
		if (e.keyCode != Hone.view.Key.ENTER) {
			return;
		}//end if
		var cp = $(this).val();
		var currentPage = new Number(cp);
		if (isNaN(currentPage)) {
			return;
		}//end if
		if (currentPage < 1) {
			currentPage = 1;
		} else if (currentPage > lastPage) {
			currentPage = lastPage;
		}//end if
		recordSetMetadata.currentPage = currentPage.valueOf();
		Hone.model.PageContext.getControl(searchControlId).eventHandler.call(this, null, true);
		Hone.model.PageContext.navigation.history = true;
	});
};

/**
 * 주어진 grid 객체에 대한 grid-ID를 리턴합니다.
 * 
 * @param grid {Object} 그리드 객체
 * @return 주어진 grid 객체에 대한 grid-ID
 */
Hone.view.GridView.getGridId = function (grid) {
	return $(".bDiv table", grid).attr("id");
};

/**
 * 주어진 grid-ID에 대한 그리드 객체를 리턴합니다.
 * 
 * @param gridId {string} 그리드 ID
 * @return 주어진 gridId에 대한 그리드 객체
 */
Hone.view.GridView.getGrid = function (gridId) {
	return $(".flexigrid:has(table#" + gridId + ")");
};

/**
 * 주어진 그리드에 하나의 레코드를 추가합니다.
 * 
 * @param recordSetId {string} 그리드 ID
 * @param record {Hone.model.Record} 레코드 객체
 */
Hone.view.GridView.addRecord = function (recordSetId, record) {
	var grid = Hone.view.GridView.getGrid(recordSetId);
	
	var recordSetMetadata = Hone.model.PageContext.getRecordSet(recordSetId).metadata;
	
	var tempRecord = $("<tr id=\"" + record.id + "\"></tr>");
	
	$("div.hDiv div.hDivBox table thead tr:first th", grid).each(function (idx) {
		
		var index = $(this).attr("axis").substr(3);
		var column = recordSetMetadata.columns[index];
		
		if (column.name == "_checkbox") {
			var td = $("<td align=\"" + $(this).attr("align") + "\" style=\"" + ($(this).attr("style") || "") + "\"></td>");
			
			var div = $("<div style=\"" + ($("div", this).attr("style")) + "\">&nbsp;</div>");
			td.append(div);
			tempRecord.append(td);
			var input = $("<input class=\"itemCheckBox\" type=\"checkbox\"/>");
			div.append(input);
		} else {
			/*
			 * 그리드 헤더 설정을 추가되는 셀에 복사하기
			 */
			var td = $("<td align=\"" + $(this).attr("align") + "\" style=\"" + ($(this).attr("style") || "") + "\"></td>").css({
				"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/dirty.png)",
				"background-repeat" : "no-repeat",
				"background-position" : "top left"
			});
			
			var div = $("<div style=\"" + ($("div", this).attr("style")) + "\">&nbsp;</div>");
			td.append(div);
			tempRecord.append(td);
			
			switch (column.type) {
				case "date" : 
					var input = $("<input type=\"text\" readonly=\"readonly\"/>").css({
						position : "relative",
						left : "-3px",
						width : "100%",
						"background-image" : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/calendar.png)",
						"background-repeat" : "no-repeat",
						"background-position" : "center right"
					});
					input.attr("cal", "Y");
					input.bind("click", function () {
						input.attr("cal", "Y");
						input.focus();
					});
					input.bind("blur keydown", function (e) {
						if (e.type == "blur" && input.attr("cal") == "Y") {
							return;
						}//end if
						
						if (e.type == "keydown" && e.keyCode != Hone.view.Key.ENTER && e.keyCode != Hone.view.Key.ESC) {
							return;
						}//end if
						var value = input.val();
						/*
						 * 수정된 내용을 ServiceContext에도 반영함
						 */
						record.cell[index] = value;
						if (Hone.model.RecordStatus.INSERTED != record.status) {
							record.status = Hone.model.RecordStatus.UPDATED;
						}//end if
					});
					if($.datepick) {//외부DatePicker라이브러리 사용시
						input.datepick({
							"dateFormat" : "yy-mm-dd",
							"onSelect" : function () {
								input.attr("cal", "N");
								input.focus();
							},
							"onClose" : function () {
								input.attr("cal", "N");
								input.focus();
							}
						});					
					}
					else {										
						input.datepicker($.extend(Hone.view.Form.datepickerInitConfig, {
							"dateFormat" : "yy-mm-dd",
							"onSelect" : function () {
								input.attr("cal", "N");
								input.focus();
							},
							"onClose" : function () {
								input.attr("cal", "N");
								input.focus();
							}
						}));
					}
					div.append(input);
					break;
				default : 
					var input = $("<input type=\"text\"/>").css({
						position : "relative",
						left : "-3px",
						width : "100%",
						"text-align" : column.type == "number" ? "right" : "left"
					});
					input.bind("blur keydown click", function (e) {
						if (e.type == "keydown" && e.keyCode != Hone.view.Key.ENTER && e.keyCode != Hone.view.Key.ESC && e.keyCode != Hone.view.Key.TAB) {
							return;
						}//end if
						var value = input.val();
						
						if (column.validator) {
							if (!column.validator.call(this, value, value)) {
								input.addClass("invalid");
								alert(column.message);
								input.focus();
								return;
							}//end if
							input.removeClass("invalid");
						} else if (column.min || column.max) {
							if (column.min && column.min > value) {
								input.addClass("invalid");
								alert(column.message);
								input.focus();
								return;
							}//end if
							if (column.max && column.max < value) {
								input.addClass("invalid");
								alert(column.message);
								input.focus();
								return;
							}//end if
							input.removeClass("invalid");
						}//end if
						
						// 수정된 내용을 ServiceContext에도 반영함
						record.cell[index] = value;
						if (Hone.model.RecordStatus.INSERTED != record.status) {
							record.status = Hone.model.RecordStatus.UPDATED;
						}//end if
					});
					div.append(input);
					break;
			}//end switch case
			
		}//end if else
		
		
	});
	
	if ($("table#" + recordSetId + " tbody").size() > 0) {
		$("table#" + recordSetId + " tbody").append(tempRecord);
	} else {
		$("table#" + recordSetId).append($("<tbody/>").append(tempRecord));
	}//end if else
	
	$("input[type=text]:first", tempRecord).focus();
};

Hone.view.GridView.deleteRecord = function (recordSetId) {
	var grid = Hone.view.GridView.getGrid(recordSetId);
	var selectedRecords = $("tr:has(.itemCheckBox:checked)", grid);
	
	if (selectedRecords.size() <= 0) {
		alert("선택된 레코드가 없습니다.");
		return;
	}//end if
	
	if (confirm("선택한 레코드를 삭제 하시겠습니까?")) {
		$("tr:has(.itemCheckBox:checked)", grid).each(function () {
			/*
			 * <tr> 선택 후, 전체 테이블 내에서의 tr을 찾아서 해당 index로 record를 찾는다.
			 */
			var idx = $(".bDiv table tbody tr", grid).index($(this));
			
			var recordSet = Hone.model.PageContext.getRecordSet(recordSetId);
			var record = recordSet.getRecord(idx);
			
			if (record.status == Hone.model.RecordStatus.INSERTED) {
				$(this).remove();
				recordSet.records.splice(idx, 1);
			} else {
				$(this).hide();
				record.status = Hone.model.RecordStatus.DELETED;
			}//end if
			
		});
	}//end if
};

Hone.view.GridView.save = function (command, grid) {	
};



/*=============================================================
 * 
 * SearchView 구현
 * 
 =============================================================*/

Hone.view.SearchView = function () {
};

Hone.view.SearchView.initConditions = function (searchId) {
	var searchCondition = Hone.model.PageContext.getSearchCondition(searchId);
	$.each(searchCondition.conditions, function (p, v) {
		$("#" + p).val(v.value);
	});
};

Hone.view.SearchView.setAllConditions = function (searchId) {
	var searchCondition = Hone.model.PageContext.getSearchCondition(searchId);
	var flag = true;
	$.each(searchCondition.conditions, function (p, v) {
		switch (v.type) {
			case "range" : 
				var fValue = $("#" + v.fKey);
				if (fValue.size() <= 0) {
					// alert("조회조건 '<hone:key id=\"" + v.key + "\" fromKey=\"" + v.fKey + "\">'에 해당하는 폼 엘리먼트가 정의되지 않았습니다.");
					flag = false;
				} else {
					v.fValue = fValue.val();
				}//end if
				
				var tValue = $("#" + v.tKey);
				if (tValue.size() <= 0) {
					// alert("조회조건 '<hone:key id=\"" + v.key + "\" toKey=\"" + v.tKey + "\">'에 해당하는 폼 엘리먼트가 정의되지 않았습니다.");
					flag = false;
				} else {
					v.tValue = tValue.val();
				}//end if
				break;
			case "multi" :				
				var checkObj = $("input[name="+p+"]");
				var selObj = $("#" + p);
				if (checkObj.size() <= 0 && selObj.size() <= 0) {
					//alert("조회조건 '<hone:key id=\"" + v.key + "\">'에 해당하는 폼 엘리먼트가 정의되지 않았습니다.");
					flag = false;
				} 
				else if(checkObj.size() > 0){//CheckBox 엘리멘트 사용하는 경우				
					var checkedValues = [];
					checkObj.each(function(i){
						if( this.checked ) {							
							checkedValues.push($(this).val());
						}
					});
					v.value = checkedValues;
				}
				else if(selObj.size() > 0){//Select 엘리멘트 사용하는 경우
					var checkedValues = [];
					for(var i=0; i<selObj[0].options.length; i++){
						if (selObj[0].options[i].selected) {
							checkedValues.push(selObj[0].options[i].value);
						}
					}
					v.value = checkedValues;
				}
				else {
					flag = false;
				}
				break;
			default :
				/*
				 * 원래 $("#" + p); 형태로 바인딩했었으나 이럴 경우 아이디값은 무조건 유일해야하며
				 * 서버측에서 request.getParameterrValues와 같은 형태로 받고자 하는건 불가능하게 됨
				 * 따라서 각 HTML 요소에 따라 name으로 조회를 해서  단일과 멀티로 나누어 모두 동작하게 수정함
				 * 2009.05.26 - gloom
				 * form input 가능 요소 : input, select, textarea
				 */								
				var inputObj = $("input[name="+p+"]");
				var selObj = $("select[name="+p+"]");
				var taObj = $("textarea[name="+p+"]");
				if (inputObj.size() <= 0 && selObj.size() <= 0 && taObj.size() <= 0) {
					// alert("조회조건 '<hone:key id=\"" + v.key + "\">'에 해당하는 폼 엘리먼트가 정의되지 않았습니다.");
					flag = false;						
				}
				else if(inputObj.size() > 0) {//input 요소인 경우
					var inputType = inputObj.attr("type");
					switch (inputType) {
						case "checkbox" :
							var inputValues = [];
							inputObj.each(function(i){
								if( this.checked ) {							
									inputValues.push($(this).val());
								}
							});
							v.value = inputValues;
							break;
						case "radio" :
							v.value = $("input[name="+p+"]:checked").val();
							break;							
						default :
							if(inputObj.size() == 1) {
								v.value = inputObj.val();
							}
							else {
								var inputValues = [];
								inputObj.each(function(i){
									if(Hone.Utils.hasText($(this).val())) {
										inputValues.push($(this).val());
									}
								});
								if(inputValues.length > 0) {
									v.value = inputValues;
								}
							}							
														
					}//end switch case
				}
				else if(selObj.size() > 0) {//select 요소인 경우
					v.value = selObj.val();					
				}
				else if(taObj.size() > 0) {//textarea 요소인 경우
					v.value = taObj.val();					
				}	
				else {
					flag = false;
				}
		}//end switch case
	});
	return flag;
};


/*=============================================================
 * 
 * Form Validation 구현
 * 
 =============================================================*/

Hone.view.Form = {
	/**
	 * Hone에서 사용하는 jQuery UI 중 datepicker의 기본 설정 값
	 * 
	 * 
	 * Hone.view.Form.datepickerInitConfig = {
	 * 	hideIfNoPrevNext : false,
	 * 	...
	 * };
	 */
	datepickerInitConfig : {
		/**
		 * 이전/이후 값이 없을 경우 링크 제거 여부
		 */
		hideIfNoPrevNext : true,
		/**
		 * 달이 변경 가능한 콤보 박스 형태로 display 되는지 여부
		 */
		changeMonth: true,
		/**
		 * 년이 변경 가능한 콤보 박스 형태로 display 되는지 여부
		 */
		changeYear: true,
		/**
		 * 콤보 박스에 년이 선택 가능한 기간. 금일 기준으로 이전 100년, 이후 10년
		 */
		yearRange : "-100:+10",
		/**
		 * 버튼에 보여질 title
		 */
		buttonText : "날짜 선택",
		/**
		 * 오늘/선택 버튼이 보여지게 할 것인지 여부
		 */
		showButtonPanel: true
	},
	display : function () {
	
		$(":text,:password,input[type='hidden']").each(function () {		
			var target = $(this);
			var id = target.attr("id");
			var name = target.attr("name");
			
			/*
			 * id나 name 둘 중 하나만 있는 경우, 동일한 값으로 채워준다.
			 * 둘 다 있거나, 둘 다 없는 경우는 무시.
			 */
			if (!Hone.Utils.hasText(id) && Hone.Utils.hasText(name)) {
				target.attr("id", name);
			} else if (Hone.Utils.hasText(id) && !Hone.Utils.hasText(name)) {
				target.attr("name", id);
			}//end if else
			
			var type = target.attr(Hone.view.FormAttribute.TYPE);
			var format = target.attr(Hone.view.FormAttribute.FORMAT);
			var mask = target.attr(Hone.view.FormAttribute.MASK);
			var event = target.attr(Hone.view.FormAttribute.EVENT) || "button";
			var required = target.attr(Hone.view.FormAttribute.REQUIRED) || "false";
			var message = target.attr(Hone.view.FormAttribute.MESSAGE);
			
			var validator = target.attr(Hone.view.FormAttribute.VALIDATOR);
			var min = target.attr(Hone.view.FormAttribute.MIN);
			var max = target.attr(Hone.view.FormAttribute.MAX);

			//hone:type 지정시
			switch (type) {
				case "date" :
					var o = {
						"dateFormat" : "yy-mm-dd",
						"hideIfNoPrevNext" : "true",
						"yearRange" : "-100:+10"
					};
					if(format) {
						o.dateFormat = format;
					}
					
					var convertDate = function (s) {
						s = s.split("-");
						return new Date(parseInt(s[0]), parseInt(s[1]) - 1, parseInt(s[2]));
					};
					if (min) {
						o.minDate = convertDate(min);
					}//end if
					if (max) {
						o.maxDate = convertDate(max);
					}//end if
					if (event == "button") {
						o.showOn = "both";
						o.buttonImage = Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/ext/plugin/grid/calendar.png";
						o.buttonImageOnly = true; 
					}//end if
					if($.datepick) {//외부DatePicker라이브러리 사용시					
						target.datepick(o);	
					}
					else {
						target.datepicker($.extend(Hone.view.Form.datepickerInitConfig, o));										
					}
					break;
				case "number" :
					target.addClass("number");
					var textAlign = target.css("text-align");
					var o = {};
					if ("left" != textAlign) {
						o["type"] = (mask) ? "reverse" : "infinite";
					}//end if
					o["mask"] = mask || "9";
					/*
					 * 숫자일 경우, mask가 역순으로 적용되므로
					 * 실제 입력할 때에는 정상적으로 입력하더라도
					 * 프레임워크 내부에서 처리할 때 역순으로 변환되도록 처리함.
					 * 
					 * 2009.02.18 - Helexis
					 */
					var temp = o["mask"].split("").reverse();
					o["mask"] = temp.join("");
					if (o["mask"].search(/-/) >= 0) {
						o["mask"] = mask.replace(/-/, "");
						o["defaultValue"] = "-000";
					}//end if
					target.setMask(o);
					break;
				default :
					if (mask) {
						target.css({
							"ime-mode" : "disabled"
						});
						target.setMask({
							mask : mask
						});
					}//end if
			}//switch case

			//hone:required 지정시
			if ("true" == required || validator) {
				var msg = message || "필수 입력 항목 입니다.";
				if("true" == required)
					target.addClass("required");
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					useMask : false,
					mask : mask,
					v : function (v, target) {
						if (!v || v.trim().length == 0) {
							return !("true" == required);
						} else {
							if(validator){
								/*
								 * validation 기본 전제는,필수 입력 체크가 아니므로, 값이 없을 경우에는validation 하지 않는다.
								 */
								validator = Hone.view.Form.validator[validator] || eval(validator);
								var msg = message || "입력 값이 잘 못 되었습니다.";

								return validator.call(this, v, target);
							}
							return true;
						}//end if
					}
				});
			}//end if

			if (min && max && type != "date") {
				var msg = message || "입력 값은 최소 '" + min + "' 이상, 최대 '" + max + "' 이하만 가능합니다.";
				
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					useMask : true,
					mask : mask,
					v : function (v) {
						if (!v || v.trim().length == 0) {
							return true;
						}//end if
						v = type == "number" ? parseInt(v) : v;
						if (v < min || v > max) {
							return false;
						} else {
							return true;
						}//end if
					}
				});
			} else if (min && type != "date") {
				var msg = message || "입력 값은 '" + min + "' 이상만 가능합니다.";
				
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					useMask : true,
					mask : mask,
					v : function (v) {
						if (!v || v.trim().length == 0) {
							return true;
						}//end if
						v = type == "number" ? parseInt(v) : v;
						if (v < min) {
							return false;
						} else {
							return true;
						}//end if
					}
				});
			} else if (max && type != "date") {
				var msg = message || "입력 값은 '" + max + "' 이하만 가능합니다.";
				
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					useMask : true,
					mask : mask,
					v : function (v) {
						if (!v || v.trim().length == 0) {
							return true;
						}//end if
						v = type == "number" ? parseInt(v) : v;
						if (v > max) {
							return false;
						} else {
							return true;
						}//end if
					}
				});
			}//end if else
			
		});
		
		$("textarea").each(function () {	
			var target = $(this);
			var id = target.attr("id");
			var name = target.attr("name");
			
			/*
			 * id나 name 둘 중 하나만 있는 경우, 동일한 값으로 채워준다.
			 * 둘 다 있거나, 둘 다 없는 경우는 무시.
			 */
			if (!Hone.Utils.hasText(id) && Hone.Utils.hasText(name)) {
				target.attr("id", name);
			} else if (Hone.Utils.hasText(id) && !Hone.Utils.hasText(name)) {
				target.attr("name", id);
			}//end if else
				
			var required = target.attr(Hone.view.FormAttribute.REQUIRED) || "false";
			var message = target.attr(Hone.view.FormAttribute.MESSAGE);
			var validator = target.attr(Hone.view.FormAttribute.VALIDATOR);
			
			//hone:required 지정시
			if ("true" == required || validator) {
				var msg = message || "필수 입력 항목 입니다.";
				if("true" == required)
					target.addClass("required");
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					v : function (v, target) {
						if (!v || v.trim().length == 0) {
							return !("true" == required);
						} else {
							if(validator){
								/*
								 * validation 기본 전제는,필수 입력 체크가 아니므로, 값이 없을 경우에는validation 하지 않는다.
								 */
								validator = Hone.view.Form.validator[validator] || eval(validator);
								var msg = message || "입력 값이 잘 못 되었습니다.";

								return validator.call(this, v, target);
							}
							return true;
						}//end if
					}
				});
			}//end if		
		});
		
		$("select").each(function () {
			var target = $(this);
			var id = target.attr("id");
			var name = target.attr("name");
			
			/*
			 * id나 name 둘 중 하나만 있는 경우, 동일한 값으로 채워준다.
			 * 둘 다 있거나, 둘 다 없는 경우는 무시.
			 */
			if (!Hone.Utils.hasText(id) && Hone.Utils.hasText(name)) {
				target.attr("id", name);
			} else if (Hone.Utils.hasText(id) && !Hone.Utils.hasText(name)) {
				target.attr("name", id);
			}//end if else
				
			var required = target.attr(Hone.view.FormAttribute.REQUIRED) || "false";
			var message = target.attr(Hone.view.FormAttribute.MESSAGE);
			var validator = target.attr(Hone.view.FormAttribute.VALIDATOR);
			
			//hone:required 지정시
			if ("true" == required || validator) {
				var msg = message || "필수 입력 항목 입니다.";
				if("true" == required)
					target.addClass("required");
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					v : function (v, target) {
						if (!v || v.trim().length == 0) {
							return !("true" == required);
						} else {
							/*
							 * validation 기본 전제는,필수 입력 체크가 아니므로, 값이 없을 경우에는validation 하지 않는다.
							 */
							if(validator){
								validator = Hone.view.Form.validator[validator] || eval(validator);
								var msg = message || "입력 값이 잘 못 되었습니다.";

								return validator.call(this, v, target);
							}
							return true;
						}//end if
					}
				});
			}//end if
		});
		
		$(":file").each(function () {
			var target = $(this);
			var id = target.attr("id");
			var name = target.attr("name");
			
			/*
			 * id나 name 둘 중 하나만 있는 경우, 동일한 값으로 채워준다.
			 * 둘 다 있거나, 둘 다 없는 경우는 무시.
			 */
			if (!Hone.Utils.hasText(id) && Hone.Utils.hasText(name)) {
				target.attr("id", name);
			} else if (Hone.Utils.hasText(id) && !Hone.Utils.hasText(name)) {
				target.attr("name", id);
			}//end if else
				
			var required = target.attr(Hone.view.FormAttribute.REQUIRED) || "false";
			var message = target.attr(Hone.view.FormAttribute.MESSAGE);
			var validator = target.attr(Hone.view.FormAttribute.VALIDATOR);
			
			//hone:required 지정시
			if ("true" == required || validator) {
				var msg = message || "필수 입력 항목 입니다.";
				if("true" == required)
					target.addClass("required");
				Hone.view.Form.makeValidator({
					target : target,
					title : Hone.Message.VALIDATION_DIALOG,
					msg : msg,
					v : function (v, target) {
						if (!v || v.trim().length == 0) {
							return !("true" == required);
						} else {
							if(validator){
								/*
								 * validation 기본 전제는,필수 입력 체크가 아니므로, 값이 없을 경우에는validation 하지 않는다.
								 */
								validator = Hone.view.Form.validator[validator] || eval(validator);
								var msg = message || "입력 값이 잘 못 되었습니다.";

								return validator.call(this, v, target);
							}
							return true;
						}//end if
					}
				});
			}//end if
		});
		/*
		 * Form Submit에 대한 이벤트 캡처 및 validation 로직 추가
		 */
		$("form").submit(function (e) {
			var vs = Hone.model.PageContext.validators;			
			for (var i = 0; i < vs.length; i++) {
				vs[i].call(this);
			}//end for
									
			if ($(".invalid",this).length > 0) {				
				$(".invalid:first",this).focus();
				e.stopImmediatePropagation();
				return false;
			}//end if
			$(":text", this).each(function () {
				var target = $(this);
				if (target.attr(Hone.view.FormAttribute.MASK)) {
					target.val(target.unmaskedVal());
				}//end if
			});
			
			/*
			 * 조회 폼에 대한 처리 추가
			 */
			var target = $(this);
			var type = target.attr(Hone.view.FormAttribute.TYPE);
			if (type == "search") {
				var id = target.attr("id");
				
				if (Hone.model.PageContext.popSearchForm) {
					Hone.view.SearchView.setAllConditions(id);
					var conditions = [];
					$.each(Hone.model.PageContext.getSearchCondition(id).conditions, function (key, value) {
						conditions.push(value);
					});
					var conditionForm;
					var temp = $("input[name=hone.web.bind.condition]", target);
					if (temp.size() > 0) {
						conditionForm = temp;
					} else {
						conditionForm = $("<input type=\"hidden\" name=\"hone.web.bind.condition\" />");
						target.append(conditionForm);
					}//end if else
					conditionForm.val(Hone.Utils.toJSON(conditions));
				}//end if
			}//end if
			
			return true;
		});

	},
	
	/**
	 * Form에 대한 built-in validator 확장지점.
	 * 추후 구현하려면, 이 지점에 구현합니다.
	 */
	validator : {
		/**
		 * 사용자정의 built-in e-mail validator
		 * 
		 * @param value validation 대상 값
		 * @return 검증 성공 여부
		 */
		email : function (value) {
			return /^.+@.+\..+$/.test(value);
		}		 
	},
	/**
	 * 경고 메시지와 관련된 툴팁을 생성하여 리턴함.
	 * 
	 * @param msg {String} 툴팁에 사용할 메시지
	 * @param tag {String} 경고 메시지 이미지를 감쌀 태그
	 * @return {Object} 생성된 툴팁 객체
	 */
	makeExclamation : function (msg, tag) {
		tag = tag || "span";
		var exclamation = $("<" + tag + " title=\"" + msg + "\"> <img src=\"" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/hone/form/exclamation.png\" style=\"vertical-align : middle;\"/> </" + tag + ">");
		exclamation.hide();
		exclamation.cluetip({
			cluetipClass : "jtip",
			splitTitle : "|",
			arrows : false
		});
		return exclamation;
	},
	/**
	 * validator를 생성하여 주어진 target에 설정함.
	 * 
	 * validation 로직 및 display에 따른 로직의 중복을 피하기 위해서
	 * 중복이 되는 코드를 별도의 메소드로 분리하고,
	 * 핵심 비즈니스 로직을 전략에 따라 변경 가능하도록
	 * strategy-pattern을 적용하였음.
	 * 
	 * 옵션 파라미터 객체는 다음과 같은 속성을 포함할 수 있음.
	 * 
	 *  - target {Object} validator 적용 대상 객체
	 *  - title {String} 툴팁의 타이틀
	 *  - msg {String} 툴팁의 메시지
	 *  - useMask {boolean} 마스크 사용여부
	 *  - m {String} 마스크
	 *  - v {Function} validator 함수
	 * 
	 * @param p {Object} validator에 필요한 옵션 객체
	 */
	makeValidator : function (p) {
		p = $.extend({
			useMask : true
		}, p || {});
		var t = p.target;
		var exclamation = Hone.view.Form.makeExclamation(p.title + "|" + p.msg);
		t.parent().append(exclamation);
		
		var validator = function () {
			var val = p.useMask ? ((p.mask) ? t.unmaskedVal() : t.val()) : t.val();
			/*
			 * custom validator 사용시 인자를 넘길수 없는 불편 해소를 위해 
			 * 타겟 Object도 함께 전달해주는 방식으로 변경함
			 * 2009.07.02 - 김윤수
			 */
			if (!p.v.call(this, val, t[0])) {
				t.addClass("invalid");
				exclamation.show();
				/*
				 * IE에서 focus 변경 이벤트 시 blur 이벤트가 동시에 발생하여
				 * invalid할 경우, form 사이를 계속 focus 반복하는 무한루프에 빠짐.
				 * 따라서, focus를 제거함.
				 * 
				 * 2009.01.05 - Helexis
				 */
				// t.focus();
			} else {
				t.removeClass("invalid");
				exclamation.hide();
			}//end if else
		};
		
		Hone.model.PageContext.validators.push(validator);
		
		/*
		 * blur 이벤트에만 vaalidator 체크가 들어있는 경우 
		 * 팝업등을 통해 데이터가 채워지는 경우 invalid 스타일이 사라지지 않는 문제 발생
		 * 우선 submit시에만 validator 체크하는것으로 변경함
		 * 2009.05.26 - gloom
		 */
		//t.bind("blur", validator);
		return validator;
	},
	isValid : function(formObj) {		
		var vs = Hone.model.PageContext.validators;			
		for (var i = 0; i < vs.length; i++) {
			vs[i].call(formObj);
		}//end for
		
		if ($(".invalid",formObj).length > 0) {				
			$(".invalid:first",formObj).focus();
			//e.stopImmediatePropagation();
			return false;
		}//end if			
		$(":text", formObj).each(function () {
			var target = $(formObj);
			if (target.attr(Hone.view.FormAttribute.MASK)) {
				target.val(target.unmaskedVal());
			}//end if
		});
		
		/*
		 * 조회 폼에 대한 처리 추가
		 */
		var target = $(formObj);
		var type = target.attr(Hone.view.FormAttribute.TYPE);
		if (type == "search") {
			var id = target.attr("id");
			
			if (Hone.model.PageContext.popSearchForm) {
				Hone.view.SearchView.setAllConditions(id);
				var conditions = [];
				$.each(Hone.model.PageContext.getSearchCondition(id).conditions, function (key, value) {
					conditions.push(value);
				});
				var conditionForm;
				var temp = $("input[name=hone.web.bind.condition]", target);
				if (temp.size() > 0) {
					conditionForm = temp;
				} else {
					conditionForm = $("<input type=\"hidden\" name=\"hone.web.bind.condition\" />");
					target.append(conditionForm);
				}//end if else
				conditionForm.val(Hone.Utils.toJSON(conditions));
			}//end if
		}//end if
		
		return true;		
	}
};

/**
 * Form Validation에 사용되는 사용자 정의 속성을 기술한 상수 모음 클래스
 */
Hone.view.FormAttribute = {
	TYPE : "hone:type",
	FORMAT : "hone:format",
	MASK : "hone:mask",
	EVENT : "hone:event",
	REQUIRED : "hone:required",
	MESSAGE : "hone:message",
	VALIDATOR : "hone:validator",
	MIN : "hone:min",
	MAX : "hone:max"
};


/*=============================================================
 * 
 * List Display 구현
 * 
 =============================================================*/

/**
 * Form에서 List 타입인 combobox, checkbox, radio 유형의 목록을
 * display 하기 위해 사용되는 클래스
 */
Hone.view.Form.List = {
	display : function (p) {
		p = $.extend({
			displayType : "select",
			separator : ","
		}, p || {});

		switch (p.displayType) {
			case "radio" :
				var tempIdx = 0;
				$.each(p.temp, function (idx, obj) {
					var radio = $("<label><input type=\"radio\" id=\"" + p.id + "_" + tempIdx++ + "\" name=\"" + p.id + "\" value=\"" + obj.id + "\"/> " + obj.value + " </label>");
					if (p.align == "vertical") {
						radio.append("<br/>");
					}//end if
					if (p.eventType && p.eventHandler) {
						radio.bind(p.eventType, p.eventHandler);
					}//end if else
					$("#" + p.id + "_div").append(radio);
				});
				if (p.selected) {
					$("input[name=" + p.id + "]").val([p.selected]);
				}//end if
				if (p.required) {
					var t = $("#" + p.id + "_div").addClass("required").css({
						float : "left"
					});
					var msg = p.message || "필수 입력 항목 입니다.";
					
					var exclamation = $("<div title=\""+Hone.Message.VALIDATION_DIALOG+"|" + msg + "\"> </div>");
					exclamation.css({
						float : "left",
						height : t.height(),
						width : "25px",
						background : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/hone/form/exclamation.png) no-repeat center right"
					});
					exclamation.hide();
					exclamation.cluetip({
						cluetipClass : "jtip",
						splitTitle : "|",
						arrows : false
					});
					
					t.parent().append(exclamation);
					
					var validator = function () {
						var len = $("input[name=" + p.id + "]:checked").length;
						if (len <= 0) {
							t.addClass("invalid");
							exclamation.show();
							t.focus();
						} else {
							t.removeClass("invalid");
							exclamation.hide();
						}//end if else
					};
					
					//$("input[type=checkbox]", t).bind("click", validator);
					
					Hone.model.PageContext.validators.push(validator);
					
					
				}//end if
				break;
			case "checkbox" :
				var tempIdx = 0;
				$.each(p.temp, function (idx, obj) {
					var checkbox = $("<label><input type=\"checkbox\" id=\"" + p.id + "_" + tempIdx++ + "\" name=\"" + p.id + "\" value=\"" + obj.id + "\"/> " + obj.value + " </label>");
					if (p.align == "vertical") {
						checkbox.append("<br/>");
					}//end if
					if (p.eventType && p.eventHandler) {
						checkbox.bind(p.eventType, p.eventHandler);
					}//end if else
					$("#" + p.id + "_div").append(checkbox);
				});
				if (p.selected) {
					var selVal = p.selected.trim();					
					selVal = selVal.substr(1,selVal.length-2);
					var selValArray = new Array();
					var tempArray = selVal.split(p.separator);
					for(i=0; i<tempArray.length; i++) {
						selValArray[i] = tempArray[i].trim();						
					}
					$("input[name=" + p.id + "]").val(selValArray);
				}//end if
				if (p.required) {
					var t = $("#" + p.id + "_div").addClass("required").css({
						float : "left"
					});
					var msg = p.message || "필수 입력 항목 입니다.";
					
					var exclamation = $("<div title=\""+Hone.Message.VALIDATION_DIALOG+"|" + msg + "\"> </div>");
					exclamation.css({
						float : "left",
						height : t.height(),
						width : "25px",
						background : "url(" + Hone.model.PageContext.WEB_RESOURCE_ROOT + "/img/hone/form/exclamation.png) no-repeat center right"
					});
					exclamation.hide();
					exclamation.cluetip({
						cluetipClass : "jtip",
						splitTitle : "|",
						arrows : false
					});
					
					t.parent().append(exclamation);
					
					var validator = function () {
						var len = $("input[name=" + p.id + "]:checked").length;
						if (len <= 0) {
							t.addClass("invalid");
							exclamation.show();
							t.focus();
						} else {
							t.removeClass("invalid");
							exclamation.hide();
						}//end if else
					};
					
					//$("input[type=checkbox]", t).bind("click", validator);
					
					Hone.model.PageContext.validators.push(validator);
				}//end if
				break;
			default : 
				var select = $("<select id=\"" + p.id + "\"></select>");
				$.each(p.temp, function (idx, obj) {
					var option = $("<option value=\"" + obj.id + "\"> " + obj.value + " </option>");
					select.append(option);
				});
				$("#" + p.id + "_div").append(select);
				if (p.css) {
					select.addClass(p.css);
				}//end if
				if (p.selected) {
					$("#" + p.id).val(p.selected);
				}//end if
				if (p.required) {
					select.addClass("required");
				}//end if
				if (p.eventType && p.eventHandler) {
					select.bind(p.eventType, p.eventHandler);
				}//end if else
				break;
		}//end switch case
	}
};



/*=============================================================
 * 
 * Modal-Dialog 구현을 위해 사용된 API
 * 이 부분은 기존의 구현을 위치만 이동하였음.
 * 
 =============================================================*/

/**
 * Dialog를 사용하기 위한 클래스
 */
Hone.view.Dialog = {
	/**
	 * 윈도우창을 띄움
	 */
	openWindow : function(url, target, attrs, id, openEventCheck, expiredays ) {
		if ( openEventCheck == true ) {
			if ( Hone.Utils.getCookie( "openevent_" + id ) == "check" ) {
				return;
			}
		}
		window.open(url, target, attrs);	
	},
	/**
	 * 윈도우 모달창을 띄움
	 */	
	openModalWindow: function(url, title, params, width_px, height_px, scroll, returnHandler, id, openEventCheck, expiredays ) {
		if ( openEventCheck == true ) {
			if ( Hone.Utils.getCookie( "openevent_" + id ) == "check" ) {
				return;
			}
		}

		if (window.showModalDialog) {
			var args = new Array();
			args["_url"] = url;
			args["_title"] = title;
			args["_params"] = params;
			args["_scroll"] = scroll;
			args["_id"] = id;
			args["_openEventCheck"] = openEventCheck;
			args["_expiredays"] = expiredays;
			if(window.dialogArguments){ //상위가 modal인 경우
				args["_parent"] = window.dialogArguments[2]; //상위 window 전달(window 객체는 항상 최상위를 유지)
			}else{
				args["_parent"] = window;
			}
			
			//TODO : 창 위치 조정 기능 추가할것.
			var features = "dialogHeight:"+height_px+"px;dialogWidth:"+width_px+"px;";
			var retValue = window.showModalDialog( Hone.model.PageContext.WEB_RESOURCE_ROOT + "/js/hone/modal.html", args, features);

			if ( returnHandler ) {
				returnHandler.call( this, retValue );
			}
			else {
				return retValue;
			}
		} else {
			attrs = 'width=' + width_px + ',height=' + height_px + ',toolbar=no,directories=no,status=no,menubar=no,scrollbars=' + scroll + ',resizable=no,modal=yes';
			Hone.view.Dialog.openWindow(url, "_blank", attrs, id, openEventCheck, expiredays );
		}
	}
};

/*=============================================================
 * 
 * Key Event 구현
 * 
 =============================================================*/

/**
 * 화면의 Key 이벤트에 대한 Key-Code를 나타내는 상수 클래스
 */
Hone.view.Key = {
	/**
	 * 탭 키 코드
	 */
	TAB : 9,
	/**
	 * 엔터 키 코드
	 */
	ENTER : 13,
	/**
	 * ESC 키 코드
	 */
	ESC : 27
};

/*=============================================================
 * 
 * 메세지
 * 
 =============================================================*/

/**
 * 화면내의 메세지 정의 상수 클래스
 */
Hone.Message = {
	/**
	 * Validation 오류 메세지
	 */
	VALIDATION_DIALOG : "[ Error ]"
};
