/**
 * @target 기본, 구성정보, 파일 관련 공통함수
 */

/**
 * 기본적인 공통함수를 제공하는 개체입니다.
 *
 * @type {object}
 * @class commLib
 * @namespace commLib
 */
var commLib = {};

/**
 * 구성정보 관련 공통함수를 제공하는 개체입니다.
 *
 * @type {object}
 * @class configLib
 * @namespace configLib
 */
var configLib = {};

/**
 * 파일 관련 공통함수를 제공하는 개체입니다.
 *
 * @type {object}
 * @class fileLib
 * @namespace fileLib
 */
var fileLib = {};

/**
 * 레포트 관련 공통함수를 제공하는 개체입니다.
 *
 * @type {object}
 * @class ubiLib
 * @namespace ubiLib
 */
var ubiLib = {};

/**
 * commLib.setGridViewResizing(arrGridView, arrAdjust) - 지정한 그리드뷰들의 높이를 자동으로 리사이징 하는 이벤트 핸들러를 설정합니다.<br>
 * commLib.setEnterKeySearch() - 페이지에서 첫번째 검색 상자를 찾아서 그 하위의 InputBox 등의 컴포넌트에 Enter 키 검색 이벤트 헨들러를 설정합니다.<br>
 * commLib.getCommonCodeList(codeList, callback) - 지정한 공통코드를 모두 조회하여 데이터리스트를 생성합니다.<br>
 * commLib.loadMessageStorage() - 지정한 메시지 목록을 SessionStorage에 적재합니다.<br>
 * commLib.getMessage(msgCode) - 지정한 메시지 코드와 일치하는 메시지를 반환합니다.
 *
 * commLib.getControlById(id) - 지정한 ID에 해당하는 WQ 컴포넌트 개체를 반환합니다.<br>
 * commLib.getTypeById(id) - 지정한 ID에 해당하는 WQ 컴포넌트 개체의 유형을 반환합니다.<br>
 * commLib.moveToW2xPath(url, target) - 지정한 target 프레임(미지정 시 self)의 페이지를 지정한 WebSquare URL로 이동합니다.<br>
 * commLib.moveToW2xPathByPost(url, params) - 지정한 WebSquare URL로 이동합니다. (HTTP Post)<br>
 * commLib.moveToLoginPage() - 세션 만료시 호출되는 함수로 현재 페이지의 형태를 감안하여 메인 프레임을 로그인 페이지로 강제 이동시킵니다.<br>
 * commLib.setItems(control, items) - 지정한 SelectBox, Checkbox, Radio에 지정한 JSON 배열, 2x2 배열, 문자열 배열 데이터를 설정합니다.<br>
 * commLib.setItemsBindding(control, dataListId, valueName, labelName) - 지정한 SelectBox, Checkbox, Radio에 지정한 DataList 정보를 설정합니다.<br>
 * commLib.setGridViewItemsBindding(gridView, columnId, dataListId, valueName, labelName) - 지정한 GridView의 SelectBox컬럼에 지정한 DataList 정보를 설정합니다.<br>
 * commLib.enableAll(control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들을 활성화시킵니다.<br>
 * commLib.disableAll(control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들을 비활성화시킵니다.<br>
 * commLib.readOnlyAll(control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들을 읽기전용 속성을 활성화시킵니다.<br>
 * commLib.writableAll(control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들을 읽기전용 속성을 비활성화시킵니다.<br>
 * commLib.getValuesByJSON(control, excludeList) -지정한 그룹 하위의 모든 컴포넌트들의 값을 JSON 형식으로 반환합니다.<br>
 * commLib.saveSnapshot = function(snapshotName, control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들의 현재 스냅샷 값을 내부적으로 저장합니다.<br>
 * commLib.reloadSnapshot(snapshotName, control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들의 스냅샷 값을 복원합니다.<br>
 * commLib.isSnapshotModified(snapshotName, control, excludeList) - 지정한 그룹 하위의 모든 컴포넌트들의 스냅샷 값이 변경되었는지 여부를 반환합니다.<br>
 * commLib._setDisabled(control, disable, excludeList) - [내부용] 지정한 그룹 하위의 모든 컴포넌트들을 활성화/비활성화시킵니다.<br>
 * commLib._setReadOnly(control, disable, excludeList) - [내부용] 지정한 그룹 하위의 모든 컴포넌트들의 읽기전용 속성을 활성화/비활성화시킵니다.<br>
 * commLib.setWframe(wframe, url, reload) - 지정한 wframe에 지정한 wframe 페이지를 동적으로 로드합니다.<br>
 * commLib.downloadExcel(gridView, filename, options) - 지정한 그리드뷰의 데이터를 EXCEL 파일로 다운로드 합니다.<br>
 * commLib.downloadExcelMulti(filename, sheetInfos) - 지정한 그리드뷰들의 데이터를 여러 개의 시트를 가진 EXCEL 파일로 다운로드 합니다.<br>
 * commLib.uploadExcel(gridView, options) - 지정한 그리드뷰에 EXCEL 파일을 업로드 합니다.<br>
 * commLib.hiddenColumnsIndex(gridView) - 지정한 그리드뷰에서 숨겨진 컬럼들의 Index 배열을 반환합니다.<br>
 * commLib.getColumnIndexs(gridView, columns) - 지정한 복수의 컬럼들의 Index 배열을 반환합니다.<br>
 * commLib.getGridViewDataList(gridView) - 그리드뷰에 바인딩된 DataList 개체를 반환합니다.<br>
 * commLib.dataExist(dataCollectionID) - 지정한 DataCollection이 존재하는지 여부를 반환합니다.<br>
 * commLib.dataCreate(dataCollectionID, type, infoArr, options, data) - 지정한 DataCollection을 동적으로 생성합니다.<br>
 * commLib.dataRemove(dataCollectionID) - 지정한 DataCollection을 제거합니다.<br>
 * commLib.getDataType(dataCollectionID) - 지정한 DataCollection의 유형을 반환합니다.<br>
 * commLib.dataReset(dataCollectionID) - 지정한 DataCollection의 데이터를 빈 값으로 초기화시킵니다.<br>
 * commLib.mergeDataMapSchema(mergedDataMapID, dataMapList, overwrite) - 지정한 DataMap 개체들의 스키마를 병합한 새로운 DataMap을 생성합니다.<br>
 * commLib.mergeDataMapData(mergedDataMapID, dataMapList, overwrite) - 지정한 DataMap 개체들의 스키마를 병합한 새로운 DataMap을 생성하고 데이터를 적재합니다.<br>
 * commLib.getDataChangeInfo(dataCollectionID, keyList) - 지정한 DataMap 개체들의 스키마를 병합한 새로운 DataMap을 생성하고 데이터를 적재합니다.<br>
 * commLib.log(message, ignoreAlert) - WebSquare가 제공하는 웹 브라우저 콘솔 및 자체 디버깅 로그를 출력합니다.
 *
 * configLib.isDebugMode() - WebSquare가 디버그 모드에서 실행되고 있는지 여부를 반환합니다.<br>
 * configLib.debugInfo() - WebSquare의 디버그 관련 정보를 반환합니다.<br>
 * configLib.scriptModuleList() - WebSquare의 공통 JavaScript 목록을 반환합니다.<br>
 * configLib.language() - WebSquare의 언어 설정을 반환합니다.<br>
 * configLib.processMsgInfo() - WebSquare의 "처리 중" 메시지 팝업 정보를 반환합니다.<br>
 * configLib.sylesInfo() - WebSquare의 StyleSheet 관련 정보를 반환합니다.<br>
 * configLib.environmentInfo() - WebSquare의 개발환경 관련 정보를 반환합니다.<br>
 * configLib.kriisInfo(key) - WebSquare 관련 boerp 사용자 지정 구성 정보를 반환합니다.
 *
 * fileLib.checkExt(control, allowList) - 선택한 파일의 확장자가 업로드 허용된 파일인지 여부를 반환합니다.<br>
 * fileLib.retXmlToJSON(retXml) - 파일 업로드 결과 XML 개체를 JSON 개체로 변환하여 반환합니다.<br>
 *
 * comboCommon.delAllCode(codeArr) - dataList - 전체(all)를 제거합니다<br>
 */

/**
 * 그리드뷰 자동 리사이즈 정보
 *
 * @date 2017. 06. 26.
 * @private
 * @memberOf valLib
 */
commLib.resize = {
	eventExist: false,
	topList: {}
};

/**
 * 지정한 그리드뷰들의 높이를 자동으로 리사이징 하는 이벤트 핸들러를 설정합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 26.
 * @memberOf commLib
 * @param {string[]} arrGridView - 크기를 조정할 그리드뷰 ID들의 배열
 * @param {number[]} arrAdjust - 보정값들의 배열
 */
commLib.setGridViewResizing = function(arrGridView, arrAdjust) {
	try {
		if (!$.isArray(arrGridView)) {
			arrGridView = [ arrGridView ];
		}

		if (!arrAdjust) {
			arrAdjust = [];
			for (var i = 0; i < arrGridView.length; i++) {
				arrAdjust.push(0);
			}
		}

		if (arrAdjust && !$.isArray(arrAdjust)) {
			arrAdjust = [ arrAdjust ];
		}

		if (arrGridView.length != arrAdjust.length) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 그리드뷰의 개수와 보정값의 개수가 일치하지 않습니다.";
		}

		// 이벤트 핸들러가 중복 설정되는 상황을 피하기 위한 설정
		if (commLib.resize.eventExist === true) {
			return;
		}

		// 이벤트 헨들러 설정
		$(window).resize(function() {
			var bodyHeight = $("body").height();

			for (var i = 0; i < arrGridView.length; i++) {
				var gridViewID = arrGridView[i];
				var top = getTopPosition($("#" + gridViewID));

				$w.comp[gridViewID].setGridHeight(bodyHeight - top - 25 - arrAdjust[i]);
			}

			commLib.resize.eventExist = true;
		});

		// 최초 1회 사이즈 조정
		setTimeout(function() {
			$(window).trigger("resize");
		}, 100);

		// Top Position을 구하는 내부 함수입니다.
		function getTopPosition(element) {
			var tagName = element[0].tagName.toLowerCase();
			var orgID = $(element[0]).prop("id");

			var top = commLib.resize.topList[orgID];
			if (top) {
				return top;
			} else {
				top = 0;
			}

			while (tagName != "body") {
				top += element.position().top;
				element = element.parent();
				tagName = element[0].tagName.toLowerCase();
			}

			commLib.resize.topList[orgID] = Math.round(top);
			return Math.round(top);
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.setGridViewResizing: " + e);
	}
};

/**
 * 페이지에서 첫번째 검색 상자를 찾아서 그 하위의 InputBox 등의 컴포넌트에 Enter 키 검색 이벤트 헨들러를 설정합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 28
 * @memberOf commLib
 */
