﻿/**
 * @type : intro
 * @desc : lafui.js는 프로젝트 전반에 걸쳐 전 시스템에서 공통으로 사용하는 자바 스크립트를 기술한
 * 자바스크립트 파일이다. 빈번히 사용되는 자바스크립트들이 화면마다 반복적으로 개발되지
 * 않도록 미리 정의되어 있어서 lafui.js를 업무화면에 import시키기만 하면 lafui.js에 정의되어
 * 있는 스크립트들에 대해서는 각 개발자가 별도로 개발할 필요가 없다.
 * lafui.js 소스는 2개의 영역으로 구성되었다.
 * <pre>
 *     1. 공통 메세지 영역   : 화면에 사용되는 공통된 메세지들을 선언한 영역
 *     2. 공통 스크립트 영역 : 화면에 사용되는 공통 스크립트들이 기술된 영역
 * </pre>
 * 함수 Naming Rule은 다음과 같다.
 * <pre>
 *     - cf  : common function
 *     - co  : common object
 *     - cov : common object for validation
 * </pre>
 * <font color=red>※주의사항</font>
 * <pre>
 *     - lafui.js를 import하는 html 화면에서는 object id를 지정할 때, 다음에 나열된 id는
 *       지정할 수 없습니다.
 *"framework/hsni/framework/taglib/saymessage/SayMessageTag.java"
 *       coTreeViewImageComnGIDS
 * </pre>
 * @version : 1.0
 * @change  :
 * <pre>
 *     <font color="blue">V1.0</font>
 *     -
  * </pre>
 */

/** 이 부분은 document로 generate되지 않습니다.
 * @JScript 참고자료
 * - isNaN : 다음은 모두 숫자로 본다. - "001", "0", "", null
 * - substr(index[, length]) -> index부터 끝까지 혹은 length갯수만큼.
 * - substring(start, end)  -> start index부터 end index전까지의 string
 * Date 오브젝트 생성자들 - dateObj = new Date()
 *                        - dateObj = new Date(dateVal)
 *                        - dateObj = new Date(year, month, date[, hours[, minutes[, seconds[,ms]]]])
 */
// 화면권한정보 (향휴 Cookie 값으로 대체된다.
var authString="";

//----------------------------- 1. 공통 메세지 -------------------------------//
// -> MessageBiz biz = new MessageBiz();
//    biz.writeMessageForJs(); 로 대체

//----------------------------- 2. 공통 스크립트 -----------------------------//
// Global 변수선언
var GLB_MONTH_IN_YEAR       = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var GLB_SHORT_MONTH_IN_YEAR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var GLB_DAY_IN_WEEK         = ["Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"];
var GLB_SHORT_DAY_IN_WEEK   = ["Sun", "Mon", "Tue", "Wed","Thu", "Fri", "Sat"];
var GLB_DAYS_IN_MONTH       = [31,28,31,30,31,30,31,31,30,31,30,31];

/*********************************************************************************
 *                                  변수 선언
 ********************************************************************************/
var TOOLTIP_ALT   = "use=true;header=false;alt=true;createtime=300;destroytime=10000;topmargin=3;bottommargin=3;leftmargin=3;rightmargin=3;width=250;fontsize=9;color=#5e5e5e;backcolor=#fffaf0;edgecolor=#6495ed;";
var TOOLTIP_NOALT = "use=true;header=false;alt=false;createtime=300;destroytime=10000;topmargin=3;bottommargin=3;leftmargin=3;rightmargin=3;width=250;fontsize=9;color=#5e5e5e;backcolor=#fffaf0;edgecolor=#6495ed;";

/*********************************************************************************
 *                              Filter 변수 선언
 ********************************************************************************/
//var PHONE_FILTER = "[0-9\\-\\(\\)]";
var PHONE_FILTER = "[0-9\\-]";

/*********************************************************************************
 *                              Color 변수 선언
 ********************************************************************************/
var DISABLE_COLOR = "#FEFEF0";

/**
 * @type   : var
 * @access : private
 * @desc   : Key 형태로 변경이 안 되는 내용을 담은 오브젝트를 담는 배열<br>
 *           input 중에서 objType 속성의 값을 "key"로 선언하면 오브젝트가 이 배열에 포함된다.<br>
 *           화면 처리 중에 readOnly 필드로, 배열 전체를 조작하여 사용자가 수정을 하지 못 하게 막거나 풀 수 있다.<br>
 * <br>
 * 화면 -
 * <pre>
 *     &lt;input type="text" id="txt_empNo" objType="key"&gt;
 * </pre>
 */
var key = new Array();

/**
 * @type   : var
 * @access : private
 * @desc   : 변경 가능한 내용을 담은 오브젝트를 담는 배열<br>
 *           input 중에서 objType 속성의 값을 "data"로 선언하면 오브젝트가 이 배열에 포함된다.<br>
 *           화면 처리 중에 일반 입력 필드로, 배열 전체를 조작하여 사용자가 수정을 하지 못 하게 막거나 풀 수 있다.<br>
 * <br>
 * 화면 -
 * <pre>
 *     &lt;input type="text" id="txt_empTel" objType="data"&gt;
 * </pre>
 */
var data = new Array();

/**
 * @type   : var
 * @access : private
 * @desc   : 제어 가능한 버튼을 담는 배열<br>
 *           input 중에서 objType 속성의 값을 "ctrlBtn"으로 선언하면 버튼이 이 배열에 포함된다.<br>
 *           배열 전체를 조작하여 한번에 disable시키거나  enable시킬 수 있다.<br>
 * <br>
 * 화면 -
 * <pre>
 *     &lt;input type="button" id="btn_save" objType="ctrlBtn"&gt;
 * </pre>
 */
var ctrlBtn = new Array();

/**
 * @type   : var
 * @access : private
 * @desc   : 파일 컨트롤 제어용 <br>
 * <br>
 * 화면 -
 * <pre>
 *     &lt;input type="button" id="btn_save" objType="fileBtn"&gt;
 * </pre>
 */
var fileBtn = new Array();

/**
 * @type   : var
 * @access : public
 * @desc   : 신규 정보를 입력하기 위한 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bCreate로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="신규" name="btn_create" objType="bCreate"&gt;
 * </pre>
 */
var bCreate;

/**
 * @type   : var
 * @access : public
 * @desc   : 조회 정보 수정 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bUpdate로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="수정" name="btn_update" objType="bUpdate"&gt;
 * </pre>
 */
var bUpdate;

/**
 * @type   : var
 * @access : public
 * @desc   : 입력 정보 저장 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bSave로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="저장" name="btn_save" objType="bSave"&gt;
 * </pre>
 */
var bSave;
var bCancel;

/**
 * @type   : var
 * @access : public
 * @desc   : 조회 정보 삭제 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bDelete로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="저장" name="btn_delete" objType="bDelete"&gt;
 * </pre>
 */
var bDelete;

/**
 * @type   : var
 * @access : public
 * @desc   : 결재요청을 하기 위한 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bRequest로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="결재" name="btn_request" objType="bRequest"&gt;
 * </pre>
 */
var bRequest;

/**
 * @type   : var
 * @access : public
 * @desc   : 신규 정보를 입력하기 위한 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bCreate2로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="신규" name="btn_create2" objType="bCreate2"&gt;
 * </pre>
 */
var bCreate2;

/**
 * @type   : var
 * @access : public
 * @desc   : 조회 정보 수정 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bUpdate2로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="수정" name="btn_update2" objType="bUpdate2"&gt;
 * </pre>
 */
var bUpdate2;

/**
 * @type   : var
 * @access : public
 * @desc   : 입력 정보 저장 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bSave2로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="저장" name="btn_save2" objType="bSave2"&gt;
 * </pre>
 */
var bSave2;

/**
 * @type   : var
 * @access : public
 * @desc   : 조회 정보 삭제 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bDelete2로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="삭제" name="btn_delete2" objType="bDelete2"&gt;
 * </pre>
 */
var bDelete2;

/**
 * @type   : var
 * @access : public
 * @desc   : 결재요청을 하기 위한 버튼<br>
 *           업무 성격에 따라 버튼을 disable/enable하기 위해 저장한다.<br>
 * <br>
 * 화면 - 아래와 같이 type이 button이고, objType 속성을 bRequest로 선언한 오브젝트를 저장한다.
 * <pre>
 *     &lt;input type="button" value="결재" name="btn_request" objType="bReques2t"&gt;
 * </pre>
 */
var bRequest2;

/**
 * @type   : var
 * @access : public
 * @desc   : popup윈도우 오픈여부<br>
 */
var GLB_SHOWPOPUP = false;

/* ********************************************************************************
 *                                  공통 함수
 * *******************************************************************************/
/**
 * @type   : function
 * @access : public
 * @desc   : Key와 Data 형태의 입력필드를 모두 enable(editable) 상태로 변경한다.
 * <pre>
 *     cfEnableKeyData();
 * </pre>
 * 주로 '신규' 입력 등의 작업에서 모든 입력필드를 입력 가능하게 만들기 위해 사용한다.
 * @author : 송동혁
 */