commLib.setEnterKeySearch = function() {
	try {
		var children = WebSquare.util.getChildren($(".shbox").wq()[0], {
				recursive: true,
				excludePlugin: "anchor autocomplete checkcombobox multiselect selectbox calendar trigger gridview group image output span textbox generator iframe upload"
			});

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

			var eks = children[i].getUserData("_eks_");
			if ("Y" != eks) {
				children[i].bind("onkeydown", function(e) {
					if (e.keyCode == 13) {
						var shbox = $(".shbox").wq();
						if (shbox.length > 0) {
							var shboxId = shbox[0].getID();

							var button = $("#" + shboxId).find(".btn_search").wq();
							if (button.length > 0) {
								button[0].trigger("onclick");
							}
						}
					}
				});

				children[i].setUserData("_eks_", "Y");
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.setEnterKeySearch: " + e);
	}
};

/**
 * 모바일 접근 확인합니다.
 *
 * @author 김종갑
 * @date 2022. 08. 23.
 * @memberOf commLib
 */
commLib.isMobile = function(){
	var UserAgent = navigator.userAgent;
	if (UserAgent.match(/iPhone|iPod|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i) != null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null)
	{
		return true;
	} else {
		return false;
	}
}

/**
 * 지정한 공통코드를 모두 조회하여 데이터리스트를 생성합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 28.
 * @memberOf commLib
 * @param {(string|string[])} codeList - 공통코드 목록
 * @param {function} callback - 후처리 익명함수
 */
commLib.getCommonCodeList = function(codeList, callback) {
	try {
		if (!codeList) {
			// 개발자 메시지: 영문지원 안 함
			throw "로딩할 공통코드 목록을 지정해주십시오.";
		}

		if (!$.isArray(codeList)) {
			codeList = [ codeList ];
		}

		if (!$w.data["dlCommonCodes"]) {
			commLib.dataCreate(
				"dlCommonCodes",
				"dataList",
				[
					{id: "grpCd",		name: "그룹코드",		dataType: "text"},
					{id: "grpCdName",	name: "그룹코드명",		dataType: "text"},
					{id: "commCd",		name: "코드",			dataType: "text"},
					{id: "cdName",		name: "코드명",		dataType: "text"},
					{id: "classCd",		name: "중분류코드",		dataType: "text"},
					{id: "applId",		name: "시스템모듈구분",	dataType: "text"},
					{id: "carrCd",		name: "항공사코드",		dataType: "text"}
				]);
		}

		$w.ajax({
			action : "/sym/selCommCdList",
			mode : "asynchronous",
			mediatype : "application/json",
			method : "POST",
			processMsg : "",
			requestData : strLib.serialize({ commCdList: codeList.join() }),
			requestHeader : "",
			success : function(e) {
				dlCommonCodes.setJSON(strLib.parse(e.responseText.trim()).commCdList);

				if (callback && typeof callback == "function") {
					callback();
				}
			},
			error : function(e) {
				// TODO: 오류 처리 추가
			}
		});
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getCommonCodeList: " + e);
	}
};

/**
 * 그리드 뷰 높이 재 지정
 *
 * @param {object} subContents - 메인 영역
 * @param {object | object[]} contTop - 그리드 상단 영역
 * @param {object} gridView - 대상 그리드 뷰
 * @param {number} extraMargn - 추가 마진
 * @author Kim Jonggab
 * @date 2022. 09. 15.
 * @memberOf commLib
 */
commLib.reSizeGridView = function(subContents , contTop, gridView, extraMargn) {
	if (gridView.setSize && subContents.getSize) {
	    var gdHeight = subContents.getSize("outerMarginHeight") - 10 - ((extraMargn) ? extraMargn : 0);
	    if (contTop !== null && contTop !== undefined) {
	    	if (Array.isArray(contTop)) {
	    		contTop.forEach(function(top) {
	        		gdHeight -= top.getSize("outerMarginHeight");
	    		});
	    	} else {
	    		gdHeight -= contTop.getSize("outerMarginHeight");
	    	}
	    }
	    gridView.setSize(null, Math.max(gdHeight, 200));
	} else {
		console.error('gridView or subContents not has setSize or getSize Method');
	}
}

/**
 * 지정한 메시지 목록을 SessionStorage에 적재합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 29.
 * @memberOf commLib
 */
commLib.loadMessageStorage = function() {
	try {
		var _msg_init_ = sessionLib.get("_msg_init_");
		if (_msg_init_ != "INIT") {
			requires("/resources/js/lib/message.js?dummy=1st&time=" + (new Date()).getTime());
			for (var i = 0; i < msgLib.properties.length; i ++) {
				var msg = msgLib.properties[i];
				sessionLib.set(msg.key, strLib.serialize({ ko: msg.koMsg, en: msg.enMsg }));
			}
			sessionLib.set("_msg_init_", "INIT");
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.loadMessageStorage: " + e);
	}
};

/**
 * 지정한 메시지 코드와 일치하는 메시지를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 29.
 * @memberOf commLib
 * @param {string} msgCode - 메시지 코드
 * @param {...string} parameter - 메시지에 대체될 키워드들
 * @returns {string} 메시지
 */
commLib.getMessage = function(msgCode) {
	try {
		// 메시지가 SessionStorage에 적재되어 있는 상태인지 확인 및 적재
		commLib.loadMessageStorage();

		// SessionStorage에서 메시지 코드에 대응하는 메시지 정보 조회
		var msgInfo = sessionLib.get(msgCode);
		if (strLib.isEmpty(msgInfo, true)) {
			// 새로 추가된 메시지인지 확인 및 재적재
			requires("/resources/js/lib/message.js?dummy=2ns&time=" + (new Date()).getTime());

			for (var i = 0; i < msgLib.properties.length; i ++) {
				var msg = msgLib.properties[i];
				sessionLib.set(msg.key, strLib.serialize({ ko: msg.koMsg, en: msg.enMsg }));
			}

			msgInfo = sessionLib.get(msgCode);
		}

		// 메시지 코드 존재 확인
		if (strLib.isEmpty(msgInfo, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "등록되지 않은 메시지 코드입니다.";
		}

		// 메시지 출력
		var msg = strLib.parse(msgInfo);

		// 사용자의 정보에 따라서 KOR/ENG 메시지 선택 로직 구현
		var langCode = "KOR";

		/*
		 * 통합정보시스템에서는 다국어가 불필요하므로 아래 코드 주석처리. yongsang 2017.08.07
		 */
//		if (sesUserInfo && sesUserInfo.lang) {
//			langCode = (sesUserInfo.lang != "ENG") ? "KOR" : "ENG";
//		}
		var msgTemplate = (langCode == "KOR") ? msg.ko : msg.en;
		if (langCode == "ENG" && strLib.isEmpty(msgTemplate, true)) {
			// ENG 메시지가 등록되어 있지 않으면 KOR 메시지 사용
			msgTemplate = msg.ko;
		}

		var argLength = arguments.length;
		if (argLength > 1) {
			for (var i = 1; i < argLength; i++) {
				var regEx = new RegExp("\\{" + (i - 1).toString() + "\\}", "img");
				msgTemplate = msgTemplate.replace(regEx, arguments[i]);
			}
		}

		return msgTemplate.replace(/\{\d{1,3}\}?/img, "");
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getMessage: " + e);
	}
};

/**
 * 지정한 ID에 해당하는 WQ 컴포넌트 개체를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {string} id - 컴포넌트 ID
 * @returns {object} 컴포넌트 개체
 */
commLib.getControlById = function(id) {
	try {
		return udcLib.getObj(id);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getControlById: " + e);
	}
};

/**
 * 지정한 ID에 해당하는 WQ 컴포넌트 개체의 유형을 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {string} id - 컴포넌트 ID
 * @returns {string} WQ 컴포넌트 개체의 유형
 */
commLib.getTypeById = function(id) {
	try {
		var control = udcLib.getObj(id);
		if (control == null) {
			return "";
		} else {
			return control.getPluginName();
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getTypeById: " + e);
	}
};

/**
 * 지정한 target 프레임(미지정 시 self)의 페이지를 지정한 WebSquare URL로 이동합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} url - 이동할 페이지의 URL
 * @param {string} [target] - 대상 프레임 이름
 */
commLib.moveToW2xPath = function(url, target) {
	try {
		if (!url) {
			// 개발자 메시지: 영문지원 안 함
			throw "이동할 WebSquare XML 파일의 URL을 지정해주십시오.";
		}

		if (!target) {
			//target = self;
		    top.location = "/websquare/?w2xPath=" + url.replace(/\?/ig, "&");
		}

		target.location.href = "/websquare/?w2xPath=" + url.replace(/\?/ig, "&");
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.moveToW2xPath: " + e);
	}
};

/**
 * 지정한 WebSquare URL로 이동합니다. (HTTP Post)
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} url - 이동할 페이지의 URL
 * @param {object} [params] - 전달할 데이터를 담고 있는 JSON 개체
 */
commLib.moveToW2xPathByPost = function(url, params) {
	try {
		if (!url) {
			// 개발자 메시지: 영문지원 안 함
			throw "이동할 WebSquare XML 파일의 URL을 지정해주십시오.";
		}

		// 임시 Form 요소를 생성합니다.
		var objForm = document.getElementById("_dummyForm");
		if (objForm != null)
			objForm.parentNode.removeChild(objForm);

		objForm = document.createElement("form");
		objForm.id = "_dummyForm";
		objForm.method = "post";
		objForm.action = "/websquare/?w2xPath=" + url.replace(/\?/ig, "&");
		objForm.style.display = "none";
		document.body.appendChild(objForm);

		// HTTP POST 매개변수 설정
		if (params) {
			for ( var key in params) {
				var objHidden = document.createElement("input");
				objHidden.type = "hidden";
				objHidden.name = key;
				objHidden.value = params[key];
				objForm.appendChild(objHidden);
			}
		}

		objForm.submit();
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.moveToW2xPathByPost: " + e);
	}
};

/**
 * 세션 만료시 호출되는 함수로 현재 페이지의 형태를 감안하여 메인 프레임을 로그인 페이지로 강제 이동시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 07. 06.
 * @memberOf commLib
 */
commLib.moveToLoginPage = function() {
    try {
		var w2xPath = $w.getParameter("w2xPath");


		// 로그인 페이지는 대상에서 제외
		if (_w2xPath_.indexOf("/ux/main/login.xml") > -1) {
			return;
		}

		// 메시지 출력
		if (sessionLib.get("_login_alert_") != "Y") {
			// sysm.0006: 사용자 세션이 만료되었거나 접근 경로가 올바르지 않습니다. 다시 로그인해주십시오.
			alert(commLib.getMessage("sysm.0006"));
			sessionLib.set("_login_alert_", "Y");
		}

		// 로그인 페이지로 이동하는 연쇄처리
		if (_w2xPath_.indexOf("/ux/main/main.xml") > -1 || _w2xPath_.indexOf("/ux/main/mainSample.xml") > -1) {
			// 메인 프레임, 샘플 메인 프레임
			top.location.href = "/";
		} else if (!WebSquare.util.isPopup()) {
			// 일반 페이지
			try {
				if (parent != self) {
					parent.commLib.moveToLoginPage();
				} else {
					top.location.href = "/";
				}
			} catch (e) {
				// Do Nothing
			}
		} else if (WebSquare.util.isPopup()) {
			// 팝업 페이지
			try {
				if (opener) {
					opener.commLib.moveToLoginPage();
					setTimeout(function() {
						self.close();
					}, 500);
				} else if (parent != self) {
					parent.sessionUser.moveToLoginPage();
				}
			} catch (e) {
				// Do Nothing
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.moveToLoginPage: " + e);
	}
};

/**
 * 지정한 SelectBox, CheckBox, Radio에 지정한 JSON 배열, 2x2 배열, 문자열 배열 데이터를 설정합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {array} items - 항목 데이터
 */
commLib.setItems = function(control, items) {
	try {
		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		if (control.removeAll && control.removeAll) {
			if ($.isArray(items)) {

				control.removeAll(true);
				for ( var i in items) {
					if ($.isArray(items[i])) {
						// 2x2 배열인 경우
						control.addItem(items[i][0], items[i][1]);
					} else if (typeof items[i] == "object") {
						// JSON 개체 배열인 경우
						var firstProp = null;
						var secondProp = null;
						for ( var key in items[i]) {
							if (items[i].hasOwnProperty(key)) {
								if (!firstProp && !secondProp) {
									firstProp = items[i][key];
								} else if (firstProp && !secondProp) {
									secondProp = items[i][key];
								} else {
									break;
								}
							}
						}
						control.addItem(firstProp, secondProp);
					} else if (items[i].indexOf(":") > -1) {
						// 문자열 배열인 경우
						var buffer = items[i].split(":");
						control.addItem(buffer[0], buffer[1]);
					}
				}
				control.refresh();

				// CheckCombobox인 경우에만 항목 레이어의 크기 오류를
				// 보정하기 위한 임시코드 개선 방법이 발견될 경우 대체필요
				if (control.getPluginName() == "checkcombobox") {
					control.openSubLayer();
					control.closeSubLayer();
				}
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.setItems: " + e);
	}
};

/**
 * 지정한 SelectBox, Checkbox, Radio에 지정한 DataList 정보를 설정합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string} dataListId - DataList ID
 * @param {string} valueName - 값 컬럼 ID
 * @param {string} labelName - 이름 컬럼 ID
 */
commLib.setItemsBindding = function(control, dataListId, valueName, labelName) {
	try {
		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		if (!dataListId || !valueName || !labelName) {
			// 개발자 메시지: 영문지원 안 함
			throw "DataList 정보가 지정되지 않았습니다.";
		}

		control.setNodeSet("data:" + dataListId, labelName, valueName);
		control.refresh();

		// CheckCombobox인 경우에만 항목 레이어의 크기 오류를
		// 보정하기 위한 임시코드 개선 방법이 발견될 경우 대체필요
		if (control.getPluginName() == "checkcombobox") {
			control.openSubLayer();
			control.closeSubLayer();
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.setItemsBindding: " + e);
	}
};

/**
 * 지정한 GridView의 SelectBox컬럼에 지정한 DataList 정보를 설정합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {string} gridView - 그리드뷰 ID, 또는 그리드뷰 개체
 * @param {string} columnId - 컬럼 ID
 * @param {string} dataListId - DataList ID
 * @param {string} valueName - 값 컬럼 ID
 * @param {string} labelName - 이름 컬럼 ID
 */
commLib.setGridViewItemsBindding = function(gridView, columnId, dataListId, valueName, labelName) {
	try {
		if (typeof gridView == "string") {
			gridView = commLib.getControlById(gridView);
			if (!gridView) {
				// 개발자 메시지: 영문지원 안 함
				throw "지정한 그리드뷰가 존재하지 않습니다.";
			}
		}

		if (commLib.getTypeById(gridView.getID()) != "gridView") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트는 그리드뷰가 아닙니다. (" + gridView.getID() + ": " + commLib.getTypeById(gridView.getID()) + ")";
		}

		if (!columnId) {
			// 개발자 메시지: 영문지원 안 함
			throw "컬럼이 지정되지 않았습니다.";
		}

		var columnIndex = gridView.getColumnIndex(columnId);
		if (typeof columnIndex == "undefined") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컬럼이 존재하지 않습니다. (" + gridView.getID() + "." + columnId + ")";
		}

		if (!dataListId || !valueName || !labelName) {
			// 개발자 메시지: 영문지원 안 함
			throw "DataList 정보가 지정되지 않았습니다.";
		}

		gridView.setColumnNodeSet(columnIndex, "data:" + dataListId, labelName, valueName);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.setGridViewItemsBindding: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들을 활성화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.enableAll = function(control, excludeList) {
	try {
		commLib._setDisabled(control, false, excludeList);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.enableAll: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들을 비활성화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.disableAll = function(control, excludeList) {
	try {
		commLib._setDisabled(control, true, excludeList);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.disableAll: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들을 읽기전용 속성을 활성화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.readOnlyAll = function(control, excludeList) {
	try {
		commLib._setReadOnly(control, true, excludeList);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.readOnlyAll: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들을 읽기전용 속성을 비활성화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.writableAll = function(control, excludeList) {
	try {
		commLib._setReadOnly(control, false, excludeList);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.writableAll: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들의 값을 JSON 형식으로 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.getValuesByJSON = function(control, excludeList) {
	try {
		if (excludeList == null)
			excludeList = [];

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		var result = {};

		var controlNodeName = control.render.nodeName.toLowerCase();
		if (controlNodeName == "table") {
			$("#" + control.getID() + " *:wq").wq().each(function(index, element) {
				if (element.getPluginName && element.getID && element.getValue) {

					var pluginName = element.getPluginName().toLowerCase();
					if (pluginName == "anchor" || pluginName == "output" || pluginName == "textbox" || pluginName == "trigger" || pluginName == "span")
						return true;

					var id = element.getID();
					if (id.length > 0) {
						if ($.inArray(id, excludeList) > -1)
							return true;

						result[id] = element.getValue();
					}
				}
			});
		} else {
			var children = control.getChildren();

			if (children != null) {
				var length = children.length;
				for (var i = 0; i < length; i++) {

					// br 등
					if (!children[i].getPluginName || !children[i].getID) {
						continue;
					}

					var pluginName = children[i].getPluginName().toLowerCase();
					if (pluginName == "anchor" || pluginName == "output" || pluginName == "textbox" || pluginName == "trigger" || pluginName == "span")
						continue;

					var id = children[i].getID();

					if ($.inArray(id, excludeList) > -1)
						continue;

					if (pluginName == "group") {
						result[id] = commLib.getValuesByJSON(children[i], excludeList);
					} else if (children[i].getValue) {
						result[id] = children[i].getValue();
					}
				}
			}
		}

		return result;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getValuesByJSON: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들의 현재 스냅샷 값을 내부적으로 저장합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {string} snapshotName - 스냅샷 이름
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.saveSnapshot = function(snapshotName, control, excludeList) {
	try {
		if (!commLib.snapshotKeys) {
			commLib.snapshotKeys = {};
		}
		commLib.snapshotKeys[snapshotName] = true;

		if (excludeList == null)
			excludeList = [];

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		var children = control.getChildren();

		if (children != null) {
			var length = children.length;
			for (var i = 0; i < length; i++) {

				// br 등
				if (!children[i].getPluginName || !children[i].getID) {
					continue;
				}

				var pluginName = children[i].getPluginName().toLowerCase();
				var id = children[i].getID();

				if ($.inArray(id, excludeList) > -1)
					continue;

				switch (pluginName) {
				case "autocomplete":
				case "checkbox":
				case "calendar":
				case "checkcombobox":
				case "input":
				case "inputcalendar":
				case "multiselect":
				case "radio":
				case "secret":
				case "selectbox":
				case "textarea":
					children[i].setUserData("ssv_" + snapshotName, children[i].getValue());
					break;
				case "editor":
					children[i].setUserData("ssv_" + snapshotName, children[i].getHTML());
					break;
				case "gridview":
				case "grid":
					break;
				case "udcsearchdeptcode":
				case "group":
					commLib.saveSnapshot(snapshotName, children[i], excludeList);
					break;
				case "anchor":
				case "image":
				case "output":
				case "span":
				case "textbox":
					// 읽기 전용 컴포넌트
					break;
				case "trigger":
					// Trigger 컴포넌트는 지원 안 함
					break;
				default:
					// 개발자 메시지: 영문지원 안 함
					alert("현재 지원되지 않는 컴포넌트(" + pluginName + ":" + id + ")입니다. 구현이 필요한 경우 문의바랍니다.");
					break;
				}
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.saveSnapshot: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들의 스냅샷 값을 복원합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {string} snapshotName - 스냅샷 이름
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib.reloadSnapshot = function(snapshotName, control, excludeList) {
	try {
		if (!commLib.snapshotKeys || !commLib.snapshotKeys[snapshotName]) {
			// 개발자 메시지: 영문지원 안 함
			throw "복원할 수 있는 스냅샷이 저장되지 않았습니다. (" + snapshotName + ")";
		}

		if (excludeList == null)
			excludeList = [];

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		if (excludeList == null)
			excludeList = [];

		var children = control.getChildren();

		if (children != null) {
			var length = children.length;
			for (var i = 0; i < length; i++) {

				// br 등
				if (!children[i].getPluginName || !children[i].getID) {
					continue;
				}

				var pluginName = children[i].getPluginName().toLowerCase();
				var id = children[i].getID();

				if ($.inArray(id, excludeList) > -1)
					continue;

				switch (pluginName) {
				case "autocomplete":
				case "checkbox":
				case "checkcombobox":
				case "input":
				case "inputcalendar":
				case "multiselect":
				case "radio":
				case "secret":
				case "selectbox":
				case "textarea":
					var snapshotValue = children[i].getUserData("ssv_" + snapshotName);
					if (typeof snapshotValue != "undefined" && children[i].getValue() != snapshotValue) {
						children[i].setValue(snapshotValue);
					}
					break;
				case "calendar":
					var snapshotValue = children[i].getUserData("ssv_" + snapshotName);
					if (typeof snapshotValue != "undefined" && children[i].getValue() != snapshotValue) {
						children[i].gotoCalendar(snapshotValue);
					}
					break;
				case "editor":
					var snapshotValue = children[i].getUserData("ssv_" + snapshotName);
					if (typeof snapshotValue != "undefined" && children[i].getValue() != snapshotValue) {
						children[i].setHTML(snapshotValue);
					}
					break;
				case "gridview":
				case "grid":
					break;
				case "udcsearchdeptcode":
				case "group":
					commLib.reloadSnapshot(snapshotName, children[i], excludeList);
					break;
				case "anchor":
				case "image":
				case "output":
				case "span":
				case "textbox":
					// 읽기 전용 컴포넌트
					break;
				case "trigger":
					// Trigger 컴포넌트는 지원 안 함
					break;
				default:
					// 개발자 메시지: 영문지원 안 함
					alert("현재 지원되지 않는 컴포넌트(" + pluginName + ":" + id + ")입니다. 구현이 필요한 경우 문의바랍니다.");
					break;
				}
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.reloadSnapshot: " + e);
	}
};

/**
 * 지정한 그룹 하위의 모든 컴포넌트들의 스냅샷 값이 변경되었는지 여부를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {string} snapshotName - 스냅샷 이름
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 * @returns {boolean} 변경여부
 */
commLib.isSnapshotModified = function(snapshotName, control, excludeList) {
	try {
		if (!commLib.snapshotKeys || !commLib.snapshotKeys[snapshotName]) {
			// 개발자 메시지: 영문지원 안 함
			throw "비교할 수 있는 스냅샷이 저장되지 않았습니다. (" + snapshotName + ")";
		}

		if (excludeList == null)
			excludeList = [];

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		if (excludeList == null)
			excludeList = [];

		var children = control.getChildren();

		if (children != null) {
			var length = children.length;
			for (var i = 0; i < length; i++) {

				// br 등
				if (!children[i].getPluginName || !children[i].getID) {
					continue;
				}

				var pluginName = children[i].getPluginName().toLowerCase();
				var id = children[i].getID();

				if ($.inArray(id, excludeList) > -1)
					continue;

				switch (pluginName) {
				case "autocomplete":
				case "checkbox":
				case "checkcombobox":
				case "input":
				case "inputcalendar":
				case "multiselect":
				case "radio":
				case "secret":
				case "selectbox":
				case "textarea":
					var snapshotValue = children[i].getUserData("ssv_" + snapshotName);
					if (typeof snapshotValue != "undefined" && children[i].getValue() != snapshotValue) {
						return true;
					}
					break;
				case "calendar":
					var snapshotValue = children[i].getUserData("ssv_" + snapshotName);
					if (typeof snapshotValue != "undefined" && children[i].getValue() != snapshotValue) {
						return true;
					}
					break;
				case "editor":
					var snapshotValue = children[i].getUserData("ssv_" + snapshotName);
					if (typeof snapshotValue != "undefined" && children[i].getHTML() != snapshotValue) {
						return true;
					}
					break;
				case "gridview":
				case "grid":
					break;
				case "udcsearchdeptcode":
				case "group":
					if (commLib.isSnapshotModified(snapshotName, children[i], excludeList)) {
						return true;
					}
					break;
				case "anchor":
				case "image":
				case "output":
				case "span":
				case "textbox":
					// 읽기 전용 컴포넌트
					break;
				case "trigger":
					// Trigger 컴포넌트는 지원 안 함
					break;
				default:
					// 개발자 메시지: 영문지원 안 함
					alert("현재 지원되지 않는 컴포넌트(" + pluginName + ":" + id + ")입니다. 구현이 필요한 경우 문의바랍니다.");
					break;
				}
			}
		}

		return false;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.isSnapshotModified: " + e);
	}
};

/**
 * [내부용] 지정한 그룹 하위의 모든 컴포넌트들을 활성화/비활성화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {boolean} disable - 비활성화 여부
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib._setDisabled = function(control, disable, excludeList) {
	try {
		if (excludeList == null)
			excludeList = [];

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		var children = control.getChildren();

		if (children != null) {
			var length = children.length;
			for (var i = 0; i < length; i++) {

				// br 등
				if (!children[i].getPluginName || !children[i].getID) {
					continue;
				}

				var pluginName = children[i].getPluginName().toLowerCase();
				var id = children[i].getID();
				var isExclude = false;

				for (var j = 0; j < excludeList.length; j++) {
					if (excludeList[j].toLowerCase() == id.toLowerCase()) {
						isExclude = true;
						break;
					}
				}

				if (isExclude)
					continue;

				switch (pluginName) {
				case "anchor":
				case "autocomplete":
				case "calendar":
				case "checkbox":
				case "checkcombobox":
				case "image":
				case "input":
				case "inputcalendar":
				case "multiselect":
				case "radio":
				case "secret":
				case "selectbox":
				case "textarea":
				case "trigger":
					children[i].setDisabled(disable);
					break;
				case "gridview":
				case "grid":
					children[i].setDisabled("grid", disable);
					break;
				case "group":
					commLib._setDisabled(children[i], disable, excludeList);
					break;
				case "output":
				case "span":
				case "textbox":
					// 읽기 전용 컴포넌트
					break;
				case "udc_ymd":
				case "udc_ym":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable));
					break;
				case "udc_rsdt_no":
				case "udc_period_ical_ymd":
				case "udc_period_ical_ym":
				case "udc_cs_site_pop":
				case "udc_cs_site_all_pop":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable));
					break;
				case "udc_dept_pop":
				case "udc_custmstrsearch_pop":
				case "udc_bsite_cd_pop":
				case "udc_emp_pop":
				case "udc_user_pop":
				case "udc_trx_cd_pop":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable,null));
					break;
				case "udc_psvs_pop":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(null,disable,null));
					break;
				case "udc_email":
				case "udc_tel_no":
				case "udc_phone_no":
				case "udc_tri_sel":
				case "udc_comm_pop":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable,disable));
					break;
				case "udc_post_no":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable,disable,disable));
					break;
				case "udc_trmnl_no_pop":
					udcLib.disableComp(udcLib.getObj(children[i].getOriginalID()),new Array(null,disable));
					break;
				default:
					// 개발자 메시지: 영문지원 안 함
					alert("현재 지원되지 않는 컴포넌트(" + pluginName + ":" + id + ")입니다. 구현이 필요한 경우 문의바랍니다.");
					break;
				}
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib._setDisabled: " + e);
	}
};

/**
 * [내부용] 지정한 그룹 하위의 모든 컴포넌트들의 읽기전용 속성을 활성화/비활성화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf commLib
 * @param {(object|string)} control - 컴포넌트 ID 또는 개체
 * @param {boolean} disable - 읽기전용 여부
 * @param {string[]} [excludeList] - 처리에서 제외할 컴포넌트들의 ID 배열
 */
commLib._setReadOnly = function(control, disable, excludeList) {
	try {
		if (excludeList == null)
			excludeList = [];

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			throw "지정한 컴포넌트가 존재하지 않습니다.";
		}

		var children = control.getChildren();

		if (children != null) {
			var length = children.length;
			for (var i = 0; i < length; i++) {

				// br 등
				if (!children[i].getPluginName || !children[i].getID) {
					continue;
				}

				var pluginName = children[i].getPluginName().toLowerCase();
				var id = children[i].getID();

				if ($.inArray(id, excludeList) > -1)
					continue;

				switch (pluginName) {
				case "anchor":
				case "autocomplete":
				case "checkbox":
				case "checkcombobox":
				case "input":
				case "inputcalendar":
				case "multiselect":
				case "radio":
				case "secret":
				case "selectbox":
				case "textarea":
					children[i].setReadOnly(disable);
					break;
				case "calendar":
				case "trigger":
					children[i].setDisabled(disable);
					children[i].setReadOnly(disable);
					break;
				case "gridview":
				case "grid":
					children[i].setReadOnly("grid", disable);
					break;
				case "group":
					commLib._setReadOnly(children[i], disable, excludeList);
					break;
				case "image":
					children[i].setDisabled(disable);
					break;
				case "output":
				case "span":
				case "textbox":
					// 읽기 전용 컴포넌트
					break;
				case "udc_ymd":
				case "udc_ym":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable));
					break;
				case "udc_rsdt_no":
				case "udc_period_ical_ymd":
				case "udc_period_ical_ym":
				case "udc_cs_site_pop":
				case "udc_cs_site_all_pop":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable));
					break;
				case "udc_dept_pop":
				case "udc_custmstrsearch_pop":
				case "udc_bsite_cd_pop":
				case "udc_emp_pop":
				case "udc_user_pop":
				case "udc_trx_cd_pop":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable,null));
					break;
				case "udc_psvs_pop":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(null,disable,null));
					break;
				case "udc_email":
				case "udc_tel_no":
				case "udc_phone_no":
				case "udc_tri_sel":
				case "udc_comm_pop":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable,disable));
					break;
				case "udc_post_no":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(disable,disable,disable,disable));
					break;
				case "udc_trmnl_no_pop":
					udcLib.readOnlyComp(udcLib.getObj(children[i].getOriginalID()),new Array(null,disable));
					break;
				default:
					// 개발자 메시지: 영문지원 안 함
					alert("현재 지원되지 않는 컴포넌트(" + pluginName + ":" + id + ")입니다. 구현이 필요한 경우 문의바랍니다.");
					break;
				}
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib._setReadOnly: " + e);
	}
};

/**
 * 지정한 wframe에 지정한 wframe 페이지를 동적으로 로드합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf commLib
 * @param {(object|string)} wframe - WFrame ID, 또는 WFrame 개체
 * @param {string} url - WFrame의 URL
 * @param {boolean} reload - 이미 동일한 WFrame이 로드되어 있는 경우에도 다시 로드할지 여부
 */
commLib.setWframe = function(wframe, url, reload) {
	try {
		if (typeof wframe == "string") {
			wframe = commLib.getControlById(wframe);
		}

		if (!wframe || wframe._wTagName != "wframe") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 wframe이 존재하지 않거나 wframe이 아닙니다.";
		}

		if (strLib.isEmpty(url, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "wframe에 로드할 xml 파일의 경로를 지정해주십시오.";
		}

		if (!reload) {
			reload = false;
		}

		if (reload) {
			wframe.setSrc(url);
		} else {
			if (strLib.isEmpty(wframe.getSrc(), true) || wframe.getSrc() != url) {
				wframe.setSrc(url);
			}
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.setWframe: " + e);
	}
};


/**
 * 지정한 그리드뷰의 데이터를 EXCEL 파일로 다운로드 합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} gridView - 그리드뷰 ID, 또는 그리드뷰 개체
 * @param {string} filename - EXCEL 파일명
 * @param {(object|string)} [options] - EXCEL 다운로드 옵션
 * @param {string} [options.sheetName] - EXCEL 파일의 시트명
 * @param {string} [options.removeColumns] - 콤마로 이어진 그리드뷰에서 제외할 컬럼들의 인덱스 목록
 * @param {number} [options.type] - EXCEL로 다운로드 받은 그리드뷰의 데이터 형식 (0: 실제 데이터, 1:눈에 보이는 대로[기본값], 2: 들어가 있는 데이터)
 * @param {boolean} [options.bodyWordwrap] - 줄바꿈 허용 여부
 * @param {boolean} [options.colMerge] - 머지된 컬럼 유지 여부
 * @param {boolean} [options.useSubTotal] - SubTotal 출력 여부
 * @param {boolean} [options.useFooter] - Footer 출력 여부
 * @param {boolean} [options.useDataFormat] - EXCEL 표시 형식 '텍스트' 출력 유무
 */
commLib.downloadExcel = function(gridView, filename, options) {
	try {
		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "EXCEL 파일을 다운로드 받을 그리드뷰를 지정해주십시오.";
		}

		if (typeof gridView == "string") {
			gridView = commLib.getControlById(gridView);
		}
		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 그리드뷰가 존재하지 않습니다.";
		} else if (gridView.getPluginName().toLowerCase() != "gridview") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정하신 컴포넌트는 그리드뷰가 아닙니다.";
		}

		if (!filename || strLib.isEmpty(filename)) {
			// 개발자 메시지: 영문지원 안 함
			throw "다운로드 받을 EXCEL 파일의 이름을 지정해주십시오.";
		}
		var dataListID = gridView.getDataList();
		if (strLib.isEmpty(dataListID) || !$w.data[dataListID]) {
			// 개발자 메시지: 영문지원 안 함
			throw "그리드뷰에 바인딩된 DataList가 존재하지 않습니다.";
		}

		var dataList = $w.data[dataListID];
		var rowCount = dataList.getRowCount();
  		if (rowCount == 0) {
			alert("다운로드 받을 수 있는 데이터가 존재하지 않습니다.");
			return;
		}
		// 기본옵션
		if (!options) {
			options = {};
		}
		var defaultSheetName = options.sheetName;
		var matches = filename.match(/(.+)\([A-Z][A-Z0-9]+\.xml\)/);
		if (matches && matches[1]) {
			filename = matches[1];
		}
		// .xlsx를 기본 형식으로 사용합니다.
		if(filename.indexOf(".")>=0){
			defaultSheetName = filename.substr(0, filename.lastIndexOf("."));
			filename = filename.substr(0, filename.lastIndexOf(".")) + ".xlsx";
		}else{
			defaultSheetName = filename;
			filename = filename + ".xlsx";
		}
		if (filename.indexOf('/') !== -1 || filename.indexOf('\\') !== -1) {
			filename = filename.replace(/[\/\\]/g,' ');
		}

		// 추가정보
		var infoArr = [];
		var sheetName = options.sheetName || defaultSheetName;
		if (sheetName.indexOf('/') !== -1 || sheetName.indexOf(':') !== -1) {
			sheetName = sheetName.replace(/[\/:]/g,' ');
		}
		var colCount = gridView.getTotalCol() - (options.removeColumns ? options.removeColumns.split(",").length : 0);
		var rowNumShow = true;
		if (!strLib.isEmpty(options.rowNumVisible)) {
			rowNumShow = options.rowNumVisible;
			if (!rowNumShow) {
				colCount--;
			}
		}

		// 타이틀
		var titleInfo = {
			"rowIndex" : 0,
			"colIndex" : 0,
			"rowSpan" : 1,
			"colSpan" : colCount + 1,
			"text" : sheetName,
			"textAlign" : "center",
			"fontSize" : "20px",
			"fontWeight" : "bold",
			"drawBorder" : false
		};
		infoArr.push(titleInfo);

		// TODO: 협의 후 반영 필요
		// 작업자
		var userInfo = {
			"rowIndex" : 2,
			"colIndex" : 0,
			"rowSpan" : 1,
			"colSpan" : 1,
			"text" : " ",
			"textAlign" : "left",
			"drawBorder" : false
		};
		infoArr.push(userInfo);

		// 작업일시
		var dateInfo = {
			"rowIndex" : 2,
			"colIndex" : colCount,
			"rowSpan" : 1,
			"colSpan" : 1,
			"text" : "다운로드 일시: " + dateLib.getCurrentDate("yyyy-MM-dd HH:mm"),
			"textAlign" : "right",
			"drawBorder" : false
		};
		infoArr.push(dateInfo);
		// EXCEL 다운로드
		gridView.advancedExcelDownload({
			"fileName" : filename,
			"sheetName" : sheetName,
			"type" : (options.type == null) ? 1 : options.type,
			"removeColumns" : options.removeColumns || "",
			"startRowIndex" : 3,
			"bodyWordwrap" : (options.bodyWordwrap == null) ? false : options.bodyWordwrap,
			"colMerge" : (options.colMerge == null) ? false : options.colMerge,
			"mergeCell" : (options.mergeCell == null) ? false : options.mergeCell,
			"useSubTotal" : (options.useSubTotal == null) ? false : options.useSubTotal,
			"useSubTotalData" : (options.useSubTotalData == null) ? false : options.useSubTotalData,
			"useFooter" : (options.useFooter == null) ? true : options.useFooter,
			"useDataFormat" : (options.useDataFormat == null) ? true : options.useDataFormat,
			"headerColor" : "#cacaca",
			"headerFontName" : "Malgun Gothic",
			"headerFontSize" : "11",
			"headerFontColor" : "",
			"bodyColor" : "",
			"bodyFontName" : "Malgun Gothic",
			"bodyFontSize" : "11",
			"bodyFontColor" : "",
			"subTotalColor" : "#dfdfdf",
			"subTotalFontName" : "Malgun Gothic",
			"subTotalFontSize" : "11",
			"subTotalFontColor" : "",
			"footerColor" : "#d4d4d4",
			"footerFontName" : "Malgun Gothic",
			"footerFontSize" : "11",
			"footerFontColor" : "",
			"oddRowBackgroundColor" : "#f6f6f6",
			"evenRowBackgroundColor" : "#ffffff",
			"rowNumVisible" : rowNumShow,
			"rowNumHeaderColor" : "#cacaca",
			"rowNumHeaderFontName" : "Malgun Gothic",
			"rowNumHeaderFontSize" : "11",
			"rowNumHeaderFontColor" : "",
			"rowNumBodyColor" : "",
			"rowNumBodyFontName" : "Malgun Gothic",
			"rowNumBodyFontSize" : "11",
			"rowNumBodyFontColor" : "",
			"rowNumFooterColor" : "#d4d4d4",
			"rowNumFooterFontName" : "Malgun Gothic",
			"rowNumFooterFontSize" : "11",
			"rowNumFooterFontColor" : "",
			"rowNumSubTotalColor" : "#dfdfdf",
			"rowNumSubTotalFontName" : "Malgun Gothic",
			"rowNumSubTotalFontSize" : "11",
			"rowNumSubTotalFontColor" : ""
		}, infoArr);

	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.downloadExcel: " + e);
	}
};

/**
 * 지정한 그리드뷰들의 데이터를 여러 개의 시트를 가진 EXCEL 파일로 다운로드 합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} filename - EXCEL 파일명
 * @param {(object|object[])} [sheetInfos] - 시트별 EXCEL 다운로드 옵션 또는 옵션의 배열
 * @param {(object|string)} [sheetInfos.gridView] - 그리드뷰 ID, 또는 그리드뷰 개체
 * @param {string} [sheetInfos.sheetName] - EXCEL 파일의 시트명
 * @param {string} [sheetInfos.removeColumns] - 콤마로 이어진 그리드뷰에서 제외할 컬럼들의 인덱스 목록
 * @param {number} [sheetInfos.type] - EXCEL로 다운로드 받은 그리드뷰의 데이터 형식 (0: 실제 데이터, 1:눈에 보이는 대로[기본값], 2: 들어가 있는 데이터)
 * @param {boolean} [sheetInfos.bodyWordwrap] - 줄바꿈 허용 여부
 * @param {boolean} [sheetInfos.colMerge] - 머지된 컬럼 유지 여부
 * @param {boolean} [sheetInfos.useSubTotal] - SubTotal 출력 여부
 * @param {boolean} [sheetInfos.useFooter] - Footer 출력 여부
 * @param {boolean} [sheetInfos.useDataFormat] - EXCEL 표시 형식 '텍스트' 출력 유무
 * @param {number} rowLimit - 최대 다운로드 행수	2020/05/14 옵션추가
 * @param {boolean} rowNumVisible - 순번표시여부	2020/06/01 옵션추가
 */
commLib.downloadExcelMulti = function(filename, sheetInfos, rowLimit, rowNumVisible) {
	try {
		if (!filename || strLib.isEmpty(filename)) {
			// 개발자 메시지: 영문지원 안 함
			throw "다운로드 받을 EXCEL 파일의 이름을 지정해주십시오.";
		}

		if (!sheetInfos) {
			// 개발자 메시지: 영문지원 안 함
			throw "EXCEL 파일을 다운로드 받을 그리드뷰 정보를 지정해주십시오.";
		}

		if (strLib.isEmpty(sheetInfos, true)) {
			sheetInfos = {};
		}

		if (!$.isArray(sheetInfos)) {
			sheetInfos = [ sheetInfos ];
		}

		// .xlsx를 기본 형식으로 사용합니다.
		filename = filename.substr(0, filename.lastIndexOf(".")) + ".xlsx";

		//최대 다운로드 행수	2020/05/14 옵션추가
		var limi = 10000;

		if(rowLimit){
			limi = rowLimit;
		}

		var rowNumShow = true;
		if (!strLib.isEmpty(rowNumVisible)) {
			rowNumShow = rowNumVisible;
		}

		// 다운로드 옵션
		var currentDateTime = dateLib.getCurrentDate("yyyy-MM-dd HH:mm");
		var options = {
			common : {
				rowNumVisible : rowNumShow,
				rowNumHeaderColor : "#cacaca",
				rowNumHeaderFontName : "Malgun Gothic",
				rowNumHeaderFontSize : "11",
				rowNumHeaderFontColor : "",
				rowNumBodyColor : "",
				rowNumBodyFontName : "Malgun Gothic",
				rowNumBodyFontSize : "11",
				rowNumBodyFontColor : "",
				rowNumSubTotalColor : "#dfdfdf",
				rowNumSubTotalFontName : "Malgun Gothic",
				rowNumSubTotalFontSize : "11",
				rowNumSubTotalFontColor : "",
				rowNumFooterColor : "#d4d4d4",
				rowNumFooterFontName : "Malgun Gothic",
				rowNumFooterFontSize : "11",
				rowNumFooterFontColor : "",
				fileName : filename,
				showProcess : true,
				rowsByN : limi
			},
			excelInfo : []
		};

		var rowCount = 0;
		// 시트별 옵션 처리
		for (var i = 0; i < sheetInfos.length; i++) {
			var sheetInfo = sheetInfos[i];

			if (!sheetInfo.gridView) {
				// 개발자 메시지: 영문지원 안 함
				throw "EXCEL 파일을 다운로드 받을 그리드뷰를 지정해주십시오.";
			}

			if (!sheetInfo.sheetName) {
				// 개발자 메시지: 영문지원 안 함
				throw "EXCEL 파일을 다운로드 받을 그리드뷰의 시트명을 지정해주십시오.";
			}

			if (typeof sheetInfo.gridView == "string") {
				sheetInfo.gridView = commLib.getControlById(sheetInfo.gridView);
			}

			if (!sheetInfo.gridView) {
				// 개발자 메시지: 영문지원 안 함
				throw "지정한 그리드뷰가 존재하지 않습니다.";
			} else if (sheetInfo.gridView.getPluginName().toLowerCase() != "gridview") {
				// 개발자 메시지: 영문지원 안 함
				throw "지정하신 컨트롤은 그리드뷰가 아닙니다. (" + sheetInfo.gridView.getID() + ")";
			}

			var gridViewID = sheetInfo.gridView.getID();
			var dataListID = sheetInfo.gridView.getDataList();
			if (strLib.isEmpty(dataListID) || !$w.data[dataListID]) {
				// 개발자 메시지: 영문지원 안 함
				throw "그리드뷰에 바인딩된 DataList가 존재하지 않습니다. (" + gridViewID + ")";
			}

			var dataList = $w.data[dataListID];
			rowCount += dataList.getRowCount();

			// 기본옵션
			var excelInfo = {
				"gridId" : gridViewID,
				"sheetName" : sheetInfo.sheetName,
				"type" : (sheetInfo.type == null) ? 1 : sheetInfo.type,
				"removeColumns" : sheetInfo.removeColumns || "",
				"startRowIndex" : 3,
				"bodyWordwrap" : (sheetInfo.bodyWordwrap == null) ? false : sheetInfo.bodyWordwrap,
				"colMerge" : (sheetInfo.colMerge == null) ? false : sheetInfo.colMerge,
				"useSubTotal" : (sheetInfo.useSubTotal == null) ? true : sheetInfo.useSubTotal,
				"useFooter" : (sheetInfo.useFooter == null) ? true : sheetInfo.useFooter,
				"useDataFormat" : (options.useDataFormat == null) ? true : options.useDataFormat,
				"infoArr" : [],
				"headerColor" : "#cacaca",
				"headerFontName" : "Malgun Gothic",
				"headerFontSize" : "11",
				"headerFontColor" : "",
				"bodyColor" : "",
				"bodyFontName" : "Malgun Gothic",
				"bodyFontSize" : "11",
				"bodyFontColor" : "",
				"subTotalColor" : "#dfdfdf",
				"subTotalFontName" : "Malgun Gothic",
				"subTotalFontSize" : "11",
				"subTotalFontColor" : "",
				"footerColor" : "#d4d4d4",
				"footerFontName" : "Malgun Gothic",
				"footerFontSize" : "11",
				"footerFontColor" : "",
				"oddRowBackgroundColor" : "#f6f6f6",
				"evenRowBackgroundColor" : "#ffffff"
			};

			// 추가정보
			var sheetName = sheetInfo.sheetName;
			var colCount = sheetInfo.gridView.getTotalCol() - (sheetInfo.removeColumns ? sheetInfo.removeColumns.split(",").length : 0);
			if (rowNumShow) {
				colCount++;
			}
			// 타이틀
			var titleInfo = {
				"rowIndex" : 0,
				"colIndex" : 0,
				"rowSpan" : 1,
				"colSpan" : colCount,
				"text" : sheetName,
				"textAlign" : "center",
				"fontSize" : "20px",
				"fontWeight" : "bold",
				"drawBorder" : false
			};
			excelInfo.infoArr.push(titleInfo);

			var searach1 = " ";	//조회조건항목

			if(sheetInfo.search1 != null){
				searach1 = sheetInfo.search1;
			}

			// TODO: 협의 후 반영 필요
			// 작업자
			var userInfo = {
				"rowIndex" : 2,
				"colIndex" : 0,
				"rowSpan" : 1,
				"colSpan" : 1,
				//"text" : "[소속] [직책/직급] [성명]",
				"text" : searach1,
				"textAlign" : "left",
				"drawBorder" : false
			};
			excelInfo.infoArr.push(userInfo);

			// 작업일시
			var dateInfo = {
				"rowIndex" : 2,
				"colIndex" : colCount - 1,
				"rowSpan" : 1,
				"colSpan" : 1,
				"text" : "다운로드 일시: " + currentDateTime,
				"textAlign" : "right",
				"drawBorder" : "false"
			};
			excelInfo.infoArr.push(dateInfo);

			options.excelInfo.push(excelInfo);
		}
		if (rowCount == 0) {
			// 개발자 메시지: 영문지원 안 함
		    commLib.getAlert("다운로드 받을 수 있는 데이터가 존재하지 않습니다. (" + gridViewID + ")","데이터 결과","V");
			return;
		}

		WebSquare.util.multipleExcelDownload(options);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.downloadExcelMulti: " + e);
	}
};

/**
 * 지정한 그리드뷰들의 데이터를 여러 개의 시트를 가진 EXCEL 파일로 다운로드 합니다.
 * 그리드의 Rowcount 상관없이 엑셀파일 생성한다
 * INC(통합고객)
 * @author beomgeun.lee
* @date 2020. 01. 06.
 * @memberOf commLib
 * @param {string} filename - EXCEL 파일명
 * @param {(object|object[])} [sheetInfos] - 시트별 EXCEL 다운로드 옵션 또는 옵션의 배열
 * @param {(object|string)} [sheetInfos.gridView] - 그리드뷰 ID, 또는 그리드뷰 개체
 * @param {string} [sheetInfos.sheetName] - EXCEL 파일의 시트명
 * @param {string} [sheetInfos.removeColumns] - 콤마로 이어진 그리드뷰에서 제외할 컬럼들의 인덱스 목록
 * @param {number} [sheetInfos.type] - EXCEL로 다운로드 받은 그리드뷰의 데이터 형식 (0: 실제 데이터, 1:눈에 보이는 대로[기본값], 2: 들어가 있는 데이터)
 * @param {boolean} [sheetInfos.bodyWordwrap] - 줄바꿈 허용 여부
 * @param {boolean} [sheetInfos.colMerge] - 머지된 컬럼 유지 여부
 * @param {boolean} [sheetInfos.useSubTotal] - SubTotal 출력 여부
 * @param {boolean} [sheetInfos.useFooter] - Footer 출력 여부
 * @param {boolean} [sheetInfos.useDataFormat] - EXCEL 표시 형식 '텍스트' 출력 유무
 * @param {number} rowLimit - 최대 다운로드 행수	2020/05/14 옵션추가
 * @param {boolean} rowNumVisible - 순번표시여부	2020/06/01 옵션추가
 */
commLib.downloadExcelMultiForm = function(filename, sheetInfos, rowLimit, rowNumVisible) {
	try {
		if (!filename || strLib.isEmpty(filename)) {
			// 개발자 메시지: 영문지원 안 함
			throw "다운로드 받을 EXCEL 파일의 이름을 지정해주십시오.";
		}

		if (!sheetInfos) {
			// 개발자 메시지: 영문지원 안 함
			throw "EXCEL 파일을 다운로드 받을 그리드뷰 정보를 지정해주십시오.";
		}

		if (strLib.isEmpty(sheetInfos, true)) {
			sheetInfos = {};
		}

		if (!$.isArray(sheetInfos)) {
			sheetInfos = [ sheetInfos ];
		}

		// .xlsx를 기본 형식으로 사용합니다.
		filename = filename.substr(0, filename.lastIndexOf(".")) + ".xlsx";

		//최대 다운로드 행수	2020/05/14 옵션추가
		var limi = 10000;

		if(rowLimit){
			limi = rowLimit;
		}

		var rowNumShow = true;
		if (!strLib.isEmpty(rowNumVisible)) {
			rowNumShow = rowNumVisible;
		}

		// 다운로드 옵션
		var currentDateTime = dateLib.getCurrentDate("yyyy-MM-dd HH:mm");
		var options = {
			common : {
				rowNumVisible : rowNumShow,
				rowNumHeaderColor : "#cacaca",
				rowNumHeaderFontName : "Malgun Gothic",
				rowNumHeaderFontSize : "11",
				rowNumHeaderFontColor : "",
				rowNumBodyColor : "",
				rowNumBodyFontName : "Malgun Gothic",
				rowNumBodyFontSize : "11",
				rowNumBodyFontColor : "",
				rowNumSubTotalColor : "#dfdfdf",
				rowNumSubTotalFontName : "Malgun Gothic",
				rowNumSubTotalFontSize : "11",
				rowNumSubTotalFontColor : "",
				rowNumFooterColor : "#d4d4d4",
				rowNumFooterFontName : "Malgun Gothic",
				rowNumFooterFontSize : "11",
				rowNumFooterFontColor : "",
				fileName : filename,
				showProcess : true,
				rowsByN : limi
			},
			excelInfo : []
		};

		var rowCount = 0;
		// 시트별 옵션 처리
		for (var i = 0; i < sheetInfos.length; i++) {
			var sheetInfo = sheetInfos[i];

			if (!sheetInfo.gridView) {
				// 개발자 메시지: 영문지원 안 함
				throw "EXCEL 파일을 다운로드 받을 그리드뷰를 지정해주십시오.";
			}

			if (!sheetInfo.sheetName) {
				// 개발자 메시지: 영문지원 안 함
				throw "EXCEL 파일을 다운로드 받을 그리드뷰의 시트명을 지정해주십시오.";
			}

			if (typeof sheetInfo.gridView == "string") {
				sheetInfo.gridView = commLib.getControlById(sheetInfo.gridView);
			}

			if (!sheetInfo.gridView) {
				// 개발자 메시지: 영문지원 안 함
				throw "지정한 그리드뷰가 존재하지 않습니다.";
			} else if (sheetInfo.gridView.getPluginName().toLowerCase() != "gridview") {
				// 개발자 메시지: 영문지원 안 함
				throw "지정하신 컨트롤은 그리드뷰가 아닙니다. (" + sheetInfo.gridView.getID() + ")";
			}

			var gridViewID = sheetInfo.gridView.getID();
			var dataListID = sheetInfo.gridView.getDataList();
			if (strLib.isEmpty(dataListID) || !$w.data[dataListID]) {
				// 개발자 메시지: 영문지원 안 함
				throw "그리드뷰에 바인딩된 DataList가 존재하지 않습니다. (" + gridViewID + ")";
			}

			var dataList = $w.data[dataListID];
			rowCount += dataList.getRowCount();

			// 기본옵션
			var excelInfo = {
				"gridId" : gridViewID,
				"sheetName" : sheetInfo.sheetName,
				"type" : (sheetInfo.type == null) ? 1 : sheetInfo.type,
				"removeColumns" : sheetInfo.removeColumns || "",
				"startRowIndex" : 3,
				"bodyWordwrap" : (sheetInfo.bodyWordwrap == null) ? false : sheetInfo.bodyWordwrap,
				"colMerge" : (sheetInfo.colMerge == null) ? false : sheetInfo.colMerge,
				"useSubTotal" : (sheetInfo.useSubTotal == null) ? true : sheetInfo.useSubTotal,
				"useFooter" : (sheetInfo.useFooter == null) ? true : sheetInfo.useFooter,
				"useDataFormat" : (options.useDataFormat == null) ? true : options.useDataFormat,
				"infoArr" : [],
				"headerColor" : "#cacaca",
				"headerFontName" : "Malgun Gothic",
				"headerFontSize" : "11",
				"headerFontColor" : "",
				"bodyColor" : "",
				"bodyFontName" : "Malgun Gothic",
				"bodyFontSize" : "11",
				"bodyFontColor" : "",
				"subTotalColor" : "#dfdfdf",
				"subTotalFontName" : "Malgun Gothic",
				"subTotalFontSize" : "11",
				"subTotalFontColor" : "",
				"footerColor" : "#d4d4d4",
				"footerFontName" : "Malgun Gothic",
				"footerFontSize" : "11",
				"footerFontColor" : "",
				"oddRowBackgroundColor" : "#f6f6f6",
				"evenRowBackgroundColor" : "#ffffff"
			};

			// 추가정보
			var sheetName = sheetInfo.sheetName;
			var colCount = sheetInfo.gridView.getTotalCol() - (sheetInfo.removeColumns ? sheetInfo.removeColumns.split(",").length : 0);
			if (rowNumShow) {
				colCount++;
			}
			// 타이틀
			var titleInfo = {
				"rowIndex" : 0,
				"colIndex" : 0,
				"rowSpan" : 1,
				"colSpan" : colCount,
				"text" : sheetName,
				"textAlign" : "center",
				"fontSize" : "20px",
				"fontWeight" : "bold",
				"drawBorder" : false
			};
			excelInfo.infoArr.push(titleInfo);

			var searach1 = " ";	//조회조건항목

			if(sheetInfo.search1 != null){
				searach1 = sheetInfo.search1;
			}

			// TODO: 협의 후 반영 필요
			// 작업자
			var userInfo = {
				"rowIndex" : 2,
				"colIndex" : 0,
				"rowSpan" : 1,
				"colSpan" : 1,
				//"text" : "[소속] [직책/직급] [성명]",
				"text" : searach1,
				"textAlign" : "left",
				"drawBorder" : false
			};
			excelInfo.infoArr.push(userInfo);

			// 작업일시
			var dateInfo = {
				"rowIndex" : 2,
				"colIndex" : colCount - 1,
				"rowSpan" : 1,
				"colSpan" : 1,
				"text" : "다운로드 일시: " + currentDateTime,
				"textAlign" : "right",
				"drawBorder" : "false"
			};
			excelInfo.infoArr.push(dateInfo);

			options.excelInfo.push(excelInfo);
		}
        if (rowCount == 0) {
            // 개발자 메시지: 영문지원 안 함
            commLib.getAlert("다운로드 받을 수 있는 데이터가 존재하지 않습니다. (" + gridViewID + ")","데이터 결과","V");
            return;
        }

		WebSquare.util.multipleExcelDownload(options);
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.downloadExcelMultiForm: " + e);
	}
};

/**
 * 지정한 그리드뷰에 EXCEL 파일을 업로드 합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {(object|string)} [gridView] - 그리드뷰 ID, 또는 그리드뷰 개체
 *
 * @param {object} [options] - EXCEL 업로드 옵션
 * @param {string} [options.sheetName] - EXCEL 파일의 시트명
 */
commLib.uploadExcel = function(gridView, options) {
	try {
		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "EXCEL 파일을 업로드 할 그리드뷰를 지정해주십시오.";
		}

		if (typeof gridView == "string") {
			gridView = commLib.getControlById(gridView);
		}

		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 그리드뷰가 존재하지 않습니다.";
		} else if (gridView.getPluginName().toLowerCase() != "gridview") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정하신 컨트롤은 그리드뷰가 아닙니다.";
		}

		var dataListID = gridView.getDataList();
		if (strLib.isEmpty(dataListID) || !$w.data[dataListID]) {
			// 개발자 메시지: 영문지원 안 함
			throw "그리드뷰에 바인딩된 DataList가 존재하지 않습니다.";
		}

		// 기본옵션
		if (!options) {
			options = {};
		}
		
		// EXCEL 업로드
		gridView.advancedExcelUpload({
			"type" : (options.type == null) ? 0 : options.type,
			"sheetNo" : (options.sheetNo == null) ? 0 : options.sheetNo,
			"startRowIndex" : (options.startRowIndex == null) ? 3 : options.startRowIndex,
			"startColumnIndex" : (options.startColumnIndex == null) ? 0 : options.startColumnIndex,
			"headerExist" : (options.headerExist == null) ? 1 : options.headerExist,
			"footerExist" : (options.footerExist == null) ? 0 : options.footerExist,
			"append" : (options.append == null) ? 0 : options.append,
			"hidden" : (options.hidden == null) ? 0 : options.hidden,
			"fillHidden" : (options.fillHidden == null) ? 1 : options.fillHidden,
			"skipSpace" : (options.skipSpace == null) ? 1 : options.skipSpace,
			"status" : (!options.status) ? "C" : options.status,
			"pwd" : (!options.pwd) ? "" : options.pwd,
			"insertColumns" : (!options.insertColumns) ? [] : options.insertColumns
		});
		
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.uploadExcel: " + e);
	}
};

/**
 * 지정한 그리드뷰에서 숨겨진 컬럼들의 Index 배열을 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} gridView - 그리드뷰 ID, 또는 그리드뷰 개체
 * @returns {string[]} 그리드뷰에서 제외할 컬럼들의 배열
 */
commLib.hiddenColumnsIndex = function(gridView) {
	try {
		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "숨겨진 컬럼들의 정보를 가져올 그리드뷰를 지정해주십시오.";
		}

		if (typeof gridView == "string") {
			gridView = commLib.getControlById(gridView);
		}

		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 그리드뷰가 존재하지 않습니다.";
		} else if (gridView.getPluginName().toLowerCase() != "gridview") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정하신 컨트롤은 그리드뷰가 아닙니다.";
		}

		var result = [];
		var totalCol = gridView.getTotalCol();
		for (var i = 0; i < totalCol; i++) {
			if (!gridView.getColumnVisible(i)) {
				result.push(i);
			}
		}

		return result;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.hiddenColumnsIndex: " + e);
	}
};

/**
 * 지정한 복수의 컬럼들의 Index 배열을 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} gridView - 그리드뷰 ID, 또는 그리드뷰 개체
 * @returns {string} 그리드뷰 컬럼들의 배열
 */
commLib.getColumnIndexs = function(gridView, columns) {
	try {
		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "컬럼들의 Index 정보를 가져올 그리드뷰를 지정해주십시오.";
		}

		if (typeof gridView == "string") {
			gridView = commLib.getControlById(gridView);
		}

		if (!gridView) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 그리드뷰가 존재하지 않습니다.";
		} else if (gridView.getPluginName().toLowerCase() != "gridview") {
			// 개발자 메시지: 영문지원 안 함
			throw "지정하신 컨트롤은 그리드뷰가 아닙니다.";
		}

		var result = [];
		if (columns) {
			if (typeof columns == "string") {
				var index = gridView.getColumnIndex(columns);
				if (typeof index != "undefined") {
					result.push(index);
				}
			} else if ($.isArray(columns)) {
				for (var i = 0; i < columns.length; i++) {
					var index = gridView.getColumnIndex(columns[i]);
					if (typeof index != "undefined" && $.inArray(index, result) == -1) {
						result.push(index);
					}
				}
			}
		}

		return result;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getColumnIndexs: " + e);
	}
};

/**
 * 그리드뷰에 바인딩된 DataList 개체를 반환합니다.
 *
 * @author SONG WONSEOK 보완
 * @date 2017. 06. 15.
 * @memberOf commLib
 * @param {object} gridView - 그리드뷰 개체
 * @return {object} DataList 개체
 */
commLib.getGridViewDataList = function(gridView) {
	try {
		var dataListID = gridView.getDataList();

		if (!strLib.isEmpty(dataListID, true)) {
			return $w.data[dataListID];
		} else {
			return null;
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getGridViewDataList: " + e);
	}
};

/**
 * 지정한 DataCollection이 존재하는지 여부를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} dataCollectionID - DataCollection ID
 * @return {boolean} 존재 여부
 */
commLib.dataExist = function(dataCollectionID) {
	try {
		if (!dataCollectionID || strLib.isEmpty(dataCollectionID, true)) {
			return false;
		}

		if ($w.data[dataCollectionID]) {
			return true;
		} else {
			return false;
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.dataExist: " + e);
	}
};

/**
 * 지정한 DataCollection을 동적으로 생성합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} dataCollectionID - DataCollection ID
 * @param {string} type - DataCollection 유형 (datamap, datalist, linkeddatalist)
 * @param {object[]} infoArr - DataCollection 컬럼 정보 배열
 * @param {object} [options] - DataCollection 옵션
 * @param {object[]} [data] - DataCollection 데이터 배열
 */
commLib.dataCreate = function(dataCollectionID, type, infoArr, options, data) {
	try {
		if (!popupLib.isPop()) {
			dataCollectionID = udc_obj.id+"_"+dataCollectionID;
		}
		if (!dataCollectionID || strLib.isEmpty(dataCollectionID, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "생성하고자 하는 DataCollection의 ID를 지정해주십시오.";
		} else if (strLib.isEmpty(type)) {
			// 개발자 메시지: 영문지원 안 함
			throw "생성하고자 하는 DataCollection의 유형을 지정해주십시오.";
		} else if (!infoArr) {
			// 개발자 메시지: 영문지원 안 함
			throw "생성하고자 하는 DataCollection의 상세 정보를 지정해주십시오.";
		}

		if (!$w.data[dataCollectionID]) {
			var createInfo = {
				"id" : dataCollectionID,
				"type" : type,
				"option" : options || {},
				"data" : data || []
			};

			switch (type.toLowerCase()) {
			case "datamap":
				createInfo["keyInfo"] = infoArr;
				break;
			case "datalist":
				createInfo["columnInfo"] = infoArr;
				break;
			case "linkeddatalist":
				createInfo["option"] = infoArr;
				break;
			default:
				// 개발자 메시지: 영문지원 안 함
				throw "올바른 DataCollection 유형을 지정해주십시오.";
				break;
			}

			$w.data.create(createInfo);
		}

		return $w.data[dataCollectionID];
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.dataCreate: " + e);
	}
};

/**
 * 지정한 DataCollection을 제거합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} dataCollectionID - DataCollection ID
 */
commLib.dataRemove = function(dataCollectionID) {
	try {
		if (!popupLib.isPop()) {
			dataCollectionID = udc_obj.id+"_"+dataCollectionID;
		}
		if (!dataCollectionID || strLib.isEmpty(dataCollectionID, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "제거할 DataCollection의 ID를 지정해주십시오.";
		}

		if ($w.data[dataCollectionID]) {
			$w.data.remove(dataCollectionID);
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.dataRemove: " + e);
	}
};

/**
 * 지정한 DataCollection의 유형을 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} dataCollectionID - DataCollection ID
 */
commLib.getDataType = function(dataCollectionID) {
	try {
		if (!popupLib.isPop()) {
			dataCollectionID = udc_obj.id+"_"+dataCollectionID;
		}
		if (!dataCollectionID || strLib.isEmpty(dataCollectionID, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "정보를 가져올 DataCollection의 ID를 지정해주십시오.";
		}

		if (!$w.data[dataCollectionID]) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 DataCollection이 존재하지 않습니다.";
		}

		var objDC = $w.data[dataCollectionID];
		var initializeType = objDC.initializeType.toLowerCase();

		if (initializeType == "datamap") {
			return "DataMap";
		} else if (initializeType == "datalist") {
			return "DataList";
		} else if (initializeType == "linkeddatalist") {
			return "LinkedDataList";
		} else {
			return null;
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.getDataType: " + e);
	}
};

/**
 * 지정한 DataCollection의 데이터를 빈 값으로 초기화시킵니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} dataCollectionID - DataCollection ID
 */
commLib.dataReset = function(dataCollectionID) {
	try {
		if (!popupLib.isPop()) {
			dataCollectionID = udc_obj.id+"_"+dataCollectionID;
		}
		if (!dataCollectionID || strLib.isEmpty(dataCollectionID, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "데이터를 초기화시킬 DataCollection의 ID를 지정해주십시오.";
		}

		if (!$w.data[dataCollectionID]) {
			// 개발자 메시지: 영문지원 안 함
			throw "지정한 DataCollection이 존재하지 않습니다.";
		}

		var objDC = $w.data[dataCollectionID];

		var type = commLib.getDataType(dataCollectionID);
		if (type == "DataList") {
			objDC.removeAll();
		} else if (type == "DataMap") {
			objDC.setArray([]);
		} else if (type == "LinkedDataList") {
			// 개발자 메시지: 영문지원 안 함
			throw "LinkedDataList는 초기화를 지원하지 않습니다. 대신 바인딩 원본 DataList를 초기화하십시오.";
		}
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.dataReset: " + e);
	}
};

/**
 * 지정한 DataMap 개체들의 스키마를 병합한 새로운 DataMap을 생성합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} mergedDataMapID - 병합된 새로운 DataMap의 ID
 * @param {(string[]|object[])} dataMapList - 병합할 DataMap 개체나 ID의 배열
 * @param {boolean} overwrite - 동일한 이름의 키를 덮어쓸지 여부
 */
commLib.mergeDataMapSchema = function(mergedDataMapID, dataMapList, overwrite) {
	try {
		if (!mergedDataMapID || strLib.isEmpty(mergedDataMapID, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "새로 생성할 DataMap의 ID를 지정해주십시오.";
		}

		if ($w.data[mergedDataMapID]) {
			$w.data.remove(mergedDataMapID);
		}

		if (!dataMapList) {
			// 개발자 메시지: 영문지원 안 함
			throw "병합할 DataMap을 지정해주십시오.";
		} else if (!$.isArray(dataMapList) || dataMapList.length < 2) {
			// 개발자 메시지: 영문지원 안 함
			throw "병합할 두 개 이상의 DataMap이 지정된 배열을 지정해주십시오.";
		}

		if (!overwrite) {
			overwrite = false;
		}

		var mergedKeyInfo = {};
		for (var i = 0; i < dataMapList.length; i++) {
			var dataMap = dataMapList[i];
			if (typeof dataMap == "string") {
				dataMap = $w.data[dataMap];
			}

			if (!dataMap || !dataMap.initializeType || dataMap.initializeType != "dataMap") {
				// 개발자 메시지: 영문지원 안 함
				throw "지정하신 개체는 DataMap 개체가 아닙니다. (" + dataMapList[i].toString() + ")";
			}

			var keyInfo = dataMap.getInfo().keyInfo;
			for ( var key in keyInfo) {
				var isExist = mergedKeyInfo.hasOwnProperty(key);
				if (!isExist || overwrite) {
					mergedKeyInfo[key] = keyInfo[key];
				}
			}
		}

		var mergedArray = [];
		for ( var key in mergedKeyInfo) {
			mergedArray.push(mergedKeyInfo[key]);
		}

		var mergedDataMap = commLib.dataCreate(mergedDataMapID, "dataMap", mergedArray);

		return mergedDataMap;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.mergeDataMapSchema: " + e);
	}
};

/**
 * 지정한 DataMap 개체들의 스키마를 병합한 새로운 DataMap을 생성하고 데이터를 적재합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} mergedDataMapID - 병합된 새로운 DataMap의 ID
 * @param {(string[]|object[])} dataMapList - 병합할 DataMap 개체나 ID의 배열
 * @param {boolean} overwrite - 동일한 이름의 키를 덮어쓸지 여부
 */
commLib.mergeDataMapData = function(mergedDataMapID, dataMapList, overwrite) {
	try {
		if (!mergedDataMapID || strLib.isEmpty(mergedDataMapID, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "새로 생성할 DataMap의 ID를 지정해주십시오.";
		}

		if ($w.data[mergedDataMapID]) {
			$w.data.remove(mergedDataMapID);
		}

		if (!dataMapList) {
			// 개발자 메시지: 영문지원 안 함
			throw "병합할 DataMap을 지정해주십시오.";
		} else if (!$.isArray(dataMapList) || dataMapList.length < 2) {
			// 개발자 메시지: 영문지원 안 함
			throw "병합할 두 개 이상의 DataMap이 지정된 배열을 지정해주십시오.";
		}

		if (!overwrite) {
			overwrite = false;
		}

		// 스키마 병합
		var mergedDataMap = commLib.mergeDataMapSchema(mergedDataMapID, dataMapList, overwrite);

		var mergedValue = {};
		for (var i = 0; i < dataMapList.length; i++) {
			var dataMap = dataMapList[i];
			if (typeof dataMap == "string") {
				dataMap = $w.data[dataMap];
			}

			var keyInfo = dataMap.getInfo().keyInfo;
			for ( var key in keyInfo) {
				var isExist = mergedValue.hasOwnProperty(key);
				if (!isExist || overwrite) {
					mergedValue[key] = dataMap.get(key);
				}
			}
		}
		mergedDataMap.setJSON(mergedValue);

		return mergedDataMap;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("commLib.mergeDataMapData: " + e);
	}
};


/**
 * 지정한 DataMap 개체들의 스키마를 병합한 새로운 DataMap을 생성하고 데이터를 적재합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 14.
 * @memberOf commLib
 * @param {string} dataCollectionID - DataCollection ID
 * @param {string} keyList - 콤마로 이어진 키 컬럼의 Key 이름
 * @return {object[]} 변경된 정보들의 배열
 */
// commLib.getDataChangeInfo = function(dataCollectionID, keyList) {
// 	try {
// 		if (!dataCollectionID || strLib.isEmpty(dataCollectionID, true)) {
// 			// 개발자 메시지: 영문지원 안 함
// 			throw "정보를 가져올 DataCollection의 ID를 지정해주십시오.";
// 		}
//
// 		if (!$w.data[dataCollectionID]) {
// 			// 개발자 메시지: 영문지원 안 함
// 			throw "지정한 DataCollection이 존재하지 않습니다.";
// 		}
//
// 		if (!keyList || strLib.isEmpty(keyList, true)) {
// 			// 개발자 메시지: 영문지원 안 함
// 			throw "DataCollection의 키 정보를 지정해주십시오.";
// 		}
//
// 		var objDC = $w.data[dataCollectionID];
// 		var initializeType = objDC.initializeType.toLowerCase();
//
// 		var result = [];
// 		var keys = keyList.split(",");
//
// 		if (initializeType == "datamap") {
//
// 			// DataMap
// 			if (objDC.getModifiedIndex().length == 0) {
// 				// 변경된 데이터가 없는 경우
// 				return;
// 			} else {
// 				// 변경된 데이터가 존재하는 경우
//
// 				// 키값 취합
// 				var keyValues = "";
// 				for (var i = 0; i < keys.length; i++) {
// 					keyValues += "," + objDC.get(keys[i]);
// 				}
// 				if (keyValues.length > 0) {
// 					keyValues = keyValues.substr(1);
// 				}
//
// 				// 변경 데이터 취합
// 				var modifiedKeys = objDC.getModifiedKey();
// 				for (var i = 0; i < modifiedKeys.length; i++) {
// 					var key = modifiedKeys[i];
// 					var item = {
// 						id : dataCollectionID,
// 						keyValues : keyValues,
// 						key : key,
// 						name : objDC.getKeyInfo(key).name,
// 						original : objDC.getOriginal(key),
// 						current : objDC.get(key)
// 					};
//
// 					result.push(item);
// 				}
//
// 				return result;
// 			}
//
// 		} else if (initializeType == "datalist") {
//
// 			// DataList
// 			if (objDC.getUpdatedIndex().length + objDC.getInsertedJSON().length == 0) {
// 				// 변경된 데이터가 없는 경우
// 				return;
// 			} else {
// 				// 변경된 데이터가 존재하는 경우
//
// 				// 컬럼 목록
// 				var idList = objDC.cellIdList;
//
// 				// 변경된 데이터
// 				var indexs = commLib.getURowArr(objDC);
// 				if (indexs.length > 0) {
// 					for (var i = 0; i < indexs.length; i++) {
// 						var rowIndex = indexs[i];
//
// 						// 키값 취합
// 						var keyValues = "";
// 						for (var j = 0; j < keys.length; j++) {
// 							keyValues += "," + objDC.getCellData(rowIndex, keys[j]);
// 						}
// 						if (keyValues.length > 0) {
// 							keyValues = keyValues.substr(1);
// 						}
//
// 						// 변경 데이터 취합
//
// 						for (var j = 0; j < idList.length; j++) {
// 							var key = idList[j];
//
// 							var original = objDC.getOriginalCellData(rowIndex, key);
// 							var current = objDC.getCellData(rowIndex, key);
//
// 							if (original != current) {
// 								var item = {
// 									id : dataCollectionID,
// 									keyValues : keyValues,
// 									key : key,
// 									name : objDC.getColumnName(key),
// 									original : original,
// 									current : current
// 								};
//
// 								result.push(item);
// 							}
// 						}
// 					}
// 				}
//
// 				// 추가된 데이터
// 				indexs = commLib.getIRowArr(objDC);
// 				if (indexs.length > 0) {
// 					for (var i = 0; i < indexs.length; i++) {
// 						var rowIndex = indexs[i];
//
// 						// 키값 취합
// 						var keyValues = "";
// 						for (var j = 0; j < keys.length; j++) {
// 							keyValues += "," + objDC.getCellData(rowIndex, keys[j]);
// 						}
// 						if (keyValues.length > 0) {
// 							keyValues = keyValues.substr(1);
// 						}
//
// 						// 추가 데이터 취합
// 						for (var j = 0; j < idList.length; j++) {
// 							var key = idList[j];
//
// 							var original = objDC.getOriginalCellData(rowIndex, key);
// 							var current = objDC.getCellData(rowIndex, key);
//
// 							if (original != current) {
// 								var item = {
// 									id : dataCollectionID,
// 									keyValues : keyValues,
// 									key : key,
// 									name : objDC.getColumnName(key),
// 									original : original,
// 									current : current
// 								};
//
// 								result.push(item);
// 							}
// 						}
// 					}
// 				}
//
// 				return result;
// 			}
// 		} else {
// 			// 개발자 메시지: 영문지원 안 함
// 			throw "지원하지 않는 DataCollection 유형입니다";
// 		}
// 	} catch (e) {
// 		//$W.exception.printStackTrace(e);
// 		//commLib.log("commLib.getDataChangeInfo: " + e);
// 	}
// };

/**
 * 지정한 DataCollection의 수정 데이터를 json 형태로 return 한다.
 *
 * @author leebeomgeun
 * @date 2019. 11. 06.
 * @memberOf commLib
 * @param {string} dataCollection - DataCollection
 * @return {json[]} 변경된 정보들의 json data
 */
commLib.getDataChangeInfo = function(dataCollection, keys) {
	try{
		if (!dataCollection || strLib.isEmpty(dataCollection, true)) {
			throw "정보를 가져올 DataCollection의 ID를 지정해주십시오.";
		}


		var result = valLib.checkModified(dataCollection)?dataCollection.getModifiedJSON({ DB: true }):[{rowStatus:""}];
		return result;
	} catch (e) {
		commLib.log("commLib.getDataChangeInfo: " + e);
	}

};


/**
 * WebSquare가 제공하는 웹 브라우저 콘솔 및 자체 디버깅 로그를 출력합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 02.
 * @memberOf commLib
 * @param {string} message - 콜솔에 출력할 메시지
 * @param {boolean} [ignoreAlert] - Alert 출력 여부
 */
commLib.log = function(message, ignoreAlert) {
	try {
		if (ignoreAlert == null) {
			ignoreAlert = false;
		}

		$w.log(message);
		if (!ignoreAlert) {
			var position = message.indexOf(":");
			alert(message.substr(0, position) + "\n\n" + message.substr(position + 1).trim());
		}

	} catch (e) {
		//$W.exception.printStackTrace(e);
	}
};

commLib.getHelpDesk = function(cmpnCd, userId, prgId, sysCd){
    commLib.getHelpDesk(cmpnCd, userId, prgId, sysCd, "600", "600");
};

/**
 * 도움말 버튼 넓이, 높이
 */
commLib.getHelpDesk = function(cmpnCd, userId, prgId, sysCd, width, height){
    popupLib.open("comHelpDeskPop", "/ux/com/pop/comHelpDeskPop.xml", {
        title: "도움말",
        useLayer: true,     //레어어팝업여부
        modal: true,        //모달팝업
        width: width,
        height: height,
        param: {
            cmpnCd : cmpnCd
          , userId  : userId
          , prgId  : prgId
          , sysCd  : sysCd
        }
    });
};

/**
 * WebSquare가 디버그 모드에서 실행되고 있는지 여부를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {boolean} 디버그 모드 여부
 */
configLib.isDebugMode = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];

		return (WebSquare.xml.getValue(configXml, "WebSquare/debug/@value") === "true");
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.isDebugMode: " + e);
	}
};

/**
 * WebSquare의 디버그 관련 정보를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {object} 디버그 관련 정보 JSON 개체
 */
configLib.debugInfo = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];

		return {
			console : (WebSquare.xml.getValue(configXml, "WebSquare/debug/@console") === "true"),
			remoteConsole : (WebSquare.xml.getValue(configXml, "WebSquare/debug/@remoteConsole") === "true"),
			value : (WebSquare.xml.getValue(configXml, "WebSquare/debug/@value") === "true")
		};
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.debugInfo: " + e);
	}
};

/**
 * WebSquare의 공통 JavaScript 목록을 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {string[]} 공통 JavaScript 목록의 배열
 */
configLib.scriptModuleList = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];
		var list = WebSquare.xml.findNodes(configXml, "WebSquare/engine/module");

		var result = [];
		for (var i = 0; i < list.length; i++) {
			result.push(WebSquare.xml.getValue(list[i], "@src"));
		}

		return result;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.scriptModuleList: " + e);
	}
};

/**
 * WebSquare의 언어 설정을 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {string} 언어 설정
 */
configLib.language = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];

		return WebSquare.xml.getValue(configXml, "WebSquare/language/@value");
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.language: " + e);
	}
};

/**
 * WebSquare의 "처리 중" 메시지 팝업 정보를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {object} "처리 중" 메시지 팝업 정보 JSON 개체
 */
configLib.processMsgInfo = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];

		return {
			height : WebSquare.xml.getValue(configXml, "WebSquare/processMsgHeight/@value"),
			width : WebSquare.xml.getValue(configXml, "WebSquare/processMsgWidth/@value"),
			background : WebSquare.xml.getValue(configXml, "WebSquare/processMsgBackground/@value"),
			backgroundColor : WebSquare.xml.getValue(configXml, "WebSquare/processMsgBackground/@backgroundColor")
		};
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.processMsgInfo: " + e);
	}
};

/**
 * WebSquare의 StyleSheet 관련 정보를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {object} StyleSheet 정보 JSON 개체
 */
configLib.sylesInfo = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];

		return {
			value : WebSquare.xml.getValue(configXml, "WebSquare/stylesheet/@value"),
			import : WebSquare.xml.getValue(configXml, "WebSquare/stylesheet/@import"),
			enable : (WebSquare.xml.getValue(configXml, "WebSquare/stylesheet/@enable") === "true"),
			earlyImportList : WebSquare.xml.getValue(configXml, "WebSquare/stylesheet/@earlyImportList").split(",")
		};
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.sylesInfo: " + e);
	}
};

/**
 * WebSquare의 개발환경 관련 정보를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @return {object} 개발환경 관련 정보 JSON 개체
 */
configLib.environmentInfo = function() {
	try {
		var configXml = WebSquare.BootLoader.configurationDOM[0];

		return {
			mode : WebSquare.xml.getValue(configXml, "WebSquare/environment/@mode"),
			cache : WebSquare.xml.getValue(configXml, "WebSquare/environment/@cache"),
			postfix : WebSquare.xml.getValue(configXml, "WebSquare/environment/@postfix")
		};
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.environmentInfo: " + e);
	}
};

/**
 * WebSquare 관련 boerp 사용자 지정 구성 정보를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 12.
 * @memberOf configLib
 * @param {string} key - 사용자 지정 구성 정보 키
 * @return {object} boerp 사용자 지정 구성 정보
 */