function cfEnableKeyData() {
	for (var i = 0; i < key.length; i++) {
		cfEnableObj(key[i], true);
	}
	for (var i = 0; i < data.length; i++) {
		cfEnableObj(data[i], true);
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : Key와 Data를 모두 disable(non-editable) 상태로 변경한다.
 * <pre>
 *     cfDisableKeyData();
 * </pre>
 * 주로 '조회'나 '저장' 등의 작업 후에 내용을 입력이나 수정 없이 확인만 가능하도록 하기 위해 사용한다.
 * @author : 송동혁
 */
function cfDisableKeyData() {
	for (var i = 0; i < key.length; i++) {
		cfEnableObj(key[i], false);
	}

	for (var i = 0; i < data.length; i++) {
		cfEnableObj(data[i], false);
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : Key는 disable(non-editable), Data는 enable(editable) 상태로 변경한다.
 * <pre>
 *     cfDisableKey();
 * </pre>
 * 주로 '수정' 버튼을 클릭했을 때, Key 필드를 제외한 나머지 내용만 변경 가능하도록 하기 위해 사용한다.
 * @author : 송동혁
 */
function cfDisableKey() {
	for (var i = 0; i < key.length; i++) {
		cfEnableObj(key[i], false);
	}

	for (var i = 0; i < data.length; i++) {
		cfEnableObj(data[i], true);
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : 모든 버튼을 enable(클릭가능) 상태로 변경한다.
 * <pre>
 *     cfEnableAllBtn();
 * </pre>
 * @author : 송동혁
 */
function cfEnableAllBtn() {
	// ctrlBtn 배열의 모든 버튼을 enable시킨다
	for (var i in ctrlBtn) {
    if (ctrlBtn[i] != null)
    	cfEnableObj(ctrlBtn[i], true);
    }
	
	// 신규
	if (bCreate != null)
    	cfEnableObj(bCreate, true);
	// 수정
	if (bUpdate != null)
    	cfEnableObj(bUpdate, true);
	// 저장
	if (bSave != null)
    	cfEnableObj(bSave, true);
	// 취소
	if (bCancel != null)
    	cfEnableObj(bCancel, true);
	// 삭제
	if (bDelete != null)
    	cfEnableObj(bDelete, true);
	// 결재요청
	if (bRequest != null)
    	cfEnableObj(bRequest, true);


	// 신규
	if (bCreate2 != null)
    	cfEnableObj(bCreate2, true);
	// 수정
	if (bUpdate2 != null)
    	cfEnableObj(bUpdate2, true);
	// 저장
	if (bSave2 != null)
    	cfEnableObj(bSave2, true);
	// 삭제
	if (bDelete2 != null)
    	cfEnableObj(bDelete2, true);
	// 결재요청
	if (bRequest2 != null)
    	cfEnableObj(bRequest2, true);
}


/**
 * @type   : function
 * @access : public
 * @desc   : 모든 버튼을 disable(클릭불가) 상태로 변경한다.
 * <pre>
 *     cfDisableAllBtn();
 * </pre>
 * @author : 송동혁
 */
function cfDisableAllBtn() {
	// ctrlBtn 배열의 모든 버튼을 enable시킨다
	for (var i in ctrlBtn) {
    if (ctrlBtn[i] != null)
    	cfEnableObj(ctrlBtn[i], false);
  }
	
	// 신규
	if (bCreate != null)
    	cfEnableObj(bCreate, false);
	// 수정
	if (bUpdate != null)
    	cfEnableObj(bUpdate, false);
	// 저장
	if (bSave != null)
    	cfEnableObj(bSave, false);
	// 취소
	if (bCancel != null)
    	cfEnableObj(bCancel, false);
	// 삭제
	if (bDelete != null)
    	cfEnableObj(bDelete, false);
	// 결재요청
	if (bRequest != null)
    	cfEnableObj(bRequest, false);

	// 신규
	if (bCreate2 != null)
    	cfEnableObj(bCreate2, false);
	// 수정
	if (bUpdate2 != null)
    	cfEnableObj(bUpdate2, false);
	// 저장
	if (bSave2 != null)
    	cfEnableObj(bSave2, false);
	// 삭제
	if (bDelete2 != null)
    	cfEnableObj(bDelete2, false);
	// 결재요청
	if (bRequest2 != null)
    	cfEnableObj(bRequest2, false);
}

/**
 * @type   : function
 * @access : public
 * @desc   : 지정한 버튼만 disable시키고, 그 외 나머지는 enable 상태로 변경한다.
 * <pre>
 *     cfDisableBtn([bUpdate, bDelete]);
 * </pre>
 * 주로 현재의 상태에서 클릭하면 안 되는 버튼을 disable시키기 위해 사용한다.<br>
 * 예) '신규' 버튼을 클릭했을 때는, '수정'과 '삭제' 버튼을 disable시키고 '저장' 버튼만 enable시킨다.
 * @sig    : btnArr
 * @param  : btnArr  disable 상태로 바꿀 버튼의 배열
 * @author : 송동혁
 */
function cfDisableBtn(btnArr) {
  cfEnableAllBtn();
  
  for (var i in btnArr) {
    if (btnArr[i] != null)
      cfEnableObj(btnArr[i], false);
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : 지정한 버튼만 enable시키고, 그 외 나머지는 disable 상태로 변경한다.
 * <pre>
 *     cfDisableBtn([bUpdate, bDelete]);
 * </pre>
 * 주로 현재의 상태에서 클릭하면 안 되는 버튼을 disable시키기 위해 사용한다.<br>
 * 예) '신규' 버튼을 클릭했을 때는, '수정'과 '삭제' 버튼을 disable시키고 '저장' 버튼만 enable시킨다.
 * @sig    : btnArr
 * @param  : btnArr  disable 상태로 바꿀 버튼의 배열
 * @author : 송동혁
 */
function cfEnableBtn(btnArr) {
  cfDisableAllBtn();
  
  for (var i in btnArr) {
    if (btnArr[i] != null)
      cfEnableObj(btnArr[i], true);
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : 지정한 버튼만 disable시키고, 그 외 나머지는 원래 상태 그대로 있는다.
 * <pre>
 *     cfDisableBtnOnly([bUpdate, bDelete]);
 * </pre>
 * @sig    : btnArr
 * @param  : btnArr  disable 상태로 바꿀 버튼의 배열
 * @author : 송동혁
 */
function cfDisableBtnOnly(btnArr) {
  for (var i in btnArr) {
    if (btnArr[i] != null)
      cfEnableObj(btnArr[i], false);
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : 파일관련 버튼을 Disable 시킨다.
 * <pre>
 *     cfDisableFileBtn();
 * </pre>
 * @sig    : btnArr
 * @param  : btnArr  disable 상태로 바꿀 버튼의 배열
 * @author : 송동혁
 */
function cfDisableFileBtn() {
  for (var i in fileBtn) {
    if (fileBtn[i] != null)
      cfEnableObj(fileBtn[i], false);
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : 파일관련 버튼을 활성화 시킨다.
 * <pre>
 *     cfEnableFileBtn();
 * </pre>
 * @sig    : btnArr
 * @param  : btnArr  disable 상태로 바꿀 버튼의 배열
 * @author : 송동혁
 */
function cfEnableFileBtn() {
  for (var i in fileBtn) {
    if (fileBtn[i] != null)
      cfEnableObj(fileBtn[i], true);
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : 지정한 버튼만 enable시키고, 그 외 나머지는 원래 상태 그대로 있는다.
 * <pre>
 *     cfEnableBtnOnly([bUpdate, bDelete]);
 * </pre>
 * @sig    : btnArr
 * @param  : btnArr  enable 상태로 바꿀 버튼의 배열
 * @author : 송동혁
 */
function cfEnableBtnOnly(btnArr) {
  for (var i in btnArr) {
    if (btnArr[i] != null)
      cfEnableObj(btnArr[i], true);
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : Object를 status 변수에 따라 enable하거나 disable 상태로 변경한다.
 * <pre>
 *     cfEnableObj(txt_empNo, true);
 * </pre>
 * 위와같이 사용했을 경우 txt_empNo라는 오브젝트를 enable 상태로 변경한다.
 * @sig    : ObjectItem, Status
 * @param  : ObjectItem required 상태변경 대상 오브젝트
 * @param  : Status required 목표상태
 * @author :
 */


function cfEnableObjs(ObjectItems, Status) {
	var objs;
	if(ObjectItems.indexOf(",") > 0) {
		objs = ObjectItems.advancedSplit(",", "it");
		for(i=0;i<objs.length;i++){
			cfEnableObj(objs[i], Status);
		}
	} else {
		cfEnableObj(ObjectItems, Status);
	}
}  

function cfEnableObj(ObjectItem, Status) {
	if(typeof(ObjectItem) == "string") {
		ObjectItem = $(ObjectItem); //document.getElementById(ObjectItem);
	}
	
	// 권한이 없으면 enable 수행 안 함
	/*
	if (Status == true && ObjectItem.userAuth && cfCheckAuth(ObjectItem.userAuth) == false) {
		return;
	}
	*/
	
    switch (ObjectItem.tagName) {
        case 'INPUT':
        	var type = ObjectItem.type.toUpperCase();
            if(type == 'FILE' || type == 'BUTTON' || type == 'IMAGE' || type == 'RESET' || type == 'SUBMIT'){
            	if(!isMSIE) ObjectItem.style.color = "#888888";
            	ObjectItem.disabled = (!Status);
            	break;
            } else if(type == 'CHECKBOX' || type == 'RADIO') {
            	var objNm = ObjectItem.name;
            	if(objNm == null) objNm = ObjectItem.id;
            	ObjectItem = document.getElementsByName(objNm);
            	if(ObjectItem.length > 1) {
                	for(i=0;i<ObjectItem.length;i++){
                    	ObjectItem[i].disabled = (!Status);
                	}
            	} else {
                	ObjectItem.disabled = (!Status);
            	}
            	break;
            } else if (type == 'PASSWORD' || type == 'TEXT') {
            	if(Status==false){
            		ObjectItem.setAttribute('readOnly','readOnly');
            		ObjectItem.style.backgroundColor = "#EEFFB6";
            	} else {
            		ObjectItem.removeAttribute('readOnly');
            		ObjectItem.style.backgroundColor = "#FFFFFF";
            	}
            	break;
            }
        case 'SELECT':
            ObjectItem.disabled = (!Status);
            break;
        case 'TEXTAREA':
            ObjectItem.readOnly = (!Status);
            break;
        case 'A':
            ObjectItem.disabled = (!Status);
            break;
        case "IMG":
            ObjectItem.disabled = (!Status);
            break;
        case "TABLE":
            ObjectItem.disabled = (!Status);
            break;
        case "TR":
            ObjectItem.disabled = (!Status);
            break;
        case "TD":
            ObjectItem.disabled = (!Status);
            break;
    }
}  
/* ********************************************************************************
 *                            파일업로드 관련 함수
 * *******************************************************************************/

  var FILE_UPLOAD_DATA_SET_ID  ;
  var CALL_BACK_FUNCTION_NAME =  "CALL_BACK_FUNCTION_NAME";

/**
 * @type   : function
 * @access : public
 * @desc   : 파일을 업로드 한다.
 * <pre>
 *    cfMultiUploadFile( fileMultipartForm, callBackFunctionName )
 * </pre>
 * @sig    : position
 * @param  : fileMultipartForm 업로드 대상 파일을  정의한 MULTI-PART FORM
 * @param  : callBackFunctionName 업로드후에 호출될 자바 스크립트 함수명
 * @author : 이정석
 */
  function cfMultiUploadFile( fileMultipartForm, callbackFunction ) {

	var actionStr =   "/pbf.comm.file.saveMultiFile.laf";
	var condition = "?callbackFunction="
	if ( callbackFunction != null )
		condition += callbackFunction;

    fileMultipartForm.action  =  actionStr + condition ;
	fileMultipartForm.method = "post";
	fileMultipartForm.encType= "multipart/form-data";
    fileMultipartForm.target =  cfGetUploadFrame() ; // fileUpWindow ;
	fileMultipartForm.submit();
	//cfShowBlockPage();
  }
  
  function f_AfterFileUpload() {
  	cfAlertMsg('파일이 첨부되었습니다.');
  }

/**
 * @type   : function
 * @access : public
 * @desc   : 파일을 업로드 한다.
 * <pre>
 *    cfUploadFile( fileMultipartForm )
 * </pre>
 * @sig    : position
 * @param  : fileMultipartForm 업로드 대상 파일을  정의한 MULTI-PART FORM
 * @param  : dataSetID 업로드된 파일 정보 저장에 쓰일 가우스 DataSet
 * @param  : callBackFunctionName 업로드후에 호출될 자바 스크립트 함수명
 * @author : 이정석
 */
  function cfUploadFile( fileMultipartForm, dataSetId, callbackFunction, policy ) {

	var actionStr = "/pbf.comm.file.saveSimpleFile.laf";
	var condition = "?callbackFunction="
	
	if ( callbackFunction != null )
		condition += callbackFunction;

	if ( policy != null )
		condition += "&policy=" + policy;
	
	FILE_UPLOAD_DATA_SET_ID = dataSetId;

    fileMultipartForm.action  =  actionStr + condition;
	fileMultipartForm.method = "post";
	fileMultipartForm.encType= "multipart/form-data";
    fileMultipartForm.target =  cfGetUploadFrame() ; // fileUpWindow ;
	fileMultipartForm.submit();
	cfShowBlockPage();
  }
  
/**
 * @type   : function
 * @access : public
 * @desc   : 파일을 삭제한다.
 * <pre>
 *    cfDeleteFile( fileMultipartForm )
 * </pre>
 * @sig    : position
 * @param  : fileMultipartForm 삭제 파일정보가 정의 된 폼 정보
 * @author : 차종호
 */
  function cfDeleteFile( fileMultipartForm ) {

	var actionStr =   "/pbf.comm.file.deleteFile.laf";

    fileMultipartForm.action  =  actionStr ;
    fileMultipartForm.target =  cfGetUploadFrame() ; // fileUpWindow ;
	fileMultipartForm.submit();
  }

/**
 * @type   : function
 * @access : public
 * @desc   : 파일업로드를 수행할 내부 IFRAME 을 생성 및 반환한다.
 * <pre>
 *    cfGetUploadFrame()
 * </pre>
 * @sig    : position
 * @author : 차종호
 */
  function cfGetUploadFrame() {
  	  var FRAMEWORK_INLINE_FRAME_FOR_FILE_UPLOAD = "FRAMEWORK_INLINE_FRAME_FOR_FILE_UPLOAD";
 	  var uploadInlineFrame = $(FRAMEWORK_INLINE_FRAME_FOR_FILE_UPLOAD); //document.getElementById(FRAMEWORK_INLINE_FRAME_FOR_FILE_UPLOAD) ;
 	  if ( !uploadInlineFrame )  {
 	  	   uploadInlineFrame = document.createElement("<IFRAME MARGINHEIGHT=0 name='" + FRAMEWORK_INLINE_FRAME_FOR_FILE_UPLOAD + "' frameborder='no' scrolling='no' width='0' height='0'></IFRAME>");
        document.body.appendChild(uploadInlineFrame);
 	  }
 	  return  uploadInlineFrame.name  ;
  }

/* ********************************************************************************
 *                            파일 다운로드 관련 함수
 * *******************************************************************************/
 /**
 * @type   : function
 * @access : public
 * @desc   : 파일 다운로드를 위한 FILE URL 정보를 반환한다.
 * <pre>
 *    cfGetFileURL( attachFileNo , fileSeq )
 * </pre>
 * @sig    : position
 * @param  : attachFileNo 다운로드할 첨부파일 번호
 * @param  : fileSeq 다운로드할 첨부파일 Sequence
 * @author : 이정석
 */
  function cfGetFileURL( attachFileNo , fileSeq ) {
  	 return "/pbf.comm.file.fileDownload.laf?atchFileBunchNo="+attachFileNo+"&fileSeq="+fileSeq;
  }
   /**
 * @type   : function
 * @access : public
 * @desc   : 해당 파일을 다운로드 한다.
 * <pre>
 *    cfDownloadFile( attachFileNo , fileSeq )
 * </pre>
 * @sig    : position
 * @param  : attachFileNo 다운로드할 첨부파일 번호
 * @param  : fileSeq 다운로드할 첨부파일 Sequence
 * @author : 차종호
 */
  function cfDownloadFile( attachFileNo , fileSeq ) {
   	var FILE_URL = cfGetFileURL( attachFileNo , fileSeq );
  	var FRAMEWORK_INLINE_FRAME_FOR_FILE_DOWNLOAD = "FRAMEWORK_INLINE_FRAME_FOR_FILE_DOWNLOAD";
 	var downloadInlineFrame = $(FRAMEWORK_INLINE_FRAME_FOR_FILE_UPLOAD); //document.getElementById(FRAMEWORK_INLINE_FRAME_FOR_FILE_DOWNLOAD) ;
 	if ( !downloadInlineFrame )  {
 	  downloadInlineFrame = document.createElement("<IFRAME MARGINHEIGHT=0 name='" + FRAMEWORK_INLINE_FRAME_FOR_FILE_DOWNLOAD + "' src='"+FILE_URL+"' frameborder='no' scrolling='no' width='0' height='0'></IFRAME>");
      document.body.appendChild(downloadInlineFrame);
 	} else {
 	  downloadInlineFrame.src = FILE_URL ;
 	}
  }
  
 function cfTabMenuAdd( fileURL , tabTitle ) {
    top.tabFrame.menu_click(fileURL, tabTitle);
 }

/* ********************************************************************************
 *                              Prototype 함수
 * *******************************************************************************/
/**
 * @type   : prototype_function
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 String 객체에 simpleReplace 메소드를 추가한다. simpleReplace 메소드는
 *           스트링 내에 있는 특정 스트링을 다른 스트링으로 모두 변환한다. String 객체의 replace 메소드와 동일한
 *           기능을 하지만 간단한 스트링의 치환시에 보다 유용하게 사용할 수 있다.
 * <pre>
 *     var str = "abcde"
 *     str = str.simpleReplace("cd", "xx");
 * </pre>
 * 위의 예에서 str는 "abxxe"가 된다.
 * @sig    : oldStr, newStr
 * @param  : oldStr required 바뀌어야 될 기존의 스트링
 * @param  : newStr required 바뀌어질 새로운 스트링
 * @return : replaced String.
 * @author : 임재현
 */
String.prototype.simpleReplace = function(oldStr, newStr) {
	var rStr = oldStr;

	rStr = rStr.replace(/\\/g, "\\\\");
	rStr = rStr.replace(/\^/g, "\\^");
	rStr = rStr.replace(/\$/g, "\\$");
	rStr = rStr.replace(/\*/g, "\\*");
	rStr = rStr.replace(/\+/g, "\\+");
	rStr = rStr.replace(/\?/g, "\\?");
	rStr = rStr.replace(/\./g, "\\.");
	rStr = rStr.replace(/\(/g, "\\(");
	rStr = rStr.replace(/\)/g, "\\)");
	rStr = rStr.replace(/\|/g, "\\|");
	rStr = rStr.replace(/\,/g, "\\,");
	rStr = rStr.replace(/\{/g, "\\{");
	rStr = rStr.replace(/\}/g, "\\}");
	rStr = rStr.replace(/\[/g, "\\[");
	rStr = rStr.replace(/\]/g, "\\]");
	rStr = rStr.replace(/\-/g, "\\-");

  	var re = new RegExp(rStr, "g");
    return this.replace(re, newStr);
}

/**
 * @type   : prototype_function
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 String 객체에 trim 메소드를 추가한다. trim 메소드는 스트링의 앞과 뒤에
 *           있는 white space 를 제거한다.
 * <pre>
 *     var str = " abcde "
 *     str = str.trim();
 * </pre>
 * 위의 예에서 str는 "abede"가 된다.
 * @return : trimed String.
 * @author : 임재현
 */
String.prototype.trim = function() {
    return this.replace(/(^\s*)|(\s*$)/g, "");
}

/**
 * @type   : prototype_function
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 String 객체에 trimAll 메소드를 추가한다. trim 메소드는 스트링 내에
 *           있는 white space 를 모두 제거한다.
 * <pre>
 *     var str = " abc de "
 *     str = str.trimAll();
 * </pre>
 * 위의 예에서 str는 "abcde"가 된다.
 * @return : trimed String.
 * @author : 임재현
 */
String.prototype.trimAll = function() {
    return this.replace(/\s*/g, "");
}

/**
 * @type   : prototype_function
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 String 객체에 cut 메소드를 추가한다. cut 메소드는 스트링의 특정 영역을
 *           잘라낸다.
 * <pre>
 *     var str = "abcde"
 *     str = str.cut(2, 2);
 * </pre>
 * 위의 예에서 str는 "abe"가 된다.
 * @sig    : start, length
 * @param  : start  required start index to cut
 * @param  : length required length to cut
 * @return : cutted String.
 * @author : 임재현
 */
String.prototype.cut = function(start, length) {
    return this.substring(0, start) + this.substr(start + length);
}

/**
 * @type   : prototype_function
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 String 객체에 insert 메소드를 추가한다. insert 메소드는 스트링의 특정 영역에
 *           주어진 스트링을 삽입한다.
 * <pre>
 *     var str = "abcde"
 *     str = str.insert(3, "xyz");
 * </pre>
 * 위의 예에서 str는 "abcxyzde"가 된다.
 * @sig    : start, length
 * @param  : index required 삽입할 위치. 해당 스트링의 index 바로 앞에 삽입된다. index는 0부터 시작.
 * @param  : str   required 삽입할 스트링.
 * @return : inserted String.
 * @author : 임재현
 */
String.prototype.insert = function(index, str) {
    return this.substring(0, index) + str + this.substr(index);
}

/**
 * @type   : prototype_function
 * @access : public
 * @desc   : String.split() 와 같지만 여러가지 옵션을 줄 수 있다.
 * <pre>
 *     option list
 *
 *     - i : ignored split
 *         구분자 문자 앞에 "\" 가 붙어있을 때는 구분자로 인식하지 않는다. ('\' 문자를 string으로 표현할 때는 "\\" 로 해야함)
 *             var str = "abc,de\\,fg"
 *             var strArr = str.advancedSplit(",", "i");
 *         위의 예에서 strArr[0]는 "abc", strArr[1]는 "de,fg"가 된다.
 *
 *     - t : trimed split
 *         split 후에 splited string 들을 trim 시킨다.
 *             var str = "abc,  de,fg"
 *             var strArr = str.advancedSplit(",", "t");
 *         위의 예에서 strArr[0]는 "abc", strArr[1]는 "de", strArr[2]는 "fg"가 된다.
 * </pre>
 * 옵션들은 복합적으로 사용될 수 있다.
 * <pre>
 *     var str = "abc,  de\\,fg"
 *     var strArr = str.advancedSplit(",", "it");
 * </pre>
 * 위의 예에서 strArr[0]는 "abc", strArr[1]는 "de,fg"가 된다.
 * @sig    : delim, options
 * @param  : delim   required delimenator
 * @param  : options required 옵션을 나타내는 문자들을 나열한 스트링
 * @return : splited string array.
 * @author : 임재현
 */
String.prototype.advancedSplit = function(delim, options) {
	if (options == null || options.trim() == "") {
		return this.split(delim);
	}

	var optionI = false;
	var optionT = false;

	options = options.trim().toUpperCase();

	for (var i = 0; i < options.length; i++) {
		if (options.charAt(i) == 'I') {
			optionI = true;
		} else if (options.charAt(i) == 'T') {
			optionT = true;
		}
	}

	var arr = new Array();
	var cnt = 0;
	var startIdx = 0;
	var delimIdx = -1;
	var str = this;
	var temp = 0;

	while ( (delimIdx = (str == null) ?
	         -1 : str.indexOf(delim, startIdx)
	        ) != -1
	      ) {

		if (optionI && str.substr(delimIdx - 1, 2) == '\\' + delim) {
			str = str.cut(delimIdx - 1, 1);
			startIdx = delimIdx;
			continue;
		}

		arr[cnt++] = optionT ? str.substring(0, delimIdx).trim() :
		                       str.substring(0, delimIdx);
		str = str.substr(delimIdx + 1);
		startIdx = 0;
	}

	arr[cnt] = (str == null) ? "" : str;

	return arr;
}

/*
var splitTestStr = "abc  , de\\,  fg , f d".advancedSplit(",", "it");
for (var i = 0; i < splitTestStr.length; i++) {
	alert("'" + splitTestStr[i] + "'");
}
*/

/**
 * @type   : prototype_function
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 String 객체에 toDate 메소드를 추가한다. toDate 메소드는 날짜를 표현하는
 *           스트링 값을 자바스크립트의 내장 객체인 Date 객체로 변환한다.
 * <pre>
 *     var date = "2002-03-05".toDate("YYYY-MM-DD")
 * </pre>
 * 위의 예에서 date 변수는 실제로 2002년 3월 5일을 표현하는 Date 오브젝트를 가르킨다.
 * @sig    : [pattern]
 * @param  : pattern optional Date를 표현하고 있는 현재의 String을 pattern으로 표현한다. (default : YYYYMMDD)
 * <pre>
 *     # syntex
 *
 *       YYYY : year(4자리)
 *       YY   : year(2자리)
 *       MM   : month in year(number)
 *       DD   : day in month
 *       HH   : hour in day (0~23)
 *       mm   : minute in hour
 *       ss   : second in minute
 *       SS   : millisecond in second
 *
 *     <font color=red>주의)</font> YYYY(YY)는 반드시 있어야 한다. YYYY(YY) 만 사용할 경우는 1월 1일을 기준으로
 *     하고 YYYY와 MM 만사용할 경우는 1일을 기준으로 한다.
 * </pre>
 * @return : 변환된 Date Object.
 * @author : 임재현
 */
String.prototype.toDate = function(pattern) {
	var index = -1;
	var year;
	var month;
	var day;
	var hour = 0;
	var min  = 0;
	var sec  = 0;
	var ms   = 0;
	var newDate;

	if (pattern == null) {
		pattern = "YYYYMMDD";
	}

	if ((index = pattern.indexOf("YYYY")) == -1 ) {
		index = pattern.indexOf("YY");
		year = "20" + this.substr(index, 2);
	} else {
		year = this.substr(index, 4);
	}

	if ((index = pattern.indexOf("MM")) != -1 ) {
		month = this.substr(index, 2);
	} else {
		month = 1;
	}

	if ((index = pattern.indexOf("DD")) != -1 ) {
		day = this.substr(index, 2);
	} else {
		day = 1;
	}

	if ((index = pattern.indexOf("HH")) != -1 ) {
		hour = this.substr(index, 2);
	}

	if ((index = pattern.indexOf("mm")) != -1 ) {
		min = this.substr(index, 2);
	}

	if ((index = pattern.indexOf("ss")) != -1 ) {
		sec = this.substr(index, 2);
	}

	if ((index = pattern.indexOf("SS")) != -1 ) {
		ms = this.substr(index, 2);
	}

	newDate = new Date(year, month - 1, day, hour, min, sec, ms);
	if (month > 12) {
		newDate.setFullYear(year + 1);
	} else {
		newDate.setFullYear(year);
	}

	return newDate;
}

/**
 * @type   : prototype_function
 * @object : Date
 * @access : public
 * @desc   : 자바스크립트의 내장 객체인 Date 객체에 format 메소드를 추가한다. format 메소드는 Date 객체가 가진 날짜를
 *           지정된 포멧의 스트링으로 변환한다.
 * <pre>
 *     var dateStr = new Date().format("YYYYMMDD");
 *
 *     참고 : Date 오브젝트 생성자들 - dateObj = new Date()
 *                                   - dateObj = new Date(dateVal)
 *                                   - dateObj = new Date(year, month, date[, hours[, minutes[, seconds[,ms]]]])
 * </pre>
 * 위의 예에서 오늘날짜가 2002년 3월 5일이라면 dateStr의 값은 "20020305"가 된다.
 * default pattern은 "YYYYMMDD"이다.
 * @sig    : [pattern]
 * @param  : pattern optional 변환하고자 하는 패턴 스트링. (default : YYYYMMDD)
 * <pre>
 *     # syntex
 *
 *       YYYY : hour in am/pm (1~12)
 *       MM   : month in year(number)
 *       MON  : month in year(text)  예) "January"
 *       mon  : short month in year(text)  예) "Jan"
 *       DD   : day in month
 *       DAY  : day in week  예) "Sunday"
 *       day  : short day in week  예) "Sun"
 *       hh   : hour in am/pm (1~12)
 *       HH   : hour in day (0~23)
 *       mm   : minute in hour
 *       ss   : second in minute
 *       SS   : millisecond in second
 *       a    : am/pm  예) "AM"
 * </pre>
 * @return : Date를 표현하는 변환된 String.
 * @author : 임재현
 */
Date.prototype.format = function(pattern) {
    var year      = this.getFullYear();
    var month     = this.getMonth() + 1;
    var day       = this.getDate();
    var dayInWeek = this.getDay();
    var hour24    = this.getHours();
    var ampm      = (hour24 < 12) ? "AM" : "PM";
    var hour12    = (hour24 > 12) ? (hour24 - 12) : hour24;
    var min       = this.getMinutes();
    var sec       = this.getSeconds();

    var YYYY = "" + year;
    var YY   = YYYY.substr(2);
    var MM   = (("" + month).length == 1) ? "0" + month : "" + month;
    var MON  = GLB_MONTH_IN_YEAR[month-1];
    var mon  = GLB_SHORT_MONTH_IN_YEAR[month-1];
    var DD   = (("" + day).length == 1) ? "0" + day : "" + day;
    var DAY  = GLB_DAY_IN_WEEK[dayInWeek];
    var day  = GLB_SHORT_DAY_IN_WEEK[dayInWeek];
    var HH   = (("" + hour24).length == 1) ? "0" + hour24 : "" + hour24;
    var hh   = (("" + hour12).length == 1) ? "0" + hour12 : "" + hour12;
    var mm   = (("" + min).length == 1) ? "0" + min : "" + min;
    var ss   = (("" + sec).length == 1) ? "0" + sec : "" + sec;
    var SS   = "" + this.getMilliseconds();

    var dateStr;
    var index = -1;

    if (typeof(pattern) == "undefined") {
    	dateStr = "YYYYMMDD";
    } else {
    	dateStr = pattern;
    }

	dateStr = dateStr.replace(/YYYY/g, YYYY);
	dateStr = dateStr.replace(/YY/g,   YY);
	dateStr = dateStr.replace(/MM/g,   MM);
	dateStr = dateStr.replace(/MON/g,  MON);
	dateStr = dateStr.replace(/mon/g,  mon);
	dateStr = dateStr.replace(/DD/g,   DD);
	dateStr = dateStr.replace(/DAY/g,  DAY);
	dateStr = dateStr.replace(/day/g,  day);
	dateStr = dateStr.replace(/hh/g,   hh);
	dateStr = dateStr.replace(/HH/g,   HH);
	dateStr = dateStr.replace(/mm/g,   mm);
	dateStr = dateStr.replace(/ss/g,   ss);
	dateStr = dateStr.replace(/(\s+)a/g, "$1" + ampm);

	return dateStr;
}

/**
 * @type   : prototype_function
 * @object : Date
 * @access : public
 * @desc   : 현재 Date 객체의 날짜보다 이후날짜를 가진 Date 객체를 리턴한다.
 *           예를 들어 내일 날짜를 얻으려면 다음과 같이 하면 된다.
 * <pre>
 *     var oneDayAfter = new Date.after(0, 0, 1);
 * </pre>
 * @sig    : [years[, months[, dates[, hours[, minutes[, seconds[, mss]]]]]]]
 * @param  : years   optional 이후 년수
 * @param  : months  optional 이후 월수
 * @param  : dates   optional 이후 일수
 * @param  : hours   optional 이후 시간수
 * @param  : minutes optional 이후 분수
 * @param  : seconds optional 이후 초수
 * @param  : mss     optional 이후 밀리초수
 * @return : 이후날짜를 표현하는 Date 객체
 * @author : 임재현
 */
Date.prototype.after = function(years, months, dates, hours, miniutes, seconds, mss) {
    if (years == null)    years    = 0;
    if (months == null)   months   = 0;
    if (dates == null)    dates    = 0;
    if (hours == null)    hours    = 0;
    if (miniutes == null) miniutes = 0;
    if (seconds == null)  seconds  = 0;
    if (mss == null)      mss      = 0;

    //alert(this.getFullYear() + ":" + years + "^" +this.getMonth() + ":" + months +"^" +this.getDate() + ":" + dates)
	return new Date(parseInt(this.getFullYear()) + parseInt(years),
	                parseInt(this.getMonth()) + parseInt(months),
	                parseInt(this.getDate()) + parseInt(dates),
	                this.getHours() + hours,
	                this.getMinutes() + miniutes,
	                this.getSeconds() + seconds,
	                this.getMilliseconds() + mss
	               );
}
// alert(new Date().after(1, 1, 1, 1, 1, 1).format("YYYYMMDD HHmmss"));

/**
 * @type   : prototype_function
 * @object : Date
 * @access : public
 * @desc   : 현재 Date 객체의 날짜보다 이전날짜를 가진 Date 객체를 리턴한다.
 *           예를 들어 어제 날짜를 얻으려면 다음과 같이 하면 된다.
 * <pre>
 *     var oneDayBefore = new Date.before(0, 0, 1);
 * </pre>
 * @sig    : [years[, months[, dates[, hours[, minutes[, seconds[, mss]]]]]]]
 * @param  : years   optional 이전으로 돌아갈 년수
 * @param  : months  optional 이전으로 돌아갈 월수
 * @param  : dates   optional 이전으로 돌아갈 일수
 * @param  : hours   optional 이전으로 돌아갈 시간수
 * @param  : minutes optional 이전으로 돌아갈 분수
 * @param  : seconds optional 이전으로 돌아갈 초수
 * @param  : mss     optional 이전으로 돌아갈 밀리초수
 * @return : 이전날짜를 표현하는 Date 객체
 * @author : 임재현
 */
Date.prototype.before = function(years, months, dates, hours, miniutes, seconds, mss) {
    if (years == null)    years    = 0;
    if (months == null)   months   = 0;
    if (dates == null)    dates    = 0;
    if (hours == null)    hours    = 0;
    if (miniutes == null) miniutes = 0;
    if (seconds == null)  seconds  = 0;
    if (mss == null)      mss      = 0;

	return new Date(parseInt(this.getFullYear()) - parseInt(years),
	                parseInt(this.getMonth()) - parseInt(months),
	                parseInt(this.getDate()) - parseInt(dates),
	                this.getHours() - hours,
	                this.getMinutes() - miniutes,
	                this.getSeconds() - seconds,
	                this.getMilliseconds() - mss
	               );
}
//alert(new Date().before(1, 1, 1, 1, 1, 1).format("YYYYMMDD HHmmss"));

/**
 * @type   : function
 * @access : public
 * @desc   : 자바스크립트의 숫자 앞에 지정된 자릿수만큼 zero character 를 삽입한다.
 * <pre>
 *     cfDigitalNumber(5, 123);
 * </pre>
 * 위와같이 사용했을 경우 "00123" 이라는 String을 리턴한다.
 * @sig    : length, number
 * @param  : length required 숫자를 표현하는 길이
 * @param  : number required 변환될 숫자
 * @return : 변환된 스트링
 * @author : 임재현
 */
function cfDigitalNumber(length, number) {
	var numStr = number + "";
	var zeroChars = "";

	for (var i = 0; i < (length - number.length); i++) {
		zeroChars = zeroChars + "0";
	}

	return (zeroChars + numStr);
}

/**
 * @type   : function
 * @access : public
 * @desc   : element를 disable 시킨다.
 * <pre>
 *     cfDisable(oRegistBtn);
 * </pre>
 * @sig    : oElement
 * @param  : oElement required disable 하고자 하는 element
 * @author : 임재현
 */
function cfDisable(obj) {
	if (cfIsNull(obj)) {
		return;
	}

	if (obj.length != null) {
		for (var i = 0; i < obj.length; i++) {
			cfProcessChildElement(obj[i], cfDisableElement);
		}
	} else {
		cfProcessChildElement(obj, cfDisableElement);
	}
}

/*
	- <input type=text> 의 경우 disable시에 글자색을 지정할 수 없다. 따라서 disable 대신 readOnly로 바꾼다.
	- <input type=checkbox> 의 경우 ReadOnly가 없으며 disabled를 true로 할 경우 box내부 색깔을 바꿀 수가 없다. box 색바꿈 포기.
*/
function cfDisableElement(oElement, argArr) {
	switch (cfGetElementType(oElement)) {
		case "BUTTON" :
			oElement.disabled = true;

			if (oElement.className != null &&
			    (oElement.className.substr(0, 7) == "btnGrid" ||
			     oElement.className.substr(0, 7) == "btnIcon" ) &&
			   	oElement.currentStyle.backgroundImage.substr(oElement.currentStyle.backgroundImage.length - 15, 9) != "_disabled"
			   ) {
			   	oElement.style.backgroundImage =
			   		oElement.currentStyle.backgroundImage.substr(0, oElement.currentStyle.backgroundImage.length - 6) + "_disabled" +
			   		oElement.currentStyle.backgroundImage.substr(oElement.currentStyle.backgroundImage.length - 6);
			}

			break;

		case "CHECKBOX" :
		case "RADIO" :
		case "RESET" :
		case "SELECT" :
		case "SUBMIT" :
			oElement.disabled = true;
			break;

		case "FILE" :
		case "PASSWORD" :
		case "TEXT" :
		case "TEXTAREA" :
			oElement.readOnly = true;
			//oElement.style.color = "#454648";  // 일반 텍스트 기본색상
			oElement.style.color = "#808080";    // EMEdit Disable시 색상과 동일.
			oElement.style.backgroundColor = "#DEDEDE";  // HTML 오브젝트의 기본 disabled color.
			                                             // Text는 background가 하얀색으로 남는다. 따라서 스타일로 임의로 지정하였음.
			break;

		default :
			break;
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : element를 enable 시킨다.
 * <pre>
 *     cfEnable(oRegistBtn);
 * </pre>
 * @sig    : oElement
 * @param  : oElement required enable 하고자 하는 element 혹은 element array
 * @author : 임재현
 */
function cfEnable(obj) {
	if (cfIsNull(obj)) {
		return;
	}

	if (obj.length != null) {
		for (var i = 0; i < obj.length; i++) {
			cfProcessChildElement(obj[i], cfEnableElement);
		}
	} else {
		cfProcessChildElement(obj, cfEnableElement);
	}
}

function cfEnableElement(oElement, argArr) {
	switch (cfGetElementType(oElement)) {
		case "BUTTON" :
			oElement.disabled = false;

			if (oElement.className != null &&
			    (oElement.className.substr(0, 7) == "btnGrid" ||
			     oElement.className.substr(0, 7) == "btnIcon"
			    )
			   ) {
			   	if (oElement.currentStyle.backgroundImage.substr(oElement.currentStyle.backgroundImage.length - 15, 9) == "_disabled") {
				   	oElement.style.backgroundImage =
				   		oElement.currentStyle.backgroundImage.cut(oElement.currentStyle.backgroundImage.length - 15, 9);
				}
			}

			break;

		case "CHECKBOX" :
		case "RADIO" :
		case "RESET" :
		case "SELECT" :
		case "SUBMIT" :
			oElement.disabled = false;
			break;

		case "FILE" :
		case "PASSWORD" :
		case "TEXT" :
		case "TEXTAREA" :
			oElement.readOnly = false;
			oElement.style.color = "#454648";
			oElement.style.backgroundColor = "";
			break;

		default :
			break;
	}
}

function findPos(obj) {
	var curleft = curtop = curwidth = curheight = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft;
		curtop = obj.offsetTop;
		curwidth = obj.offsetWidth;
		curheight = obj.offsetHeight;
		
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		}
	}
	return [curleft,curtop,curwidth,curheight];
}

/**
 * @type   : function
 * @access : public
 * @desc   : 스트링의 자릿수를 Byte 단위로 환산하여 알려준다. 영문, 숫자는 1Byte이고 한글은 2Byte이다.(자/모 중에 하나만 있는 글자도 2Byte이다.)
 * @sig    : value
 * @param  : value required 스트링
 * @return : 스트링의 길이
 * @author : 차종호
 */
function cfGetByteLength(value){
	var byteLength = 0;

	if (cfIsNull(value)) {
		return 0;
	}
	var c;
	for(var i = 0; i < value.length; i++) {
		c = escape(value.charAt(i));
		// alert(value.charAt(i) + "/" + c);
		if (c.length == 1) {		// when English then 1byte
			byteLength ++;
		} else if (c.indexOf("%u") != -1)  {	// when Korean then 2byte
			// if charset = utf8 then length = 3
			//byteLength += 2;
			byteLength += 3;	// utf-8 : 3
		} else if (c.indexOf("%") != -1)  {	// else 3byte
			byteLength += c.length/3;
		}
	}
	return byteLength;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 공통메세지에 정의된 메세지를 리턴한다.
 * <pre>
 * // 공통 메세지 영역
 * var MSG_NO_CHANGED        = "변경된 사항이 없습니다.";
 * var MSG_SUCCESS_LOGIN     = "@님 안녕하세요?";
 * ...
 * var message1 = cfGetMsg(MSG_NO_CHANGED);
 * var message2 = cfGetMsg(MSG_SUCCESS_LOGIN, ["홍길동"]);
 * </pre>
 * 위의 예에서 message2 의 값은 "홍길동님 안녕하세요?" 가 된다.
 * @sig    : msgId[, paramArray]
 * @param  : msgId      required lafui.js의 공통 메세지 영역에 선언된 메세지 ID
 * @param  : paramArray optional 메세지에서 '@' 문자와 치환될 데이터 Array. Array의 index와
 *           메세지 내의 '@' 문자의 순서가 일치한다. 치환될 데이터는 [] 사이에 콤마를 구분자로 하여 기술하면 Array 로 인식된다.
 * @return : 치환된 메세지 스트링
 * @author : 임재현
 */
function cfGetMsg(msgId, paramArray) {
	return new coMessage().getMsg(msgId, paramArray);
}
//
///**
// * @type   : function
// * @access : public
// * @desc   : 사용자가 누른 key가 enter key 인지 여부를 알려준다.
// * <pre>
// *     function fncOnKeyPress() {
// *         ...
// *         if (cfIsEnterKey()) {
// *             ...
// *         }
// *     }
// *     ...
// *     &lt;input type="text" onkeypress="fncOnKeyPress()"&gt;
// * </pre>
// * @return : enter key 여부
// * @author : 임재현
// */
//function cfIsEnterKey() {
//	if (event.keyCode == 13) {
//		return true;
//	}
//
//	return false;
//}

/**
 * @type   : function
 * @access : public
 * @desc   : 값이 null 이거나 white space 문자로만 이루어진 경우 true를 리턴한다.
 * <pre>
 *     cfIsNull("  ");
 * </pre>
 * 위와같이 사용했을 경우 true를 리턴한다.
 * @sig    : value
 * @param  : value required 입력값
 * @return : boolean. null(혹은 white space) 여부
 * @author : 임재현
 */
function cfIsNull(value) {
	if (value == null ||
	    (typeof(value) == "string" && value.trim() == "")
	   ) {
		return true;
	}

	return false;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 값이 지정된 그룹내에 존재하는지를 알려준다.
 * <pre>
 *     cfIsIn(3, [1, 2, 3]);                     // -> true
 *     cfIsIn(3, [4, 5, 6]);                     // -> false
 *     cfIsIn('F', ['A', 'B', 'F']);             // -> true
 *     cfIsIn('F', ['A', 'B', 'C']);             // -> false
 *     cfIsIn("lim", ["lim", "kim", "park"]);    // -> true
 *     cfIsIn("lim", ["lee", "kim", "park"]);    // -> false
 * </pre>
 * @sig    : value, valueArray
 * @param  : value      required 비교하고 싶은 값
 * @param  : valueArray required 비교하고 싶은 값에 대한 비교 대상이 되는 값들의 집합. array 타입이며 array
 *           내의 각 element의 데이터 타입은 value 파라미터의 타입과 일치해야 한다.
 * @return : boolean. 값이 지정된 그룹내에 존재하는지 여부.
 * @author : 임재현
 */
function cfIsIn(value, valueArray) {
	for (var i = 0; i < valueArray.length; i++) {
		if (value == valueArray[i]) {
			return true;
		}
	}

	return false;
}

/**
 * @type   : function
 * @access : public
 * @desc   : window.open으로 서브창을 띄울 때 서브창의 위치를 간단하게 지정할 수 있다.
 * @sig    : width, height, position, [sURL] [, sName] [, sFeatures] [, bReplace]
 * @param  : width - 서브창의 넓이
 * @param  : height - 서브창의 높이
 * @param  : position  - 서브창의 위치 (default : 5) <br><br>
 * <table border='1'>
 *     <tr>
 *         <td>1</td>
 *         <td>2</td>
 *         <td>3</td>
 *     </tr>
 *     <tr>
 *         <td>4</td>
 *         <td>5</td>
 *         <td>6</td>
 *     </tr>
 *     <tr>
 *         <td>7</td>
 *         <td>8</td>
 *         <td>9</td>
 *     </tr>
 * </table>
 * @param  : sURL      required window.open의 sURL 파라미터와 동일
 * @param  : sName     required window.open의 sName 파라미터와 동일
 * @param  : sFeatures required window.open의 sFeatures 파라미터와 동일
 * @param  : bReplace  required window.open의 bReplace 파라미터와 동일
 * @author : 임재현
 */
function cfOpen(width, height, position, sURL, sName, sFeatures, bReplace) {
	var left = 0;
	var top = 0;


	var featureNames  = ["status", "menubar", "toolbar"];
	var featureValues = ["no", "no", "no"];
	var featureTypes  = ["boolean", "boolean", "boolean"];

	if (sFeatures != null) {
		cfParseFeature(sFeatures, featureNames, featureValues, featureTypes);
	}

	var status = featureValues[0];
	var menubar = featureValues[1];
	var toolbar = featureValues[2];

	if (width != null && height != null) {
		width = width + 10; // window의 좌우 border 5px씩 감안.
		height = height + 29; // titlebar는 기본으로 감안.

		if (status) {
			height = height + 20;
		}

		if (menubar) {
			height = height + 48;
		}

		if (toolbar) {
			height = height + 27;
		}

		switch (position) {
			case 1 :
				left = 0;
				top = 0;
				break;

			case 2 :
				left = (screen.availWidth - width) / 2;
				top = 0;
				break;

			case 3 :
				left = screen.availWidth - width;
				top = 0;
				break;

			case 4 :
				left = 0;
				top = (screen.availHeight - height) / 2;
				break;

			case 5 :
				left = (screen.availWidth - width) / 2;
				top = (screen.availHeight - height) / 2;
				break;

			case 6 :
				left = screen.availWidth - width;
				top = (screen.availHeight - height) / 2;
				break;

			case 7 :
				left = 0;
				top = screen.availHeight - height;
				break;

			case 8 :
				left = (screen.availWidth - width) / 2;
				top = screen.availHeight - height;
				break;

			case 9 :
				left = screen.availWidth - width;
				top = screen.availHeight - height;
				break;

			default :
				left = (screen.availWidth - width) / 2;
				top = (screen.availHeight - height) / 2;
				break;
		}

		if (cfIsNull(sFeatures)) {
			sFeatures = sFeatures + "left=" + left + ",top=" + top;
		} else {
			sFeatures = sFeatures + ",left=" + left + ",top=" + top;
		}
	}

	window.open(sURL, sName, sFeatures, bReplace);
}

/**
 * @type   : function
 * @access : private
 * @desc   : features 스트링을 파싱하여 array에 셋팅하는 내부 함수
 * @sig    : features, fNameArray, fValueArray, fTypeArray
 * @param  : features    required features를 표현한 스트링
 * @param  : fNameArray  required 추출해야 할 feature의 이름에 대한 array
 * @param  : fValueArray required 추출해야 할 feature의 기본값에 대한 array
 * @param  : fTypeArray  required 추출해야 할 feature의 데이터타입에 대한 array
 * @author : 임재현
 */
function cfParseFeature(features, fNameArray, fValueArray, fTypeArray) {
	if (features == null) {
		return;
	}

	var featureArray = features.split(",");
	var featurePair;

	for (var i = 0; i < featureArray.length; i++) {
		featurePair = featureArray[i].trim().split("=");

		for (var j = 0; j < fNameArray.length; j++) {
			if (featurePair[0] == fNameArray[j]) {
				switch (fTypeArray[j]) {
					case "string" :
						fValueArray[j] = featurePair[1];
						break;
					case "number" :
						fValueArray[j] = Number(featurePair[1]);
						break;
					case "boolean" :
						if (featurePair[1].toUpperCase() == "YES" || featurePair[1].toUpperCase() == "TRUE" || featurePair[1] == "1") {
							fValueArray[j] = true;
						} else {
							fValueArray[j] = false;
						}
						break;
				}
			}
		}
	}
}


/**
 * @type   : function
 * @access : private
 * @desc   : html상에서 parent element에 대한 child element 들에 대해 일괄적으로 동일한 함수를 수행시킨다.
 * @sig    : parentObj, fnc[, argArr]
 * @param  : parentObj required parent object
 * @param  : fnc required 각 input element 마다 수행시킬 함수 포인터
 * @param  : argArr optional 함수에 전달할 파라미터. 이 메소드를 통해 호출되는 함수는 무조건 두 개의 파라미터로만
 *           구성되어야 한다. 하나는 처리하려는 element, 나머지 하나는 처리시 필요한 파라미터들의 array 객체이다.
 * @author : 임재현
 */
function cfProcessChildElement(parentObj, fnc, argArr) {
	fnc(parentObj, argArr);

	if (parentObj.all == null) {
		return;
	}

	for (var i = 0; i < parentObj.all.length; i++) {
		fnc(parentObj.all[i], argArr);
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : 공통메세지에 정의된 메세지를 prompt box 로 보여준다. 만약 패스워드를 입력받는 prompt box를
 *           띄우면서 공통메세지에 정의된 메세지를 보여주고 싶다면 다음과 같이 하면 된다.
 * <pre>
 *     // 공통메세지 영역
 *     var MSG_INPUT_PASSWORD = "@님, 패스워드를 입력하십시오.";
 *     ...
 *     cfPromptMsg(MSG_INPUT_PASSWORD, ["홍길동"], "입력하세요.");
 * </pre>
 * @sig    : msgId[, paramArray[, defaultVal]]
 * @param  : msgId      required lafui.js의 공통 메세지 영역에 선언된 메세지 ID
 * @param  : paramArray optional 메세지에서 '@' 문자와 치환될 스트링 Array. (Array의 index와
 *           메세지 내의 '@' 문자의 순서가 일치한다.)
 * @param  : defaultVal optional prompt box 의 입력필드에 보여줄 기본값.
 * @return : 입력받은 String 혹은 Integer 타입의 패스워드 데이터
 * @author : 임재현
 */
function cfPromptMsg(msgId, paramArray, defaultVal) {
	if (cfIsNull(msgId)) {
		alert("존재하지 않는 메시지입니다.");
		return null;
	}

	return prompt(new coMessage().getMsg(msgId, paramArray), defaultVal);
}

/**
 * @type   : function
 * @access : public
 * @desc   : parent object (Div, Table, FieldSet 태그)에 속한 모든 child object의 값을 초기화한다.
 * @sig    : parentObj[, iniVal]
 * @param  : parentObj required 초기화할 부모 오브젝트
 * @param  : iniVal    optional 초기값
 * @author : 김수호
 */
function cfReset(parentObj, iniVal) {
	cfProcessChildElement(parentObj, cfIniObject);
}

/**
 * @type   : function
 * @access : public
 * @desc   : 해당 화면에 대한 도움말 창을 띄운다.
 * @sig    : helpId
 * @param  : helpId required 도움말 화면의 아이디
 * @author : 송동혁
 */
function cfShowHelp(helpId) {
	alert("도움말 화면을 준비중입니다.");
}

/**
 * @type   : function
 * @access : public
 * @desc   : 해당 span에 그리드의 총건수를 표시한다.
 * @sig    : spanId, totalRows
 * @param  : spanId required 건수를 표시할 span
 * @param  : totalRows required 총건수
 * @author : 송동혁
 */
function cfShowTotalRows(spanId, totalRows) {
	totalRows = "" + totalRows;

	if (totalRows.length > 3) {
		totalRows = totalRows.substr(0, totalRows.length-3) + "," + totalRows.substr(totalRows.length-3);
	}

	spanId.innerHTML = "총 " + totalRows + "건";
}

/**
 * @type   : function
 * @access : public
 * @desc   : 화면상의 입력과 관련된 오브젝트에 대한 유효성 검사를 실시한다. 유효성 검사를 받는 오브젝트들은 "alt" 속성값을 설정해야 한다. <br><br>
 *           - 해당 오브젝트에 대한 child 오브젝트들까지도 검사한다. 예를들어, 검사받을 오브젝트들을 &lt;div&gt; 태그로 감싸고
 *             &lt;div&gt; 태그의 id를 파라미터로 준다면 &lt;div&gt; 태그내의 모든 오브젝트들이 자동으로 검사받게 된다. 또,
 *             &lt;table&gt;안에 입력필드들은 &lt;table&gt;의 id를 파라미터로 주면 된다.<br><br>
 *           - 입력값의 앞과 뒤의 공백은 유효성 검사를 하면서 자동으로 trim된다.
 * <pre>
 *    function fncSave() {
 *        if (<b>cfValidate([oRecevInfo])</b>) {
 *            oDomRegiRecevGTR.post();
 *        }
 *    }
 *    <input type="text" name="userId" alt="접수번호:yes:length=6">
 * </pre>
 * alt 속성값은 정해진 형식에 맞게 작성되어야 하는데 형식은 오브젝트의 종류에 따라 두 가지로 나뉜다.<br>
 * <pre>
 *    1. 일반 오브젝트의 경우 (예1 참조)
 *        "item_name:필수여부:valid_expression"
 *
 *        - "item_name"에는 해당 항목에 대한 이름을 기술한다.
 *        - "필수여부"에는 해당 오브젝트가 필수 항목인지 여부를 yes|true|1 혹은 no|false|0 타입으로 기술한다.
 *        - "valid_expression" 은  cfValidateValue 함수의 설명을 참조하기 바란다.
 *        - 필수항목인지만 체크하려면 "valid_expression" 을 표기하지 않으면 된다.
 *          예)
 *          <input type="text" name="userId" alt="배달일자:yes"</b>&gt;
 *              ...
 *        - alt 내에 임의로 ",", ":", "=", "&", 문자를 사용하고자 한다면 "\\,", "\\:", "\\=", "\\&" 라고 표기해야 한다.<br>
 * </pre>
 * @sig    : objArr
 * @param  : objectArr required 유효성검사를 하고자 하는 오브젝트들의 Array.
 * @return : boolean. 유효성 여부.
 * @author : 임재현
 */
function cfValidate(obj) {
	if (cfIsNull(obj)) return;

	var objArr;
	var oElement;
	var validYN = false;

	if (obj.length == null) {
		objArr = new Array(1);
		objArr[0] = obj;
	} else {
		objArr = obj;
	}

	for (var objArrIdx = 0; objArrIdx < objArr.length; objArrIdx++) {
		oElement = objArr[objArrIdx];

		switch (oElement.tagName) {
			case "TABLE":
			case "DIV":
			case "FIELDSET":
				for (var i = 0; i < oElement.all.length; i++) {
					if (!cfValidateElement(oElement.all[i])) {
						return false;
					}
				}
				break;
			default:
				if (!cfValidateElement(oElement)) {
					return false;
				}
		}
	}

	return true;
}

/**
 * @type   : function
 * @access : private
 * @desc   : html 의 모든 오브젝트에 대해 유효성 검사를 한다.
 * @sig    : oElement
 * @param  : oElement required 검사 대상 Element.
 * @return : boolean. 유효성 여부.
 * @author : 임재현
 */
function cfValidateElement(oElement) {
	return cfValidateItem(oElement);
}


/**
 * @type   : function
 * @access : private
 * @desc   : 모든 오브젝트와 html의 모든 오브젝트에 대해 유효성 검사를 한다.
 * @sig    : oElement
 * @param  : oElement required 검사 대상 Element.
 * @return : boolean. 유효성 여부.
 * @author : 임재현
 */
function cfValidateItem(oElement) {
	var value;
	var validExp;
	var strObj;
	switch (oElement.tagName) {
		case "INPUT":
			validExp = oElement.alt;
        	var type = oElement.type.toUpperCase();
			value = oElement.value;
        	switch (type) {
				case "CHECKBOX":
					if(cfAnyCheck(oElement.name)) value = "1";
					break;
				case "RADIO":
					if(cfAnyCheck(oElement.name)) value = "1";
					break;
				case "FILE":
					break;
        	}
			break;
		case "SELECT":
			// firefox일 경우
			if (oElement.outerHTML) {
				validExp=oElement.outerHTML;
			} else {
				validExp=(new XMLSerializer).serializeToString(oElement);
			}
			validExp = validExp.substring(validExp.indexOf("alt") + 5, validExp.length)
			validExp = validExp.substring(0, validExp.indexOf("\""));
			value = oElement.value;
			break;
		case "TEXTAREA":
			if (oElement.outerHTML) {
				validExp=oElement.outerHTML;
			} else {
				validExp=(new XMLSerializer).serializeToString(oElement);
			}
			validExp = validExp.substring(validExp.indexOf("alt") + 5, validExp.length)
			validExp = validExp.substring(0, validExp.indexOf("\""));
			oElement.value = oElement.value.trim();  // element의 값을 trim 시켜준다.
			value = oElement.value;
			break;
	}

	if (cfIsNull(validExp)) {
		return true;
	}

	var itemValidExp = new covItemValidExp(validExp);
	if (!itemValidExp.validate(value)) {
		alert(new coMessage().getMsg(itemValidExp.errMsg, [itemValidExp.itemName]));

		if(oElement.enable != false && oElement.disabled!=true) {
			oElement.style.backgroundColor = "#EEFFB6";
			oElement.focus();
		}

		return false;
	}

	return true;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 사용자의 입력값이 Byte로 환산된 최대길이를 넘을 경우 입력이 안되도록 하는 함수. <br>
 *           안타깝게도 Windows XP 환경에서는 한글에 대한 키이벤트가 발생하지 않아서 동작하지 않는다.<br>
 *           오브젝트 선언시 onkeydown 이벤트에 다음과 같이 기술해 주어야만 한다.
 * <pre>
 *     onkeydown="cfValidateMaxByteLength(this, max_byte_length)"
 *     (여기서 max_byte_length 자리에는 Byte로 환산시 최대길이를 숫자로 적어준다.)
 *
 *     예)
 *     &lt;input type="text" size="10" onkeydown="cfValidateMaxByteLength(this, 10)"&gt;
 * </pre>
 *           현재는 html의 text input, textarea에만 적용된다.
 * @sig    : oElement, length
 * @param  : oElement required 입력필드 객체
 * @param  : length   required max byte length
 * @author : 임재현
 */
function cfValidateMaxByteLength(oElement, length) {
	var value = "";

//	if (event.keyCode == 8 ||   // backspace
//	    event.keyCode == 35 ||  // end key
//	    event.keyCode == 36 ||  // home key
//	    event.keyCode == 37 ||  // left key
//	    event.keyCode == 38 ||  // up key
//	    event.keyCode == 39 ||  // right key
//	    event.keyCode == 40 ||  // down key
//	    event.keyCode == 46     // delete key
//	   ) {
//	   	return true;
//	}

	switch (cfGetElementType(oElement)) {
		case "TEXT" :
		case "TEXTAREA" :
			value = oElement.value;
			break;

		default :
			return;
	}

	if (cfGetByteLength(value) > length ) {
  		oElement.blur();
		oElement.focus();
     	oElement.value = oElement.value.substr(0, oElement.value.length - 1);
//		event.returnValue = false;
		return;
	}

	if (oElement.onkeyup == null) {
		oElement.onkeyup =
			function() {
				if (cfGetByteLength(oElement.value) > length) {
			    	oElement.blur();
			        oElement.focus();
			        oElement.value = oElement.value.substr(0, oElement.value.length - 1);
				}
			}
	}

	if (cfGetByteLength(value) == length ) {
       // 완성한글 : 0xAC00 <= c && c <= 0xD7A3
       // 자음 : 0x3131 <= c
       // 모음 : c <= 0x318E
		var c = value.charCodeAt(value.length - 1);

		if ( (0xAC00 <= c && c <= 0xD7A3) || (0x3131 <= c && c <= 0x318E) ) {
//			event.returnValue = true;
    	} else {
//			event.returnValue = false;
		}
	} else {
//		event.returnValue = true;
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : 특정 값에 대한 유효성검사를 수행한다.
 * <pre>
 *     cfValidateValue(50, "minNumber=100");
 * </pre>
 * 위의 경우 50은 최소값 100을 넘지 않으므로 false가 리턴된다.<br>
 * 유효성 검사를 수행하기 위해서는 검사조건을 명시해야 하는데
 * 검사조건은 'valid expression' 이라고 불리우는 String 값으로 표현된다. valid expression에 대한 표기형식은
 * 다음과 같다.
 * <pre>
 *  	validator_name=valid_value[&validator_name=valid_value]..
 *
 *  	예) "minNumber=100"
 * </pre>
 * - validator_name은 검사유형을 의미하며 valid_value는 기준 값이 된다. <br>
 * - 검사항목은 하나 이상일 수 있으며 검사항목간에는 "&" 문자로 구분하여 필요한 만큼 나열하면 된다. <br>
 * - valid_value에 ",", ":", "=", "&", 문자를 사용하고자 한다면 "\\,", "\\:", "\\=", "\\&" 라고 표기해야 한다.<br>
 * - 위의 예에서는 "minNumber" (최소값)라는 유효성 검사항목을 명시하였고 minNumber 에대한 기준값으로 "100" 이 설정되어 있다.
 * 만일 100보다 작은 값을 입력했을 때는 100 이상의 값을 입력하라는 alert box가 뜨게 된다.
 * - validator_name은 미리 정의되어 있는 것만 사용할 수 있고 각 검사유형마다 valid_value의 형태도 다르다.(valid_value가 없는 것도 있다.)
 * 현재 정의된 검사유형은 다음과 같다.
 * <br><br>
 * <table border='1' style="border-collapse:collapse; border-width:1pt; border-style:solid; border-color:000000;">
 * 		<tr>
 * 			<td align="center" bgcolor="#CCCCFFF">검사유형</td>
 * 			<td align="center" bgcolor="#CCCCFFF">기준값 형태</td>
 * 			<td align="center" bgcolor="#CCCCFFF">설명</td>
 * 			<td align="center" bgcolor="#CCCCFFF">예</td>
 * 		</tr>
 * 		<tr>
 * 			<td>length</td>
 * 			<td>0보다 큰 정수</td>
 * 			<td>자릿수 검사. 입력값의 자릿수가 기준값과 일치하는지를 검사한다. 일반적으로 HTML에서는 한글, 영문, 숫자 모두 1자리씩 인식된다.</td>
 * 			<td>length=6</td>
 * 		</tr>
 * 		<tr>
 * 			<td>byteLength</td>
 * 			<td>0보다 큰 정수</td>
 * 			<td>Byte로 환산된 자릿수 검사. 입력값의 자릿수를 byte로 환산하여 자릿수가 기준값과 일치하는지를 검사한다.(숫자 및 영문은 1byte, 한글은 2byte이다.)</td>
 * 			<td>byteLength=6</td>
 * 		</tr>
 * 		<tr>
 * 			<td>minLength</td>
 * 			<td>0보다 큰 정수</td>
 * 			<td>최소자릿수 검사. 입력값의 자릿수가 기준값 이상이 되는지를 검사한다.</td>
 * 			<td>minLength=6</td>
 * 		</tr>
 * 		<tr>
 * 			<td>minByteLength</td>
 * 			<td>0보다 큰 정수</td>
 * 			<td>Byte로 환산된 최소자릿수 검사. 입력값의 자릿수를 byte로 환산하여 자릿수가 기준값 이상이 되는지를 검사한다.(숫자 및 영문은 1byte, 한글은 2byte이다.)</td>
 * 			<td>minByteLength=6</td>
 * 		</tr>
 * 		<tr>
 * 			<td>maxLength</td>
 * 			<td>0보다 큰 정수</td>
 * 			<td>최대자릿수 검사. 입력값의 자릿수가 기준값 이하가 되는지를 검사한다.</td>
 * 			<td>maxLength=6</td>
 * 		</tr>
 * 		<tr>
 * 			<td>maxByteLength</td>
 * 			<td>0보다 큰 정수</td>
 * 			<td>Byte로 환산된 최대자릿수 검사. 입력값의 자릿수를 byte로 환산하여 자릿수가 기준값 이하가 되는지를 검사한다.(숫자 및 영문은 1byte, 한글은 2byte이다.)</td>
 * 			<td>maxByteLength=6</td>
 * 		</tr>
 * 		<tr>
 * 			<td>number</td>
 * 			<td>None or decimal format string. decimal format string 형식은 "(정수자릿수.소수자릿수)" 이다.</td>
 * 			<td>숫자검사. 입력값이 숫자인지를 검사한다. 만일 입력값에 대한 decimal format을 지정하였을 때는 format에 맞는지도 검사한다.</td>
 * 			<td>number, number=(5.2)</td>
 * 		</tr>
 * 		<tr>
 * 			<td>minNumber</td>
 * 			<td>숫자</td>
 * 			<td>최소수 검사. 입력값이 최소한 기준값 이상이 되는지를 검사한다.</td>
 * 			<td>minNumber=100</td>
 * 		</tr>
 * 		<tr>
 * 			<td>maxNumber</td>
 * 			<td>숫자</td>
 * 			<td>최대수 검사. 입력값이 기준값 이하인지를 검사한다.</td>
 * 			<td>maxNumber=300</td>
 * 		</tr>
 * 		<tr>
 * 			<td>inNumber</td>
 * 			<td>"숫자~숫자" 형식으로 표기.</td>
 * 			<td>범위값 검사. 입력값이 기준이 되는 두 수와 같거나 혹은 두 수 사이에 존재하는 값인지를 검사한다.</td>
 * 			<td>inNumber=100~300</td>
 * 		</tr>
 * 		<tr>
 * 			<td>minDate</td>
 * 			<td>YYYYMMDD 형식의 날짜 스트링.</td>
 * 			<td>최소날짜 검사. 입력된 날짜가 기준날짜이거나 기준날짜 이후인지를 검사한다.</td>
 * 			<td>minDate=20020305</td>
 * 		</tr>
 * 		<tr>
 * 			<td>maxDate</td>
 * 			<td>YYYYMMDD 형식의 날짜 스트링. 예) maxDate=20020305</td>
 * 			<td>최대날짜 검사. 입력된 날짜가 기준날짜이거나 기준날짜 이전인지를 검사한다.</td>
 * 			<td>maxDate=20020305</td>
 * 		</tr>
 * 		<tr>
 * 			<td>format</td>
 * 			<td>format character들과 다른 문자들을 조합한 스트링.<br>
 * 				<table>
 * 					<tr>
 * 						<td><b>format character</b></td>
 * 						<td><b>desc</b></td>
 * 					</tr>
 * 					<tr>
 * 						<td>#</td>
 * 						<td>문자와 숫자</td>
 * 					</tr>
 * 					<tr>
 * 						<td>h, H</td>
 * 						<td>한글(H는 공백포함)</td>
 * 					</tr>
 * 					<tr>
 * 						<td>A, Z</td>
 * 						<td>문자(Z는 공백포함)</td>
 * 					</tr>
 * 					<tr>
 * 						<td>0, 9</td>
 * 						<td>숫자 (9는 공백포함)</td>
 * 					</tr>
 * 				</table>
 * 			</td>
 * 			<td>형식 검사. 입력된 값이 지정된 형식에 맞는지를 검사한다.</td>
 * 			<td>format=000-000</td>
 * 		</tr>
 * 		<tr>
 * 			<td>ssn</td>
 * 			<td>주민등록번호 13자리</td>
 * 			<td>주민등록번호 검사. 입력한 주민등록번호가 유효한지를 검사한다.</td>
 * 			<td>ssn</td>
 * 		</tr>
 * 		<tr>
 * 			<td>csn</td>
 * 			<td>사업자등록번호 10자리</td>
 * 			<td>사업자등록번호 검사. 입력한 사업자등록번호가 유효한지를 검사한다.
 *              (예, 2019009930)
 *          </td>
 * 			<td>csn</td>
 * 		</tr>
 * 		<tr>
 * 			<td>filterIn</td>
 * 			<td>필터링하여 얻고자 하는 스트링을 ";"문자를 구분자로 사용하여 나열한다.(단 ";" 문자를 필터링하고 싶을 땐 "\;"라고 표기한다.
 *          </td>
 * 			<td>입력값에 지정된 문자나 스트링 이외에 다른 값이 있는지를 검사한다. 하나도 없다면 유효하다.</td>
 * 			<td>filter=%;<;임재현;\\;;haha<br>(입력값 내에 "%","<","임재현",";","haha" 중에 하나라도 있는지 검사한다.)
 *          </td>
 * 		</tr>
 * 		<tr>
 * 			<td>filterOut</td>
 * 			<td>필터링하여 걸러내고 싶은 스트링을 ";"문자를 구분자로 사용하여 나열한다.(단 ";" 문자를 필터링하고 싶을 땐 "\;"라고 표기한다.
 *          </td>
 * 			<td>입력값에 지정된 문자나 스트링이 있는지를 검사한다. 하나도 없다면 유효하다.</td>
 * 			<td>filter=%;<;임재현;\\;;haha<br>(입력값 내에 "%","<","임재현",";","haha" 중에 하나라도 있는지 검사한다.)
 *          </td>
 * 		</tr>
 * 		<tr>
 * 			<td>email</td>
 * 			<td>이메일 주소</td>
 * 			<td>입력한 메일주소가 유효한 이메일 형식인지를 검사한다.</td>
 * 			<td>email</td>
 * 		</tr>
 * 		<tr>
 * 			<td>date</td>
 * 			<td>format character의 조합으로 이루어진 날자에 대한 패턴 스트링.<br>
 * 				<table>
 * 					<tr>
 * 						<td><b>format character</b></td>
 * 						<td><b>desc</b></td>
 * 					</tr>
 * 					<tr>
 * 						<td>YYYY</td>
 * 						<td>4자리 년도</td>
 * 					</tr>
 * 					<tr>
 * 						<td>YY</td>
 * 						<td>2자리 년도. 2000년 이후</td>
 * 					</tr>
 * 					<tr>
 * 						<td>MM</td>
 * 						<td>2자리 숫자의 달</td>
 * 					</tr>
 * 					<tr>
 * 						<td>DD</td>
 * 						<td>2자리 숫자의 일</td>
 * 					</tr>
 * 					<tr>
 * 						<td>hh</td>
 * 						<td>2자리 숫자의 시간. 12시 기준</td>
 * 					</tr>
 * 					<tr>
 * 						<td>HH</td>
 * 						<td>2자리 숫자의 시간. 24시 기준 </td>
 * 					</tr>
 * 					<tr>
 * 						<td>mm</td>
 * 						<td>2자리 숫자의 분</td>
 * 					</tr>
 * 					<tr>
 * 						<td>ss</td>
 * 						<td>2자리 숫자의 초</td>
 * 					</tr>
 * 				</table>
 * 			</td>
 * 			<td>날짜 검사. 입력된 스트링값을 날짜로 환산하여 유효한 날짜인지를 검사한다.</td>
 * 			<td>date=YYYYMMDD  일 때 입력값이 '20020328' 일 경우 -> 유효<br>
 *              date=YYYYMMDD  일 때 입력값이 '20020230' 일 경우 -> 오류<br>
 *              date=Today is YY-MM-DD' 일 때 입력값이 'Today is 02-03-28' 일 경우 -> 유효<br><br>
 * 				참고) format문자가 중복해서 나오더라도 처음 나온 문자에 대해서만 format문자로 인식된다.
 *                    YYYY와 YY, hh와 HH 도 중복으로 본다. 날짜는 년,월이 존재할 때만 정확히 체크하고
 *                    만일 년, 월이 없다면 1 ~ 31 사이인지만 체크한다.
 * 			</td>
 * 		</tr>
 * </table>
 * @sig    : value, validExp
 * @param  : value    required 검사 대상이 되는 값.
 * @param  : validExp required 사용자가 지정한 Valid Expression String.
 * @return : boolean. 유효성 여부.
 * @author : 임재현
 */
function cfValidateValue(value, validExp) {
	var valueValidExp = new covValueValidExp(validExp);

	if (!valueValidExp.validate(value)) {
		return false;
	}

	return true;
}
//---------------------------------------- 이하 객체선언 ------------------------------------------------------------------------------//

///////////////////////////// coMessage /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 메세지를 관리하는 객체이다.
 * @author : 임재현
 */
function coMessage() {
	// method
	this.getMsg = coMessage_getMsg;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 공통메세지에 정의된 메세지를 alert box로 보여준 후 리턴한다. cfGetMsg 참조.
 * @sig    : msgId[, paramArray]
 * @param  : msgId required lafui.js의 공통 메세지 영역에 선언된 메세지 ID
 * @param  : paramArray optional 메세지에서 '@' 문자와 치환될 데이터 Array. Array의 index와 메세지 내의 '@' 문자의 순서가 일치한다.
             치환될 데이터는 [] 사이에 콤마를 구분자로 하여 기술하면 Array 로 인식된다.
 * @return : 치환된 메세지 스트링
 * @author : 임재현
 */
function cfAlertMsg(msgId, paramArray) {
	if (cfIsNull(msgId)) {
		alert("존재하지 않는 메시지입니다.");
		return null;
	}
	var msg = new coMessage().getMsg(ezMessage(msgId), paramArray);
	alert(msg);
	return msg;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 공통메세지에 정의된 메세지를 confirm box로 보여준 후 리턴한다. cfGetMsg 참조.
 * @sig    : msgId[, paramArray]
 * @param  : msgId      required lafui.js의 공통 메세지 영역에 선언된 메세지 ID
 * @param  : paramArray optional 메세지에서 '@' 문자와 치환될 스트링 Array. (Array의 index와
 *           메세지 내의 '@' 문자의 순서가 일치한다.)
 * @return : 치환된 메세지 스트링
 * @author : 임재현
 */
function cfConfirmMsg(msgId, paramArray) {
	if (cfIsNull(msgId)) {
		alert("존재하지 않는 메시지입니다.");
		return null;
	}
	return confirm(new coMessage().getMsg(ezMessage(msgId), paramArray));
}

/**
 * @type   : method
 * @access : public
 * @object : coMessage
 * @desc   : 공통메세지에 정의된 메세지를 치환하여 알려준다.
 * @sig    : message[, paramArray]
 * @param  : message    required lafui.js의 공통 메세지 영역에 선언된 메세지 ID
 * @param  : paramArray optional 메세지에서 '@' 문자와 치환될 스트링 Array. (Array의 index와
 *           메세지 내의 '@' 문자의 순서가 일치한다.)
 * @return : 치환된 메세지 스트링
 */
function coMessage_getMsg(message, paramArray) {
	if (cfIsNull(message)) {
		return null;
	}
	var index = 0;
	var re = /@/g;
	var count = 0;

	if (paramArray == null) {
		return message;
	}
	while ( (index = message.indexOf("@", index)) != -1) {
		if (paramArray[count] == null) {
			paramArray[count] = "";
		}

		message = message.substr(0, index) + String(paramArray[count]) +
		          message.substring(index + 1);

		index = index + String(paramArray[count++]).length;
	}

	return message;
}

///////////////////////////// coGridColumn /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : Grid 에 선언된 컬럼정보를 담고있는 객체이다.
 * @author : 임재현
 */
function coGridColumn() {
	this.attrNames = new Array();
	this.attrValues = new Array();
	this.attrCnt = 0;

	// method
	this.hasAttribute = coGridColumn_hasAttribute;
	this.setAttribute = coGridColumn_setAttribute;
	this.getAttribute = coGridColumn_getAttribute
}

/**
 * @type   : method
 * @access : public
 * @object : coGridColumn
 * @desc   : 컬럼에 특정 속성이 정의되어 있는지 알려준다.
 * @sig    : attrName
 * @param  : attrName required 속성명
 * @return : 속성 존재여부
 */
function coGridColumn_hasAttribute(attrName) {
	for (var i = 0; i < this.attrCnt; i++) {
		if (attrName.toUpperCase() == this.attrNames[i].toUpperCase()) {
			return true;
		}
	}

	return false;
}

/**
 * @type   : method
 * @access : public
 * @object : coGridColumn
 * @desc   : 컬럼에 새로운 속성을 추가한다.
 * @sig    : attrName, attrValue
 * @param  : attrName required 속성명
 * @param  : attrValue required 속성값
 * @return : 속성 존재여부
 */
function coGridColumn_setAttribute(attrName, attrValue) {
	this.attrNames[this.attrCnt]  = attrName.toUpperCase();
	this.attrValues[this.attrCnt] = attrValue;
	this.attrCnt++;
}

/**
 * @type   : method
 * @access : public
 * @object : coGridColumn
 * @desc   : 컬럼의 특정 속성값을 알려준다.
 * @sig    : attrName
 * @param  : attrName required 속성명
 * @return : 속성값
 */
function coGridColumn_getAttribute(attrName) {
	for (var i = 0; i < this.attrCnt; i++) {
		if (this.attrNames[i] == attrName) {
			return this.attrValues[i];
		}
	}
}

///////////////////////////// coGridFormat /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : Grid Format을 파싱한 후 정보를 저장한다.
 * @author : 임재현
 */
function coGridFormat(format) {
	this.format = format;
	this.columns = new Array();

	// method
	this.existsColumn = coGridFormat_existsColumn;
	this.parse  = coGridFormat_parse;

	// initialize
	this.parse();
}

/**
 * @type   : method
 * @access : parse
 * @object : coGridFormat
 * @desc   : 파싱한다.
 */
function coGridFormat_parse() {
	var tagRE = /<(fc|c|g|fg|x|fx)>/i;
	var colAttrRE = /([\w_]+)\s*=\s*['"]?([^<'"\s,]+)/i;
	var gFormat = this.format;
	var tagMatch;
	var colAttrData;
	var colAttrMatch;
	var colAttrName;
	var colAttrValue;
	var colCnt = 0;

	while ((tagMatch = gFormat.match(tagRE)) != null) {
		this.columns[colCnt] = new coGridColumn();
		colAttrData = gFormat.substring(tagMatch.lastIndex, gFormat.indexOf("<", tagMatch.lastIndex));

		while ( (colAttrMatch = colAttrData.match(colAttrRE)) != null) {
			colAttrName = colAttrMatch[1].toUpperCase();
			colAttrValue = colAttrMatch[2];
			this.columns[colCnt].setAttribute(colAttrName, colAttrValue);
			colAttrData = colAttrData.substr(colAttrMatch.lastIndex);
		}

		gFormat = gFormat.substr(tagMatch.lastIndex);
		colCnt++;
	}
}

/**
 * @type   : method
 * @access : public
 * @object : coGridFormat
 * @desc   : Grid에 선언된 컬럼들 중에서 특정 colid를 가진 컬럼이 존재하는지를 알려준다.
 * @sig    : colId
 * @param  : colId required 속성명
 * @return : 컬럼 존재여부
 */
function coGridFormat_existsColumn(colId) {
	for (var i = 0; i < this.columns.length; i++) {
		if (this.columns[i].hasAttribute("ID") &&
		    this.columns[i].getAttribute("ID") == colId) {
			return true;
		}
	}

	return false;
}

///////////////////////////// coMap /////////////////////////////
/**
 * @type   : object
 * @access : public
 * @desc   : String parameter 에 대한 name과 value 쌍들을 가진 객체
 * @author : 임재현
 */
function coMap() {
	// fields

	this.names = new Array();
	this.values = new Array();
	this.count = 0;

	// methods
	this.getValue          = coMap_getValue;
	this.put               = coMap_put;
	this.getNameAt         = coMap_getNameAt;
	this.getValueAt        = coMap_getValueAt;
	this.size              = coMap_size;
	this.getMaxNameLength  = coMap_getMaxNameLength;
}

/**
 * @type   : method
 * @access : public
 * @object : coMap
 * @desc   : name에 맞는 파라미터값을 리턴한다.
 * @sig    : name
 * @param  : name required map의 name으로 사용할 값
 * @return : 파라미터값
 */
function coMap_getValue(name) {
	for (var i = 0; i < this.count; i++) {
		if (this.names[i] == name) {
			return this.values[i];
		}
	}

	return null;
}

/**
 * @type   : method
 * @access : public
 * @object : coMap
 * @desc   : 새로운 map을 추가한다. 같은 name가 존재할 경우 overwrite한다.
 * @sig    : name, value
 * @param  : name  required map의 name로 사용할 값
 * @param  : value required map의 value로 사용할 값
 * @return : 파라미터값
 */
function coMap_put(name, value) {
	for (var i = 0; i < this.count; i++) {
		if (this.names[i] == name) {
			this.values[i] = value;
			return;
		}
	}

	this.names[this.count] = name;
	this.values[this.count++] = value;
}

/**
 * @type   : method
 * @access : public
 * @object : coMap
 * @desc   : 지정된 index에 있는 map의 name을 알려준다.
 * @sig    : index
 * @param  : index - map의 index
 * @return : name
 */
function coMap_getNameAt(index) {
	return this.names[index];
}

/**
 * @type   : method
 * @access : public
 * @object : coMap
 * @desc   : 지정된 index에 있는 map의 value를 알려준다.
 * @sig    : index
 * @param  : index required map의 index
 * @return : value
 */
function coMap_getValueAt(index) {
	return this.values[index];
}

/**
 * @type   : method
 * @access : public
 * @object : coMap
 * @desc   : map의 name-value 쌍의 갯수를 알려준다.
 * @return : name-value 쌍의 갯수
 */
function coMap_size() {
	return this.count;
}

/**
 * @type   : method
 * @access : public
 * @object : coMap
 * @desc   : map 내의 name 값들을 String으로 환산하여 최대길이를 알려준다.
 * @return : max name length
 */
function coMap_getMaxNameLength() {
	var maxLength = 0;

	for (var i = 0; i < this.count; i++) {
		if (String(this.names[i]).length > maxLength) {
			maxLength = String(this.names[i]).length;
		}
	}

	return maxLength;
}

///////////////////////////// coParameterMap /////////////////////////////
/**
 * @type   : object
 * @access : public
 * @desc   : String parameter 에 대한 name과 value 쌍들을 가진 객체
 * @author : 임재현
 */
function coParameterMap() {
	// fields

	/**
	 * @type   : field
	 * @access : private
	 * @object : coParameterMap
	 * @desc   : 파라미터 이름을 담고있는 array
	 */
	this.names = new Array();

	/**
	 * @type   : field
	 * @access : private
	 * @object : coParameterMap
	 * @desc   : 파라미터 값을 담고있는 array
	 */
	this.values = new Array();

	/**
	 * @type   : field
	 * @access : private
	 * @object : coParameterMap
	 * @desc   : 파라미터의 개수
	 */
	this.count = 0;

	// methods
	this.getValue          = coParameterMap_getValue;
	this.put               = coParameterMap_put;
	this.getNameAt         = coParameterMap_getNameAt;
	this.getValueAt        = coParameterMap_getValueAt;
	this.size              = coParameterMap_size;
	this.getMaxNameLength  = coParameterMap_getMaxNameLength;
	this.getMaxValueLength = coParameterMap_getMaxValueLength;
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : name에 맞는 파라미터값을 리턴한다.
 * @sig    : name
 * @param  : name required map의 name으로 사용할 값
 * @return : 파라미터값
 */
function coParameterMap_getValue(name) {
	for (var i = 0; i < this.count; i++) {
		if (this.names[i] == name) {
			return this.values[i];
		}
	}

	return null;
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : 새로운 map을 추가한다. 같은 name가 존재할 경우 overwrite한다.
 * @sig    : name, value
 * @param  : name  required map의 name로 사용할 값
 * @param  : value required map의 value로 사용할 값
 * @return : 파라미터값
 */
function coParameterMap_put(name, value) {
	for (var i = 0; i < this.count; i++) {
		if (this.names[i] == name) {
			this.values[i] = value;
			return;
		}
	}

	this.names[this.count] = name;
	this.values[this.count++] = value;
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : 지정된 index에 있는 map의 name을 알려준다.
 * @sig    : index
 * @param  : index required map의 index
 * @return : name
 */
function coParameterMap_getNameAt(index) {
	return this.names[index];
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : 지정된 index에 있는 map의 value를 알려준다.
 * @sig    : index
 * @param  : index required map의 index
 * @return : value
 */
function coParameterMap_getValueAt(index) {
	return this.values[index];
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : map의 name-value 쌍의 갯수를 알려준다.
 * @return : name-value 쌍의 갯수
 */
function coParameterMap_size() {
	return this.count;
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : map 내의 name 값들을 String으로 환산하여 최대길이를 알려준다.
 * @return : max name length
 */
function coParameterMap_getMaxNameLength() {
	var maxLength = 0;

	for (var i = 0; i < this.count; i++) {
		if (String(this.names[i]).length > maxLength) {
			maxLength = String(this.names[i]).length;
		}
	}

	return maxLength;
}

/**
 * @type   : method
 * @access : public
 * @object : coParameterMap
 * @desc   : map 내의 value 값들을 String으로 환산하여 최대길이를 알려준다.
 * @return : max value length
 */
function coParameterMap_getMaxValueLength() {
	var maxLength = 0;

	for (var i = 0; i < this.count; i++) {
		if (String(this.values[i]).length > maxLength) {
			maxLength = String(this.values[i]).length;
		}
	}

	return maxLength;
}

//-------------------------- 유효성 검사를 위한 객체 선언 -----------------------------//
/*
 * @Validator 객체의 구조
 *   - 속성 : exception,   -> validity의 sub속성이다. validity가 true면 exception은 무조건 false이고
 *                            validity가 false인 경우 false의 원인이 exception인지 여부를 알려준다.
 *                            exception은 사용자 입력에 대한 실제 validation과는 무관한 에러를 의미한다.
 *                            true/false 중 하나.
 *            message,     -> 오류메세지를 담고 있다.
 *            validity,    -> 유효성검사결과를 담고 있다. true/false 중 하나.
 *            value        -> 유효성 검사 대상 값.
 *
 *   - 메소드 : validate() -> 유효성 검사를 수행한다.
 *                            유효할 경우, validity를 true로하고 true를 return하고
 *                            유효하지 않을 경우,  validity를 false로하고 false를 return하고
 *                            message에 오류메세지를 기술한다.
 *                            exception의 경우는 exception을 true로 하고 message에 메세지를 기술한다.
 *
 *   - 추가시 할일 :
 *     1) validator객체를 정의한다.
 *     2) covValidExp 객체의 getValidators 메소드에 validator객체를 등록한다.
 */

///////////////////////////// covValueValidExp /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 유효성 검사에 대한 표현(expression)을 객체화 하였다.
 *             - expression 형식<br>
 *               항목이름:필수항목여부:유효성항목<br>
 *               예) "접수번호:yes:length=6"
 *             - 유효성 항목 형식
 *               유효성항목명=유효값[&유효성항목명=유효값]..
 *               예) "length=13&ssn"
 * @sig    : expression
 * @param  : expression required valid expression string.
 * @author : 임재현
 */
function covValueValidExp(expression) {
    // data;
    this.validItems = new Array();
    this.errMsg = "";

    // method
    this.init = covValueValidExp_init;
    this.parse = covValueValidExp_parse;
    this.validate = covValueValidExp_validate;

    // initialize
    this.init(expression);
}

/**
 * @type   : method
 * @access : private
 * @object : covValueValidExp
 * @desc   : 초기화를 수행한다.
 * @sig    : expression
 * @param  : expression required valid expression string.
 * @author : 임재현
 */
function covValueValidExp_init(expression) {
	this.parse(expression);
}

/**
 * @type   : method
 * @access : private
 * @object : covValueValidExp
 * @desc   : covValidExp 객체의 parse 메소드.
 *           valid expression을 parsing한다.
 * @sig    : expression
 * @param  : expression required valid expression string.
 */
function covValueValidExp_parse(expression) {
	if (cfIsNull(expression)) {
		return;
	}

	var validItemExps = expression.advancedSplit("&", "i");
	var validItem;

	for (var i = 0; i < validItemExps.length; i++) {
		validItemPair = validItemExps[i].trim().advancedSplit("=", "i");
		validItem = new Object();
		validItem.name  = validItemPair[0].trim();
		validItem.value = validItemPair[1];  // parsedExp[1] 은 존재하지 않을 수도 있지만 자바스크립트에서는
		this.validItems[i] = validItem;      // 이런 경우 "undefined" 라는 값을 리턴한다.
	}
}

/**
 * @type   : method
 * @access : private
 * @object : covValueValidExp
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 검사대상값
 */
function covValueValidExp_validate(value) {
	var validators = new Array();
	var count = 0;

	for (var i = 0; i < this.validItems.length; i++) {
		switch (this.validItems[i].name) {
			case "length" :
				validators[count++] = new covLengthValidator(this.validItems[i].value);
				break;

			case "byteLength" :
				validators[count++] = new covByteLengthValidator(this.validItems[i].value);
				break;

			case "minLength" :
				validators[count++] = new covMinLengthValidator(this.validItems[i].value);
				break;

			case "minByteLength" :
				validators[count++] = new covMinByteLengthValidator(this.validItems[i].value);
				break;

			case "maxLength" :
				validators[count++] = new covMaxLengthValidator(this.validItems[i].value);
				break;

			case "maxByteLength" :
				validators[count++] = new covMaxByteLengthValidator(this.validItems[i].value);
				break;

			case "number" :
				validators[count++] = new covNumberValidator(this.validItems[i].value);
				break;

			case "minNumber" :
				validators[count++] = new covMinNumberValidator(this.validItems[i].value);
				break;

			case "maxNumber" :
				validators[count++] = new covMaxNumberValidator(this.validItems[i].value);
				break;

			case "inNumber" :
				validators[count++] = new covInNumberValidator(this.validItems[i].value);
				break;

			case "minDate" :
				validators[count++] = new covMinDateValidator(this.validItems[i].value);
				break;

			case "maxDate" :
				validators[count++] = new covMaxDateValidator(this.validItems[i].value);
				break;

			case "format" :
				validators[count++] = new covFormatValidator(this.validItems[i].value);
				break;

			case "ssn" :
				validators[count++] = new covSsnValidator(this.validItems[i].value);
				break;

			case "fssn" :
				validators[count++] = new covFSsnValidator(this.validItems[i].value);
				break;

			case "csn" :
				validators[count++] = new covCsnValidator(this.validItems[i].value);
				break;

			case "filterIn" :
				validators[count++] = new covFilterInValidator(this.validItems[i].value);
				break;

			case "filterOut" :
				validators[count++] = new covFilterOutValidator(this.validItems[i].value);
				break;

			case "email" :
				validators[count++] = new covEmailValidator(this.validItems[i].value);
				break;

			case "date" :
				validators[count++] = new covDateValidator(this.validItems[i].value);
				break;

			case "phone" :
				validators[count++] = new covPhoneValidator(this.validItems[i].value);
				break;

			case "hphone" :
				validators[count++] = new covHPhoneValidator(this.validItems[i].value);
				break;

			case "gphone" :
				validators[count++] = new covGPhoneValidator(this.validItems[i].value);
				break;

			case "corp" :
				validators[count++] = new covCorpValidator(this.validItems[i].value);
				break;

			default :
				break;
		}
	}

	for (var i = 0; i < validators.length; i++) {
		if (!validators[i].validate(value)) {
			this.errMsg = validators[i].message;
			return false;
		}
	}

	return true;
}

///////////////////////////// covItemValidExp /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 유효성 검사에 대한 표현(expression)을 객체화 하였다.
 *             - expression 형식<br>
 *               항목이름:필수항목여부:유효성항목<br>
 *               예) "접수번호:yes:length=6"
 *             - 유효성 항목 형식
 *               유효성항목명=유효값[&유효성항목명=유효값]..
 *               예) "length=13&ssn"
 * @sig    : expression, itemName
 * @param  : expression required valid expression string.
 * @param  : itemName   required 아이템명
 * @author : 임재현
 */
function covItemValidExp(expression, itemName) {
    // data;
    this.itemName;
    this.required;
    this.valueValidExp;

    // method
    this.parse = covItemValidExp_parse;
    this.validate = covItemValidExp_validate;

    // initialize
    this.parse(expression, itemName);
}

/**
 * @type   : method
 * @access : public
 * @object : covItemValidExp
 * @desc   : valid expression을 parsing한다.
 * @sig    : expression, itemName
 * @param  : expression required valid expression string.
 * @param  : itemName   required 아이템명
 */
function covItemValidExp_parse(expression, itemName) {
	if (cfIsNull(expression)) {
		return;
	}

	var columns = expression.advancedSplit(":", "i");

	if (cfIsNull(columns[1])) {
		return;
	}

	if (cfIsNull(columns[0])) {
		if (!cfIsNull(itemName)) {
			this.itemName = itemName.trim();
		} else {
			return;
		}
	} else {
		this.itemName = columns[0].trim();
	}
	//alert("columns[0]:" + columns[0]);
	//alert("columns[1]:" + columns[1]);
	//alert("columns[2]:" + columns[2]);
	this.required = (columns[1].trim().toUpperCase() == "YES" ||
	                 columns[1].trim().toUpperCase() == "TRUE" ||
	                 columns[1].trim() == "1"
	                ) ? true : false;

	if ((columns[2]) != null) {
		this.valueValidExp = new covValueValidExp(columns[2].trim());
	}
}

/**
 * @type   : method
 * @access : public
 * @object : covItemValidExp
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 검사할 값
 */
function covItemValidExp_validate(value) {
	// 표현식에 필수항목들(아이템명, 필수여부)을 기술하지 않을 경우는 표현식이 없다고 간주.
	if (cfIsNull(this.itemName) || cfIsNull(this.required)) {
		return true;
	}
	if (this.required && cfIsNull(value)) {
		this.errMsg = ezMessage("pbf.err.com.required");
		return false;
	}

	if (!this.required && cfIsNull(value)) {
		return true;
	}

	if (this.valueValidExp == null) {
		return true;
	}

	if (!this.valueValidExp.validate(value)) {
		this.errMsg = this.valueValidExp.errMsg;
		return false;
	}

	return true;
}

function ezMessage(code) {
	code = code.simpleReplace(".", "_");
	code = $langCd + "_" + code;
	return eval(code);
}

///////////////////////////// covLengthValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'length' 항목에 대한 validator. 값이 지정된 길이를 가지고 있는지 검사한다.
 * @param  : length required 유효한 기준길이.
 * @author : 임재현
 */
function covLengthValidator(length) {
    // data;
    this.message = "";
    this.validity = false;
    this.length = length;

    // method
    this.validate = covLengthValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covLengthValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covLengthValidator_validate(value) {
	if (value.length != this.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.length"), ["@", String(this.length)]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covByteLengthValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'byteLength' 항목에 대한 validator. 값이 지정된 byte단위의 길이를 가지고 있는지 검사한다.
 * @param  : length required 유효한 기준길이.
 * @author : 임재현
 */
function covByteLengthValidator(length) {
    // data;
    this.message = "";
    this.validity = false;
    this.length = length;

    // method
    this.validate = covByteLengthValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covByteLengthValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covByteLengthValidator_validate(value) {
	if (cfGetByteLength(value) != this.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.length1"), ["@", String(this.length), String(Math.floor(this.length / 2))]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMinLengthValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'minLength' 항목에 대한 validator. 값이 지정된 길이 이상인지를 검사한다.
 * @sig    : length
 * @param  : length required 유효한 기준길이.
 * @author : 임재현
 */
function covMinLengthValidator(length) {
    // data;
    this.message = "";
    this.validity = false;
    this.length = length;

    // method
    this.validate = covMinLengthValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMinLengthValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMinLengthValidator_validate(value) {
	if (value.length < this.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.minLength"), ["@", String(this.length)]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMinByteLengthValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'minByteLength' 항목에 대한 validator. 값이 지정된 byte단위의 길이 이상인지를 검사한다.
 * @sig    : length
 * @param  : length required 유효한 기준길이.
 * @author : 임재현
 */
function covMinByteLengthValidator(length) {
    // data;
    this.message = "";
    this.validity = false;
    this.length = length;

    // method
    this.validate = covMinByteLengthValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMinByteLengthValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMinByteLengthValidator_validate(value) {
	if (cfGetByteLength(value) < this.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.minLength1"), ["@", String(this.length), String(Math.floor(this.length / 2))]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMaxLengthValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'maxLength' 항목에 대한 validator. 값이 지정된 길이 이상인지를 검사한다.
 * @sig    : length
 * @param  : length required 유효한 기준길이.
 * @author : 임재현
 */
function covMaxLengthValidator(length) {
    // data;
    this.message = "";
    this.validity = false;
    this.length = length;

    // method
    this.validate = covMaxLengthValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMaxLengthValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMaxLengthValidator_validate(value) {
	if (value.length > this.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.maxLength"), ["@", String(this.length)]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMaxByteLengthValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'maxByteLength' 항목에 대한 validator. 값이 지정된 byte단위의 길이 이하인지를 검사한다.
 * @sig    : length
 * @param  : length required 유효한 기준길이.
 * @author : 임재현
 */
function covMaxByteLengthValidator(length) {
    // data;
    this.message = "";
    this.validity = false;
    this.length = length;

    // method
    this.validate = covMaxByteLengthValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMaxByteLengthValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMaxByteLengthValidator_validate(value) {
//	alert(value + '/'+ cfGetByteLength(value) + '/'+ this + '/'+ this.length)
	if (cfGetByteLength(value) > this.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.maxLength1"), ["@", String(this.length), String(Math.floor(this.length / 3))]);	// utf-8 : this.length / 3
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covNumberValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'number' 항목에 대한 validator. 값이 숫자인지를 검사한다. 또한 format을 지정하였을 경우에는 format에 맞는지 검사한다.
 * <pre>
 *     "number" 로 지정시 : 숫자인지 체크
 *     "number=(5.2)" 로 지정시 : 숫자이면서 정수부 5자리 이하, 소수부 2자리 이하인지를 체크
 * </pre>
 * @author : 임재현
 */
function covNumberValidator(format) {
    // data;
	re = /\(\s*(\d+)\s*.\s*(\d+)\s*\)/;
	this.iLength;
	this.dLength;

	this.message = "";
	this.validity = false;

    // method
    this.validate = covNumberValidator_validate;

	// initialize
	{
		if (cfIsNull(format)) {
			return;
		}

		r = format.match(re);

		if (r == null) {
			return;
		}

		this.iLength = Number(r[1]);
		this.dLength = Number(r[2]);
	}
}

/**
 * @type   : method
 * @access : public
 * @object : covNumberValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covNumberValidator_validate(value) {
	if (isNaN(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	} else if (!cfIsNull(this.iLength)) {
		var strValue = String(value);
		var idx = strValue.indexOf('.');
		var iNumStr = 0;
		var dNumStr = 0;
		var ciLength = 0;
		var cdLength = 0;
		
		if(idx > 0) {
			iNumStr = strValue.substr(0, idx);
			dNumStr = strValue.substr(idx + 1);
			ciLength = this.iLength;
			cdLength = this.dLength;
		} else {
			ciLength = this.iLength + this.dLength;
			iNumStr = strValue;
		}
		if (iNumStr.length > ciLength) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.integerLength"), ["@", String(ciLength)]);
			return false;
		} else if (dNumStr.length > cdLength) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.decimalLength"), ["@", String(cdLength)]);
			return false;
		}
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMinNumberValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'minNumber' 항목에 대한 validator. 값이 지정된 최소값을 넘는지를 검사한다.
 * @sig    : minNumber
 * @param  : minNumber required 유효한 기준 최소값.
 * @author : 임재현
 */
function covMinNumberValidator(minNumber) {
    // data;
    this.message = "";
    this.validity = false;
    this.minNumber = minNumber;

    // method
    this.validate = covMinNumberValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMinNumberValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMinNumberValidator_validate(value) {
	// 기준값이 숫자가 아닌경우 무조건 true;
	if (isNaN(this.minNumber)) {
		this.validity = true;
		return true;
	}

	if (isNaN(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}

	this.minNumber = Number(this.minNumber);
	value          = Number(value);

	if (value < this.minNumber) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.minLength"), ["@", String(this.minNumber)]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMaxNumberValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'maxNumber' 항목에 대한 validator. 값이 지정된 최대값을 넘지 않는지를 검사한다.
 * @sig    : maxNumber
 * @param  : maxNumber 유효한 기준 최대값.
 * @author : 임재현
 */
function covMaxNumberValidator(maxNumber) {
    // data;
    this.message = "";
    this.validity = false;
    this.maxNumber = (maxNumber == null) ? "" : maxNumber.trim();

    // method
    this.validate = covMaxNumberValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMaxNumberValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMaxNumberValidator_validate(value) {
	// 기준값이 숫자가 아닌경우 무조건 true;
	if (isNaN(this.maxNumber)) {
		this.validity = true;
		return true;
	}

	if (isNaN(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}

	this.maxNumber = Number(this.maxNumber);
	value          = Number(value);

	if (value > this.maxNumber) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.maxLength"), ["@", String(this.maxNumber)]);
		return false;
	}

	this.validity = true;
	return true;
}


///////////////////////////// covInNumberValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'inNumber' 항목에 대한 validator. 값이 지정된 범위 내의 값인지를 검사한다.
 * @sig    : inNumber
 * @param  : inNumber required 숫자의 범위를 나타내는 스트링. 예) "1~100"
 * @author : 임재현
 */
function covInNumberValidator(inNumber) {
    // data;
    this.message = "";
    this.validity = false;
    this.minNumber;
    this.maxNumber;

    // method
    this.validate = covInNumberValidator_validate;

    // initialize
	this.minNumber = inNumber.substring(0, inNumber.indexOf("~"));
	this.maxNumber = inNumber.substr(inNumber.indexOf("~") + 1);

	this.minNumber = (this.minNumber == null) ? "" : this.minNumber.trim();
	this.maxNumber = (this.maxNumber == null) ? "" : this.maxNumber.trim();
}

/**
 * @type   : method
 * @access : public
 * @object : covInNumberValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covInNumberValidator_validate(value) {
	// 기준값이 숫자가 아닌경우 무조건 true;
	if (isNaN(this.minNumber) || isNaN(this.maxNumber)) {
		this.validity = true;
		return true;
	}

	if (isNaN(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}

	this.minNumber = Number(this.minNumber);
	this.maxNumber = Number(this.maxNumber);
	value     = Number(value);

	if (value < this.minNumber || value > this.maxNumber) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.range"), ["@", String(this.minNumber), String(this.maxNumber)]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMinDateValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'minDate' 항목에 대한 validator. 값이 지정된 날짜를 넘는지를 검사한다.
 *           'YYYYMMDD' 형식으로 날짜를 표기해야 한다.
 *             예) minDate=20020315
 * @sig    : minDate
 * @param  : minDate required 유효한 기준 최소값.
 * @author : 임재현
 */
function covMinDateValidator(minDate) {
    // data;
    this.message = "";
    this.validity = false;
    this.minDate = minDate;

    // method
    this.validate = covMinDateValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMinDateValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMinDateValidator_validate(value) {
	if (!(new covDateValidator("YYYYMMDD").validate(value))) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	if (value < this.minDate) {
		var msgParams = new Array(4);
		msgParams[0] = "@";
		msgParams[1] = this.minDate.substring(0,4);
		msgParams[2] = this.minDate.substring(4,5) == "0" ? this.minDate.substring(5,6) : this.minDate.substring(4,6);
		msgParams[3] = this.minDate.substring(6,7) == "0" ? this.minDate.substring(7,8) : this.minDate.substring(6,8)
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.afterDate"), msgParams);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covMaxDateValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'maxDate' 항목에 대한 validator. 값이 지정된 최대값을 넘지 않는지를 검사한다.
 * @sig    : maxDate
 * @param  : maxDate required 유효한 최대날짜값.
 * @author : 임재현
 */
function covMaxDateValidator(maxDate) {
    // data;
    this.message = "";
    this.validity = false;
    this.maxDate = maxDate;

    // method
    this.validate = covMaxDateValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covMaxDateValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covMaxDateValidator_validate(value) {
	if (!(new covDateValidator("YYYYMMDD").validate(value))) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	if (value > this.maxDate) {
		var msgParams = new Array(4);
		msgParams[0] = "@";
		msgParams[1] = this.maxDate.substring(0,4);
		msgParams[2] = this.maxDate.substring(4,5) == "0" ? this.maxDate.substring(5,6) : this.maxDate.substring(4,6);
		msgParams[3] = this.maxDate.substring(6,7) == "0" ? this.maxDate.substring(7,8) : this.maxDate.substring(6,8)
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.beforeDate"), msgParams);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covFormatValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'format' 항목에 대한 validator. 값이 마스크로 표현된 형식과 일치하는지 검사한다.
 *             - format characters
 *               #    : 문자와 숫자
 *               h, H : 한글 (H는 공백포함)
 *               A, Z : 문자 (Z는 공백포함)
 *               0, 9 : 숫자 (9는 공백포함)
 * @sig    : format
 * @param  : format required 포멧 스트링.
 * @author : 임재현
 */
function covFormatValidator(format) {
    // data;
    this.message  = "";
    this.validity = false;
    this.format   = format

    // method
    this.validate = covFormatValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covFormatValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covFormatValidator_validate(value) {
	if (value.length != this.format.length) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
		return false;
	}

	for (var i = 0; i < this.format.length; i++) {
		switch(this.format.charAt(i)) {
			case 'h' :
				var cCode = value.charCodeAt(i);
				if ( (value.charAt(i) == " ") ||
				     !((0xAC00 <= cCode && cCode <= 0xD7A3) || (0x3131 <= cCode && cCode <= 0x318E))
				   ) {
					this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
					return false;
				}
				break;

			case 'H' :
				var cCode = value.charCodeAt(i);
				if ( (value.charAt(i) != " ") &&
				     !((0xAC00 <= cCode && cCode <= 0xD7A3) || (0x3131 <= cCode && cCode <= 0x318E))
				   ) {
					this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
					return false;
				}
				break;

			case '0' :
				if (isNaN(value.charAt(i)) || value.charAt(i) == " ") {
					this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
					return false;
				}
				break;

			case '9' :
				if (isNaN(value.charAt(i))) {
					if (value.charAt(i) != " ") {
						this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
						return false;
					}
				}
				break;

			case 'A' :
				if ( (value.charAt(i) == " ") || !isNaN(value.charAt(i)) ) {
					this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
					return false;
				}
				break;

			case 'Z' :
				if ( (value.charAt(i) != " ") && !isNaN(value.charAt(i)) ) {
					this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
					return false;
				}
				break;

			case '#' :
				break;

			default :
				if (value.charAt(i) != this.format.charAt(i)) {
					this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format"), ["@", this.format]);
					return false;
				}
				break;
		}
	}

	this.validity = true;
	return true;
}

///////////////////////////// covSsnValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'ssn' 항목에 대한 validator. 입력된 주민등록번호가 유효한지 검사한다.
 * @author : 임재현
 */
function covSsnValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covSsnValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covSsnValidator
 * @desc   : validation을 수행한다.
 * @sig    : ssn
 * @param  : ssn required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covSsnValidator_validate(ssn) {
	if ( ssn == null || ssn.trim().length != 13 || isNaN(ssn) )  {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	var jNum1 = ssn.substr(0, 6);
	var jNum2 = ssn.substr(6);

	/*
	  잘못된 생년월일을 검사합니다.
	  2000년도부터 성구별 번호가 바뀌었으므로 구별수가 2보다 작다면
	  1900년도 생이되고 2보다 크다면 2000년도 이후 출생이 됩니다.
	  단 1800년도 생은 계산에서 제외합니다.
	*/
	bYear = (jNum2.charAt(0) <= "2") ? "19" : "20";

	// 주민번호의 앞에서 2자리를 이어서 4자리의 생년을 저장합니다.
	bYear += jNum1.substr(0, 2);

	// 달을 구합니다. 1을 뺀것은 자바스크립트에서는 1월을 0으로 표기하기 때문입니다.
	bMonth = jNum1.substr(2, 2) - 1;

	bDate = jNum1.substr(4, 2);

	bSum = new Date(bYear, bMonth, bDate);

	// 생년월일의 타당성을 검사하여 거짓이 있을시 에러메세지를 나타냄
	if ( bSum.getYear() % 100 != jNum1.substr(0, 2) || bSum.getMonth() != bMonth || bSum.getDate() != bDate) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	total = 0;
	temp = new Array(13);

	for (i = 1; i <= 6; i++) {
		temp[i] = jNum1.charAt(i-1);
	}

	for (i = 7; i <= 13; i++) {
		temp[i] = jNum2.charAt(i-7);
	}

	for (i = 1; i <= 12; i++) {
		k = i + 1;

		// 각 수와 곱할 수를 뽑아냅니다. 곱수가 만일 10보다 크거나 같다면 계산식에 의해 2로 다시 시작하게 됩니다.
		if(k >= 10) k = k % 10 + 2;

		// 각 자리수와 계산수를 곱한값을 변수 total에 누적합산시킵니다.
		total = total + (temp[i] * k);
	}

	// 마지막 계산식을 변수 last_num에 대입합니다.
	last_num = (11- (total % 11)) % 10;

	// laster_num이 주민번호의마지막수와 같은면 참을 틀리면 거짓을 반환합니다.
	if(last_num != temp[13]) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	this.validity = true;
	return true;
}


///////////////////////////// covSsnValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'fssn' 항목에 대한 validator. 입력된 외국인등록번호가 유효한지 검사한다.
 * @author : 홍두희
 */
function covFSsnValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covFSsnValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covFSsnValidator
 * @desc   : validation을 수행한다.
 * @sig    : fssn
 * @param  : fssn required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covFSsnValidator_validate(ssn) {
	var sum=0;
	var odd=0;
	buf = new Array(13);
	for(i=0; i<13; i++) { buf[i]=parseInt(ssn.charAt(i)); }
	odd = buf[7]*10 + buf[8];
	if(odd%2 != 0) { return false; }
	if( (buf[11]!=6) && (buf[11]!=7) && (buf[11]!=8) && (buf[11]!=9) ) {
	return false;
	}
	multipliers = [2,3,4,5,6,7,8,9,2,3,4,5];
	for(i=0, sum=0; i<12; i++) { sum += (buf[i] *= multipliers[i]); }
	sum = 11 - (sum%11);
	if(sum >= 10) { sum -= 10; }
	sum += 2;
	if(sum >= 10) { sum -= 10; }
	if(sum != buf[12]) { return false }

	this.validity = true;

	return true;
}

///////////////////////////// covCsnValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 'csn' 항목에 대한 validator. 입력된 사업자등록번호가 유효한지 검사한다.
 * @author : 임재현
 */
function covCsnValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covCsnValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covCsnValidator
 * @desc   : validation을 수행한다.
 * @sig    : csn
 * @param  : csn required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covCsnValidator_validate(csn) {
	if ( csn == null || csn.length != 10 || isNaN(csn) )  {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	var sum = 0;
	var nam = 0;
	var checkDigit = -1;
	var checkArray = [1,3,7,1,3,7,1,3,5];

	for(i=0 ; i < 9 ; i++)
	  sum += csn.charAt(i) * checkArray[i];

	sum = sum + ((csn.charAt(8) * 5 ) / 10);

	nam = Math.floor(sum) % 10;

	checkDigit = ( nam == 0 ) ? 0 : 10 - nam;

	if ( csn.charAt(9) != checkDigit) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covFilterInValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 지정된 문자 이외에 다른 문자가 들어있을 경우 유효하지 않은 것으로 판단한다.
 *           특정 문자들에 대한 특수문자가 아래에 나와있다.<br>
 * <pre>
 *         ;    - \;
 *         한글 - \h
 *         영문 - \a
 *         숫자 - \n
 * </pre>
 * @sig    : fStr
 * @param  : fStr required filter에 대한 표현
 * @author : 임재현
 */
function covFilterInValidator(fStr) {
    // data;
    this.message = "";
    this.validity = false;
    this.fStrArr = fStr.advancedSplit(";", "i");

    for (var i = 0; i < this.fStrArr.length; i++) {
    	if (this.fStrArr[i] == "\\h") {
    		this.fStrArr[i] = "한글";
    	} else if (this.fStrArr[i] == "\\a") {
    		this.fStrArr[i] = "영문";
    	} else if (this.fStrArr[i] == "\\n") {
    		this.fStrArr[i] = "숫자";
    	}
    }

    // method
    this.validate = covFilterInValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covFilterInValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covFilterInValidator_validate(value) {
	var isIn = false;
	var c
	var cCode;

	for (var i = 0; i < value.length; i++) {
		isIn = false;
		c = value.charAt(i);
		cCode = value.charCodeAt(i);

		for (var j = 0; j < this.fStrArr.length; j++) {
			if (this.fStrArr[j] == "한글" &&
			    ((0xAC00 <= cCode && cCode <= 0xD7A3) || (0x3131 <= cCode && cCode <= 0x318E))
			   ) {
				isIn = true;
			} else if ( this.fStrArr[j] == "영문" &&
			            ((0x61 <= cCode && cCode <= 0x7A) || (0x41 <= cCode && cCode <= 0x5A))
			          ) {
				isIn = true;
			} else if (this.fStrArr[j] == "숫자" && !isNaN(c)) {
				isIn = true;
			} else if (this.fStrArr[j] == c) {
				isIn = true;
			}
		}

		if (!isIn) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.acceptCharacter"), ["@", this.fStrArr.toString()]);
			return false;
		}
	}

	this.validity = true;
	return true;
}

///////////////////////////// covFilterOutValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 지정된 스트링들이 들어있을 경우 유효하지 않은것으로 판단한다.
 *           분리자는 ";"를 사용한다. ";" 혹은 ";"문자가 들어간 스트링을 필터링하려 할 경우는
 *           "\\;"라고 표기해야 한다.
 * @sig    : fStr
 * @param  : fStr required filter에 대한 표현
 * @author : 임재현
 */
function covFilterOutValidator(fStr) {
    // data;
    this.message = "";
    this.validity = false;
    this.fStrArr = fStr.advancedSplit(";", "i");

    // method
    this.validate = covFilterOutValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covFilterValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covFilterOutValidator_validate(value) {
	for (var i = 0; i < this.fStrArr.length; i++) {
		if (value.indexOf(this.fStrArr[i]) != -1) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noAcceptCharacter"), ["@", this.fStrArr.toString()]);
			return false;
		}
	}

	this.validity = true;
	return true;
}

///////////////////////////// covEmailValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 입력값이 email 형식에 적합한지를 검사한다.
 * @author : 임재현
 */
function covEmailValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covEmailValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covEmailValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covEmailValidator_validate(value) {
	var format = /^((\w|[\-\.])+)@((\w|[\-\.])+)\.([A-Za-z]+)$/;

	if (value.search(format) == -1) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covPhoneValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 입력값이 phone 형식에 적합한지를 검사한다.
 * @author : 홍두희
 */
function covPhoneValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covPhoneValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covPhoneValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covPhoneValidator_validate(value) {
	
	var format = /^0\d{1,2}-\d{3,4}-\d{4}$/;
	if(value != "") {
		if (!value.match(format)) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
			return false;                
		}        
		var str = value.substr(1,2);
		if (!(str == "2-" || str == "31" || str == "32" || str == "33" || str == "41"|| str =="42" || str == "43" ||
			   str == "51" || str == "52" || str == "53"|| str == "54" || str =="55" || str =="61" || str =="62" || str =="63"  || str =="64")) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
			return false;
		}
	}

	if (value.search(format) == -1) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
		return false;
	}

	value = cfReplaceAll(value,"-","");

	if(!covNumberValidator_validate(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covHPhoneValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 입력값이 phone 형식에 적합한지를 검사한다.
 * @author : 홍두희
 */
function covHPhoneValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covHPhoneValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covHPhoneValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covHPhoneValidator_validate(value) {
	
	var format = /^0\d{1,2}-\d{3,4}-\d{4}$/;
	if(value != "") {
		if (!value.match(format)) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
			return false;                
		}        
		var str = value.substr(0,3);
		if (!(str == "010" || str == "011" || str == "019" || str == "018" || str == "017"|| str =="016" || str == "070")) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
			return false;
		}
	}

	if (value.search(format) == -1) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
		return false;
	}

	value = cfReplaceAll(value,"-","");

	if(!covNumberValidator_validate(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covGPhoneValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 입력값이 phone 형식에 적합한지를 검사한다. (phone 또는 hphone 모두 체크)
 * @author : 홍두희
 */
function covGPhoneValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covGPhoneValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covGPhoneValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covGPhoneValidator_validate(value) {
	var format = /^0\d{1,2}-\d{3,4}-\d{4}$/;
	if(value != "") {
		if (!value.match(format)) {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
			return false;                
		}        
		var str = value.substr(1,2);
		var str2 = value.substr(0,3);
		if ((str2 == "010" || str2 == "011" || str2 == "019" || str2 == "018" || str2 == "017"|| str2 =="016" || str2 == "070") ||
			(str == "2-" || str == "31" || str == "32" || str == "33" || str == "41"|| str =="42" || str == "43" ||
			   str == "51" || str == "52" || str == "53"|| str == "54" || str =="55" || str =="61" || str =="62" || str =="63"  || str =="64")) {
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
			return false;
		}
	}

	if (value.search(format) == -1) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.format1"), ["@"]);
		return false;
	}

	value = cfReplaceAll(value,"-","");

	if(!covNumberValidator_validate(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}

	this.validity = true;
	return true;
}

///////////////////////////// covCorpValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 입력값이 phone 형식에 적합한지를 검사한다.
 * @author : 홍두희
 */
function covCorpValidator() {
    // data;
    this.message = "";
    this.validity = false;

    // method
    this.validate = covCorpValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covCorpValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value required 유효성 검사 대상값.
 * @return : boolean. 유효성 여부.
 */
function covCorpValidator_validate(value) {
	
	value = cfReplaceAll(value,"-","");

	if(!covNumberValidator_validate(value)) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.onlyNumber"), ["@"]);
		return false;
	}
	
	if(value.length != 13) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
		return false;
	}
	
	var arr_regno = value.split("");
	var arr_wt = new Array(1,2,1,2,1,2,1,2,1,2,1,2);
	var iSum_regno = 0;
	var iCheck_digit = 0;

	//1~12자리까지 가중치를 곱하여 모두 더한다.
	for (i = 0; i < 12; i++) {
		iSum_regno +=	eval(arr_regno[i]) * eval(arr_wt[i]);
	}

	//합계를 10으로 나눈 나머지를 10에서 뺀다.
	iCheck_digit = 10 - (iSum_regno % 10);

	//계산 값을 10으로 나눈 나머지를 구한다. (Check Digit)
	iCheck_digit = iCheck_digit % 10;

	if (iCheck_digit != arr_regno[12]) {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
    	return false;
	}	

	this.validity = true;
	return true;
}

///////////////////////////// covDateValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 값이 Date형식인지를 검사한다.
 *
 *            format문자 :  YYYY,  -> 4자리 년도
 *                          YY,    -> 2자리 년도. 2000년 이후.
 *                          MM,    -> 2자리 숫자의 달.
 *                          DD,    -> 2자리 숫자의 일.
 *                          hh,    -> 2자리 숫자의 시간. 12시 기준
 *                          HH,    -> 2자리 숫자의 시간. 24시 기준
 *                          mm,    -> 2자리 숫자의 분.
 *                          ss     -> 2자리 숫자의 초.
 *
 *            예)
 *                'YYYYMMDD' -> '20020328'
 *                'YYYY/MM/DD' -> '2002/03/28'
 *                'Today : YY-MM-DD' -> 'Today : 02-03-28'
 *
 *            참고)
 *                  format문자가 중복해서 나오더라도 처음 나온 문자에 대해서만
 *                  format문자로 인식된다. YYYY와 YY, hh와 HH 도 중복으로 본다.
 *                  날짜는 년,월이 존재할 때만 정확히 체크하고 만일 년, 월이 없다면
 *                  1 ~ 31 사이인지만 체크한다.
 *
 * @sig    : dateExp
 * @param  : dateExp required Date Format expression.
 *             예) 2002년 3월 12일 -> "YYYY-MM-DD"(Date Format Expression) -> "2002-03-12"
 * @author : 임재현
 */
function covDateValidator(dateExp) {
    // data;
    this.message = "";
    this.validity = false;
    this.dateExp = dateExp;
    this.year = null;
    this.month = null;

    // method
    this.validate = covDateValidator_validate;
    this.checkLength = covDateValidator_checkLength;
    this.checkYear = covDateValidator_checkYear;
    this.checkMonth = covDateValidator_checkMonth;
    this.checkDay = covDateValidator_checkDay;
    this.checkHour = covDateValidator_checkHour;
    this.checkMin = covDateValidator_checkMin;
    this.checkSec = covDateValidator_checkSec;
    this.checkRest = covDateValidator_checkRest;
}

/**
 * @type   : method
 * @access : public
 * @object : covDateValidator
 * @desc   : validation을 수행한다.
 * @sig    : value
 * @param  : value   required 검사대상이 되는 Date 스트링 값.
 * @return : boolean - 유효성 여부
 */
function covDateValidator_validate(value) {
	this.value = value;

	if ( this.checkLength(value) &&
		 this.checkYear(value) &&
		 this.checkMonth(value) &&
		 this.checkDay(value) &&
		 this.checkHour(value) &&
		 this.checkMin(value) &&
		 this.checkSec(value) &&
		 this.checkRest(value)
	   ) {
		this.validity = true;
		return true;
	} else {
		this.validity = false;
		return false;
	}
}

function covDateValidator_checkLength() {
	if (this.value.length == this.dateExp.length) {
		return true;
	} else {
		this.message = new coMessage().getMsg(ezMessage("pbf.err.com.length"), ["@", String(this.dateExp.length)]);
		return false;
	}
}

function covDateValidator_checkYear() {
	var index = -1;

	if ( (index = this.dateExp.indexOf("YYYY")) != -1 ) {
		subValue = this.value.substr(index, 4);
		if ( !isNaN(subValue) &&
			 (subValue > 0)
		   ) {
			this.dateExp = this.dateExp.cut(index, 4);
			this.value = this.value.cut(index, 4);
			this.year = subValue;
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	if ( (index = this.dateExp.indexOf("YY")) != -1 ) {
		subValue = "20" + this.value.substr(index, 2);
		if ( !isNaN(subValue) &&
			 (subValue > 0)
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			this.year = subValue;
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	return true;
}

function covDateValidator_checkMonth() {
	var index = -1;

	if ( (index = this.dateExp.indexOf("MM")) != -1 ) {
		subValue = this.value.substr(index, 2);
		if ( !isNaN(subValue) &&
		     (subValue > 0) &&
		     (subValue <= 12)
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			this.month = subValue;
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	return true;
}

function covDateValidator_checkDay() {
	var index = -1;
	var days = 0;

	if ( (index = this.dateExp.indexOf("DD")) != -1 ) {
		if ( (this.year != null) && (this.month != null) ) {
			days = (this.month != 2) ? GLB_DAYS_IN_MONTH[this.month-1] : (( (this.year % 4) == 0 && (this.year % 100) != 0 || (this.year % 400) == 0 ) ? 29 : 28 );
		} else {
			days = 31;
		}

		subValue = this.value.substr(index, 2);
		if ( (!isNaN(subValue)) &&
		     (subValue > 0) &&
		     (subValue <= days)
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	return true;
}

function covDateValidator_checkHour() {
	var index = -1;

	if ( (index = this.dateExp.indexOf("hh")) != -1 ) {
		subValue = this.value.substr(index, 2);
		if ( !isNaN(subValue) &&
		     (subValue >= 0) &&
		     (subValue <= 12)
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	if ( (index = this.dateExp.indexOf("HH")) != -1 ) {
		subValue = this.value.substr(index, 2);
		if ( !isNaN(subValue) &&
		     (subValue >= 0) &&
		     (subValue < 24)
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	return true;
}

function covDateValidator_checkMin() {
	var index = -1;

	if ( (index = this.dateExp.indexOf("mm")) != -1 ) {
		subValue = this.value.substr(index, 2);
		if ( !isNaN(subValue) &&
		     (subValue >= 0) &&
		     (subValue < 60 )
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			this.month = subValue;
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	return true;
}

function covDateValidator_checkSec() {
	var index = -1;

	if ( (index = this.dateExp.indexOf("ss")) != -1 ) {
		subValue = this.value.substr(index, 2);
		if ( (!isNaN(subValue)) &&
		     (subValue >= 0) &&
		     (subValue < 60 )
		   ) {
			this.dateExp = this.dateExp.cut(index, 2);
			this.value = this.value.cut(index, 2);
			this.month = subValue;
			return true;
		} else {
			this.message = new coMessage().getMsg(ezMessage("pbf.err.com.noValid2"), ["@"]);
			return false;
		}
	}

	return true;
}

function covDateValidator_checkRest() {
	if (this.value == this.dateExp) {
		return true;
	}

	return false;
}


///////////////////////////// covNullValidator /////////////////////////////
/**
 * @type   : object
 * @access : private
 * @desc   : 무조건 valid한 결과를 가진 validator.
 * @author : 임재현
 */
function covNullValidator() {
    // data;
    this.message = "";
    this.validity = true;

    // method
    this.validate = covNullValidator_validate;
}

/**
 * @type   : method
 * @access : public
 * @object : covNullValidator
 * @desc   : validation을 수행한다.
 * @return : boolean - 무조건 true.
 */
function covNullValidator_validate() {
	this.message = new coMessage().getMsg(ezMessage("pbf.info.com.valid"));
	return true;
}

/*********************************************************************************
 *                            권한 체크 관련 함수
 ********************************************************************************/
var CREATE_AUTH;
var RETRIEVE_AUTH;
var UPDATE_AUTH;
var DELETE_AUTH;
var PRINT_AUTH;
var UP_AUTH;
var DOWN_AUTH;
var NAVI_AUTH;
  
/**
 * @type   : function
 * @access : public
 * @desc   : 권한 코드  정보를 반환한다. 
 * <pre>
 *    cfGetAuthCode( authStr )
 * </pre>
 * @sig    : position 
 * @param  : authStr 권한명 
 * @author : 차종호 
 */  
  function cfGetAuthCode( authStr ) {   
      if ( authStr == "C" ) return 40 ;
      else if ( authStr == "D" ) return 30 ;
      else if ( authStr == "U" ) return 20 ;      
      else if ( authStr == "R" ) return 10 ;  
      else return 100 ;                    
  }

/**
 * @type   : function
 * @access : public
 * @desc   : 권한 코드  정보를 반환한다. 
 * <pre>
 *    cfGetAuthCode( authStr )
 * </pre>
 * @sig    : position 
 * @param  : authStr 권한명 
 * @author : 차종호 
 */  
  function cfSetAuthCode( authStr ) {  
  	var auths = authStr.split(":");

	for (var i = 0; i < auths.length; i++) {
	  	switch (auths[i]) {
	  	case 'P':
	  		PRINT_AUTH = auths[i];
	  		break;
	  	case 'W':
	  		UP_AUTH = auths[i];
	  		break;
	  	case 'X':
	  		DOWN_AUTH = auths[i];
	  		break;
	  	case 'C':
	     	CREATE_AUTH = auths[i];
	  		break;
	  	case 'R':
	        RETRIEVE_AUTH = auths[i];
	  		break;
	  	case 'U':
	        UPDATE_AUTH = auths[i];
	  		break;
	  	case 'D':
	  		DELETE_AUTH = auths[i];
	  		break;
	  	case 'N':
	  		NAVI_AUTH = auths[i];
	  		break;
	  	default:
	  		break;
		}
	}  	                   
  }

/**
 * @type   : function
 * @access : public
 * @desc   : 해당 권한을 가지고 있는지 여부를  반환한다. userAuth에 ":"으로 분리되어 설정된 모든 권한이 있을 경우에만 true를 리턴한다.<br>
 * <pre>
 *    cfCheckAuth( authStr )
 * </pre>
 * @sig    : position 
 * @param  : baseAuth 기본권한명  
 * @author : 이정 
 */    
  function cfCheckAuth( baseAuth ) {
    var isAuth = true;
  	var auths = baseAuth.split(":");
  	
	for (var i = 0; i < auths.length; i++) {
	  	switch (auths[i]) {
	  	// 프린트
	  	case 'P':
	  		isAuth = cfCheckAuthPrint(auths[i]);
	  		break;
	  	// 파일 업로드
	  	case 'W':
	  		isAuth = cfCheckAuthUpload(auths[i]);
	  		break;
	  	// 파일 다운로드
	  	case 'X':
	  		isAuth = cfCheckAuthDownload(auths[i]);
	  		break;
	  	// 화면 네비게이션
	  	case 'N':
	  		isAuth = cfCheckAuthNavi(auths[i]);
	  		break;
	  	// CRUD
	  	case 'C':
	     	isAuth = cfCheckAuthCreate(auths[i]);
	  		break;
	  	case 'R':
	        isAuth = cfCheckAuthRetrieve(auths[i]);
	  		break;
	  	case 'U':
	        isAuth = cfCheckAuthUpdate(auths[i]);
	  		break;
	  	case 'D':
	  		isAuth = cfCheckAuthDelete(auths[i]);
	  		break;
	  	default:
	  		alert("'" + auths[i] + "'는 정의되지 않은 권한코드입니다");
	  		isAuth = false;
	  		break;
		}
		
		if (isAuth == false)
			return false;
	}
  	
  	return true;
  }
   
/**
 * @type   : function
 * @access : public
 * @desc   : 생성 CREATE  권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthCreate(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */    
  function cfCheckAuthCreate() { 
   if (  CREATE_AUTH == "C" ) return true ; 
   else return false ; 
  }
  
/**
 * @type   : function
 * @access : public
 * @desc   : 조회  RETRIEVE  권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthRetrieve(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */    
  function cfCheckAuthRetrieve() { 
   if (  RETRIEVE_AUTH == "R" ) return true ; 
   else return false ; 
  } 
    
/**
 * @type   : function
 * @access : public
 * @desc   : 수정 UPDATE  권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthUpdate(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */    
  function cfCheckAuthUpdate() { 
   if (  UPDATE_AUTH == "U" ) return true ; 
   else return false ; 
  }  
  
/**
 * @type   : function
 * @access : public
 * @desc   : 삭제  DELETE  권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthDelete(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */    
  function cfCheckAuthDelete() { 
   if (  DELETE_AUTH == "D" ) return true ; 
   else return false ; 
  } 

    
/**
 * @type   : function
 * @access : public
 * @desc   : 출력 PRINT  권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthPrint(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */    
  function cfCheckAuthPrint() { 
   if (  PRINT_AUTH == "P" ) return true ; 
   else return false ; 
  }
  
/**
 * @type   : function
 * @access : public
 * @desc   : 다운로드 권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthDownload(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */      
  function cfCheckAuthDownload() { 
   if ( DOWN_AUTH == "X" ) return true ; 
   else return false ; 
  }  
  
/**
 * @type   : function
 * @access : public
 * @desc   : 업로드 권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthDownload(  )
 * </pre>
 * @sig    : position 
 * @author : 홍두희 
 */      
  function cfCheckAuthUpload() { 
   if ( UP_AUTH == "W" ) return true ; 
   else return false ; 
  }    
  
/**
 * @type   : function
 * @access : public
 * @desc   : 화면이동 권한을 가지고 있는지 여부를  반환한다. 
 * <pre>
 *    cfCheckAuthNavi(  )
 * </pre>
 * @sig    : position 
 * @author : 차종호 
 */      
  function cfCheckAuthNavi() { 
   if ( NAVI_AUTH == "N" ) return true ; 
   else return false ; 
  }  
  
function tabberAutomaticOnLoad(tabberArgs)
{
  var oldOnLoad;

  if (!tabberArgs) { tabberArgs = {}; }

  oldOnLoad = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = function() {
      tabberAutomatic(tabberArgs);
    };
  } else {
    window.onload = function() {
      oldOnLoad();
      tabberAutomatic(tabberArgs);
    };
  }
}

/**
 * @type   : function
 * @access : public
 * @desc   : 입력된 영문 중 소문자를 대문자로 변경해 주는 함수
 * @sig    : inputObj
 * @param  : inputObj required input type=text 또는 textarea 오브젝트
 */
function cfToUpper(inputObj) {
	if (inputObj.tagName == "INPUT") {
		if (inputObj.type.toUpperCase() == "TEXT") {
			inputObj.value = inputObj.value.toUpperCase();
		}
	}
	else if (inputObj.tagName == "TEXTAREA") {
		inputObj.value = inputObj.value.toUpperCase();
	}
}

/**
 * @type   : function
 * @access : public
 * @desc   : 입력된 문자열이 한글로 된 정보인지를 체크한다. 해당문자열이 한글과 스페이스의 조합일때만 true를 리턴한다.
 * @sig    : oValue
 * @param  : oValue required 문자열
 */
function cfIsHan(oValue){ 
    var pattern = new RegExp('[^가-?\x20]', 'i'); 
    if (pattern.exec(oValue) != null) { 
        return false; 
    } else { 
        return true; 
    } 
} 

var stringXsyncResult;

/**
 * @type   : function
 * @access : public
 * @desc   : DB 조회를 통해 특정 키값이 있는지 여부를 체크한다.
 * @sig    : qId, urlQuery
 * @param  : qId required 키값을 Count 하는 쿼리 아이디.
 * @param  : urlQuery required 문자열
 */
function cfCheckUniqueFromDB(qId, urlQuery) {
    stringXsyncResult = '';
    var aJax = new lafj.xSync("/pbf.comm.xsync.retrieveKeyCheck.laf");
    aJax.addQuery("qId", qId);
    aJax.addStringQuery(urlQuery);
    aJax.async=false;
    aJax.fire();
    
    return stringXsyncResult;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 레벨정보를 가지는 공통코드정보를 럭스콤보 데이터 형태로 리턴한다.
 * @sig    : pClasCd, pUpperClasCd, pUpComCd
 * @param  : pClasCd required 마스터 코드
 * @param  : pUpperClasCd required 상위코드클래스
 * @param  : pUpComCd required 상위코드
 */
function cfGetCBDataByLvl(pClasCd, pUpperClasCd, pUpperComnCd) {
    stringXsyncResult = '';
    var aJax = new lafj.xSync("/pbf.comm.xsync.retrieveCBDataByLvl.laf");
    aJax.addQuery("clasCd", pClasCd);
    aJax.addQuery("upperClasCd", pUpperClasCd);
    aJax.addQuery("upperComnCd", pUpperComnCd);

    aJax.async=false;
    aJax.fire();
    return stringXsyncResult;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 공통코드정보를 럭스콤보 데이터 형태로 리턴한다.
 * @sig    : pClasCd
 * @param  : pClasCd required 마스터 코드
 */
function cfGetCBData(pClasCd) {
    stringXsyncResult = '';
    var aJax = new lafj.xSync("/pbf.comm.xsync.retrieveCBData.laf");
    aJax.addQuery("clasCd", pClasCd);

    aJax.async=false;
    aJax.fire();
    
    return stringXsyncResult;
}


var GLB_POPPY = new Object();

function cfGetWinWidth() {
  var myWidth = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myWidth = window.innerWidth;
  } else if( document.body.scrollWidth ) {
    //IE 7+ in 'standards compliant mode'
    myWidth = document.body.scrollWidth;
  } else if( document.documentElement && document.documentElement.clientWidth ) {
    //IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
  } else if( document.body && ( document.body.clientWidth ) ) {
    //IE 4 compatible
    myWidth = document.body.clientWidth;
  }
  return myWidth;
}

function cfGetWinHeight() {
  var myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myHeight = window.innerHeight;
  } else if( document.body.scrollHeight ) {
    //IE 7+ in 'standards compliant mode'
    myWidth = document.body.scrollHeight;
  } else if( document.documentElement && document.documentElement.clientHeight ) {
    //IE 6+ in 'standards compliant mode'
    myHeight = document.documentElement.clientHeight;
  } else if( document.body && document.body.clientHeight ) {
    //IE 4 compatible
    myHeight = document.body.clientHeight;
  }
  return myHeight;
}

/**
 * @type   : function
 * @access : public
 * @desc   : IFrame을 통하여 document내에 팝업 페이지를 오픈한다.
 * @sig    : oUrl, oWidth, oHeight, oItem
 * @param  : oUrl required 팝업 src 정보
 * @param  : oWidth required 팝업창 가로사이즈
 * @param  : oHeight required 팝업창 세로사이즈
 * @param  : oItem 팝업이 열릴 위치를 판단하는 object
 */
function cfCreatePopup(oUrl, oWidth, oHeight, oItem, oLeft, oTop) {
  var leftPos = (cfGetWinWidth()-oWidth)/2;
  var topPos  = (cfGetWinHeight()-oHeight)/2;
  
  if(oItem) {
	leftPos  = oItem.getBoundingClientRect().right-oWidth + 5;
    topPos = oItem.getBoundingClientRect().bottom + 5;
  }
  
  if ( leftPos < 0 )
    leftPos=50;

  if ( topPos < 0 )
    topPos=50;

  if(oLeft != undefined) leftPos = oLeft;
  //alert("leftPos : "+leftPos);

  if(oTop != undefined) topPos = oTop;

  var poppy = document.getElementById("poppy");

  cfStoreCurState();
  
  if(poppy == null){
	var div = document.getElementById("popup");
	
	div.innerHTML = "<IFRAME id='poppy'  style='position : absolute; left: "+leftPos+"px; top: "+topPos+"px; width: "+oWidth+"px; height: "+oHeight+"px;' frameborder='0' src='"+oUrl+"' scrolling='no' ></IFRAME>";
//    document.body.insertAdjacentHTML("beforeEnd", "<IFRAME id='poppy'  style='position:absolute; left:"+leftPos+"px; top:"+topPos+"px; width:" + oWidth + "; height:"+oHeight+"' frameborder='0' src='"+oUrl+"' scrolling='no'></IFRAME>");  
  }else{
	if(poppy.src == oUrl){
		
	    setTimeout("document.getElementById('poppy').style.visibility='visible'",100);
	    setTimeout("poppy.focus()",100);
	}else{
		
	    poppy.src="/common/include/blank.jsp";
	    poppy.style.left=leftPos;
	    poppy.style.top=topPos;
	    poppy.style.width=oWidth;
	    poppy.style.height=oHeight;
		poppy.src=oUrl;
	    poppy.style.visibility='visible';
	}
  }
}

function cfCreatePopupHidden(oUrl, oWidth, oHeight, oItem, oLeft, oTop) {
  var leftPos = (cfGetWinWidth()-oWidth)/2;
  var topPos  = (cfGetWinHeight()-oHeight)/2;
  if(oItem) {
	leftPos  = oItem.getBoundingClientRect().right-oWidth + 5;
    topPos = oItem.getBoundingClientRect().bottom + 5;
  }

  if ( leftPos < 0 )
    leftPos=50;

  if ( topPos < 0 )
    topPos=50;

  if(oLeft) leftPos = oLeft;

  if(oTop) topPos = oTop;

  var poppy = document.getElementById("poppy");

  document.body.style.cursor='wait';
  cfStoreCurState();
  if(poppy == null){
    document.body.insertAdjacentHTML("beforeEnd", "<IFRAME id='poppy'  style='visibility=hidden; position:absolute; left:"+leftPos+"px; top:"+topPos+"px; width:" + oWidth + "; height:"+oHeight+"' frameborder='0' src='"+oUrl+"' scrolling='no'></IFRAME>");  
  }else{
	if(poppy.src == oUrl){
		//alert(poppy.src + " : " + oUrl);
		//added by koo
	    setTimeout("document.getElementById('poppy').style.visibility='hidden'",100);
	    setTimeout("poppy.focus()",100);
	}else{
		//alert(poppy.src + " : " + oUrl);
	    poppy.src="/common/include/blank.jsp";
	    poppy.style.left=leftPos;
	    poppy.style.top=topPos;
	    poppy.style.width=oWidth;
	    poppy.style.height=oHeight;
		poppy.src=oUrl;
	    poppy.style.visibility='hidden';
	}
  }
  setTimeout("document.body.style.cursor='default'",100);
}

var STATUS_STORE = new coMap();
//cross-browsing 가능하도록 변경: jwkoo
function cfStoreCurState() {
	var btnCnt = 0;
	var imgCnt = 0;
	var allTags = document.getElementsByTagName("body")[0].getElementsByTagName("*");
	for ( var inx = 0; inx < allTags.length; inx++) {
		if (allTags[inx].tagName.toUpperCase() == "INPUT") {
			if (allTags[inx].type.toUpperCase() == "BUTTON") {
				if (!allTags[inx].disabled) {
					if (allTags[inx].id == null || allTags[inx].id == '') {
						allTags[inx] = 'btnMade' + btnCnt;
						btnCnt++;
						STATUS_STORE.put(allTags[inx].id, allTags[inx].disabled);
						allTags[inx].disabled = true;
					} else {
						STATUS_STORE.put(allTags[inx].id, allTags[inx].disabled);
						allTags[inx].disabled = true;
					}
				}
			} else {
				if (!allTags[inx].disabled && allTags[inx].id != '') {
					STATUS_STORE.put(allTags[inx].id, allTags[inx].disabled);
					allTags[inx].disabled = true;
				}
			}
		} else if (allTags[inx].tagName.toUpperCase() == "IMG") {
			if (!allTags[inx].disabled) {
				if (allTags[inx].id == null || allTags[inx].id == '') {
					allTags[inx].id = 'imgMade' + imgCnt;
					imgCnt++;
					STATUS_STORE.put(allTags[inx].id, allTags[inx].disabled);
					allTags[inx].disabled = true;
				} else {
					STATUS_STORE.put(allTags[inx].id, allTags[inx].disabled);
					allTags[inx].disabled = true;
				}
			}
		}
	}
}
//cross-browsing 가능하도록 변경: jwkoo
function cfRestoreCurState() {
	var ele;
	for (i = 0; i < STATUS_STORE.size(); i++) {
		ele = document.getElementById(STATUS_STORE.getNameAt(i));
		if (ele != null && typeof (ele.tagName) != "undefined") {
			if (ele.tagName.toUpperCase() == "INPUT") {
				ele.disabled = STATUS_STORE.getValueAt(i);
			} else if (ele.tagName.toUpperCase() == "IMG") {
				ele.disabled = STATUS_STORE.getValueAt(i);
			}
		}
	}
}

/**
 * @type : function
 * @access : public
 * @desc : 객체 클릭시 팝업객체가 있으면 리로딩
 * 
 document.onmousedown = showPopupHandler;	
function showPopupHandler(){
  var poppy = document.all("poppy");
  if(poppy != null){
	if(poppy.style.visibility != "hidden" ){
	  if( poppy.src != "/common/include/blank.jsp" ){
    	topPos = new Number(poppy.style.top.replace("px", ""));
		poppy.style.top=topPos+1;
		document.all("poppy").style.top=topPos;
		setTimeout("document.all('poppy').style.top=new Number(document.all('poppy').style.top.replace('px', ''))-1",1);
		poppy.style.top=topPos+1;
  	  }
  	}
  }
}
 */

/**
 * @type   : function
 * @access : public
 * @desc   : IFrame을 통하여 오픈된 팝업 페이지를 감춘다.
 */
function cfClosePopup() {
   	GLB_SHOWPOPUP = false;
   	var poppy = document.getElementById("poppy");
   	//if (document.all("poppy") != null) {
   	if( document.getElementById("poppy") != null){	
   	  cfRestoreCurState();
	  //document.all("poppy").focus();
   	  poppy.src="/common/include/blank.jsp";
   	  poppy.style.visibility = "hidden";
	}
}

///**
// * @type   : function
// * @access : public
// * @desc   : IFrame을 통하여 오픈된 팝업 페이지를 감춘다. 팝업창이외의 부분을 누르면 사라짐
// */ 
//function cfClosePopupByEvent() {
//  var width = new Number(event.srcElement.style.width.replace("px", ""));
//  var height = new Number(event.srcElement.style.height.replace("px", ""));
//  var left = new Number(event.srcElement.style.left.replace("px", ""));
//  var top = new Number(event.srcElement.style.top.replace("px", ""));
//  
//  //alert('area=' + left + "~" + (left+width) + ',' + top + "~" + (top+height) + ', client=' + event.clientX + ',' + event.clientY );
//  if( (left <= event.clientX && event.clientX < left+width) && (top <= event.clientY && event.clientY < top+height) ){
//  }else{
//  
//    if (document.all("poppy") != null) {
//       // document.all("poppy").style.visibility = "hidden";       
//	}
//  }
//}

/**
 * @type   : function
 * @access : public
 * @desc   : 쿠키정보를 리턴한다.
 */
function getCookie(sName) {
  // cookies are separated by semicolons
  var aCookie = document.cookie.split("; ");
  for (var i=0; i < aCookie.length; i++)  {
    // a name/value pair (a crumb) is separated by an equal sign
    var aCrumb = aCookie[i].split("=");
    if (sName == aCrumb[0]) {
    	if (typeof(aCrumb[1]) == "undefined" || aCrumb[1] =="" || aCrumb[1] == null) return null;
      return unescape(aCrumb[1]);
    }
  }

  // a cookie with the requested name does not exist
  return null;
}

function f_OnLoad() {
}

var GLB_IMG_PATH;
function cfOpenImageUploader(oUpload, arg) {
  GLB_IMG_PATH = oUpload;
  cfCreatePopup("/jsp/pbf/comm/file/imageUploader.jsp?atchFileBunchNo=" + arg, 270, 100, oUpload);
}

function cfOpenImageUploader1(oUpload) {
  GLB_IMG_PATH = oUpload;
  cfCreatePopup("/jsp/cs/com/popup/imageUploader.jsp", 270, 200, oUpload);
}

function cfSetImagePath(uploadPath) {
	GLB_IMG_PATH.value = uploadPath;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 로컬 CSV 파일을 이용하여 Report Designer Viewer를 구동할 때 사용한다.<br>
 *           구동시 지정된 그리드의 내용을 로컬 C드라이브에 CSV파일을 자동으로 작성한다.
 * @sig    : oGrid, mrdFileNm, exParam, isOpenWindow, width, height
 * @param  : oGrid required CSV 파일로 export할 대상 그리드
 * @param  : mrdFileNm required 서버의 mrd 파일 경로
 * @param  : exParam mrd 파일 구동에 필요한 파라미터 정보
 */
function cfPrintReportByFile(oGrid, mrdFileNm, exParam) {
  cfReportByFile(oGrid, mrdFileNm, exParam, false, null, 1, 1, 1);
}
function cfReportByFile(oGrid, mrdFileNm, exParam, isOpenWindow, width, height) {
  cfReportByFile(oGrid, mrdFileNm, exParam, isOpenWindow, null, width, height);
}
function cfReportByFile(oGrid, mrdFileNm, exParam, isOpenWindow, innerObj, width, height, option) {
  // 파라메터 설정
  oGrid.OpenSaveAsDlg="False";
  cfGridToCSV(oGrid, 'C:\\rd_temp.csv', 1+4+8);  // Save Temp 파일
  if ( exParam == null ) exParam = "/rfn [C:/rd_temp.csv]";
  var actionUrl = '/jsp/pbf/report/csvReport.jsp';
  // RD연동
  cfReportView(actionUrl, mrdFileNm, exParam, null, isOpenWindow, innerObj, width, height, option);
}

/**
 * @type   : function
 * @access : public
 * @desc   : 로컬 CSV 파일을 이용하여 Report Designer Viewer를 구동할 때 사용한다.<br>
 *           구동시 지정된 그리드의 내용을 로컬 C드라이브에 CSV파일을 자동으로 작성한다.
 * @sig    : mrdFileNm, exParam
 * @param  : mrdFileNm required 서버의 mrd 파일 경로
 * @param  : exParam mrd 파일 구동에 필요한 파라미터 정보
 */
function cfPrintReportByDB(mrdFileNm, exParam) {
  cfReportByDB(mrdFileNm, exParam, false, null, 1, 1, 1);
}
function cfReportByDB(mrdFileNm, exParam, isOpenWindow, width, height) {
  cfReportByDB(mrdFileNm, exParam, isOpenWindow, null, width, height);
}
function cfReportByDB(mrdFileNm, exParam, isOpenWindow, innerObj, width, height, option) {
  // 파라메터 설정
  var actionUrl = '/jsp/pbf/report/dbReport.jsp';
  exParam += $rdAgentParam;
  // RD연동
  cfReportView(actionUrl, mrdFileNm, exParam, null, isOpenWindow, innerObj, width, height, option);
}

/**
 * @type   : function
 * @access : public
 * @desc   : 로컬 CSV 파일을 이용하여 Report Designer Viewer를 구동할 때 사용한다.<br>
 *           구동시 지정된 그리드의 내용을 로컬 C드라이브에 CSV파일을 자동으로 작성한다.
 * @sig    : mrdFileNm, exParam
 * @param  : mrdFileNm required 서버의 mrd 파일 경로
 * @param  : exParam mrd 파일 구동에 필요한 파라미터 정보
 */
function cfPrintReportByRdData(mrdFileNm, exParam, rdData) {
  cfReportByRdData(mrdFileNm, exParam, rdData, false, null, 1, 1, 1);
}
function cfReportByRdData(mrdFileNm, exParam, rdData, isOpenWindow, width, height) {
  cfReportByRdData(mrdFileNm, exParam, rdData, isOpenWindow, null, width, height);
}
function cfReportByRdData(mrdFileNm, exParam, rdData, isOpenWindow, innerObj, width, height, option) {
  // 파라메터 설정
  var actionUrl = '/jsp/pbf/report/rdReport.jsp';
  if(typeof(rdData) == "undefined" || rdData.length == 0){
  	cfAlertMsg("레포트을 실행할 데이터가 없습니다."); return;
  }else{
  	rdData = customizestrForRd(rdData); // RD에서 사용할 수 문자열로 치환
  }
  // RD연동
  cfReportView(actionUrl, mrdFileNm, exParam, rdData, isOpenWindow, innerObj, width, height, option);
}

function customizestrForRd(str){
  var returnStr = str
  if(typeof(returnStr) == "undefined") return str;
  returnStr=cfReplaceAll(returnStr, '\"', ""); // 쌍따옴표 삭제
  returnStr=cfReplaceAll(returnStr, '\n', "%^%"); // 개행문자를 %^%로 치환
  returnStr=cfReplaceAll(returnStr, '\r', ""); // 나머지 잔여 개행문자는 삭제
  return returnStr;
}

function ReverseForCustomizestr(str){
  var returnStr = str
  if(typeof(returnStr) == "undefined") return str;
  returnStr=cfReplaceAll(returnStr, "%^%", "\r\n"); //  %^%를 개행문자로 치환
  return returnStr;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 로컬 CSV 파일을 이용하여 Report Designer Viewer를 구동할 때 사용한다.<br>
 *           구동시 지정된 그리드의 내용을 로컬 C드라이브에 CSV파일을 자동으로 작성한다.
 * @sig    : actionUrl, mrdFileNm, exParam, rdData, isOpenWindow, innerObj, width, height
 * @param  : option : 
 *            - 1 : 인쇄
 */
function cfReportView(actionUrl, mrdFileNm, exParam, rdData, isOpenWindow, innerObj, width, height, option) {

  var target = "";

  var mainObj = null;

  if(typeof(innerObj) == "undefined" || innerObj == null){
    mainObj = document;
  }else{
    mainObj = innerObj;
  }

  if(typeof(isOpenWindow) == "undefined") isOpenWindow = true;                                                                                                                                        
                                                                                                                                                                                                      
  if(isOpenWindow){
	if(typeof(width) == "undefined") width = screen.width/2 + 100;
 	if(typeof(height) == "undefined") height = screen.height/2 + 100;

	var top = (screen.height-height)/2;
	var left = (screen.width-width)/2;
  	if(typeof(mainObj.all.reportContents) != "undefined") mainObj.all.reportContents.outerHTML = "";
  	target = "reportTargetWindow";
    window.open("/jsp/pbf/loadsignal/blank.jsp", target, "top="+top+", left="+left+", height="+height+",width="+width+",status=no,toolbar=no,menubar=no,location=no,scrollbars=yes,resizable=yes");

  }else{
  	if(typeof(width) == "undefined") width="100%";
  	if(typeof(height) == "undefined") height="460px";

  	if(typeof(mainObj.id) != "undefined"){
	  	target = "reportTargetFrame_" + mainObj.id;
	}else{
		target = "reportTargetFrame";
	}

  	if(typeof(mainObj.all.reportContents) == "undefined"){
  	  iFrame = null;
	  if(typeof(innerObj) == "undefined" || innerObj == null){
   	    iFrame = document.createElement("<div id='reportContents' class='layout_page' style='padding: 0px 0px 100px 0px'>");
	    mainObj.body.insertAdjacentElement("beforeEnd", iFrame);
	  }else{
   	    iFrame = document.createElement("<div id='reportContents'>");
	    innerObj.insertAdjacentElement("beforeEnd", iFrame);
	  }
   	  var reportFrame = document.createElement("<iframe id='reportFrame' name='" + target + "' frameborder='0' border='0' scrolling='no' width=" + width + " height=" + height + "></iframe>");
      iFrame.insertAdjacentElement("beforeEnd", reportFrame);
    }else{
      // 있을 경우에는 사이즈만 재조절
      document.all.reportFrame.width = width;
      document.all.reportFrame.height = height;
    }
  }

  var parameterForm = mainObj.all("reportForm");
  if ( parameterForm != null ) {
  	if( typeof(mainObj.body) != "undefined"){
  	  // 주석 처리
      //mainObj.body.removeChild(parameterForm);
    }
  }

  parameterForm = document.createElement("<FORM id=reportForm method=post action='" +  actionUrl + "' target='" + target + "'>");

  if( typeof(mainObj.body) != "undefined"){
    mainObj.body.insertAdjacentElement("beforeEnd", parameterForm);
  }else{
    mainObj.insertAdjacentElement("beforeEnd", parameterForm);
  }

  var paramObj = document.createElement("<INPUT>");
  paramObj.name = "mrdFileNm";
  paramObj.type = "hidden";
  paramObj.value = mrdFileNm;
  parameterForm.insertAdjacentElement("beforeEnd", paramObj);

  var paramObj1 = document.createElement("<INPUT>");
  paramObj1.name = "rdParam";
  paramObj1.type = "hidden";
  paramObj1.value = exParam;
  parameterForm.insertAdjacentElement("beforeEnd", paramObj1);

  var paramObj2 = document.createElement("<INPUT>");
  paramObj2.name = "isOpenWindow";
  paramObj2.type = "hidden";
  paramObj2.value = isOpenWindow;
  parameterForm.insertAdjacentElement("beforeEnd", paramObj2);

  if(rdData != null && typeof(rdData) != "undefined"){
	var paramObj3 = document.createElement("<INPUT>");
	paramObj3.name = "rdData";
	paramObj3.type = "hidden";
	paramObj3.value = rdData;
	parameterForm.insertAdjacentElement("beforeEnd", paramObj3);
  }

  if(option != null && typeof(option) != "undefined"){
	var paramObj4 = document.createElement("<INPUT>");
	paramObj4.name = "option";
	paramObj4.type = "hidden";
	paramObj4.value = option;
	parameterForm.insertAdjacentElement("beforeEnd", paramObj4);
	//reportContents.style.display = "none";
  }
  parameterForm.submit();

}

function cfHideObj(aObj){
	var obj =  $(aObj);
	if (obj!=null)
	obj.style.display = "none";
}

function loadingPageHide(){
	cfHideObj("LOADING");
}

/**
 * @type   : function
 * @access : public
 * @desc   : 입력된 값을 comma 포맷의 원화형태로 변환하는 함수.
 * @sig    : inputStr
 * @param  : inputStr required input 숫자값
 */
function cfToComma(inputStr) {
   var str = inputStr+"";
   var nam = str.length % 3;
   var value = "";
   for ( var i = 0; i < str.length; i++ ) {
	  var ch = str.charAt(i);
	  for ( var k = 0; k<str.length/3; k++ ) {
		 if ( i == nam + 3 * k && i != 0 ) value =  value + ',';
	  }
	  value = value + ch;
   }
   return value;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 화면상의 입력과 관련된 오브젝트에 대한 유효성 검사를 실시한다. 유효성 검사를 받는 오브젝트들은 "alt" 속성값을 설정해야 한다<br><br>
 *           - 해당 오브젝트에 대한 child 오브젝트들까지도 검사한다. 예를들어, 검사받을 오브젝트들을 &lt;div&gt; 태그로 감싸고
 *             &lt;div&gt; 태그의 id를 파라미터로 준다면 &lt;div&gt; 태그내의 모든 오브젝트들이 자동으로 검사받게 된다. 또,
 *             &lt;table&gt;안에 입력필드들은 &lt;table&gt;의 id를 파라미터로 주면 된다.<br><br>
 *           - 입력값의 앞과 뒤의 공백은 유효성 검사를 하면서 자동으로 trim된다.
 * @sig    : objArr
 * @param  : objectArr required 유효성검사를 하고자 하는 오브젝트들의 Array.
 * @return : boolean. 유효성 여부.
 * @author : 임재현
 */
function cfValidateAll() {
	var returnValue = cfValidate(document.all);
	if( typeof(returnValue) == "undefined" ) return true;
	return returnValue;
}

/**
 * @type   : function
 * @access : public
 * @desc   : 해당 문자열의 내용에서 필요한 부분의 문자열을 모두 치환한다.
 * <pre>
 * ex) cfReplaceAll(str, orgStr, destStr)
 * </pre>
 * @sig    : oEmedit
 * @param  : str     수정하는 문자열
 * @param  : orgStr  수정할 문자열
 * @param  : destStr 수정될 문자열
 */
function cfReplaceAll(str, orgStr, destStr){
  var i = 0;
  while(i >= 0){
    i = str.indexOf(orgStr, i);
    if(i >= 0){
      str = str.replace(orgStr,destStr);
    }else{
      break; 
    }
    //alert(orgStr + " : " + destStr);
  }
  return str;
}

function cfFilterOnKeyPress(ele, valType, evnt) { 
   var filterType;
   var evntSrc = evnt ? evnt : window.event;
   var sKey = String.fromCharCode(evntSrc.keyCode);

   if ( valType=="phone" )
     filterType = PHONE_FILTER;
   var re = new RegExp(filterType);
   // Enter는 키검사를 하지 않는다.
   if(sKey!="\r" && !re.test(sKey)) {
     evntSrc.returnValue=false;
   }
   delete re;
}

function cfFilterOnBlur() { 
  var filterType;
  var eleValue = '';
  var eleTemp = this.value;

  filterType = PHONE_FILTER;
     
  var re = new RegExp(filterType);

  for (var i = 0; i < eleTemp.length; i++) {
	if (re.test(eleTemp.charAt(i))) {
	  eleValue += eleTemp.charAt(i);
	}
  }
  this.value = eleValue;
  delete re;
}

// 팝업 객체의 사용 유무를 조정
function cfEnablePopupObj(sObj, isEnable){
  var obj = eval("poppy." + sObj);
  cfEnableObj(obj,false);
}

// 날짜 사이의 일수를 계산하여 반환
function cfGetDaysBetween(stDate, edDate){
  var stDate = stDate.toDate("YYYYMMDD");
  var edDate = edDate.toDate("YYYYMMDD");
  //alert(stDate.getTime() + " : " + edDate.getTime());
  var duration = edDate.getTime() - stDate.getTime();
  var days = (duration / (1000 * 60 * 60 * 24));
  return days;
}