configLib.kriisInfo = function(key) {
	try {
		if (!key || strLib.isEmpty(key, true)) {
			// 개발자 메시지: 영문지원 안 함
			throw "구성 정보를 가져올 키를 지정해주십시오.";
		}

		var configXml = WebSquare.BootLoader.configurationDOM[0];
		var result = WebSquare.xml.getValue(configXml, "WebSquare/" + key + "/@value");

		return strLib.isEmpty(result, true) ? "" : result.trim();
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("configLib.kriisInfo: " + e);
	}
};

/**
 * 선택한 파일의 확장자가 업로드 허용된 파일인지 여부를 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf fileLib
 * @param {(object|string)} control - 업로드 컴포넌트 ID, 또는 업로드 컴포넌트 개체
 * @param {string[]} allowList - 허용된 파일 확장자의 문자열 배열
 * @return {boolean} 허용된 파일 확장자 여부
 */
fileLib.checkExt = function(control, allowList) {
	try {
		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "확장자를 검사할 Upload의 ID를 지정해주십시오.";
		}

		if (typeof control == "string") {
			control = commLib.getControlById(control);
		}

		if (!control) {
			// 개발자 메시지: 영문지원 안 함
			throw "확장자를 검사할 Upload의 ID를 지정해주십시오.";
		}

		var path = control.getValue();
		if (strLib.isEmpty(path, true)) {
			return false;
		}

		// 확장자
		var buffer = path.split(".");
		var ext = buffer[buffer.length - 1].toLowerCase();

		if (!$.isArray(allowList)) {
			if (allowList.indexOf(",") > -1) {
				allowList = allowList.split(",");
			} else {
				allowList = [ allowList ];
			}
		}

		var isAllowed = false;
		for (var i = 0; i < allowList.length; i++) {
			if (ext == allowList[i].replace(/\./g, "").toLowerCase()) {
				isAllowed = true;
				break;
			}
		}

		return isAllowed;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("fileLib.checkExt: " + e);
	}
};

/**
 * 파일 업로드 결과 XML 개체를 JSON 개체로 변환하여 반환합니다.
 *
 * @author SONG WONSEOK
 * @date 2017. 06. 05.
 * @memberOf fileLib
 * @param {object} retXml - 파일 업로드 결과 XML 개체
 * @return {object} 파일 업로드 결과 JSON 개체
 */
fileLib.retXmlToJSON = function(retXml) {
	try {
		var result = {};

		var key = WebSquare.xml.getValue(retXml, "ret/key");
		var storedFileList = WebSquare.xml.getValue(retXml, "ret/storedFileList");
		var localfileList = WebSquare.xml.getValue(retXml, "ret/localfileList");
		var fileSizeList = WebSquare.xml.getValue(retXml, "ret/fileSizeList");
		var maxUploadSize = WebSquare.xml.getValue(retXml, "ret/maxUploadSize");
		var deniedList = WebSquare.xml.getValue(retXml, "ret/deniedList");
		var deniedCodeList = WebSquare.xml.getValue(retXml, "ret/deniedCodeList");

		if (strLib.isEmpty(deniedList, true) && strLib.isEmpty(deniedCodeList, true)) {
			// 업로드 성공
			result.serverPath = key;
			result.serverFilename = storedFileList;
			result.clientFilename = localfileList;
			result.fileSize = fileSizeList;
		} else {
			// 업로드 실패
			result.maxUploadSize = maxUploadSize;
			result.deniedFilename = deniedList;
			result.deniedCode = deniedCodeList;
		}

		return result;
	} catch (e) {
		//$W.exception.printStackTrace(e);
		//commLib.log("fileLib.retXmlToJSON: " + e);
	}
};

/**
 * 파일업로드
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {String}
 *            folder - 경로정보 ex) "bo/hr/lab/calc" OR ""
 * @param {String}
 *            upGbn - 싱글("S") / 멀티("M") 구분
 * @param {String}
 *            callback - 콜백함수명
 */
fileLib.uploadFilePop = function(fileId,folder,upGbn,callback){
	if (!upGbn || !callback) return;
    popupLib.open("comFileUpload", "/ux/com/pop/comFileUpload.xml", {
        title: "파일첨부",
        useLayer: true,     // 레어어팝업여부
        modal: true,        // 모달팝업
        width: "600",
        height: upGbn == "M" ? "380" : "215",
        close:false,
        param: {
            folder: folder,
            fileId: fileId,
            upGbn: upGbn
        },
        callback: callback
    });
};

/**
 * 파일업로드2
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {String}
 *            folder - 경로정보 ex) "bo/hr/lab/calc" OR ""
 * @param {String}
 *            upGbn - 싱글("S") / 멀티("M") 구분
 * @param {Boolean}
 *            isControlYn - 파일 추가, 삭제 가능 여부
 * @param {String}
 *            callback - 콜백함수명
 */
fileLib.uploadFilePop2 = function(fileId,folder,upGbn,isControlYn,callback, imageOnly){
	if (!upGbn || !callback) return;
    popupLib.open("comFileUpload", "/ux/com/pop/comFileUpload2.xml", {
        title: "파일첨부",
        useLayer: true,     // 레어어팝업여부
        modal: true,        // 모달팝업
        width: "600",
        height: upGbn == "M" ? "400" : "215",
        close:false,
        param: {
            folder: folder,
            fileId: fileId,
            upGbn: upGbn,
            isControlYn: isControlYn,
            imageOnly : imageOnly == undefined ? false : imageOnly
        },
        callback: callback
    });
};

/**
 * 파일업로드(다국어)
 *
 * @author 송보권
 * @date 2023. 09. 19.
 * @memberOf fileLib
 * @param {String} fileId 	- 파일 아이디
 * @param {String} folder 	- 경로정보 ex) "bo/hr/lab/calc" OR ""
 * @param {String} upGbn 	- 싱글("S") / 멀티("M") 구분
 * @param {String} callback - 콜백함수명
 */
fileLib.uploadFilePopGlobal = function(fileId,folder,upGbn,callback){
	if (!upGbn || !callback) return;
    popupLib.open("comFileUploadGlobal", "/ux/com/pop/comFileUploadGlobal.xml", {
        title: commLib.getMsgGlobal("title.0021"),
        useLayer: true,     // 레어어팝업여부
        modal: true,        // 모달팝업
        width: "600",
        height: upGbn == "M" ? "380" : "215",
        close:false,
        param: {
            folder: folder,
            fileId: fileId,
            upGbn: upGbn
        },
        callback: callback
    });
};

/**
 * 파일업로드(다국어)
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String} fileId - 파일 아이디
 * @param {String} folder - 경로정보 ex) "bo/hr/lab/calc" OR ""
 * @param {String} upGbn - 싱글("S") / 멀티("M") 구분
 * @param {Boolean} isControlYn - 파일 추가, 삭제 가능 여부
 * @param {String} callback - 콜백함수명
 */
fileLib.uploadFilePop2Global = function(fileId,folder,upGbn,isControlYn,callback, imageOnly){
	if (!upGbn || !callback) return;
    popupLib.open("comFileUpload2Global", "/ux/com/pop/comFileUpload2Global.xml", {
        title: commLib.getMsgGlobal("title.0021"),
        useLayer: true,     // 레어어팝업여부
        modal: true,        // 모달팝업
        width: "600",
        height: upGbn == "M" ? "400" : "215",
        close:false,
        param: {
            folder: folder,
            fileId: fileId,
            upGbn: upGbn,
            isControlYn: isControlYn,
            imageOnly : imageOnly == undefined ? false : imageOnly
        },
        callback: callback
    });
};

/**
 * 이미지업로드
 *
 * @author 송보권
 * @date 2022. 08. 17.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {String}
 *            folder - 경로정보 ex) "bo/hr/lab/calc" OR ""
 * @param {String}
 *            upGbn - 싱글("S") / 멀티("M") 구분
 * @param {Boolean}
 *            isControlYn - 파일 추가, 삭제 가능 여부
 * @param {String}
 *            callback - 콜백함수명
 */
fileLib.uploadImgPop = function(fileId,folder,upGbn,isControlYn,callback){
	if (!upGbn || !callback) return;
    popupLib.open("comFileUpload", "/ux/com/pop/comFileUpload2.xml", {
        title: "파일첨부",
        useLayer: true,     // 레어어팝업여부
        modal: true,        // 모달팝업
        width: "600",
        height: upGbn == "M" ? "380" : "215",
        close:false,
        param: {
            folder: folder,
            fileId: fileId,
            upGbn: upGbn,
            isControlYn: isControlYn
        },
        callback: callback
    });
};

/**
 * 파일다운로드팝업
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {String}
 *            folder - 경로정보 ex) "bo/hr/lab/calc" OR ""
 * @param {String}
 *            upGbn - 싱글("S") / 멀티("M") 구분
 * @param {String}
 *            callback - 콜백함수명
 */
fileLib.downldFilePop = function(fileId){
	if(!fileId) return;
    popupLib.open("comFileDownload", "/ux/com/pop/comFileDownload.xml", {
        title: "파일 다운로드",
        useLayer: true,     //레어어팝업여부//
        modal: true,        //모달팝업
        width: "500",
        height: "305",
        param: {
            fileId : fileId
        }
    });
};

/**
 * 파일다운로드
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {String}
 *            fileNo - 파일 번호
 * @param {String}
 *            originalFilename - 파일 명
 */
fileLib.downldFile = function(fileId, fileNo, originalFilename){
	if(!fileId) return;
	if (originalFilename) {
		let link = document.createElement('a');
		link.setAttribute('download', originalFilename);
		link.setAttribute(
			'href',
			'/files/' + fileId + ((fileNo != undefined && fileNo != null ) ? '/' + fileNo : '') + '/download'
		);
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
	} else {
		ajaxLib.ajax('files/' + fileId + ((fileNo != undefined && fileNo != null ) ? '/' + fileNo : ''), {
            method: "GET",
            requestData : {},
            callback: function(result) {
				if (result.originalFilename) {
					fileLib.downldFile(fileId, fileNo, result.originalFilename);
				}
			}
        });
		/*
		var ifr = document.createElement("iframe");
		ifr.id = "ifr";
		ifr.name = "__TEMP__1";
		ifr.style = "display:none;";
		var link = document.createElement("form");
		link.download = "";
		link.target="__TEMP__1";
		var action = "";
		if (fileNo == undefined) {
			action = "/files/"+fileId+"/download";
		} else {
			action = "/files/"+fileId+"/"+fileNo+"/download";
		}
		link.action = action;
		link.id = "link";
		document.body.appendChild(link);
		document.body.appendChild(ifr);
		link.submit();
		window.setTimeout(function(){
			document.body.removeChild(link);
			document.body.removeChild(ifr);
			delete link;
			delete ifr;
		}, 1000);
		*/
	}
};

/**
 * 파일다운로드 다건
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {Array}
 *            fileNo - 파일 번호 배열
 */
fileLib.downldFileMult = function(fileId, fileNoArr){
	if(!fileId) return;
	if(!fileNoArr) return;
	var ifr = document.createElement("iframe");
	ifr.id = "ifr";
	ifr.name = "__TEMP__1";
	ifr.style = "display:none;";
	var link = document.createElement("form");
	link.download = "";
	link.target="__TEMP__1";
	link.action = "/files/"+fileId+"/"+fileNoArr+"/download/partial";
	link.id = "link";
	document.body.appendChild(link);
	document.body.appendChild(ifr);
	link.submit();
	window.setTimeout(function(){
		document.body.removeChild(link);
		document.body.removeChild(ifr);
		delete link;
		delete ifr;
	}, 1000);
};

/**
 * 엑셀템플릿다운로드
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            url - 경로
 */
fileLib.excelTpt = function(url){
    var link = document.createElement("a");
    link.download = "";
    link.href = url;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    delete link;
};

/**
 * 파일삭제
 *
 * @author 고규호
 * @date 2020. 03. 23.
 * @memberOf fileLib
 * @param {String}
 *            fileId - 파일 아이디
 * @param {Array}
 *            fileNoArr - 파일 번호 배열
 */
fileLib.deleteFile = function(fileId, fileNoArr){
	if(!fileId) return;
	var url = "/files/"+fileId;
	if (fileNoArr) {
		url += "/"+fileNoArr.join(",");
	}
    $.ajax({
        type: "DELETE",
        url: url,
        async: false,
        success: function(data2) {
            alert("삭제하였습니다.");
        },
        error: function(e) {
            alert("삭제를 실패하였습니다.");
        }
    });
};

/**
 * 공통 처리용 유틸성 기능을 제공한다.
 * @type comboCommon
 * @class comboCommon
 * @namespace comboCommon
 */
var comboCommon = {
    CONTEXT_PATH : "/erp", // Context Path 경로
    DEFAULT_OPTIONS_MODE : "synchronous", // 기본 통신 모드 ( asynchronous / synchronous)
    DEFAULT_OPTIONS_MEDIATYPE : "application/json", // 기본 미디어 타입
    MESSAGE_CODE : {
        STATUS_ERROR : "E",
        STATUS_SUCCESS : "S",
        STATUS_WARNING : "W"
    },
    commonCodeInfo : {
        idPrefix:"dlt_CommonCode",
        label:"CODE_NM",
        value:"CODE_CD",
        fieldArr : [
        	"GRP_CD",
        	"CODE_CD",
        	"CODE_NM",
        	"ARRY_ODER",
        	"SPEC_EXPL",
        	"ESBS_CD1",
        	"ESBS_CD2",
        	"ESBS_CD3",
        	"ESBS_CD4",
        	"ESBS_CD5",
        	"ESBS_CD6",
        	"ESBS_CD7",
        	"ESBS_CD8",
        	"ESBS_CD9",
        	"ESBS_CD10",
        	"USE_YN"
        ]
    },
};

comboCommon.setCommonCode = function(codeJsonArr, callbackFuncStr){
};

/**
 * 코드성 데이터와 컴포넌트의 nodeSet(아이템 리스트)연동 기능을 제공한다.
 * code별로 JSON객체를 생성하여 array에 담아 첫번째 파라메터로 넘겨준다.
 * 그리드뷰의 경우 compID는 [컴포넌트아이디]:[컬럼명]으로 작성한다.
 * @date 2016. 07. 27.
 * @param {JSON} codeJsonArr {"code" : "코드넘버", "compID" : "적용할 컴포넌트명"}
 * @param {String} callbackFuncStr 콜백 함수명
 * @memberOf comboCommon
 * @author InswaveSystems
 * @example
 * comboCommon.setCommonCode([
 *      {"code:":"04","compID":"sbx_CommCodeReligion"},
 *      {"code:":"24","compID":"grd_CommCodeSample:JOB_CD"}
 *      ], "setCommonCodeCallback");
 */
comboCommon.setCommonCode = function(codeJsonArr, callbackFuncStr, callMode){
    var codeJsonArrLen;
    var dataGb = "";

    if(codeJsonArr){
         codeJsonArrLen = codeJsonArr.length;
    }else{
        $w.log("=== comboCommon.setCommonCode Parameter Type Error ===\nex) comboCommon.setCommonCode([{\"code:\":\"04\",\"compID\":\"sbx_Gender\"}],\"edu.callbackFunction\")\n===================================");
        return;
    }

    var i, j, codeObj, dltId, dltIdArr=[], paramCode = "", compArr, compArrLen, tmpIdArr;
    var commCodeInfo = comboCommon.commonCodeInfo;
    var dataPrefix = "";
    if (WebSquare.util.getComponentById( "tabc_layout" )) {
    	dataPrefix = udc_obj.id+"_";
	}

    var dcFormObj = comboCommon.getCodeDCForm(commCodeInfo.fieldArr);
    for(i=0;i<codeJsonArrLen;i++){
        codeObj = codeJsonArr[i];
        try{
            if(i>0){
                paramCode += ",";
            }
            dltId = dataPrefix+codeObj.code;
            dltIdArr.push(dltId);

            paramCode += codeObj.code;

            dcFormObj.id = dltId;

            try{
                $w.data.remove(dltId);
            }catch(ex){}

            $w.data.create(dcFormObj);

            if(codeObj.compID){ //컴포넌트의 ID가 없는 경우도 있음.
                compArr = (codeObj.compID).replaceAll(" ","").split(",");
                compArrLen = compArr.length;
                for(j=0;j<compArrLen;j++){
                    tmpIdArr = compArr[j].split(":");
                    try{
                    	var target;
                    	
                    	if (window[tmpIdArr[j]]) { //없으면 그룹웨어 링크시 동작 오류
                    		target = window[tmpIdArr[j]];
                    	} else if (window[tmpIdArr]) { //없으면 팝업창에서 동작 오류		2022.12.14 박성훈 수정
                            target = window[tmpIdArr];
                        } else {
                            var idPreFix = udc_obj.id+"_";
                            target = $p.getComponentById(idPreFix+tmpIdArr[0]);
                        }
                        if(tmpIdArr.length === 1){  //기본 컴포넌트
                        	target.setNodeSet("data:"+dltId, commCodeInfo.label, commCodeInfo.value);
                        }else{  //gridView 컴포넌트
                        	target.setColumnNodeSet(tmpIdArr[1], "data:"+dltId, commCodeInfo.label, commCodeInfo.value);
                        }
                    }catch(ex){
                        $w.log(tmpIdArr[0] + "이 존재하지 않습니다.");
                    }
                }
            }

        }catch(ex){
            $w.log("comboCommon.setCommonCode Error");
            $w.log(JSON.stringify(codeObj));
            $w.log(ex);
            continue;
        }
    }

    $.ajax({
        url: "/getCodeList",
        type: "GET",
        data: {
        	GRP_CD : paramCode,
        	DATA_PREFIX : dataPrefix
        },
        contentType: "application/json;charset=utf-8",
        dataType: "json",
        async: false,
        success: function(data) {
        	delete data.msg;
        	delete data.msgCode;
        	for(var key in data){
        		if (!(key.lastIndexOf("_") == key.length-1)) {
        			WebSquare.util.getComponentById(key).setJSON(data[key]);
				}
    		}
        },
        error: function(data) {
        	alert("잘못된 요청입니다.");
        },
        complete: function(data) {
        	if (callbackFuncStr) {
        		if (typeof callbackFuncStr == "function") {
					callbackFuncStr();
				} else {
					callbackFuncStr = callbackFuncStr.replace("(","").replace(")","").replace(";","").replace("scwin.","");
					if (opener) {//윈도우팝업
						scwin[callbackFuncStr]();
					} else {//그외
						if ($("#tabc_layout").length == 0) {//윈도우 팝업 자식 레이어팝업
							scwin[callbackFuncStr]();
						} else {//그외
							udc_obj.scope.scwin[callbackFuncStr]();
						}
					}
				}
        	}
        }
    });
};



/**
 * 코드성 데이터와 컴포넌트의 nodeSet(아이템 리스트)연동 기능을 제공한다.
 * code별로 JSON객체를 생성하여 array에 담아 첫번째 파라메터로 넘겨준다.
 * 그리드뷰의 경우 compID는 [컴포넌트아이디]:[컬럼명]으로 작성한다.
 * @date 2022. 07. 08.
 * @param {String} 회사코드
 * @param {JSON} codeJsonArr {"code" : "코드넘버", "compID" : "적용할 컴포넌트명"}
 * @param {String} callbackFuncStr 콜백 함수명
 * @memberOf comboCommon
 * @author InswaveSystems
 * @example
 * comboCommon.setCommonCodeCmpn("S0001",[
 *      {"code:":"04","compID":"sbx_CommCodeReligion"},
 *      {"code:":"24","compID":"grd_CommCodeSample:JOB_CD"}
 *      ], "setCommonCodeCallback");
 */
comboCommon.setCommonCodeCmpn = function(cmpn, codeJsonArr, callbackFuncStr, callMode){
    var codeJsonArrLen;
    var dataGb = "";

    if(codeJsonArr){
         codeJsonArrLen = codeJsonArr.length;
    }else{
        $w.log("=== comboCommon.setCommonCode Parameter Type Error ===\nex) comboCommon.setCommonCode([{\"code:\":\"04\",\"compID\":\"sbx_Gender\"}],\"edu.callbackFunction\")\n===================================");
        return;
    }

    var i, j, codeObj, dltId, dltIdArr=[], paramCode = "", compArr, compArrLen, tmpIdArr;
    var commCodeInfo = comboCommon.commonCodeInfo;
    var dataPrefix = "";
    if (WebSquare.util.getComponentById( "tabc_layout" )) {
    	dataPrefix = udc_obj.id+"_";
	}

    var dcFormObj = comboCommon.getCodeDCForm(commCodeInfo.fieldArr);
    for(i=0;i<codeJsonArrLen;i++){
        codeObj = codeJsonArr[i];
        try{
            if(i>0){
                paramCode += ",";
            }
            dltId = dataPrefix+codeObj.code;
            dltIdArr.push(dltId);

            paramCode += codeObj.code;

            dcFormObj.id = dltId;

            try{
                $w.data.remove(dltId);
            }catch(ex){}

            $w.data.create(dcFormObj);

            if(codeObj.compID){ //컴포넌트의 ID가 없는 경우도 있음.
                compArr = (codeObj.compID).replaceAll(" ","").split(",");
                compArrLen = compArr.length;
                for(j=0;j<compArrLen;j++){
                    tmpIdArr = compArr[j].split(":");
                    try{
                    	var target;
                        if (window[tmpIdArr[j]]) {
                            target = window[tmpIdArr[j]];
                        } else {
                            var idPreFix = udc_obj.id+"_";
                            target = $p.getComponentById(idPreFix+tmpIdArr[0]);
                        }
                        if(tmpIdArr.length === 1){  //기본 컴포넌트
                        	target.setNodeSet("data:"+dltId, commCodeInfo.label, commCodeInfo.value);
                        }else{  //gridView 컴포넌트
                        	target.setColumnNodeSet(tmpIdArr[1], "data:"+dltId, commCodeInfo.label, commCodeInfo.value);
                        }
                    }catch(ex){
                        $w.log(tmpIdArr[0] + "이 존재하지 않습니다.");
                    }
                }
            }

        }catch(ex){
            $w.log("comboCommon.setCommonCode Error");
            $w.log(JSON.stringify(codeObj));
            $w.log(ex);
            continue;
        }
    }
    
    $.ajax({
        url: "/getCodeCmpnList",
        type: "GET",
        data: {
        	CMPN : cmpn,
        	GRP_CD : paramCode,
        	DATA_PREFIX : dataPrefix
        },
        contentType: "application/json;charset=utf-8",
        dataType: "json",
        async: false,
        success: function(data) {
        	delete data.msg;
        	delete data.msgCode;
        	for(var key in data){
        		if (!(key.lastIndexOf("_") == key.length-1)) {
        			WebSquare.util.getComponentById(key).setJSON(data[key]);
				}
    		}
        },
        error: function(data) {
        	alert("잘못된 요청입니다.");
        },
        complete: function(data) {
        	if (callbackFuncStr) {
        		if (typeof callbackFuncStr == "function") {
					callbackFuncStr();
				} else {
					callbackFuncStr = callbackFuncStr.replace("(","").replace(")","").replace(";","").replace("scwin.","");
					if (opener) {//윈도우팝업
						scwin[callbackFuncStr]();
					} else {//그외
						if ($("#tabc_layout").length == 0) {//윈도우 팝업 자식 레이어팝업
							scwin[callbackFuncStr]();
						} else {//그외
							udc_obj.scope.scwin[callbackFuncStr]();
						}
					}
				}
        	}
        }
    });
};

/**
 * 공통 코드용 dataList의 골격을 생성하여 반환한다.
 * setCommonCode에서 사용.
 * @private
 * @date 2016. 11. 15.
 * @param {JSON} idStr 생성할 DataList ID
 * @memberOf comboCommon
 * @author InswaveSystems
 */

comboCommon.getCodeDCForm = function(infoArr){
    var option = {
        "type" : "dataList",
        "option":{ "baseNode": "list", "repeatNode": "map"},
        "columnInfo":[]
    };
    //{"id":"GRP_CD", "name":"코드그룹", "dataType":"text"}
    var i, infoArrLen;
    infoArrLen = infoArr.length;

    for(i=0;i<infoArrLen;i++){
        //option.columnInfo.push({"id":"GRP_CD", "name":"코드그룹", "dataType":"text"});
        option.columnInfo.push({"id":infoArr[i]});
    }

    return option;
};

/**
 * submission를 실행한다.
 * submission의 id로 객체가 존재하지 않으면 생성후 실행한다.
 *
 * @date 2014. 12. 9.
 * @private
 * @param {JSON} options createSubmission의 options 참고
 * @param {JSON} requestData 요청 데이터
 * @param {JSON} obj 전송중 disable시킬 컴퍼넌트
 * @memberOf comboCommon
 * @author InswaveSystems
 * @example
 * var searchCodeGrpOption = {
 *      id : "sbm_SearchCodeGrp"
 *      ,action : "serviceId=CD0001&action=R"
 *      ,target : 'data:json,{"id":"dlt_CodeGrp","key":"data"}'
 *      ,submitDoneHandler : "searchCodeGrpCallback", isShowMeg : false };
 * executeSubmission_dynamic(searchCodeGrpOption);
 */
comboCommon.executeSubmission_dynamic = function(options, requestData , obj) {
    var submissionObj = $w.getSubmission(options.id);
    if (submissionObj === null) {
        comboCommon.createSubmission(options);
    } else {
       comboCommon.setSubmission(submissionObj, options);
    }

    $w.executeSubmission( options.id, requestData, obj);
};


/**
 * Submission 객체를 동적으로 생성한다.
 *
 * @date 2014. 12. 9.
 * @private
 * @param {JSON} options ※options JSON형태 객체
 *  ----------------------------------------------------options arguments----------------------------------------------------
 * {String} options.id : submission 객체의 ID. 통신 모듈 실행 시 필요.
 * {String} options.ref : 서버로 보낼(request) DataCollection의 조건 표현식.(조건에 때라 표현식이 복잡하다) 또는 Instance Data의 XPath.
 * {String} options.target : 서버로 응답(response) 받은 데이터가 위치 할 DataCollection의 조건 표현식. 또는 Instance Data의 XPath.
 * {String} options.action : 통신 할 서버 측 URI.(브라우저 보안 정책으로 crossDomain은 지원되지 않는다.)
 * {String} options.method : [default: post, get, urlencoded-post] get:파라메타를 url에 붙이는 방식 (HTML과 동일).
 * post:파라메타를 body 구간에 담는 방식 (HTML과 동일) urlencoded-post:urlencoded-post.
 * {String} options.mediatype : [default: application/xml, text/xml, application/json, application/x-www-form-urlencoded]
 * application/x-www-form-urlencoded : 웹 form 방식(HTML방식). application/json : json 방식. application/xml : XML 방식. text/xml : xml방식
 * (두 개 차이는 http://stackoverflow.com/questions/4832357 참조)
 * {String} options.mode : [default: synchronous, synchronous] 서버와의 통신 방식.  asynchronous:비동기식.  synchronous:동기식
 * {String} options.encoding : [default: utf-8, euc-kr, utf-16] 서버 측 encoding 타입 설정 (euc-kr/utf-16/utf-8)
 * {String} options.replace : [default: none, all, instance] action으로부터 받은 response data를 적용 구분 값.
 * all : 문서 전체를 서버로부터 온 응답데이터로 교체.  Instance : 해당되는 데이터 구간.  None : 교체안함.
 * {String} options.processMsg : submission 통신 중 보여줄 메세지.
 * {String} options.errorHandler : submission오류 발생 시 실행 할 함수명.
 * {String} options.customHandler : submssion호출 시 실행 할 함수명.
 * {Function} options.submitHandler : {script type="javascript" ev:event="xforms-submit"} 에 대응하는 함수.
 * {Function} options.submitDoneHandler : {script type="javascript" ev:event="xforms-submit-done"} 에 대응하는 함수
 * {Function} options.submitErrorHandler : {script type="javascript" ev:event="xforms-submit-error"} 에 대응하는 함수
 * @memberOf comboCommon
 * @author InswaveSystems
 * @example
 * comboCommon.createSubmission(options);
 */
comboCommon.createSubmission = function(options) {
    var ref = options.ref || "";
    var target = options.target || "";
    var action = options.action;// 요청주소
    var mode = options.mode || comboCommon.DEFAULT_OPTIONS_MODE; //asynchronous(default)/synchronous
    var mediatype = options.mediatype || comboCommon.DEFAULT_OPTIONS_MEDIATYPE; //application/x-www-form-urlencoded
    var method = (options.method || "post"); //get/post/put/delete
    var processMsg = options.processMsg || "";
    var submitHandler = options.submitHandler || "";
    var submitDoneHandler = options.submitDoneHandler || "";
    var submitErrorHandler = options.submitErrorHandler || "";

    if ((options.isProcessMsg === true) && (processMsg === "")) {
        processMsg = "해당 작업을 처리중입니다";
    }

    var submissionObj = {
        "id" : options.id, //submission 객체의 ID. 통신 모듈 실행 시 필요.
        "ref" : ref, //서버로 보낼(request) DataCollection의 조건 표현식.(조건에 때라 표현식이 복잡하다) 또는 Instance Data의 XPath.
        "target" : target, //서버로 응답(response) 받은 데이터가 위치 할 DataCollection의 조건 표현식. 또는 Instance Data의 XPath.
        "action" : action, //통신 할 서버 측 URI.(브라우저 보안 정책으로 crossDomain은 지원되지 않는다.)
        "method" : method, //[default: post, get, urlencoded-post] get:파라메타를 url에 붙이는 방식 (HTML과 동일).
                           // post:파라메타를 body 구간에 담는 방식 (HTML과 동일).  urlencoded-post:urlencoded-post.
        "mediatype" : mediatype, //application/json
        "encoding" : "UTF-8", //[default: utf-8, euc-kr, utf-16] 서버 측 encoding 타입 설정 (euc-kr/utf-16/utf-8)
        "mode" : mode, //[default: synchronous, synchronous] 서버와의 통신 방식.  asynchronous:비동기식.  synchronous:동기식
        "processMsg" : processMsg, //submission 통신 중 보여줄 메세지.
        "submitHandler" : submitHandler, //<script type="javascript" ev:event="xforms-submit"> 에 대응하는 함수.
        "submitDoneHandler" : function(e){
            if(submitDoneHandler){
                var callbackFn = eval(submitDoneHandler);
                callbackFn(e.responseText);
            }
        }, //<script type="javascript" ev:event="xforms-submit-done"> 에 대응하는 함수
        "submitErrorHandler" : submitErrorHandler //<script type="javascript" ev:event="xforms-submit-error">에 대응하는 함수
    };

    $w.createSubmission(submissionObj);

};

/**
 * Submission 정보를 세팅한다.
 *
 * @date 2014. 12. 9.
 * @private
 * @param {Object} submissionObj 서브미션 ID
 * @param {Object} options 서브미션 옵션 (comboCommon.createSubmission의 옵션 참고)
 * @memberOf comboCommon
 * @author InswaveSystems
 * @example
 * comboCommon.setSubmission(submissionObj, options);
 */
comboCommon.setSubmission = function(submissionObj, options) {
    var ref = options.ref || "";
    var target = options.target || "";
    var action = options.action;// 요청주소
    var mode = options.mode || comboCommon.DEFAULT_OPTIONS_MODE;
    var mediatype = options.mediatype || comboCommon.DEFAULT_OPTIONS_MEDIATYPE;
    var method = (options.method || "post");
    var processMsg = options.processMsg || "";

    if ((options.isProcessMsg === true) && (processMsg === "")) {
        processMsg = "해당 작업을 처리중입니다";
    }

    var instance = options.instance || "";
    var replace = options.replace || "instance";

    submissionObj.id = options.id;
    submissionObj.ref = ref;
    submissionObj.target = target;
    submissionObj.action = action;
    submissionObj.method = method;
    submissionObj.mediatype = mediatype;
    submissionObj.encoding = "UTF-8";
    submissionObj.instance = instance;
    submissionObj.replace = replace;
    submissionObj.mode = mode;
    submissionObj.processMsg = processMsg;
};

/* dataList - 전체(all) 제거  */
comboCommon.delAllCode = function(codeArr){
    commLib.log('[delAllCode]'+codeArr, true);
    var dataPrefix = comboCommon.commonCodeInfo.idPrefix;
    var dltId = '';
    $.each(codeArr, function(i, code){
        dltId = dataPrefix+code;
        // dataList 존재 확인
        commLib.log('[delAllCode] dltId:'+dltId, true);
        if(!commLib.dataExist(dltId)){
            return;
        }
        // dataList에 'all' 존재하는 경우 삭제
        if($w.data[dltId].getCellData(0, 1) == 'all'){
            $w.data[dltId].removeRow(0);
        }
    });
};

/**
 * 도움말 버튼 넓이, 높이
 */
commLib.getBookMark = function(cmpnCd, userId, prgId, sysCd){
    popupLib.open("comBookMarkPop", "/ux/com/pop/comBookMarkPop.xml", {
        title: "즐겨찾기",
        useLayer: true,     //레어어팝업여부
        modal: true,        //모달팝업
        width: "700",
        height: "600",
        param: {
            cmpnCd 	: cmpnCd
          , userId  : userId
          , prgId  	: prgId
          , sysCd  	: sysCd
        }
    });
};

/**
 * 프로그램별 권한 정보 데이터리스트를 생성합니다.
 *
 * @author Mir
 * @date 2018. 02. 2.
 * @memberOf commLib
 * @param {function} callback - 후처리 익명함수
 */
commLib.getPrgAuthCode = function(prgId, userId, sysCd) {
    try {
    	var prgAuth;

		let params = { searchData1: prgId, searchData2: userId, searchData3: sysCd };

	    $.ajax({
	        url: "/com/cmm/selectPrgAuth",
	        type: "GET",
	        data: params,
	        contentType: "application/json;charset=utf-8",
	        dataType: "json",
	        async: false,
	        success: function(data) {
	        	prgAuth = data.prgAuth;
	        }
	    });
	    return prgAuth;
    } catch (e) {
        //$W.exception.printStackTrace(e);
        //commLib.log("commLib.getPrgAuthCode: " + e);
    }
};

/**
 * 공통 확인창 호출
 * @author kkh
 * @date 2018. 03. 27.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목(팝업창이름) = 유효성체크인경우 : 데이터 확인, 결과(조회및저장)인경우 : 데이터 결과
 * @param {String} gbn - 구분 (이미지 변경용구분자 R:결과 V:유효성)
 * @param {function} 콜백
 * @param {String} comp - 컴포넌트ID
 */
commLib.getAlert = function(msg,title,gbn,comp){
	//commLib.getAlert(출력할메시지,팝업이름,구분);
	popupLib.open("comAlert", "/ux/com/pop/comAlert.xml", {
		useLayer: true,     //레어어팝업여부
		modal: true,        //모달팝업
		title: title,
		width: "400",
		height: "230",
		param: {
			msg : msg,
			gbn : gbn,
			comp : comp
		},
		callback: "scwin.fnFocus"
	});
};

/**
 * 공통 확인창 호출(통합고객관리)
 * @author mks
 * @date 2019. 11. 26.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목(팝업창이름) = 유효성체크인경우 : 데이터 확인, 결과(조회및저장)인경우 : 데이터 결과
 * @param {String} gbn - 구분 (이미지 변경용구분자 R:결과 V:유효성)
 * @param {String} comp - 컴포넌트ID
 * @param {String} fnCallback - 콜백함수
 */
commLib.getAlertAfterProc = function(msg,title,gbn,comp,fnCallback){
	popupLib.open("comAlert", "/ux/com/pop/comAlert.xml", {
		useLayer: true,     //레어어팝업여부
		modal: true,        //모달팝업
		title: title,
		width: "400",
		height: "230",
		param: {
			msg : msg,
			gbn : gbn,
			comp : comp
		},
		callback: fnCallback,
        close:false
	});
};

/**
 * 공통 confirm 메시지 창 호출(회계관리)
 * @author Mir
 * @date 2018. 03. 27.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목
 * @param {function} fnCallback - 함수
 */
commLib.getConfirmMsg = function(msg, title, fnCallback){
	if( msg == null){
		msg == '';
	}

	popupLib.open("comDataFormSave", "/ux/com/pop/comConfirmMsg.xml", {
		useLayer: true,     //레어어팝업여부
		modal: true,        //모달팝업
		title: title,
		width: "400",
		height: "230",
		param: {
			msg : msg
		},
		callback: fnCallback
	});
};

commLib.getSaveForm  = function(msg, fnCallback){
    commLib.getSaveForm(msg, fnCallback, "400", "220");
};

commLib.getSaveForm  = function(msg, fnCallback, width, height){
	if( width == null || width == ''){
		width = "400";
	}

	if( height == null || height == ''){
		height = "220";
	}
	if( msg == null){
		msg == '';
	}
	popupLib.open("comDataFormSave", "/ux/com/pop/comDataFormSave.xml", {
		useLayer: true,     //레어어팝업여부
		modal: false,        //모달팝업
		title: "데이터저장",
		width: width,
		height: height,
		param: {
			msg : msg
		},
		callback: fnCallback
	});
};

/**
 * 저장 버튼클릭시에 저장, 수정, 삭제 팝업을 띄운다.
 */
commLib.getSaveCnt = function(crowCnt, urowCnt, drowCnt, fnCallback){
	popupLib.open("comDataSave", "/ux/com/pop/comDataSave.xml", {
		useLayer: true,     //레어어팝업여부
		modal: true,        //모달팝업
		title: "데이터저장",
		width: "356",
		height: "226",
		param: {
			crowCnt : crowCnt
			, urowCnt : urowCnt
			, drowCnt : drowCnt
		},
		callback: fnCallback
	});
};

/**
 * Grid Delete Status Handle 처리(통합고객관리)
 * @author mks
 * @date 2019. 11. 26.
 * @memberOf commLib
 * @param {Object} - gridview id
 * @param {Integer} - cell event row value
 * @param {Integer} - cell event coll value
 */
commLib.onCellClickDelChk = function(grdObj,cellCurrentRow,cellCurrentCol){
    var dcObj = $w.data[grdObj.getDataList()];
    var colId = grdObj.getColumnID(cellCurrentCol);           // 컬럼아이디
    var delChk = dcObj.getCellData(cellCurrentRow , "chk");   // 삭제여부
    var rowstatus = dcObj.getRowStatus(cellCurrentRow);       // 로우 상태값

    if(colId == "chk"){
        if(delChk == "Y" && rowstatus == "C"){
            dcObj.removeRow(cellCurrentRow);
        }else if(delChk == "Y"){
            dcObj.deleteRow(cellCurrentRow);
        }else{
            dcObj.undoRow(cellCurrentRow);
        }
    }
};

/**
 * Grid 셀 삭제체크 처리 undo
 * @author SDCIT
 * @date 2020. 08. 28.
 * @memberOf commLib
 * @param {Object} - grd 그리드
 */
commLib.delChkUndo = function(grd){
    var dc = $w.data[grd.getDataList()];
    var row = grd.getFocusedRowIndex();
    var rs = dc.getRowStatus(row);
    var val = grd.getFocusedCellData();
    if(val == "Y"){
    	if (rs == "C") {
    		dc.removeRow(row);
		} else {
			dc.deleteRow(row);
		}
    }else{
    	dc.undoRow(row);
    }
};

/**
 * Grid 셀 삭제체크 처리 undelete
 * @author SDCIT
 * @date 2020. 08. 28.
 * @memberOf commLib
 * @param {Object} - grd 그리드
 */
commLib.delChkUndel = function(grd){
    var dc = $w.data[grd.getDataList()];
    var row = grd.getFocusedRowIndex();
    var rs = dc.getRowStatus(row);
    var val = grd.getFocusedCellData();
    if(val == "Y"){
    	if (rs == "C") {
    		dc.removeRow(row);
		} else {
			dc.deleteRow(row);
		}
    }else{
        dc.undeleteRow(row);
    }
};

/**
 * Grid 헤더셀 삭제체크 처리 undo
 * @author SDCIT
 * @date 2020. 08. 28.
 * @memberOf commLib
 * @param {Object} - grd 그리드
 * @param {String} - hid 헤더아이디
 * @param {String} - cid 체크컬럼아이디
 * @param {boolean} - checked 체크여부
 * @param {Array} - rowArr 반영 행 인덱스 배열
 * @param {Array} - extArr 제외 행 인덱스 배열
 */
commLib.hdelChkUndo = function(grd,hid,cid,rowArr,extArr){
	var dc = $w.data[grd.getDataList()];
	dc.removeRows( commLib.getIRowArr(dc) );
	if (grd.getHeaderValue( hid )) {
		if (rowArr) {
			dc.deleteRows( rowArr );
			if (extArr) {
				for (var i = 0; i < extArr.length; i++) {
					dc.setCellData( extArr[i] , cid , "N" );
				}
			}
		} else {
			dc.modifyAllStatus("D");
		}
	} else {
		dc.undoRows(commLib.getDRowArr(dc));
	}
};

/**
 * Grid 헤더셀 삭제체크 처리 undelete
 * @author SDCIT
 * @date 2020. 08. 28.
 * @memberOf commLib
 * @param {Object} - grd 그리드
 * @param {String} - hid 헤더아이디
 * @param {String} - cid 체크컬럼아이디
 * @param {boolean} - checked 체크여부
 * @param {Array} - rowArr 반영 행 인덱스 배열
 * @param {Array} - extArr 제외 행 인덱스 배열
 */
commLib.hdelChkUndel = function(grd,hid,cid,rowArr,extArr){
	var dc = $w.data[grd.getDataList()];
	dc.removeRows( commLib.getIRowArr(dc) );
	if (grd.getHeaderValue( hid )) {
		if (rowArr) {
			dc.deleteRows( rowArr );
			if (extArr) {
				for (var i = 0; i < extArr.length; i++) {
					dc.setCellData( extArr[i] , cid , "N" );
				}
			}
		} else {
			dc.modifyAllStatus("D");
		}
	} else {
		dc.undeleteRows(commLib.getDRowArr(dc));
	}
};

/**
 * 공통 확인창 콜백
 * @author kkh
 * @date 2018. 04. 30.
 * @memberOf commLib
 * @param {String} param - 전달내용
 */
scwin.fnFocus = function(param){
    if(param){
        var param_data = JSON.parse(strLib.serialize(param));
        if(param_data.retval=="true"){
            if(!strLib.isEmpty(param_data.comp)){
                var compVal = param_data.comp.split(":");
                var idPfx = "";
                if (!WebSquare.util.getComponentById( compVal[0].split("#")[0] )) {
                	idPfx = udc_obj.id+"_";
                }
                var compId = idPfx + compVal[0].split("#")[0];
                if(compVal.length==1){
                	if (compVal[0].indexOf("#") == -1) {
                		var comp = WebSquare.util.getComponentById( compId );
                		var compType = document.getElementById(compId);
                		if(compType.tagName == "INPUT"){
                			comp.setValue("");
                			comp.focus();
                		}else{
                			comp.focus();
                		}
					} else {
						var udcComp = compVal[0].split("#");
						if (udcComp[1] == "f") {
							WebSquare.util.getComponentById(idPfx + udcComp[0] + "_ical1").focus();
						} else if (udcComp[1] == "t") {
							WebSquare.util.getComponentById(idPfx + udcComp[0] + "_ical2").focus();
						} else if (udcComp[1] == "1") {
							WebSquare.util.getComponentById(idPfx + udcComp[0] + "_txt1").focus();
						} else if (udcComp[1] == "2") {
							WebSquare.util.getComponentById(idPfx + udcComp[0] + "_txt2").focus();
						} else if (udcComp[1] == "3") {
							WebSquare.util.getComponentById(idPfx + udcComp[0] + "_txt3").focus();
						} else {
							WebSquare.util.getComponentById(idPfx + udcComp[0] + "_ical").focus();
						}
					}
                }else if(compVal.length==3){
                    var grid = WebSquare.util.getComponentById( compId );
                    var row = compVal[1];
                    var col = compVal[2];

                    grid.setFocusedCell(row,col,!grid.getCellReadOnly( row , col ));
                }
            }
        }
    }
};

/**
 * 컨텍스트 메뉴
 *
 * @author 고규호
 * @date 2020. 03. 03.
 * @memberOf commLib
 * @param {string} grdId 그리드 아이디
 */
commLib.contextMenu = function(grdId){
	return {
		hideSystemMenu: [
			"ColumnHide",
			"ColumnShowAll",
			"ColumnFix",
			"ColumnUnfixAll",
			"ColumnAdjustWidth",
			"ColumnAdjustAuto",
			"ColumnAdjustAutoNone",
			"FoldAll",
			"UnfoldAll",
			"Group",
			"Ungroup",
			"UngroupAll"
		], // 특정 항목의 시스템 메뉴를 보여주지 않습니다.
		appendMenu: [{
			label:"엑셀 다운로드　　",
			// 사용자 메뉴의 표시 문자열
			userMenuId:"excel_z"+grdId,
			// 사용자 메뉴의 id, 해당 컨텍스트 메뉴가 클릭될때, 입력값으로 전달됨
			className:"userMenu"
				// 사용자 메뉴의 스타일 클래스 이름
			}
		], // 시스템 메뉴 아래에, 사용자 메뉴를 추가합니다.
	};
};

/**
 * 컨텍스트 메뉴
 *
 * @author 고규호
 * @date 2020. 03. 03.
 * @memberOf commLib
 * @param {String}
 *            grdId - 그리드 아이디
 * @param {String}
 *            menuId - 메뉴 아이디
 */
commLib.contextMenuFunc = function(grdId, menuId){
	if(menuId == "excel_z"+grdId) {
		var grd = WebSquare.util.getComponentById( grdId );
		var idArr = grd.cellIdList;
		var colArr = new Array();
		for (var i = 0; i < idArr.length; i++) {
			var colType = grd.getColumnType(idArr[i]);
			var colVisb = grd.getColumnVisible(idArr[i]);
			if (colType == "checkbox" ||  colType == "button" || !colVisb) {
				colArr.push(i);
			}
		}
		//그리드에 select 있는지 여부 체크
		var grd = WebSquare.util.getComponentById(grdId);
		var idArr = WebSquare.util.getComponentById(grdId).tdIdList;
		var cnt = 0;
		for (var i = 0; i < idArr.length; i++) {
			if(grd.getColumnType(idArr[i]) == "select"){
				cnt++;
			}
		}
		var title = $(".pgt_tit", $('#' + grd.id).closest('.fixed_cont')).text().trim();
		if (title == "") {
			title = $(".df_tit", $('#' + grd.id).closest('.dfbox')).text().trim();
		}
		if (title == "") {
			if(opener){
				title = opener.$("#pageTitle").text();
			}
		}
		if (title == '') {
			title = document.title || 'unknown';
		}
		commLib.downloadExcel(grd,title ,{
			type: cnt == 0 ? 0 : 1,
			removeColumns : colArr.join(","),
			rowNumVisible : grd.getRowNumVisible()
		});
	}
};

/**
 * 컨택스트메뉴 그리드 이벤트 추가
 *
 * @author 고규호
 * @date 2020. 06. 08.
 * @memberOf commLib
 */
commLib.grdContextMenuAddEvent = function(){
    for (var i = 0 ; i < $(".wq_gvw").length ; i++){
        var grdId = $(".wq_gvw")[i].id;
        var grdObj = WebSquare.util.getComponentById(grdId);

        var evObj = {};
        evObj.ev_oncontextopen = function(row,col){
            return commLib.contextMenu(this.id);
        }
        evObj.ev_oncontextclick = function(row,col,userMenuId,isSystemMenu,systemMenu){
            commLib.contextMenuFunc(this.id, userMenuId);
        }

        grdObj.unbind("oncontextopen");
        grdObj.unbind("oncontextclick");
        grdObj.bind("oncontextopen",evObj.ev_oncontextopen);
        grdObj.bind("oncontextclick",evObj.ev_oncontextclick);
    }
};

/**
 * 입력행 리턴
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 */
commLib.getIRowArr = function(ds){
	return ds.getInsertedIndex();
};

/**
 * 수정행 리턴
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 */
commLib.getURowArr = function(ds){
	return ds.getUpdatedIndex();
};

/**
 * 삭제행 리턴
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 */
commLib.getDRowArr = function(ds){
	return ds.getDeletedIndex();
};

/**
 * 입력행 수 리턴
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 */
commLib.getIRowCnt = function(ds){
	return commLib.getIRowArr(ds).length;
};

/**
 * 수정행 수 리턴
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 */
commLib.getURowCnt = function(ds){
	return commLib.getURowArr(ds).length;
};

/**
 * 삭제행 수 리턴
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 */
commLib.getDRowCnt = function(ds){
	return commLib.getDRowArr(ds).length;
};

/**
 * 저장확인메시지
 *
 * @author SDCIT
 * @date 2020. 05. 27.
 * @memberOf commLib
 * @param {Object}
 *            ds - 데이터리스트
 * @param {String}
 *            callback - 콜백
 */
commLib.saveMsg = function(ds, callback){
	var icnt = commLib.getIRowCnt(ds);
	var ucnt = commLib.getURowCnt(ds);
	var dcnt = commLib.getDRowCnt(ds);
	commLib.getSaveCnt(icnt, ucnt, dcnt, callback);
};

/**
 * 프로그램ID 조회
 *
 * @author SDCIT
 * @date 2020. 09. 17.
 * @memberOf commLib
 * @param {String} prgUrl - 프로그램url
 */
commLib.getPrgId = function(prgUrl){
	var prgId = "";
    ajaxLib.ajax("com/com/selectPrgId", {
        method: "POST",
        mode: "synchronous",
        requestData : {
        	prgUrl : prgUrl
        },
        callback : function(result){
        	prgId = result.prgId;
        }
    });
    return prgId;
};

/**
 * DAUM 주소팝업
 *
 * @author SDCIT
 * @date 2020. 10. 07.
 * @memberOf commLib
 * @param {JSON} themeObj - 테마정보JSON객체
 * @param {Object} psNoObj - 우편번호컴포넌트
 * @param {Object} addrObj - 주소컴포넌트
 * @param {Object} focsObj - 주소상세포커스컴포넌트
 */
commLib.addrSearch = function(themeObj,psNoObj,addrObj,focsObj){
    if (!themeObj) {
    	//아래 코드처럼 테마 객체를 생성합니다.(color값은 #F00, #FF0000 형식으로 입력하세요.)
    	//변경되지 않는 색상의 경우 주석 또는 제거하시거나 값을 공백으로 하시면 됩니다.
    	themeObj = {
			//bgColor: "", //바탕 배경색
			searchBgColor: "#0B65C8", //검색창 배경색
			//contentBgColor: "", //본문 배경색(검색결과,결과없음,첫화면,검색서제스트)
			//pageBgColor: "", //페이지 배경색
			//textColor: "", //기본 글자색
			queryTextColor: "#FFFFFF" //검색창 글자색
			//postcodeTextColor: "", //우편번호 글자색
			//emphTextColor: "", //강조 글자색
			//outlineColor: "", //테두리
    	};
	}
    daum.postcode.load(function(){
        new daum.Postcode({
            oncomplete: function(data) {
                // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
                // 각 주소의 노출 규칙에 따라 주소를 조합한다.
                // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
                var fullAddr = ''; // 최종 주소 변수
                var extraAddr = ''; // 조합형 주소 변수

                // 사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
                if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
                    fullAddr = data.roadAddress;
                } else { // 사용자가 지번 주소를 선택했을 경우(J)
                    fullAddr = data.jibunAddress;
                }
                // 사용자가 선택한 주소가 도로명 타입일때 조합한다.
                if (data.userSelectedType === 'R'){
                    //법정동명이 있을 경우 추가한다.
                    if (data.bname !== '') {
                        extraAddr += data.bname;
                    }
                    // 건물명이 있을 경우 추가한다.
                    if (data.buildingName !== '') {
                        extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                    }
                    // 조합형주소의 유무에 따라 양쪽에 괄호를 추가하여 최종 주소를 만든다.
                    fullAddr += (extraAddr !== '' ? ' ('+ extraAddr +')' : '');
                }
                psNoObj.setValue(data.zonecode);
                addrObj.setValue(fullAddr);
                if (focsObj) {
                	focsObj.focus();
				}
            }
        }).open();
    });
};

/**
 * DAUM 주소팝업 그리드
 *
 * @author SDCIT
 * @date 2020. 10. 07.
 * @memberOf commLib
 * @param {JSON} themeObj - 테마정보JSON객체
 * @param {Object} grd - 그리드객체
 * @param {String} row - 행정보
 * @param {Array} col - 컬럼정보
 */
commLib.addrSearchGrd = function(themeObj,grd,row,col){
	if (!themeObj) {
		//아래 코드처럼 테마 객체를 생성합니다.(color값은 #F00, #FF0000 형식으로 입력하세요.)
		//변경되지 않는 색상의 경우 주석 또는 제거하시거나 값을 공백으로 하시면 됩니다.
		themeObj = {
			//bgColor: "", //바탕 배경색
			searchBgColor: "#0B65C8", //검색창 배경색
			//contentBgColor: "", //본문 배경색(검색결과,결과없음,첫화면,검색서제스트)
			//pageBgColor: "", //페이지 배경색
			//textColor: "", //기본 글자색
			queryTextColor: "#FFFFFF" //검색창 글자색
			//postcodeTextColor: "", //우편번호 글자색
			//emphTextColor: "", //강조 글자색
			//outlineColor: "", //테두리
		};
	}
	daum.postcode.load(function(){
		new daum.Postcode({
			oncomplete: function(data) {
				// 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
				// 각 주소의 노출 규칙에 따라 주소를 조합한다.
				// 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
				var fullAddr = ''; // 최종 주소 변수
				var extraAddr = ''; // 조합형 주소 변수

				// 사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
				if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
					fullAddr = data.roadAddress;
				} else { // 사용자가 지번 주소를 선택했을 경우(J)
					fullAddr = data.jibunAddress;
				}
				// 사용자가 선택한 주소가 도로명 타입일때 조합한다.
				if (data.userSelectedType === 'R'){
					//법정동명이 있을 경우 추가한다.
					if (data.bname !== '') {
						extraAddr += data.bname;
					}
					// 건물명이 있을 경우 추가한다.
					if (data.buildingName !== '') {
						extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
					}
					// 조합형주소의 유무에 따라 양쪽에 괄호를 추가하여 최종 주소를 만든다.
					fullAddr += (extraAddr !== '' ? ' ('+ extraAddr +')' : '');
				}
				var dc = udcLib.getObj(grd.getDataList());
                dc.setCellData( row , col[0] , fullAddr );
                dc.setCellData( row , col[1] , data.zonecode );
                if (col[2]) {
                	grd.setFocusedCell( row , col[2] , true );
				}
			}
		}).open();
	});
};

/**
 * Grid 셀 선택체크 처리
 * @author SDCIT
 * @date 2020. 08. 28.
 * @memberOf commLib
 * @param {Object} - grd 그리드
 */
commLib.selChkUndo = function(grd, row, col){
    var dc = $w.data[grd.getDataList()];
    var val = grd.getFocusedCellData();
    if(val == "N"){
    	dc.setCellData(row, col, "");
    }
};

/**
 * Call String Function
 * @author 김종갑
 * @date 2022. 08. 18.
 * @memberOf commLib
 * @param {String} - event 이벤트명
 * @param {any} - params 전달 파람
 */
commLib.callEvents = function(event , params){
	try {
		if (event !== null && event !== undefined && event.length > 0) {
			var eventName = event.replace("scwin.","");
			if (scwin && typeof scwin[eventName] === 'function') {
				scwin[eventName](params);
				return ;
			}
			var target = window.opener || window.parent || window;
			if (target.tabc_layout) {
				var callback = eventName.replace(target.tabc_layout.childControlList[target.tabc_layout.getSelectedTabIndex()].id+"_","");
				if(target.scwin && !target.scwin[callback]){
					target = target.tabc_layout.childControlList[target.tabc_layout.getSelectedTabIndex()].scope;
					eventName = callback;
				}
			}
			if (target && target.scwin && typeof target.scwin[eventName] === 'function') {
				target.scwin[eventName](params);
				return ;
			}
		}
	} catch (e) {
		commLib.logEvent(e);
	}
}

commLib.udcOndestroyed = function(udc) {
	if (udc._udcFunctions !== undefined && Array.isArray(udc._udcFunctions)) {
		udc._udcFunctions.forEach(function(funcName) {
			delete scwin[funcName];
		});
		delete udc._udcFunctions;
	}
}


commLib.udcGetFunction = function(udc, funcName) {
	return 'scwin.' + commLib.udcGetFunctionNameShort(udc, funcName);
}

commLib.udcGetFunctionNameShort = function(udc, funcName) {
	return udc.uuid + '_' + funcName;
}

commLib.udcSetFunction = function(udc, funcName, func){
	if (udc._udcFunctions == undefined) {
		udc._udcFunctions = [];
	}
	var shortName = commLib.udcGetFunctionNameShort(udc, funcName);
	if (!udc._udcFunctions.includes(shortName)) {
		udc._udcFunctions.push(shortName);
	}
	scwin[shortName] = func;
}

commLib.logEvent = function(obj) {
	console.log('logEvent',obj);
}

commLib.registerEvents = function(obj , func){
	obj
}

function imgError(img) {
	img.src= '/resources/images/noimage/no_photo.jpg';
}

/**
 * UBI Report 팝업
 * @param {String} jrfId -> UBI jrf파일명
 * @param {JSON} param -> 파라미터 : json ex) { test1 : 'test', test2 : 'test' }
 * @param {String} jobGbCd -> 업무구문 : ex) CF
 * @param {String} callbackurl -> 콜백URL : 생략가능, http://koffice.sdcit.co.kr 를 제외한 /ubi4/ubiCallbackTest 입력
 *
 * 샘플 : ubiLib.ubiReportPopup("ubi_sample.jrf", {test1:'test'}, "CF", "/ubi4/ubiCallbackTest");
 *
 * 콜백URL의 실행 : 리포트 프린트 및 저장(내보내기) 할 때 발생 프린트/저장 구분 ubifunc:'print' / ubifunc:'export'로
 * 파라메터 전송 Controller 에서 파라메터를 받아 분기처리(CFEtcController 의 ubi4CallbackTest 참조)
 *
 */
ubiLib.ubiReportPopup = function(jrfId, param, jobGbCd, callbackurl) {
    var data = [];
    const sessionStorage = WebSquare.session.getAttribute('user');
    for(var key in param) {
		data.push(key + '#' + (param[key] || '') + '#')
	}
	data.push('user#' + sessionStorage.userNm + '#')
    data.push('userId#' + sessionStorage.userId + '#')
    let KOFFICE_MAIN_URL = null;
    let UBI_HTML_URL = null;
	switch(window.location.hostname) {
		case 'localhost' :
			KOFFICE_MAIN_URL = 'http://localhost:8180';
			UBI_HTML_URL = 'http://localhost:9099/ubi4/ubihtml.jsp';
			break;
		case 'portal2.sgc.co.kr' :
		case 'as2.sgcetec.co.kr' :
		case 'as2.sgcenc.co.kr' :
			KOFFICE_MAIN_URL = 'https://portal2.sgc.co.kr';
			UBI_HTML_URL = 'https://portal2.sgc.co.kr/ubi4/ubihtml.jsp';
			break;
		case 'portal.sgc.co.kr' :
		case 'as.sgcetec.co.kr' :
		case 'as.sgcenc.co.kr' :
			KOFFICE_MAIN_URL = 'https://portal.sgc.co.kr';
			UBI_HTML_URL = 'https://portal.sgc.co.kr/ubi4/ubihtml.jsp';
			break;
		default : 
			break;
	}
	if (KOFFICE_MAIN_URL === null || UBI_HTML_URL == null) {
		return ;
	}
    // 콜백 URL처리
    var khneurl = "";
    if( callbackurl != undefined && callbackurl != "" && callbackurl != null ) {
        khneurl = KOFFICE_MAIN_URL + callbackurl; // koffice 콜백 URL
    }
    var url = UBI_HTML_URL; // UBI리포트 HTML페이지 변수 개발서버
    var $form = $('<form></form>');
    $form.attr('action', url);
    $form.attr('method', 'post');
    $form.attr('target', 'watchwin');
    $form.appendTo('body');
    //var _jrf = $('<input type="hidden" value="'+ jobGbCd.toLowerCase() + '/' +jrfId+'" name="jrf">');
    var _jrf = $('<input type="hidden" value="'+jrfId+'" name="file">');
    var _arg = $('<input type="hidden" value="'+data.join('')+'" name="arg">');
    var _resid = $('<input type="hidden" value="UBIHTML" name="resid">');
    var _khneurl = $('<input type="hidden" value="'+khneurl+'" name="khneurl">');
    $form.append(_jrf).append(_arg).append(_resid).append(_khneurl);
    var features ='height=900, width=980, status=no, scrollbars=yes, resizable=yes';
    window.open("", 'watchwin', features);

    $form.submit();
};

/**
 * 공통 확인창 호출(Global)
 * @author SBK
 * @date 2023. 07. 25.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목(팝업창이름) = 유효성체크인경우 : 데이터 확인, 결과(조회및저장)인경우 : 데이터 결과
 * @param {String} gbn - 구분 (이미지 변경용구분자 R:결과 V:유효성)
 * @param {function} 콜백
 * @param {String} comp - 컴포넌트ID
 */
commLib.getAlertGlobal = function(msg,title,gbn,comp){
    popupLib.open("comAlertGlobal", "/ux/com/pop/comAlertGlobal.xml", {
        useLayer: true,     //레어어팝업여부
        modal: true,        //모달팝업
        title: title,
        width: "400",
        height: "230",
        param: {
            msg : msg,
            gbn : gbn,
            comp : comp
        },
        callback: "scwin.fnFocus"
    });
};

/**
 * 공통 확인창 호출(통합고객관리)
 * @author mks
 * @date 2019. 11. 26.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목(팝업창이름) = 유효성체크인경우 : 데이터 확인, 결과(조회및저장)인경우 : 데이터 결과
 * @param {String} gbn - 구분 (이미지 변경용구분자 R:결과 V:유효성)
 * @param {String} comp - 컴포넌트ID
 * @param {String} fnCallback - 콜백함수
 */
commLib.getAlertAfterProcGlobal = function(msg,title,gbn,comp,fnCallback){
	popupLib.open("comAlertGlobal", "/ux/com/pop/comAlertGlobal.xml", {
		useLayer: true,     //레어어팝업여부
		modal: true,        //모달팝업
		title: title,
		width: "400",
		height: "230",
		param: {
			msg : msg,
			gbn : gbn,
			comp : comp
		},
		callback: fnCallback
	});
};

/**
 * 공통 confirm 메시지 창 호출(Global)
 * @author SBK
 * @date 2023. 07. 25.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목
 * @param {function} fnCallback - 콜백함수
 */
commLib.getConfirmMsgGlobal = function(msg, title, fnCallback){
    if( msg == null ) msg = "";
    popupLib.open("comDataFormSaveGlobal", "/ux/com/pop/comConfirmMsgGlobal.xml", {
        useLayer: true,     //레어어팝업여부
        modal: true,        //모달팝업
        title: title,
        width: "400",
        height: "230",
        param: {
            msg : msg
        },
        callback: fnCallback
    });
};

/**
 * 공통 confirm 메시지 창 호출(Global)
 * @author SBK
 * @date 2023. 09. 05.
 * @memberOf commLib
 * @param {String} msg - 메시지내용
 * @param {String} title - 제목
 * @param {String} index - index
 * @param {function} fnCallback - 콜백함수
 */
commLib.getConfirmMsgIndexGlobal = function(msg, title, index, fnCallback){
    if( msg == null ) msg = "";
    popupLib.open("comDataFormSaveGlobal", "/ux/com/pop/comConfirmMsgGlobal.xml", {
        useLayer: true,     //레어어팝업여부
        modal: true,        //모달팝업
        title: title,
        width: "400",
        height: "230",
        param: {
            msg : msg,
            index : index
        },
        callback: fnCallback
    });
};

/**
 * 지정한 메시지 코드와 일치하는 메시지를 반환(Global)
 * @author SBK
 * @date 2023. 07. 25.
 * @memberOf commLib
 * @param {string} msgCode - 메시지 코드
 * @param {...string} parameter - 메시지에 대체될 키워드들
 * @returns {string} 메시지
 */
commLib.getMsgGlobal = function(msgCode) {

    try {
        // 메시지가 SessionStorage에 적재되어 있는 상태인지 확인 및 적재
        commLib.loadMessageStorage();
        
        // SessionStorage에서 메시지 코드에 대응하는 메시지 정보 조회
        var msgInfo = sessionLib.get(msgCode);
        
        if (strLib.isEmpty(msgInfo, true)) {
            // 새로 추가된 메시지인지 확인 및 재적재
            requires("/resources/js/lib/message.js?dummy=2ns&time=" + (new Date()).getTime());

            for (var i = 0; i < msgLib.properties.length; i ++) {
                var msg = msgLib.properties[i];
                sessionLib.set(msg.key, strLib.serialize({ ko: msg.koMsg, en: msg.enMsg }));
            }
            msgInfo = sessionLib.get(msgCode);
        }

        // 메시지 코드 존재 확인
        if (strLib.isEmpty(msgInfo, true)) {
            // 개발자 메시지: 영문지원 안 함
            throw "등록되지 않은 메시지 코드입니다.";
        }

        // 메시지 출력
        var msg = strLib.parse(msgInfo);
        
        // 사용자의 정보에 따라서 KOR/ENG 메시지 선택 로직 구현
        if (cookieLib.get( "system_language" ) == "ko"){
            var langCode = "KOR";
        } else if (cookieLib.get( "system_language" ) == "en"){
            var langCode = "ENG";
        } else {
            var langCode = "KOR";
        }

        var msgTemplate = (langCode == "KOR") ? msg.ko : msg.en;
        if (langCode == "ENG" && strLib.isEmpty(msgTemplate, true)) {
            // ENG 메시지가 등록되어 있지 않으면 KOR 메시지 사용
            msgTemplate = msg.ko;
        }
        
        var argLength = arguments.length;
        if (argLength > 1) {
            for (var i = 1; i < argLength; i++) {
                var regEx = new RegExp("\\{" + (i - 1).toString() + "\\}", "img");
                msgTemplate = msgTemplate.replace(regEx, arguments[i]);
            }
        }

        return msgTemplate.replace(/\{\d{1,3}\}?/img, "");
    } catch (e) {
    }
};

/**
 * 저장확인메시지(Global)
 * @author SBK
 * @date 2023. 07. 25.
 * @memberOf commLib
 * @param {Object} ds - 데이터리스트
 * @param {String} title - 제목
 * @param {String} callback - 콜백
 */
commLib.saveMsgGlobal = function(ds, title, callback){
	var icnt = commLib.getIRowCnt(ds);
	var ucnt = commLib.getURowCnt(ds);
	var dcnt = commLib.getDRowCnt(ds);
	commLib.getSaveCntGlobal(icnt, ucnt, dcnt, title, callback);
};

/**
 * 저장 버튼클릭시에 저장, 수정, 삭제 팝업을 띄운다.(Global)
 * @author SBK
 * @date 2023. 07. 25.
 * @memberOf commLib
 */
commLib.getSaveCntGlobal = function(crowCnt, urowCnt, drowCnt, title, fnCallback){
	popupLib.open("comDataSaveGlobal", "/ux/com/pop/comDataSaveGlobal.xml", {
		useLayer: true,     //레어어팝업여부
		modal: true,        //모달팝업
		title: title,
		width: "356",
		height: "226",
		param: {
			crowCnt : crowCnt
			, urowCnt : urowCnt
			, drowCnt : drowCnt
		},
		callback: fnCallback
	});
};

/**
 * 코드성 데이터와 컴포넌트의 nodeSet(아이템 리스트)연동 기능을 제공한다.
 * code별로 JSON객체를 생성하여 array에 담아 첫번째 파라메터로 넘겨준다.
 * 그리드뷰의 경우 compID는 [컴포넌트아이디]:[컬럼명]으로 작성한다.
 * @date 2016. 07. 27.
 * @param {JSON} codeJsonArr {"code" : "코드넘버", "compID" : "적용할 컴포넌트명"}
 * @param {String} callbackFuncStr 콜백 함수명
 * @memberOf comboCommon
 * @author InswaveSystems
 * @example
 * comboCommon.setCommonCode([
 *      {"code:":"04","compID":"sbx_CommCodeReligion"},
 *      {"code:":"24","compID":"grd_CommCodeSample:JOB_CD"}
 *      ], "setCommonCodeCallback");
 */
comboCommon.setCommonCodeGlobal = function(codeJsonArr, callbackFuncStr, callMode){
    var codeJsonArrLen;
    var dataGb = "";

    if(codeJsonArr){
         codeJsonArrLen = codeJsonArr.length;
    }else{
        $w.log("=== comboCommon.setCommonCode Parameter Type Error ===\nex) comboCommon.setCommonCode([{\"code:\":\"04\",\"compID\":\"sbx_Gender\"}],\"edu.callbackFunction\")\n===================================");
        return;
    }

    var i, j, codeObj, dltId, dltIdArr=[], paramCode = "", compArr, compArrLen, tmpIdArr;
    var commCodeInfo = comboCommon.commonCodeInfo;
    var dataPrefix = "";
    if (WebSquare.util.getComponentById( "tabc_layout" )) {
    	dataPrefix = udc_obj.id+"_";
	}

    var dcFormObj = comboCommon.getCodeDCForm(commCodeInfo.fieldArr);
    for(i=0;i<codeJsonArrLen;i++){
        codeObj = codeJsonArr[i];
        try{
            if(i>0){
                paramCode += ",";
            }
            dltId = dataPrefix+codeObj.code;
            dltIdArr.push(dltId);

            paramCode += codeObj.code;

            dcFormObj.id = dltId;

            try{
                $w.data.remove(dltId);
            }catch(ex){}

            $w.data.create(dcFormObj);

            if(codeObj.compID){ //컴포넌트의 ID가 없는 경우도 있음.
                compArr = (codeObj.compID).replaceAll(" ","").split(",");
                compArrLen = compArr.length;
                for(j=0;j<compArrLen;j++){
                    tmpIdArr = compArr[j].split(":");
                    try{
                    	var target;
                    	
                    	if (window[tmpIdArr[j]]) { //없으면 그룹웨어 링크시 동작 오류
                    		target = window[tmpIdArr[j]];
                    	} else if (window[tmpIdArr]) { //없으면 팝업창에서 동작 오류		2022.12.14 박성훈 수정
                            target = window[tmpIdArr];
                        } else {
                            var idPreFix = udc_obj.id+"_";
                            target = $p.getComponentById(idPreFix+tmpIdArr[0]);
                        }
                        if(tmpIdArr.length === 1){  //기본 컴포넌트
                        	target.setNodeSet("data:"+dltId, commCodeInfo.label, commCodeInfo.value);
                        }else{  //gridView 컴포넌트
                        	target.setColumnNodeSet(tmpIdArr[1], "data:"+dltId, commCodeInfo.label, commCodeInfo.value);
                        }
                    }catch(ex){
                        $w.log(tmpIdArr[0] + "이 존재하지 않습니다.");
                    }
                }
            }

        }catch(ex){
            $w.log("comboCommon.setCommonCode Error");
            $w.log(JSON.stringify(codeObj));
            $w.log(ex);
            continue;
        }
    }
    
    // 사용자의 정보에 따라서 KOR/ENG 메시지 선택 로직 구현
    if (cookieLib.get( "system_language" ) == "ko"){
    	var url = "/getCodeList"
    } else if (cookieLib.get( "system_language" ) == "en"){
    	var url = "/getCodeListEn"
    } else {
    	var url = "/getCodeList"
    }
    
    $.ajax({
        url: url,
        type: "GET",
        data: {
        	GRP_CD : paramCode,
        	DATA_PREFIX : dataPrefix
        },
        contentType: "application/json;charset=utf-8",
        dataType: "json",
        async: false,
        success: function(data) {
        	delete data.msg;
        	delete data.msgCode;
        	for(var key in data){
        		if (!(key.lastIndexOf("_") == key.length-1)) {
        			WebSquare.util.getComponentById(key).setJSON(data[key]);
				}
    		}
        },
        error: function(data) {
        	alert("잘못된 요청입니다.");
        },
        complete: function(data) {
        	if (callbackFuncStr) {
        		if (typeof callbackFuncStr == "function") {
					callbackFuncStr();
				} else {
					callbackFuncStr = callbackFuncStr.replace("(","").replace(")","").replace(";","").replace("scwin.","");
					if (opener) {//윈도우팝업
						scwin[callbackFuncStr]();
					} else {//그외
						if ($("#tabc_layout").length == 0) {//윈도우 팝업 자식 레이어팝업
							scwin[callbackFuncStr]();
						} else {//그외
							udc_obj.scope.scwin[callbackFuncStr]();
						}
					}
				}
        	}
        }
    });
};