/**
 * PQPortalServiceQueryConnection JS 클래스 list
 * 
 * PQPortalService
 * PQQuery
 * WebConnectionModel
 * ResizableObject
 */

var g_lPortalFormUID = null;

function SqlMode ()
{
}

SqlMode._None = -1;
SqlMode._Select = 0;
SqlMode._Insert = 1;
SqlMode._Update = 2;
SqlMode._Delete = 3;
SqlMode._Procedure = 4;
SqlMode._Text = 5;

/**
 * PQPortalService는 웹페이지 모델의 모든 서비스를 처리 합니다.
 */
function PQPortalService (objPQQuery)
{
}

/////////////////////////
// public methods
/**
 * 웹페이지 모델의 서비스를 수행한다.
 */
PQPortalService.prototype.executeService = function (xnRequest)
{
	var strModelPath = GetModelSubPath() + GetModelName();
	
	if (null == g_lPortalFormUID)
	{
		var objDate = new Date();
		g_lPortalFormUID = objDate.getTime();
	}
	
	var strURL = this._getPortalServiceURL("executeService") + "&ModelPath=" + strModelPath + "&ModelUID=" + g_lPortalFormUID;
	
	// 요청에 쿼리 정보를 더한다.
	this._addQueryRequest(xnRequest);
	
	// 요청에 연산식정보를 더한다.
	this._addOperateRequest(xnRequest);
	
	// 요청이 최상위 document이여야 한다.
	if ("#document" != xnRequest.nodeName)
	{
		xnRequest = xnRequest.ownerDocument;
	}
	
	var strResult = PQAjax.post(strURL, xnRequest);
	var xnResult = XmlLib.loadXMLFromString(strResult);
	
	// 결과에서 쿼리 정보를 추출한다.
	this._extractQueryResult(xnResult);
	
	return xnResult;
}

/**
 * 웹페이지 모델의 스크립트 서비스를 수행한다.
 */
PQPortalService.prototype.executeScriptService = function (xnRequest, bIncludePreProcess)
{
	// 포탈 서비스에서 스크립트실행체를 가지고 오는 것은 현재 모델의 Path이다.
	var strModelPath = GetModelSubPath() +  GetModelName();
	var strURL = this._getPortalServiceURL("executeScriptService") + "&ModelPath=" + strModelPath + "&IncludePreProcess=" + bIncludePreProcess;
	
	// 요청에 쿼리 정보를 더한다.
	this._addQueryRequest(xnRequest);		
	
	// 요청에 연산식정보를 더한다.
	this._addOperateRequest(xnRequest);
	
	// 요청이 최상위 document이여야 한다.
	if ("#document" != xnRequest.nodeName)
	{
		xnRequest = xnRequest.ownerDocument;
	}
	
	var strResult = PQAjax.post(strURL, xnRequest);
	var xnResult = XmlLib.loadXMLFromString(strResult);
	
	// 결과에서 쿼리 정보를 추출한다.
	this._extractQueryResult(xnResult);
	
	return xnResult;
}

/**
 * 웹페이지 모델의 후처리 스크립트를 수행한다.
 */
PQPortalService.prototype.executeProcessManagerAfterAction = function (xnRequest, strPath)
{
	// 포탈 서비스에서 스크립트실행체를 가지고 오는 것은 현재 모델의 Path이다.
	var strModelPath = GetModelSubPath() +  GetModelName();
	var strURL = this._getPortalServiceURL("executeProcessManagerAfterAction") + "&ModelPath=" + strModelPath + "&strPath=" + strPath;
	
	// 요청에 쿼리 정보를 더한다.
	this._addQueryRequest(xnRequest);		
	
	// 요청에 연산식정보를 더한다.
	this._addOperateRequest(xnRequest);
	
	// 요청이 최상위 document이여야 한다.
	if ("#document" != xnRequest.nodeName)
	{
		xnRequest = xnRequest.ownerDocument;
	}
	
	var strResult = PQAjax.post(strURL, xnRequest);
	var xnResult = XmlLib.loadXMLFromString(strResult);
	
	// 결과에서 쿼리 정보를 추출한다.
	this._extractQueryResult(xnResult);
	
	return xnResult;
}

PQPortalService.prototype.executeServerScriptService = function (xnRequest, bIncludePreProcess)
{
	// 포탈 서비스에서 스크립트실행체를 가지고 오는 것은 현재 모델의 Path이다.
	var strModelPath = GetModelSubPath() +  GetModelName();
	var strURL = this._getPortalServiceURL("executeServerScriptService") + "&ModelPath=" + strModelPath + "&IncludePreProcess=" + bIncludePreProcess;
	
	// 요청에 연산식정보를 더한다.
	this._addOperateRequest(xnRequest);
	
	// 요청이 최상위 document이여야 한다.
	if ("#document" != xnRequest.nodeName)
	{
		xnRequest = xnRequest.ownerDocument;
	}
	
	var strResult = PQAjax.post(strURL, xnRequest);
	var xnResult = XmlLib.loadXMLFromString(strResult);
	
	// 결과에서 쿼리 정보를 추출한다.
	this._extractQueryResult(xnResult);
	
	return xnResult;
}

PQPortalService.prototype.executeCloseModel = function (strModelName)
{
	var strModelPath = GetModelSubPath() + GetModelName();
	var strURL = this._getPortalServiceURL("executeCloseModel") + "&ModelPath=" + strModelPath + "&ModelUID=" + g_lPortalFormUID;
	
	var strResult = PQAjax.post(strURL, null);
}

PQPortalService.prototype.executeCloseModelPopup = function (strTotalPath)
{
	var strURL = this._getPortalServiceURL("executeCloseModelPopup") + "&ModelPath=" + strTotalPath + "&ModelUID=" + g_lPortalFormUID;
	
	var strResult = PQAjax.post(strURL, null);
}

/**
 * 웹페이지 모델의 연산식 정보를 구해온다.
 */
PQPortalService.prototype.getOperationInfo = function ()
{
	var strModelPath = GetProjectName() + "/" + GetModelSubPath() + GetModelName();
	var strOperationPath = "";
	if (0 < GetModelName().indexOf(".QPM"))
	{
		strOperationPath = strModelPath.replace(".QPM", ".xml");
	}
	else
	{
		strOperationPath = strModelPath.replace(".QWP", ".xml");
	}
	
	var strURL = "/ups/" + strOperationPath;
	var strResult = PQAjax.get(strURL, null);
	var xnResult = XmlLib.loadXMLFromString(strResult);
	
	return xnResult;
}

PQPortalService.prototype._getPortalServiceURL = function (strServiceName)
{
	return "/ups/PortalService.do?pn=" + GetProjectName() + "&clk=" + GetCommonLoginKey() 
			+ "&ServiceName=" + strServiceName;
}

/**
 * 웹페이지 모델의 게시판 아톰의 서비스를 수행한다.
 */
PQPortalService.prototype.executeWebBoardAtomService = function (xnRequest)
{
	var strURL = this._getPortalServiceURL("executeWebBoardAtomService");
	try
	{
		PQAjax.post(strURL, xnRequest);
	}
	catch (e)
	{		
	}
}

PQPortalService.prototype.executeRenameUploadPathService = function (xnRequest)
{
	var strURL = this._getPortalServiceURL("executeRenameUploadPathService");
	
	try
	{
		PQAjax.post(strURL, xnRequest);
	}
	catch (e)
	{		
	}
}

PQPortalService.prototype.executeFileAttachService = function (xnRequest)
{
	var strModelPath = GetModelSubPath() + GetModelName();
	
	var strURL = this._getPortalServiceURL("executeFileAttachService") + "&ModelPath=" + strModelPath + "&ModelUID=" + g_lPortalFormUID;
	try
	{
		PQAjax.post(strURL, xnRequest);
	}
	catch (e)
	{		
	}
}

PQPortalService.prototype.executeClientInfoService = function ()
{
	var strURL = this._getPortalServiceURL("executeClientInfomation");
	try
	{
		return PQAjax.post(strURL, null);
	}
	catch (e)
	{		
	}
}

/**
 * 웹세션정보 읽기/쓰기 서비스 실행
 * @param nDirection 0:읽기, 1:쓰기
 * @param strKey
 * @param strValue
 */
PQPortalService.prototype.executeSessionService = function (nDirection, strKey, strValue)
{
	if (0 == nDirection)
	{
		var strRequest = "/ups/PortalGlobalInfoService.do?pn=" + GetProjectName() + "&clk=" + GetCommonLoginKey() + "&type=getSession&strKey=" + strKey;
		var strResult = PQAjax.post(strRequest, "");
		
		if (null != strResult && 0 < strResult.length)
		{
			var xnResult = XmlLib.loadXMLFromString(strResult);
			
			var xnValue = XmlLib.selectSingleNode(xnResult, "//getSession");
			if (null != xnValue)
			{
				return strValue = Utils.decodeBase64(XmlLib.getTextValue(xnValue));
			}
		}
		return "";
	}
	else if (1 == nDirection)
	{
		var strRequest = "/ups/PortalGlobalInfoService.do?pn=" + GetProjectName() + 
		"&clk=" + GetCommonLoginKey() + "&type=setSession&strKey=" + strKey + 
		"&strValue=" + Utils.replace(Utils.encodeBase64(strValue), "\\+", "-");
	
		PQAjax.post(strRequest, "");
	}
}

/////////////////////////
// private methods
/**
 * 요청에 쿼리 정보를 더한다.
 */
PQPortalService.prototype._addQueryRequest = function (xnRequest)
{
	PQQuery.makeRequest(xnRequest);
}

PQPortalService.prototype._addOperateRequest = function (xnRequest)
{
	PQOperation.makeRequest(xnRequest);
}

PQPortalService.prototype._extractQueryResult = function (xnResult)
{
	PQQuery.handleResult(xnResult);
}

/////////////////////////
// static methods
PQPortalService.init = function ()
{
	g_objPQPortalService = new PQPortalService();
}

/**
 * 웹 포탈 모델의  서비스를 수행한다.
 */
PQPortalService.executeService = function (xnRequest)
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.executeService(xnRequest);
	}
}

PQPortalService.executeCloseModel = function (strModelName)
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.executeCloseModel(strModelName);
	}
}

PQPortalService.executeCloseModelPopup = function (strTotalName)
{
	return g_objPQPortalService.executeCloseModelPopup(strTotalName);
}

/**
 * 웹 포탈 모델의 스크립트 서비스를 수행한다.
 */
PQPortalService.executeScriptService = function (xnRequest, bIncludePreProcess)
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.executeScriptService(xnRequest, bIncludePreProcess);
	}
}

/**
 * 웹 포탈 모델의 후처리 스크립트를 수행한다.
 */
PQPortalService.executeProcessManagerAfterAction = function (xnRequest, strPath)
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.executeProcessManagerAfterAction(xnRequest, strPath);
	}
}

/**
 * 웹 포탈 모델의 연산식 정보를 구해온다.
 */
PQPortalService.getOperationInfo = function ()
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.getOperationInfo();
	}
}

/**
 * 웹페이지 모델의 웹게시판 아톰의 서비스를 실행합니다.
 */
PQPortalService.executeWebBoardAtomService = function (xnRequest)
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.executeWebBoardAtomService(xnRequest);
	}
}

PQPortalService.executeSessionService = function (nDirection, strKey, strValue)
{
	if (null != g_objPQPortalService)
	{
		return g_objPQPortalService.executeSessionService(nDirection, strKey, strValue);
	}
}

/**
 * 웹  PQ쿼리  Javascript 클래스 목록
 * 	- PQQuery
 * ----------------
 *	- DefaultKeyManager
 *	- DefalutKeyGroup
 *	- DefalutKeyAtom
 * ----------------
 *  - MaxQuery
 *	- FormQuery
 *  - OuterQuery
 *	- ModifyQuery
 * -----------------
 *	- SelectQuery
 *	- TransactionQuery
 * -----------------
 *	- AtomVariable
 *	- ProcedureParamInfo
 */

/**
 * 웹페이지의 쿼리를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
var g_objPQQuery;

function PQQuery (arModuleKeys, objDefaultKeyManager, objFormQuery, arOuterQueries, htServerQueryInfo)
{
	this.m_arModuleKeys = arModuleKeys;
	this.m_objDefaultKeyManager = objDefaultKeyManager;
	this.m_objFormQuery = objFormQuery;
	this.m_arOuterQueries = arOuterQueries;
	this.m_htServerQueryInfo = htServerQueryInfo;
	
	this.m_objQueryGen = null;
	
	this.m_htQueryModifyInfo = new Hashtable();		// 서버,클라이언트 스크립트 둘다 사용하는 질의수정 정보 저장
}

PQQuery.prototype.initQueryGenerator = function ()
{
	if (DB_KIND._dbOracle == g_nDBKind)
	{
		this.m_objQueryGen = new MsSqlGenerator ();
	}
	else
	{
		this.m_objQueryGen = new OracleSqlGenerator();
	}
}

PQQuery.prototype.getModuleKeys = function ()
{
	return this.m_arModuleKeys;
}

PQQuery.prototype.getDefaultKeyManager = function ()
{
	return this.m_objDefaultKeyManager;
}

PQQuery.prototype.getFormQuery = function ()
{
	return this.m_objFormQuery;
}

PQQuery.prototype.getOuterQuery = function ()
{
	return this.m_arOuterQueries;
}

PQQuery.prototype.getOuterQueryByIndex = function (nSQLIndex)
{
	for (var i = 0; i < this.m_arOuterQueries.length; i++)
	{
		var objQuery = this.m_arOuterQueries[i];
		
		if (objQuery.getSQLIndex() == nSQLIndex)
		{
			return objQuery;
		}
	}

	return null;
}

PQQuery.prototype.getOuterQueryByName = function (strSQLName)
{
	for (var i = 0; i < this.m_arOuterQueries.length; i++)
	{
		var objQuery = this.m_arOuterQueries[i];
		
		if (objQuery.getSQLName() == strSQLName)
		{
			return objQuery;
		}
	}

	return null;
}

PQQuery.prototype.getServerQueryInfo = function (strSQLName)
{
	return this.m_htServerQueryInfo[strSQLName];
}

PQQuery.prototype._getQueryLinkedVarList = function (strVarNames)
{
	var arVarNames = strVarNames.split(",");
		
	for (var i = 0; i < arVarNames.length; i+=1)
	{
		var strVarName = Utils.trim(arVarNames[i]);

		if (Utils.isEmpty(strVarName))
		{
			continue;
		}
		
		if (strVarName.charAt(0) == "'" && strVarName.charAt(strVarName.length - 1) == "'")
		{
			strVarName = strVarName.substring(1, strVarName.length - 1);
		}

		if (strVarName.charAt(0) == "#")
		{
			strVarName = strVarName.substring(1);
		}
		else if (strVarName.charAt(0) == "?" && strVarName.charAt(strValue.length - 1) == "?")
		{
			strVarName = strVarName.substring(1, strVarName.length - 1);
		}

		arVarNames[i] = strVarName;
	}
	
	return arVarNames;
}

/**
 * 변수연결 문장을 파싱하여, 변수명의 리스트를 생성한다.
 * 변수 형태는 '#변수명' 또는 '?변수명?'이다. 변수 사이는 ','로 구분된다.
 */
PQQuery.prototype.initServerQueryLinkedVar = function ()
{
	for (var strName in this.m_htServerQueryInfo)
	{
		var arQueryInfo = this.m_htServerQueryInfo[strName].split("||");
		var strLinkedVar = arQueryInfo[0];
		var strWhere = arQueryInfo[1];
		var strInsertVar = arQueryInfo[2];
		
		var arNewInfo = new Array(3);
		
		if (null != strLinkedVar && 0 < strLinkedVar.length)
		{
			arNewInfo[0] = this._getQueryLinkedVarList(strLinkedVar);
		}
		
		if (null != strWhere && 0 < strWhere.length)
		{
			var arWhere = strWhere.split(" ");
			arNewInfo[1] = new Array();
			
			for (var i = 0; i < arWhere.length; i+=1)
			{
				var strItem = Utils.trim(arWhere[i]);
				
				if (strItem.charAt(0) == "'")
				{
					if(strItem.charAt(strItem.length - 1) == "'")
					{
						strItem = strItem.substring(1, strItem.length - 1);
					}
				}
				
				if (strItem.charAt(0) == "#")
				{
					arNewInfo[1].push(strItem.substring(1));
				}
			}
		}
		
		if (null != strInsertVar && 0 < strInsertVar.length)
		{
			arNewInfo[2] = this._getQueryLinkedVarList(strInsertVar);
		}
		
		this.m_htServerQueryInfo[strName] = arNewInfo;
	}
}

PQQuery.prototype.makeQueryModifyRequest = function (xnRequest, strFuncName)
{
	var xnQuery = XmlLib.createChild(xnRequest, "QueryModify");
	
	for (var strKey in this.m_htQueryModifyInfo)
	{
		var strValue = this.m_htQueryModifyInfo[strKey];
		if (null != strValue)
		{
			var arKey = strKey.split("__");
			var strQueryName = arKey[0];
			
			var htServerQueryName = g_htScriptQueryVarMap[strFuncName];
			
			if (null != htServerQueryName[strQueryName])
			{
				var arValue = strValue.split("__");
				var strStatement = arValue[0];
				var strAppend = arValue[1];
				
				var xnInfo = XmlLib.createChildWithValue(xnQuery, strKey, strStatement);
				XmlLib.setAttribute(xnInfo, "bAppend", strAppend);
				
				this.m_htQueryModifyInfo[strKey] = null;
				this.getOuterQueryByName(strQueryName).initModify();
			}
		}
	}
}

PQQuery.prototype.getMaxQuery = function (strVarName)
{
	var arMaxQuery = this.m_objFormQuery.getMaxQuery();
	if (null == arMaxQuery)
	{
		return null;
	}

	var objMaxQuery = null;
	var nLen = arMaxQuery.length;

	for (var i = 0; i < nLen; i++)
	{
		objMaxQuery = arMaxQuery[i];
		var arAtomVariableList = objMaxQuery.getLoadFieldAtomList();
		var nVarLen = arAtomVariableList.length;
		for (var j = 0; j < nVarLen; j+=1)
		{
			if (strVarName == arAtomVariableList[j].getVarName())
			{
				return objMaxQuery;
			}
		}
	}

	return null;
}

PQQuery.prototype.convertQuery = function (strQuery, nDBIndex)
{
	if (null != this.m_objQueryGen)
	{
		return this.m_objQueryGen.convertSQL(strQuery, this.m_arModuleKeys, nDBIndex);
	}

	return strQuery;
}

PQQuery.prototype.getSelectQuery = function (nSQLIndex)
{
	var arSelectQuery = this.m_objFormQuery.getSelectQuery();
	
	/**
	 * Select 쿼리는 DefaultKeyGroup의 기본검색키인 아톰의 SQLIndex 값으로 쿼리를 찾는다.
	 * 
	 * 이전의 테이블명으로 찾는 방식은, 서로 다른 뷰가 같은 테이블을 참조할 경우, 제대로 쿼리를 찾을수 없었다.
	 * Transaction 쿼리는 SQLIndex가 아니라 쿼리 종류별로 순서가 결정되므로 이전 방식을 그대로 쓴다.
	 * SQLIndex가 -1이거나 유효한 값이 아닐 경우에는, 값이 잘못 생성된 것이다. 
	 */
	if (-1 < nSQLIndex)
	{
		for (var i = 0; i < arSelectQuery.length; i+=1)
		{
			objSelectQuery = arSelectQuery[i];
			
			if (nSQLIndex == objSelectQuery.getSQLIndex())
			{
				return objSelectQuery;
			}
		}
	}
	
	return null;
}

PQQuery.prototype.getTransactionQuery = function (strTableName, nQueryKind)
{
	var arTransactionQuery;
	
	if (nQueryKind == FORMQUERY_KIND.INSERT)
	{
		arTransactionQuery = this.m_objFormQuery.getInsertQuery();
	}
	else if (nQueryKind == FORMQUERY_KIND.UPDATE)
	{
		arTransactionQuery = this.m_objFormQuery.getUpdateQuery();
	}
	else if (nQueryKind == FORMQUERY_KIND.DELETE)
	{
		arTransactionQuery = this.m_objFormQuery.getDeleteQuery();
	}
	
	if (null == arTransactionQuery)
	{
		return null;
	}
	
	var nQueryIndex = this.findQueryIndex(strTableName, arTransactionQuery);
	if (-1 == nQueryIndex)
	{
		return null;
	}

	return arTransactionQuery[nQueryIndex];
}

/**
 * 해당 테이블에 대한 쿼리 인덱스를 찾습니다.
 * 저장,수정,삭제 쿼리를 찾을 때 사용합니다.
 * 저장,수정,삭제 쿼리는 테이블당 하나씩 생기는 것을 조건으로 합니다. 
 */
PQQuery.prototype.findQueryIndex = function (strTableName, arQuery)
{
	/**
	 * 스크롤의 테이블명에서 JOIN 테이블 제거
	 * 스크롤 기본키의 strTableName 형태 : 스크롤테이블 + join 테이블 + ...
	 * 예) "_OWNER_(1)선수과목목록_OWNER_(1)교과목정보"
	 */
	var nIndex = strTableName.indexOf("_OWNER_", 7);

	if (0 < nIndex)
	{
		strTableName = strTableName.substring(0, nIndex);
	}		 

	for (var i = 0, nQueryLen = arQuery.length; i < nQueryLen; i+=1)
	{
		var strTable = arQuery[i].getTableName();
		if (0 == strTable.indexOf("_OWNER_"))
		{
			strTable = strTable.substring(strTable.indexOf(")") + 1);
		}
		
		if (strTable == strTableName)
		{
			return i;
		}
	}

	return -1;
}

/**
 * 요청을 만든다.
 */
PQQuery.prototype.makeRequest = function (xnRequest)
{
	var xnRequest = XmlLib.selectSingleNode(xnRequest, "Request");
	if (null != xnRequest)
	{
		var xnPQQuery = XmlLib.createChild(xnRequest, "PQQuery");
		
		// ModuleKey
		var xnModulKey = XmlLib.createChild(xnPQQuery, "ModuleKey");
		for (strKey in this.m_arModuleKeys)
		{
			var xnKey = XmlLib.createChild(xnModulKey, "Key");
			XmlLib.setTextValue(xnKey, this.m_arModuleKeys[strKey]);
			xnKey.setAttribute("key", strKey);
		}
		
		// 기본키
		this.m_objDefaultKeyManager.makeRequest(xnPQQuery);
		
		// 폼쿼리
		this.m_objFormQuery.makeRequest(xnPQQuery);
		
		// 외부질의
		var xnOuter = XmlLib.createChild(xnPQQuery, "Outer");
		for (var i = 0; i < this.m_arOuterQueries.length; i += 1)
		{
			this.m_arOuterQueries[i].makeRequest(xnOuter);
		}
	}
}

/**
 * 결과를 반영한다.
 */
PQQuery.prototype.handleResult = function (xnResult)
{
	// 외부질의
	var xlOuterQuery = XmlLib.selectNodeList(xnResult, "//OuterQuery");
	if (!xlOuterQuery)
	{
		return;
	}
	
	for (var nSQLIndex = 0; nSQLIndex < xlOuterQuery.length; nSQLIndex += 1)
	{
		var objOuterQuery = this.m_arOuterQueries[nSQLIndex];
		
		if (objOuterQuery)
		{
			var xnOuterQuery = xlOuterQuery[nSQLIndex];
			objOuterQuery.handleResult(xnOuterQuery);
		}
	}
}

PQQuery.getModuleKey = function (nDBIndex)
{
	var strDBName = g_arDBName[nDBIndex];
	
	for (var strModuleKey in g_htDBNameModuleKey)
	{
		if (strDBName == g_htDBNameModuleKey[strModuleKey])
		{
			return strModuleKey;
		}
	}
	return "";
}

PQQuery.makeRequest = function (xnRequest)
{
	if (null != g_objPQQuery)
	{
		g_objPQQuery.makeRequest(xnRequest);
	}
}

PQQuery.handleResult = function (xnResult)
{
	if (null != g_objPQQuery)
	{
		g_objPQQuery.handleResult(xnResult);
	}
}


/**
 * MSSQL 쿼리 생성
 */
function MsSqlGenerator ()
{
	
}

/**
 * MSSQL문에 맞는 쿼리문을 생성합니다.
 */
MsSqlGenerator.prototype.convertSQL = function (strQuery, arModuleKeys, nDBIndex)
{
	var alOwner = this.getOwner(arModuleKeys);
	
	for (var i = 0 ; i < alOwner.length; i+=1)
	{
		var token = "_OWNER_(" + i + ")";
		if ( -1 != strQuery.indexOf(token))
		{
			strQuery = Utils.replaceAll(strQuery, token, alOwner[i]);
		}

		token = "#DB오너(" + i + ")";
		if (-1 != strQuery.indexOf(token) && null != owner[i])
		{
			strQuery = Utils.replaceAll(strQuery, token, alOwner[i]);
		}
	}

	if (-1 < strQuery.indexOf("_OWNER_"))
	{
		if (-1 < nDBIndex && nDBIndex < alOwner.length)
		{
			var strOwner = alOwner[nDBIndex];
			strQuery = Utils.replaceAll(strQuery, "_OWNER_", strOwner);
		}
	}

	if (-1 <  strQuery.indexOf("#OWNER."))
	{
		if (1 < alOwner.length)
		{
			var strOwner = alOwner[1];
			strQuery = Utils.replaceAll(strQuery, "#OWNER.", strOwner);
		}
	}
	
	//strQuery = this.convertGlobal (strQuery);
	
	return strQuery;
}

MsSqlGenerator.prototype.getOwner = function (arModuleKeys)
{
	if (null != arModuleKeys && 0 < arModuleKeys.length)
	{
		var alOwner = new Array();
		
		for (var nModuleKeyIndex = 0; nModuleKeyIndex < arModuleKeys.length; nModuleKeyIndex++)
		{
			var strKey = arModuleKeys[nModuleKeyIndex];
			var strDBNameOwner = g_htDBNameModuleKey[strKey];
			
			if (null != strDBNameOwner)
			{
				var strDBName = strDBNameOwner;
				
				var nIndex = strDBNameOwner.indexOf(".");
				if (0 < nIndex)
				{
					strDBName = strDBNameOwner.substring(0, nIndex);
				}
			
				for (var nDBNameIndex = 0 ; nDBNameIndex < g_arDBName.length; nDBNameIndex++)
				{
					if (strDBName == g_arDBName[nDBNameIndex])
					{
						alOwner.push(g_arDBNameOwner[nDBNameIndex] + ".");
						break;
					}
				}
			}
		}
		
		return alOwner;
	}

	return null;	//getOwner();
}

/**
 * Oracle 쿼리 생성
 */
function OracleSqlGenerator ()
{
	
}

/**
 * "소유자." 리스트를 가져온다.
 */
OracleSqlGenerator.prototype.getOwner = function (arModuleKeys)
{
	if (null != arModuleKeys && 0 < arModuleKeys.length)
	{
		var alOwner = new Array();
		
		for (var nModuleKeyIndex = 0; nModuleKeyIndex < arModuleKeys.length; nModuleKeyIndex++)
		{
			var strKey = arModuleKeys[nModuleKeyIndex];
			var strDBNameOwner = g_htDBNameModuleKey[strKey];
			
			if (null != strDBNameOwner)
			{
				var strDBName = strDBNameOwner;
				
				var nIndex = strDBNameOwner.indexOf(".");
				if (0 < nIndex)
				{
					strDBName = strDBNameOwner.substring(0, nIndex);
				}
			
				for (var nDBNameIndex = 0 ; nDBNameIndex < g_arDBName.length; nDBNameIndex++)
				{
					if (strDBName == g_arDBName[nDBNameIndex])
					{
						alOwner.push(g_arDBNameOwner[nDBNameIndex] + ".");
						break;
					}
				}
			}
		}
		
		return alOwner;
	}

	return null;	//getOwner();
}

OracleSqlGenerator.prototype.convertSQL = function (strQuery, arModuleKeys, nDBIndex)
{
	var alOwner = this.getOwner(arModuleKeys);
	
	for (var i = 0 ; i < alOwner.length; i+=1)
	{
		var token = "_OWNER_(" + i + ")";
		if ( -1 != strQuery.indexOf(token))
		{
			strQuery = Utils.replaceAll(strQuery, token, alOwner[i]);
		}

		token = "_OWNER_" + i;
		if (-1 != strQuery.indexOf(token) && null != alOwner[i])
		{
			strQuery = Utils.replaceAll(strQuery, token, owner[i]);
		}
		
		token = "#DB오너(" + i + ")";
		if (-1 != strQuery.indexOf(token) && null != owner[i])
		{
			strQuery = Utils.replaceAll(strQuery, token, alOwner[i]);
		}
	}
	
	if (-1 < strQuery.indexOf("_OWNER_"))
	{
		if (-1 < nDBIndex && nDBIndex < alOwner.length)
		{
			var strOwner = alOwner[nDBIndex];
			strQuery = Utils.replaceAll(strQuery, "_OWNER_", strOwner);
		}
	}

	if (-1 <  strQuery.indexOf("#OWNER."))
	{
		if (1 < alOwner.length)
		{
			var strOwner = alOwner[1];
			strQuery = Utils.replaceAll(strQuery, "#OWNER.", strOwner);
		}
	}

	// global info convert
	//strQuery = convertGlobal(strQuery);
	
	return strQuery;
}


//----------------------------------------------------------------------------------
/**
 * 기본검색키 정보를 관리합니다.
 * @author 김지환
 * @since UPS1.0
 */
function DefaultKeyManager (bAllSave, arDefaultKeyGroup, nDefaultKeyAtomLength)
{
	this.m_bAllSave = bAllSave;
	this.m_arDefaultKeyGroup = arDefaultKeyGroup;
	this.m_nDefaultKeyAtomLength = nDefaultKeyAtomLength;
}

// getter, setter
DefaultKeyManager.prototype.isAllSave = function ()
{
	return this.m_bAllSave;
}

DefaultKeyManager.prototype.getDefaultKeyGroup = function ()
{
	return this.m_arDefaultKeyGroup;
}

DefaultKeyManager.prototype.getDefaultKeyAtomLength = function ()
{
	return this.m_nDefaultKeyAtomLength;
}

DefaultKeyManager.prototype.makeRequest = function (xnRequest)
{
	var xnDefaultKeyManager = XmlLib.createChild(xnRequest, "DefaultKeyManager");
	xnDefaultKeyManager.setAttribute("AllSave", this.m_bAllSave ? "true" : "false")
	xnDefaultKeyManager.setAttribute("DefaultKeyAtomLength", this.m_nDefaultKeyAtomLength)
	
	for (var i = 0; i < this.m_arDefaultKeyGroup.length; i=i+1)
	{
		var objDefaultKeyGroup = this.m_arDefaultKeyGroup[i]
		if (null != objDefaultKeyGroup)
		{
			objDefaultKeyGroup.makeRequest(xnDefaultKeyManager);
		}
	}
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 기본검색키 그룹을 관리합니다.
 * @author 김지환
 * @since UPS1.0
 */
function DefaultKeyGroup (strTableName, strScrollName, strTabID, arDefaultKeyAtom, nSQLIndex)
{
	this.m_strTableName = strTableName;
	this.m_strScrollName = strScrollName;
	this.m_strTabID = strTabID;
	this.m_arDefaultKeyAtom = arDefaultKeyAtom;
	this.m_nSQLIndex = nSQLIndex;
}

// getter, setter
DefaultKeyGroup.prototype.getTableName = function ()
{
	return this.m_strTableName;
}

DefaultKeyGroup.prototype.ScrollName = function ()
{
	return this.m_strScrollName;
}

DefaultKeyGroup.prototype.getTabID = function ()
{
	return this.m_strTabID;
}

DefaultKeyGroup.prototype.getDefaultKeyAtom = function ()
{
	return this.m_arDefaultKeyAtom;
}

DefaultKeyGroup.prototype.makeRequest = function (xnRequest)
{
	var xnDefaultKeyGroup = XmlLib.createChild(xnRequest, "DefaultKeyGroup");
	xnDefaultKeyGroup.setAttribute("TableName", this.m_strTableName);
	xnDefaultKeyGroup.setAttribute("ScrollName", this.m_strScrollName);
	xnDefaultKeyGroup.setAttribute("TabID", this.m_strTabID);
	xnDefaultKeyGroup.setAttribute("SQLIndex", this.m_nSQLIndex);
	
	for (var i = 0; i < this.m_arDefaultKeyAtom.length; i=i+1)
	{
		var objDefaultKeyAtom = this.m_arDefaultKeyAtom[i];
		if (null != objDefaultKeyAtom)
		{
			objDefaultKeyAtom.makeRequest(xnDefaultKeyGroup);
		}
	}
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 기본검색키아톰 정보를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function DefaultKeyAtom (strAtomType, // 1
						strVarName, // 2
						bAutoLoad, // 7
						bAutoInc, // 8
						bSaveField, // 9
						nScrollType, // 10
						nFieldLen, // 11
						strFieldName, // 12
						strFieldType) // 13
{
	this.m_strAtomType = strAtomType;
	this.m_strVarName = strVarName;
	this.m_bAutoLoad = bAutoLoad;
	this.m_bAutoInc = bAutoInc;
	this.m_bSaveField = bSaveField;
	this.m_nScrollType = nScrollType;
	this.m_nFieldLen = nFieldLen;
	this.m_strFieldName = strFieldName;
	this.m_strFieldType = strFieldType;
}

DefaultKeyAtom.prototype.makeRequest = function (xnRequest)
{
	var xnDefaultKeyAtom = XmlLib.createChild(xnRequest, "DefaultKeyAtom");
	xnDefaultKeyAtom.setAttribute("AtomType", this.m_strAtomType);
	xnDefaultKeyAtom.setAttribute("VarName", this.m_strVarName);
	xnDefaultKeyAtom.setAttribute("AutoLoad", this.m_bAutoLoad ? "true" : "false");
	xnDefaultKeyAtom.setAttribute("AutoInc", this.m_bAutoInc ? "true" : "false");
	xnDefaultKeyAtom.setAttribute("SaveField", this.m_bSaveField ? "true" : "false");
	xnDefaultKeyAtom.setAttribute("ScrollType", this.m_nScrollType);
	xnDefaultKeyAtom.setAttribute("FieldLen", this.m_nFieldLen);
	xnDefaultKeyAtom.setAttribute("FieldName", this.m_strFieldName);
	xnDefaultKeyAtom.setAttribute("FieldType", this.m_strFieldType);
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * MaxQuery
 * @author 김지환
 * @since UPS1.0
 */
function MaxQuery (strQuery, arOuputAtomList, arLoadFieldAtomList)
{
	this.m_strQuery = strQuery;
	
	this.m_arOutputAtomList = arOuputAtomList;
	this.m_arLoadFieldAtomList = arLoadFieldAtomList;
}

MaxQuery.prototype.makeRequest = function (xnRequest)
{
	var xnMaxQuery = XmlLib.createChild(xnRequest, "MaxQuery");
	xnMaxQuery.setAttribute("Query", this.m_strQuery);
	
	// OutputAtomList
	var xnOutputAtomList = XmlLib.createChild(xnMaxQuery, "OutputAtomList");
	for (var i = 0; i < this.m_arOutputAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arOutputAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnOutputAtomList);
		}
	}
	
	// LoadFieldAtomList
	var xnLoadFieldAtomList = XmlLib.createChild(xnMaxQuery, "LoadFieldAtomList");
	for (var i = 0; i < this.m_arLoadFieldAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arLoadFieldAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnLoadFieldAtomList);
		}
	}
}

MaxQuery.prototype.getMaxQuery = function ()
{
	return this.m_strQuery;
}

MaxQuery.prototype.getLoadFieldAtomList = function ()
{
	return this.m_arLoadFieldAtomList;
}

MaxQuery.prototype.getOutputAtomList = function ()
{
	return this.m_arOutputAtomList;
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 폼쿼리, 폼 전체적인 동작의 쿼리를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function FormQuery (arSelectQuery, arMaxQuery, arUpdateQuery, arDeleteQuery, arInsertQuery)
{
	this.m_arSelectQuery = arSelectQuery;
	this.m_arMaxQuery = arMaxQuery;
	this.m_arUpdateQuery = arUpdateQuery;
	this.m_arDeleteQuery = arDeleteQuery;
	this.m_arInsertQuery = arInsertQuery;
}

// getter, setter
FormQuery.prototype.getSelectQuery = function ()
{
	return this.m_arSelectQuery;
}

FormQuery.prototype.getMaxQuery = function ()
{
	return this.m_arMaxQuery;
}

FormQuery.prototype.getUpdateQuery = function ()
{
	return this.m_arUpdateQuery;
}

FormQuery.prototype.getDeleteQuery = function ()
{
	return this.m_arDeleteQuery;
}

FormQuery.prototype.getInsertQuery = function ()
{
	return this.m_arInsertQuery;
}

FormQuery.prototype.makeRequest = function (xnRequest)
{
	var xnFormQuery = XmlLib.createChild(xnRequest, "FormQuery");
	
	// Select쿼리
	var xnSelect = XmlLib.createChild(xnFormQuery, "Select");
	for (var i = 0; i < this.m_arSelectQuery.length; i=i+1)
	{
		var objSelectQuery = this.m_arSelectQuery[i];
		if (null != objSelectQuery)
		{
			objSelectQuery.makeRequest(xnSelect);
		}
	}
	
	// Max쿼리
	var xnMax = XmlLib.createChild(xnFormQuery, "Max");
	for (var i = 0; i < this.m_arMaxQuery.length; i=i+1)
	{
		var objMaxQuery = this.m_arMaxQuery[i];
		if (null != objMaxQuery)
		{
			objMaxQuery.makeRequest(xnMax);
		}
	}
	
	// Update쿼리
	var xnUpdateQuery = XmlLib.createChild(xnFormQuery, "UpdateQuery");
	for (var i = 0; i < this.m_arUpdateQuery.length; i=i+1)
	{
		var objTransaction = this.m_arUpdateQuery[i];
		if (null != objTransaction)
		{
			objTransaction.makeRequest(xnUpdateQuery);
		}
	}
	
	// Delete쿼리
	var xnDeleteQuery = XmlLib.createChild(xnFormQuery, "DeleteQuery");
	for (var i = 0; i < this.m_arDeleteQuery.length; i=i+1)
	{
		var objTransaction = this.m_arDeleteQuery[i];
		if (null != objTransaction)
		{
			objTransaction.makeRequest(xnDeleteQuery);
		}
	}
	
	
	// Insert쿼리
	var xnInsertQuery = XmlLib.createChild(xnFormQuery, "InsertQuery");
	for (var i = 0; i < this.m_arInsertQuery.length; i=i+1)
	{
		var objTransaction = this.m_arInsertQuery[i];
		if (null != objTransaction)
		{
			objTransaction.makeRequest(xnInsertQuery);
		}
	}
}

//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 외부질의 정보를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function OuterQuery (strQueryName,
					nSQLIndex,
					strSelect,
					objModifyQuery,
					arProcedureParamInfo,
					strKey,
					strField,
					strTable,
					strWhere,
					strGroupBy,
					strHaving,
					strOrderBy,
					strUnion,
					strInsertValue,
					strLinkedVariables,
					strDBIndex,
					nSQLKind,
					bDistinct,
					nServerUseLevel)
{
	this.m_strQueryName = strQueryName;
	this.m_nSQLIndex = nSQLIndex;
	this.m_strSelect = strSelect;
    this.m_objModifyQuery = objModifyQuery;
    this.m_arProcedureParamInfo = arProcedureParamInfo;
    
    this.m_strKey = strKey;
	this.m_strField = strField;
	this.m_strTable = strTable;
	this.m_strWhere = strWhere;
	this.m_strGroupBy = strGroupBy;
	this.m_strHaving = strHaving;
	this.m_strOrderBy = strOrderBy;
	this.m_strUnion = strUnion;
	this.m_strInsertValue = strInsertValue;
	this.m_strLinkedVariables = strLinkedVariables;
	this.m_strDBIndex = strDBIndex;
	this.m_nSQLKind = nSQLKind;
	this.m_bDistinct = bDistinct;
	this.m_strAppendWhere = "";
	this.m_strAppendOrderBy = "";
	this.m_htTableAlias = this.makeTableAlias();
	this.m_nServerUseLevel = nServerUseLevel;		// 0: Client Only, 1: Server Only, 2: Server Client
}

OuterQuery.prototype.getSQLIndex = function ()
{
	return this.m_nSQLIndex;
}

OuterQuery.prototype.getSQLName = function ()
{
	return this.m_strQueryName;
}

OuterQuery.prototype.getDBIndex = function ()
{
	return Utils.parseInt(this.m_strDBIndex);
}

OuterQuery.prototype.getSQLKind = function ()
{
	return this.m_nSQLKind
}

OuterQuery.prototype.getLinkedVariables = function ()
{
	return this.m_strLinkedVariables;
}

OuterQuery.prototype.getProcedureParamInfoList = function ()
{
	return this.m_arProcedureParamInfo;
}

OuterQuery.prototype.setModifyQuery = function (nModifyPart, strModifyStatement, bAppend)
{
	var nResult = 1;
	switch (nModifyPart)
	{
	// #실행테이블(1103), #실행조건(1104), #그룹기준(1105), #정렬기준(1106) 
	// #결합문장(1107), #실행필드(1108), #입력변수(1109)
	case 1103 :
		this.m_objModifyQuery.setTable(strModifyStatement, bAppend);
		break;
	case 1104 :
		this.m_objModifyQuery.setWhere(strModifyStatement, bAppend);
		break;
	case 1105 :
		this.m_objModifyQuery.setGroupBy(strModifyStatement, bAppend);
		break;
	case 1106 :
		this.m_objModifyQuery.setOrderBy(strModifyStatement, bAppend);
		break;
	case 1107 :
		this.m_objModifyQuery.setUnion(strModifyStatement, bAppend);
		break;
	case 1108 :
		this.m_objModifyQuery.setField(strModifyStatement, bAppend);
		break;
	case 1109 :
		this.m_objModifyQuery.setInsertValue(strModifyStatement,bAppend);
		break;
	case 1110 :
		this.m_objModifyQuery.setHaving(strModifyStatement, bAppend);
		break;
	default:
		nResult = 0;
	break;
	}
	
	if (2 == this.m_nServerUseLevel)
	{
		// 서버에 전달할 질의수정 정보 생성
		var strKey = this.m_strQueryName + "__" + nModifyPart;
		g_objPQQuery.m_htQueryModifyInfo[strKey] = strModifyStatement + "__" + bAppend;
	}
}

/**
 * 요청을 만든다.
 */
OuterQuery.prototype.makeRequest = function (xnRequest)
{
	var xnOuterQuery = XmlLib.createChild(xnRequest, "OuterQuery");
	xnOuterQuery.setAttribute("SQLIndex", this.m_nSQLIndex);
	xnOuterQuery.setAttribute("Field", this.m_strField);
	xnOuterQuery.setAttribute("Table", this.m_strTable);
	xnOuterQuery.setAttribute("Where", this.m_strWhere);
	xnOuterQuery.setAttribute("GroupBy", this.m_strGroupBy);
	xnOuterQuery.setAttribute("Having", this.m_strHaving);
	xnOuterQuery.setAttribute("OrderBy", this.m_strOrderBy);
	xnOuterQuery.setAttribute("Union", this.m_strUnion);
	xnOuterQuery.setAttribute("InsertValue", this.m_strInsertValue);
	xnOuterQuery.setAttribute("LinkedVariables", this.m_strLinkedVariables);
	xnOuterQuery.setAttribute("DBIndex", this.m_strDBIndex);
	xnOuterQuery.setAttribute("SQLKind", this.m_nSQLKind);
	xnOuterQuery.setAttribute("QueryName", this.m_strQueryName);
	xnOuterQuery.setAttribute("Select", this.m_strSelect);
	xnOuterQuery.setAttribute("Distinct", this.m_bDistinct ? "true" : "false");
	xnOuterQuery.setAttribute("AppendWhere", this.m_strAppendWhere);
	
	var xnParam = XmlLib.createChild(xnOuterQuery, "Param");
	for (var i = 0 ; i < this.m_arProcedureParamInfo.length; i+=1)
	{
		this.m_arProcedureParamInfo[i].makeRequest(xnParam);
	}
	
	this.m_objModifyQuery.makeRequest(xnOuterQuery);
}

/**
 * 결과를 반영한다.
 */
OuterQuery.prototype.handleResult = function (xnOuterQuery)
{
	this.m_nSQLIndex = Number(xnOuterQuery.getAttribute("SQLIndex"));
	this.m_strField = xnOuterQuery.getAttribute("Field");
	this.m_strTable = xnOuterQuery.getAttribute("Table");
	this.m_strWhere = xnOuterQuery.getAttribute("Where");
	this.m_strGroupBy = xnOuterQuery.getAttribute("GroupBy");
	this.m_strHaving = xnOuterQuery.getAttribute("Having");
	this.m_strOrderBy = xnOuterQuery.getAttribute("OrderBy");
	this.m_strUnion = xnOuterQuery.getAttribute("Union");
	this.m_strInsertValue = xnOuterQuery.getAttribute("InsertValue");
	this.m_strLinkedVariables = xnOuterQuery.getAttribute("LinkedVariables");
	this.m_strDBIndex = xnOuterQuery.getAttribute("DBIndex");
	this.m_nSQLKind = Number(xnOuterQuery.getAttribute("SQLKind"));
	this.m_strQueryName = xnOuterQuery.getAttribute("QueryName");
	this.m_strSelect = xnOuterQuery.getAttribute("Select");
	this.m_strAppendWhere = xnOuterQuery.getAttribute("AppendWhere")
	
	// ModifyQuery
	var xnModifyQuery = XmlLib.selectSingleNode(xnOuterQuery, "ModifyQuery");
	this.m_objModifyQuery.handleResult(xnModifyQuery);
	
	// ParamInfo
	var xnParam = XmlLib.selectSingleNode(xnOuterQuery, "Param");
	if (null != xnParam)
	{
		var xlParamInfo = xnParam.childNodes;
		for (var i = 0; i < xlParamInfo.length; i += 1)
		{
			var xnParamInfo = xlParamInfo[i];
			var objParamInfo = this.m_arProcedureParamInfo[i];
			if (null != objParamInfo && null != xnParamInfo)
			{
				objParamInfo.handleResult(xnParamInfo);
			}
		}
	}
}

OuterQuery.prototype.initAppendWhere = function ()
{
	this.m_strAppendWhere = "";
}

OuterQuery.prototype.getAppendWhere = function ()
{
	return this.m_strAppendWhere;
}

OuterQuery.prototype.getQuery = function ()
{
	switch (this.m_nSQLKind)
	{
	case SqlMode._Select: 
		return this.makeSelectQuery ();
	}

	return "";
}

OuterQuery.prototype.makeSelectQuery = function ()
{
	var strFieldQuery = this.m_objModifyQuery.getField(this.m_strField);
	var strGroupByQuery = this.m_objModifyQuery.getGroupBy(this.m_strGroupBy);
	var strOrderByQuery = this.m_objModifyQuery.getOrderBy(this.m_strOrderBy);
	var strUnionQuery = this.m_objModifyQuery.getUnion(this.m_strUnion);
	var strFromQuery = this.m_objModifyQuery.getTable(this.m_strTable);
	var strWhereQuery = this.m_objModifyQuery.getWhere(this.m_strWhere);
	var strHavingQuery = this.m_objModifyQuery.getHaving(this.m_strHaving);

	var strSQL = "SELECT";

	if (this.m_bDistinct)
	{
		strSQL = strSQL + " DISTINCT";
	}

	if (0 == strFromQuery.length)
		strSQL += " " + strFieldQuery;
	else
		strSQL += " " + strFieldQuery + " FROM " + strFromQuery;

	if (0 != strWhereQuery.length)
		strSQL += " WHERE " + strWhereQuery;

	if (false == Utils.isEmpty(this.m_strAppendWhere))
	{
		if (null != strWhereQuery && 0 < strWhereQuery.length)
		{
			strSQL += " AND " + this.m_strAppendWhere;
		}
		else
		{
			strSQL += " WHERE " + this.m_strAppendWhere;
		}
	}

	if (0 != strGroupByQuery.length)
		strSQL += " GROUP BY " + strGroupByQuery;

	if (0 != strUnionQuery.length)
		strSQL += " UNION " + strUnionQuery;

	if (0 != strHavingQuery.length)
		strSQL += " HAVING " + strHavingQuery;

	if (0 != strOrderByQuery.length)
		strSQL += " ORDER BY " + strOrderByQuery;

	return strSQL;
}

OuterQuery.prototype.initModify = function ()
{
	this.m_objModifyQuery.init();
}

OuterQuery.prototype.getQueryStatement = function ()
{
	var strQuery = "";

	try
	{
		switch (this.m_nSQLKind)
		{
		case SqlMode._Insert:
			strQuery = this.getInsertQuery();
			break;
		case SqlMode._Update:
			strQuery = this.getUpdateQuery();
			break;
		case SqlMode._Delete:
			strQuery = this.getDeleteQuery();
			break;
		case SqlMode._Select:
			strQuery = this.getSelectQuery();
			break;
		case SqlMode._Text:
			strQuery = this.m_objModifyQuery.getTable(this.m_strTable);
			break;
		case SqlMode._Procedure :
			strQuery = this.m_strTable;
			break;
		}
	}
	catch (e)
	{
		alert ("OuterQuery.getQueryStatement:" + e.message);
	}

	return strQuery;
}

OuterQuery.prototype.getSelectQuery = function ()
{
	var strTable = this.m_objModifyQuery.getTable(this.m_strTable);
	var strField = this.m_objModifyQuery.getField(this.m_strField);
	var strWhere = this.m_objModifyQuery.getWhere(this.m_strWhere);
	var strGroupBy = this.m_objModifyQuery.getGroupBy(this.m_strGroupBy);
	var strOrderBy = this.m_objModifyQuery.getOrderBy(this.m_strOrderBy);
	var strUnion = this.m_objModifyQuery.getUnion(this.m_strUnion);
	var strHaving = this.m_objModifyQuery.getHaving(this.m_strHaving);

	var strQuery = "SELECT " + strField + " FROM " + strTable;

	if (!Utils.isEmpty(strWhere))
	{
		strQuery += " WHERE " + strWhere;
	}

	if (!Utils.isEmpty(strGroupBy))
	{
		strQuery += " GROUP BY " + strGroupBy;
	}

	if (!Utils.isEmpty(strHaving))
	{
		strQuery += " HAVING " + strHaving;
	}

	if (!Utils.isEmpty(strUnion))
	{
		strQuery += " UNION (" + strUnion + ")";
	}

	if (!Utils.isEmpty(strOrderBy))
	{
		strQuery += " ORDER BY " + strOrderBy;
	}

	return strQuery;
}

OuterQuery.prototype.getInsertQuery = function ()
{
	var strTable = this.m_objModifyQuery.getTable(this.m_strTable);
	var strField = this.m_objModifyQuery.getField(this.m_strField);
	var strValue = this.m_objModifyQuery.getInsertValue(this.m_strInsertValue);

	if (Utils.isEmpty(this.m_strSelect))
	{
		return "INSERT INTO " + strTable + "(" + strField + ") VALUES (" + strValue + ") ";
	}

	return "INSERT INTO " + strTable + "(" + strField + ") " + this.m_strSelect + " ";
}

OuterQuery.prototype.getUpdateQuery = function ()
{
	var strTable = this.m_objModifyQuery.getTable(this.m_strTable);
	var strField = this.m_objModifyQuery.getField(this.m_strField);
	var strWhere = this.m_objModifyQuery.getWhere(this.m_strWhere);

	return "UPDATE " + strTable + " SET " + strField + " WHERE " + strWhere;
}

OuterQuery.prototype.getDeleteQuery = function ()
{
	var strTable = this.m_objModifyQuery.getTable(this.m_strTable);
	var strWhere = this.m_objModifyQuery.getWhere(this.m_strWhere);

	var strQuery = "";
	if (false == Utils.isEmpty(strTable))
	{
		strQuery = "DELETE FROM " + strTable;

		if (false == Utils.isEmpty(strWhere))
		{
			strQuery = strQuery + " WHERE " + strWhere;
		}
	}

	return strQuery;
}

/**
 * 테이블절을 이용해서 앨리어스 목록을 만든다.
 * @return map:<테이블명, <_OWNER_()테이블명, 앨리어스>> 
 */
OuterQuery.prototype.makeTableAlias = function ()
{
	if (false == g_bQWPClientMode)
	{
		return;
	}
	
	var hmTableAlias = new Hashtable ();
	
	if (0 == this.m_strTable.length)
	{
		return hmTableAlias;
	}
	else if (-1 == this.m_strTable.indexOf(" "))
	{
		var arAlias = new Array(2);
		arAlias[0] = this.m_strTable;
		arAlias[1] = "";
		hmTableAlias[this.removeOwnerKeyword(this.m_strTable)] = arAlias;
		return hmTableAlias;
	}

	//테이블 단위로 쪼개는 구분단위는 ','(쉼표), 'inner join', 'left outer join', 'full outer join' 또는 'left join'이다.
	var arTables = this.m_strTable.split(/,|INNER JOIN|LEFT OUTER JOIN|FULL OUTER JOIN|LEFT JOIN/gi)
	
	for (var i = 0; i < arTables.length; i++)
	{
		var strSource = Utils.trim(arTables[i]);
		var strTableName = this.getTableName(strSource);
		var strAliasName = this.getAliasName(strSource);

		if (!Utils.isEmpty(strTableName) && !Utils.isEmpty(strAliasName))
		{
			var strOwnerTableName = strTableName;
			//_OWNER_( 가 있다면 제거해야 한다. 실제 테이블명이 아닌 부분이니까.
			strTableName = this.removeOwnerKeyword(strTableName);

			var arAlias = new Array(2);
			arAlias[0] = strOwnerTableName;
			arAlias[1] = strAliasName;
			hmTableAlias[strTableName] = arAlias;
		}
	}

	return hmTableAlias;
}

/**
 * _OWNER_() 키워드 부분을 제거한다.
 * @param strSource "[_OWNER_()]테이블명"
 * @return "테이블명"
 */
OuterQuery.prototype.removeOwnerKeyword = function (strSource)
{
	var strData = strSource;
	if (-1 < strData.indexOf("_OWNER_("))
	{
		if (-1 < strData.indexOf(")"))
		{
			strData = strData.substring(strData.lastIndexOf(")") + 1);
		}
	}

	return strData;
}

/**
 * 유효한 테이블명을 리턴한다.
 * @param strSource "[_OWNER_()]테이블명 [앨리어스명]"
 * @return "[_OWNER_()]테이블명"
 */
OuterQuery.prototype.getTableName = function (strSource)
{
	if (Utils.isEmpty(strSource))
	{
		return "";
	}

	var strData = Utils.trim(strSource);
	var strTableName = strData;
	if (0 < strData.indexOf(" "))
	{
		strData = strData.substring(0, strData.indexOf(" "));
		//_OWNER_( 가 있다면 제거해야 한다. 실제 테이블명이 아닌 부분이니까.
		strTableName = this.removeOwnerKeyword(strData);
	}
	
	/*
	 * TODO : 패턴 때문에 구현되지 않았음
	if (!SqlQueryLib.isValidIdentifier(strTableName))
	{
		strData = "";
	}
	*/

	return strData;
}

/**
 * 유효한 앨리어스명을 리턴한다.
 * 'AS'에 대한 처리는 안 되어있음.
 * @param strSource "[_OWNER_()]테이블명 [["]앨리어스명["]]"
 * @return "앨리어스명"
 */
OuterQuery.prototype.getAliasName = function (strSource)
{
	if (Utils.isEmpty(strSource))
	{
		return "";
	}

	//앨리어스명은 테이블명 다음에 공백으로 구분돼서 붙는다.
	//앨리어스명 뒤에 공백으로 구분돼서 다른 구문이 올 수 있다.
	//앨리어스명은 큰따옴표로 감싸져있을 수 있다.
	var strData = Utils.trim(strSource);
	if (0 < strData.indexOf(" "))
	{
		strData = Utils.trim(strData.substring(strData.indexOf(" ")));
		if (0 < strData.indexOf(" "))
		{
			strData = Utils.trim(strData.substring(0, strData.indexOf(" ")));
			if (strData.charAt(0) == '"')
			{
				if (!g_objQueryLib.isValidQuotedIdentifier(strData))
				{
					strData = "";
				}
			}
			else
			{
				if (!g_objQueryLib.isValidIdentifier(strData))
				{
					strData = "";
				}
			}
		}
	}
	else
	{
		strData = "";
	}

	return strData;
}

/**
 * 스크립트의 '기본조건'에 값을 설정할 때 사용한다.
 * @param strWhere 조건절
 */
OuterQuery.prototype.setScriptWhere = function (strWhere)
{
	var strLeftJoin = this.getLeftJoin(strWhere);
	if (0 < strLeftJoin.length)
	{
		this.setTable(this.makeLeftJoinTableStatement(strLeftJoin));
	}
	this.m_strWhere = this.makeWhereStatement(strWhere);
}

OuterQuery.prototype.setAppendWhere = function (strAppendWhere)
{
	this.m_strAppendWhere = strAppendWhere;
}

OuterQuery.prototype.getLeftJoin = function (strWhereStmt)
{
	var strLeftJoin = "";

	if (0 == strWhereStmt.length)
	{
		return strLeftJoin;
	}

	var strCond = strWhereStmt.toUpperCase();
	var nPos = -1;
	if (-1 < (nPos = strCond.indexOf("$LEFT")) || 
			-1 < (nPos = strCond.indexOf("$ LEFT")) || 
			-1 < (nPos = strCond.indexOf("$[J_")) || 
			-1 < (nPos = strCond.indexOf("$ [J_")))
	{
		strLeftJoin = strWhereStmt.substring(nPos + 1);
	}

	return strLeftJoin;
}

/**
 * Left Join 공통문법을 가공한 새로운 Table절을 만든다.
 * @param strLeftJoin "(([J_LEFT])|(LEFT))"
 * @return "테이블명 [J_LEFT]{}"
 */
OuterQuery.prototype.makeLeftJoinTableStatement = function (strLeftJoinClause)
{
	var alJoinTable = new Array();

	var strLeftJoin = strLeftJoinClause;
	var strResult = "";
	var nNot   = 0;
	var nIndex = strLeftJoin.indexOf ("#");

	while (-1 != nIndex)
	{
		nNot++;
		var strData = strLeftJoin.substring (0, nIndex);
		if (0 == nNot % 2 && 0 < strData.length) //#테이블명# 처리
		{
			var nPeriod = strData.lastIndexOf(".");
			var strOrgTable = (-1 != nPeriod) ? strData.substring(nPeriod+1) : strData;
			var strOwnerTable = parsingTableNameFromOwnerTable(strOrgTable);
			strData = Utils.trim(strOwnerTable);

			alJoinTable.add(strData); // owner붙인 table을 저장한다.

			var strAlias = this.getTableAlias(strOrgTable, strOwnerTable);
			if (0 < strAlias.length)
			{
				strData = strData + " " + strAlias;
			}
		}
		strResult = strResult + strData;
		strLeftJoin = strLeftJoin.substring(nIndex+1);
		nIndex = strLeftJoin.indexOf ("#");
	}

	if (strLeftJoin.length > 0)
	{
		strResult = strResult + strLeftJoin;
	}

	strResult = this.appendLeftJoinStatement(strResult, alJoinTable);
	strResult = this.executeTableAliasing(strResult);

	return strResult;
}

/**
 * 오른쪽 테이블 명에 Left Join 절을 붙인다.
 * @param strLeftJoin "^(LEFT)"
 * @param alJoinTable left join 에 포함된 테이블명들
 * @return "테이블명 LEFT{}" 
 */
OuterQuery.prototype.appendLeftJoinStatement = function (strLeftJoin, alJoinTable)
{
	if (null == this.m_htTableAlias)
		return "";

	var strOwnerTableName = "";
	var arAlias = null;

	for (var strTableName in m_htTableAlias)
	{
		arAlias = this.m_htTableAlias[strTableName];
		if (null == alJoinTable || -1 == alJoinTable.indexOf(arAlias[0]))
		{
			if (0 < strOwnerTableName.length)
			{
				strOwnerTableName = strOwnerTableName + ", ";
				strOwnerTableName = strOwnerTableName + arAlias[0];
			}
			else
			{
				strOwnerTableName = arAlias[0];
			}

			var strAlias = this.getTableAlias(strTableName, strOwnerTableName);
			if (0 < strAlias.length)
			{
					strOwnerTableName = strOwnerTableName + " " + strAlias;
			}
		}
	}

	return Utils.trim((strOwnerTableName + " " + strLeftJoin));
}

/**
 * table aliasing을 실행한다.
 * @param strQueryStatement 쿼리
 * @return 앨리어싱된 쿼리
 */
OuterQuery.prototype.executeTableAliasing = function (strQueryStatement)
{
	if (null == this.m_htTableAlias)
	{
		return strQueryStatement;
	}

	var strQuery = strQueryStatement;
	var hmAliasing = new Hashtable();

	for (var strTable in this.m_htTableAlias)
	{
		var arAlias = this.m_htTableAlias[strTable];

		hmAliasing[strTable] = arAlias[1];
	}

	//#A[테이블명] 형태의 앨리어싱처리
	strQuery = g_objQueryLib.tableAliasingByKeyword(strQuery, hmAliasing);

	//테이블명.필드명 형태의 앨리어싱처리
	strQuery = g_objQueryLib.tableAliasingByMap(strQuery, hmAliasing); 

	return strQuery; 
}

/**
 * TableAlias 목록에서 해당 테이블명의 앨리어스를 리턴하거나 없으면 새로운 앨리어스를 만들어서 리턴한다.
 * @param strTableName "테이블명"
 * @param strOwnerTable "[_OWNER_()]테이블명"
 * @return "앨리어스명"
 */
OuterQuery.prototype.getTableAlias = function (strTableName, strOwnerTable)
{
	var strAlias = "";

	if (Utils.isEmpty(strTableName))
	{
		return strAlias;
	}

	if (null != this.m_htTableAlias)
	{
		var arAlias = this.m_htTableAlias[strTableName];
		if (null != arAlias && 2 <= arAlias.length)
		{
			strAlias = arAlias[1];
		}

		if (Utils.isEmpty(strAlias))
		{
			var nTableAliasCount = this.m_htTableAlias.size();
			strAlias = TableMaster.getAliasStringByIndex(nTableAliasCount);
		}
	}
	else
	{
		//			strAlias = "TAB0";
	}

	this.addTableAlias(strTableName, strOwnerTable, strAlias);

	return strAlias;
}

/**
 * 테이블 앨리어스 목록에 추가한다.
 * @param strTableName "TableName"
 * @param strOwnerTable "[_OWNER_()]TableName"
 * @param strAlias "AliasName"
 */
OuterQuery.prototype.addTableAlias = function (strTableName, strOwnerTable, strAlias)
{
	if (null == strTableName)
	{
		return;
	}

	var strTable = (null == strOwnerTable) ? "" : strOwnerTable;
	var arAlias = new Array (strTable, strAlias);

	this.m_htTableAlias[strTableName] = arAlias;
}

/**
 * LEFT JOIN이 제거되고, aliasing된 where 절을 만든다.
 * @param strWhereStmt "조건절 [$((J_LEFT)|(LEFT))]"
 * @return "앨리어싱된 조건절"
 */
OuterQuery.prototype.makeWhereStatement = function (strWhereStmt)
{
	var strTemp = strWhereStmt.toUpperCase();
	var nPos = -1;
	var strRealCond = strWhereStmt;
	if (-1 < (nPos = strTemp.indexOf("$LEFT")) || 
			-1 < (nPos = strTemp.indexOf("$ LEFT")) ||
			-1 < (nPos = strTemp.indexOf("$[J_")) || 
			-1 < (nPos = strTemp.indexOf("$ [J_")))
	{
		strRealCond =  strWhereStmt.substring(0, nPos);
	}

	//where절 뒤에 붙는 $#테이블명#, #테이블명#을 잘라낸다. (공통문법에서 Left Join 분석에서 발생됨)
	nPos = strRealCond.lastIndexOf("$#");
	if (-1 < nPos)
	{
		strRealCond = Utils.trim(strRealCond.substring(0, nPos));
	}

	strRealCond = this.executeTableAliasing(strRealCond);

	return strRealCond;
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 수정쿼리정보를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function ModifyQuery ()
{
	this.s_NOT_MODIFY = 0;
	this.s_APPEND = 1;
	this.s_CHANGE = 2;
	
	this.s_AND = " AND ";	// where, having
	this.s_COMMA = " , ";	// table, field, order by, group by
	
	this.m_strTable = "";
	this.m_strField = "";
	this.m_strWhere = "";
	this.m_strGroupBy = "";
	this.m_strHaving = "";
	this.m_strOrderBy = "";
	this.m_strUnion = "";
	this.m_strInsertValue = "";
	
	this.m_nTableFlag = this.s_NOT_MODIFY;
	this.m_nFieldFlag = this.s_NOT_MODIFY;
	this.m_nWhereFlag = this.s_NOT_MODIFY;
	this.m_nGroupByFlag = this.s_NOT_MODIFY;
	this.m_nHavingFlag = this.s_NOT_MODIFY;
	this.m_nOrderByFlag = this.s_NOT_MODIFY;
	this.m_nUnionFlag = this.s_NOT_MODIFY;
	this.m_nInsertValueFlag = this.s_NOT_MODIFY;
}

/**
 * 요청을 만든다.
 */
ModifyQuery.prototype.makeRequest = function (xnRequest)
{
	var xnModifyQuery = XmlLib.createChild(xnRequest, "ModifyQuery");
	xnModifyQuery.setAttribute("Table", this.m_strTable);
	xnModifyQuery.setAttribute("Field", this.m_strField);
	xnModifyQuery.setAttribute("Where", this.m_strWhere);
	xnModifyQuery.setAttribute("GroupBy", this.m_strGroupBy);
	xnModifyQuery.setAttribute("Having", this.m_strHaving);
	xnModifyQuery.setAttribute("OrderBy", this.m_strOrderBy);
	xnModifyQuery.setAttribute("Union", this.m_strUnion);
	xnModifyQuery.setAttribute("InsertValue", this.m_strInsertValue);
	
	xnModifyQuery.setAttribute("TableFlag", this.m_nTableFlag);
	xnModifyQuery.setAttribute("FieldFlag", this.m_nFieldFlag);
	xnModifyQuery.setAttribute("WhereFlag", this.m_nWhereFlag);
	xnModifyQuery.setAttribute("GroupByFlag", this.m_nGroupByFlag);
	xnModifyQuery.setAttribute("HavingFlag", this.m_nHavingFlag);
	xnModifyQuery.setAttribute("OrderByFlag", this.m_nOrderByFlag);
	xnModifyQuery.setAttribute("UnionFlag", this.m_nUnionFlag);
	xnModifyQuery.setAttribute("InsertValueFlag", this.m_nInsertValueFlag);
}

/**
 * 결과를 반영한다.
 */
ModifyQuery.prototype.handleResult = function (xnModifyQuery)
{
	this.m_strTable = xnModifyQuery.getAttribute("Table");
	this.m_strField = xnModifyQuery.getAttribute("Field");
	this.m_strWhere = xnModifyQuery.getAttribute("Where");
	this.m_strGroupBy = xnModifyQuery.getAttribute("GroupBy");
	this.m_strHaving = xnModifyQuery.getAttribute("Having");
	this.m_strOrderBy = xnModifyQuery.getAttribute("OrderBy");
	this.m_strUnion = xnModifyQuery.getAttribute("Union");
	this.m_strInsertValue = xnModifyQuery.getAttribute("InsertValue");
	
	this.m_nTableFlag = Number(xnModifyQuery.getAttribute("TableFlag"));
	this.m_nFieldFlag = Number(xnModifyQuery.getAttribute("FieldFlag"));
	this.m_nWhereFlag = Number(xnModifyQuery.getAttribute("WhereFlag"));
	this.m_nGroupByFlag = Number(xnModifyQuery.getAttribute("GroupByFlag"));
	this.m_nHavingFlag = Number(xnModifyQuery.getAttribute("HavingFlag"));
	this.m_nOrderByFlag = Number(xnModifyQuery.getAttribute("OrderByFlag"));
	this.m_nUnionFlag = Number(xnModifyQuery.getAttribute("UnionFlag"));
	this.m_nInsertValueFlag = Number(xnModifyQuery.getAttribute("InsertValueFlag"));
}

ModifyQuery.prototype.init = function ()
{
	this.m_nTableFlag = 0;
	this.m_nFieldFlag = 0;
	this.m_nWhereFlag = 0;
	this.m_nOrderByFlag = 0;
	this.m_nGroupByFlag = 0;
	this.m_nHavingFlag = 0;
	this.m_nUnionFlag = 0;

	this.m_strTable = "";
	this.m_strField = "";
	this.m_strWhere = "";
	this.m_strOrderBy = "";
	this.m_strGroupBy = "";
	this.m_strHaving = "";
	this.m_strUnion = "";
}

ModifyQuery.prototype.getField = function (strOriginField)
{
	return this.getSubQueryString(strOriginField, this.s_COMMA, this.m_strField, this.m_nFieldFlag);
}

/**
 * 원본 부분 쿼리문장과 스크립트로 수정된 부분 쿼리문장을 조합하여 완성된 부분 쿼리문장을 반환합니다.
 */
ModifyQuery.prototype.getSubQueryString = function (strOrgin, strCon, strModify, nType)
{
	var strString = "";

	switch (nType)
	{
	case this.s_NOT_MODIFY :
		strString = strOrgin;
		break;
	case this.s_APPEND :
		strString = strOrgin + strCon + strModify;
		break;
	case this.s_CHANGE :
		strString = strModify;
		break;
	default :
		strString = strOrgin;
	break;
	}

	return strString;
}

ModifyQuery.prototype.getGroupBy = function (strOriginGroupBy)
{
	return this.getSubQueryString(strOriginGroupBy, this.s_COMMA, this.m_strGroupBy, this.m_nGroupByFlag);
}

ModifyQuery.prototype.getOrderBy = function (strOriginOrderBy)
{
	return this.getSubQueryString(strOriginOrderBy, this.s_COMMA, this.m_strOrderBy, this.m_nOrderByFlag);
}

ModifyQuery.prototype.getUnion = function (strUnion)
{
	return this.getSubQueryString(strUnion, this.s_COMMA, this.m_strUnion, this.m_nUnionFlag);
}

/**
 * 인자없는 overriding 함수는 클라이언트 동작에서는 쓰이지 않으므로, 인자가 있는 함수를 사용
 */
ModifyQuery.prototype.getTable = function (strOriginTable)
{
	return this.getSubQueryString(strOriginTable, this.s_COMMA, this.m_strTable, this.m_nTableFlag);
}

ModifyQuery.prototype.getWhere = function (strOrginWhere)
{
	return this.getSubQueryString(strOrginWhere, this.s_AND, this.m_strWhere, this.m_nWhereFlag);
}

ModifyQuery.prototype.getHaving = function (strHaving)
{
	return this.getSubQueryString(strHaving, this.s_AND, this.m_strHaving, this.m_nHavingFlag);
}

ModifyQuery.prototype.getInsertValue = function (strValue)
{
	return this.getSubQueryString(strValue, this.s_COMMA, this.m_strInsertValue, this.m_nInsertValueFlag);
}

/**
 * 문자열 대치여부에 따라 flag값을 반환합니다.
 */
ModifyQuery.prototype.getFlag = function (bAppend)
{
	if (bAppend)
	{
		return this.s_APPEND;
	}
	return this.s_CHANGE;
}

ModifyQuery.prototype.setField = function (strField, bAppend)
{
	this.m_strField = strField;
	this.m_nFieldFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setGroupBy = function (strGroupBy, bAppend)
{
	this.m_strGroupBy = strGroupBy;
	this.m_nGroupByFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setHaving = function (strHaving, bAppend)
{
	this.m_strHaving = strHaving;
	this.m_nHavingFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setInsertValue = function (strValue, bAppend)
{
	this.m_strInsertValue = strValue;
	this.m_nInsertValueFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setOrderBy = function (strOrderBy, bAppend)
{
	this.m_strOrderBy = strOrderBy;
	this.m_nOrderByFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setTable = function (strTable, bAppend)
{
	this.m_strTable = strTable;
	this.m_nTableFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setUnion = function (strUnion, bAppend)
{
	this.m_strUnion = strUnion;
	this.m_nUnionFlag = this.getFlag(bAppend);
}

ModifyQuery.prototype.setWhere = function (strWhere, bAppend)
{
	this.m_strWhere = strWhere;
	this.m_nWhereFlag = this.getFlag(bAppend);
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * SelectQuery, 조회쿼리를 가지고 있다.
 * @author 김지환
 * @since UPS1.0
 */
function SelectQuery (nSQLIndex, // 1
					strTableName, // 2
					strScrollName, // 3
					strNormalQuery, // 4
					strNextQuery, // 5
					strPrevQuery, // 6
					arInputAtomList, // 7
					arOutputAtomList, // 8
					arLoadFieldAtomList) // 9
{
	this.m_nSQLIndex = nSQLIndex;
	this.m_strTableName = strTableName;
	this.m_strScrollName = strScrollName;
	this.m_strNormalQuery = strNormalQuery;
	this.m_strNextQuery = strNextQuery;
	this.m_strPrevQuery = strPrevQuery;
	this.m_arInputAtomList = arInputAtomList;
	this.m_arOutputAtomList = arOutputAtomList;
	this.m_arLoadFieldAtomList = arLoadFieldAtomList;
}

SelectQuery.prototype.getSQLIndex = function ()
{
	return this.m_nSQLIndex;
}

SelectQuery.prototype.getNormalQuery = function () 
{
	return this.m_strNormalQuery;
}
	
SelectQuery.prototype.getPrevQuery = function () 
{
	return this.m_strPrevQuery;
}

SelectQuery.prototype.getNextQuery = function () 
{
	return this.m_strNextQuery;
}

SelectQuery.prototype.getOutputAtomList = function () 
{
	return this.m_arOutputAtomList;
}

SelectQuery.prototype.makeRequest = function (xnRequest)
{
	var xnSelectQuery = XmlLib.createChild(xnRequest, "SelectQuery");
	xnSelectQuery.setAttribute("SQLIndex", this.m_nSQLIndex);
	xnSelectQuery.setAttribute("TableName", this.m_strTableName);
	xnSelectQuery.setAttribute("ScrollName", this.m_strScrollName);
	xnSelectQuery.setAttribute("NormalQuery", this.m_strNormalQuery);
	xnSelectQuery.setAttribute("NextQuery", this.m_strNextQuery);
	xnSelectQuery.setAttribute("PrevQuery", this.m_strPrevQuery);
	
	// InputAtomList
	var xnInputAtomList = XmlLib.createChild(xnSelectQuery, "InputAtomList");
	for (var i = 0; i < this.m_arInputAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arInputAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnInputAtomList);
		}
	}
	
	// OutputAtomList
	var xnOutputAtomList = XmlLib.createChild(xnSelectQuery, "OutputAtomList");
	for (var i = 0; i < this.m_arOutputAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arOutputAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnOutputAtomList);
		}
	}
	
	// LoadFieldAtomList
	var xnLoadFieldAtomList = XmlLib.createChild(xnSelectQuery, "LoadFieldAtomList");
	for (var i = 0; i < this.m_arLoadFieldAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arLoadFieldAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnLoadFieldAtomList);
		}
	}
}



//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * TransactionQuery 정보를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function TransactionQuery (nSQLIndex, strQuery, strTableName, arInputAtomList, arOutputAtomList, arLoadFieldAtomList)
{
	this.m_nSQLIndex = nSQLIndex;
	this.m_strQuery = strQuery;
	this.m_strTableName = strTableName
	this.m_arInputAtomList = arInputAtomList;
	this.m_arOutputAtomList = arOutputAtomList;
    this.m_arLoadFieldAtomList = arLoadFieldAtomList;
}

TransactionQuery.prototype.getTableName = function ()
{
	return this.m_strTableName;
}

TransactionQuery.prototype.getTransactionQuery = function ()
{
	return this.m_strQuery;
}

TransactionQuery.prototype.makeRequest = function (xnRequest)
{
	var xnTransactionQuery = XmlLib.createChild(xnRequest, "TransactionQuery");
	
	xnTransactionQuery.setAttribute("SQLIndex", this.m_nSQLIndex);
	xnTransactionQuery.setAttribute("TableName", this.m_strTableName);
	xnTransactionQuery.setAttribute("Query", this.m_strQuery);
	
	// InputAtomList
	var xnInputAtomList = XmlLib.createChild(xnTransactionQuery, "InputAtomList");
	for (var i = 0; i < this.m_arInputAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arInputAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnInputAtomList);
		}
	}
	
	// OutputAtomList
	var xnOutputAtomList = XmlLib.createChild(xnTransactionQuery, "OutputAtomList");
	for (var i = 0; i < this.m_arOutputAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arOutputAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnOutputAtomList);
		}
	}
	
	// LoadFieldAtomList
	var xnLoadFieldAtomList = XmlLib.createChild(xnTransactionQuery, "LoadFieldAtomList");
	for (var i = 0; i < this.m_arLoadFieldAtomList.length; i=i+1)
	{
		var objAtomVariable = this.m_arLoadFieldAtomList[i];
		if (null != objAtomVariable)
		{
			objAtomVariable.makeRequest(xnLoadFieldAtomList);
		}
	}
}



//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 외부질의중 스토어드프로시져의 파라미터 정보를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function ProcedureParamInfo (strParamName, strProperVarName, nDataType, nDataLength, strValue, nParamDirection, bConstant)
{
	this.m_strParamName = strParamName;
	this.m_strProperVarName = strProperVarName;
	this.m_nDataType = nDataType;
	this.m_nDataLength = nDataLength;
	this.m_strValue = strValue;
	this.m_nParamDirection = nParamDirection;
	this.m_bConstant = bConstant;
}

ProcedureParamInfo.prototype.getProperVarName = function ()
{
	return this.m_strProperVarName;
}

ProcedureParamInfo.prototype.getIsConstant = function ()
{
	return this.m_bConstant;
}

ProcedureParamInfo.prototype.setValue = function (strValue)
{
	this.m_strValue = strValue; 
}

ProcedureParamInfo.prototype.getParamName = function ()
{
	return this.m_strParamName;
}

ProcedureParamInfo.prototype.getDataType = function ()
{
	return this.m_nDataType;
}

ProcedureParamInfo.prototype.getDataLength = function ()
{
	return this.m_nDataLength;
}

ProcedureParamInfo.prototype.getValue = function ()
{
	return this.m_strValue;
}

ProcedureParamInfo.prototype.getParamDirection = function ()
{
	return this.m_nParamDirection;
}
	
/**
 * 요청을 만든다.
 */
ProcedureParamInfo.prototype.makeRequest = function (xnRequest)
{
	var xnParamInfo = XmlLib.createChild(xnRequest, "ProcedureParamInfo");
	xnParamInfo.setAttribute("ParamName", this.m_strParamName);
	xnParamInfo.setAttribute("ProperVarName", this.m_strProperVarName);
	xnParamInfo.setAttribute("DataType", this.m_nDataType);
	xnParamInfo.setAttribute("DataLength", this.m_nDataLength);
	xnParamInfo.setAttribute("Value", this.m_strValue);
	xnParamInfo.setAttribute("ParamDirection", this.m_nParamDirection);
	xnParamInfo.setAttribute("Constant", this.m_bConstant ? "true" : "false");
}

/**
 * 결과를 반영한다.
 */
ProcedureParamInfo.prototype.handleResult = function (xnParamInfo)
{
	this.m_strParamName = xnParamInfo.getAttribute("ParamName");
	this.m_strProperVarName = xnParamInfo.getAttribute("ProperVarName");
	this.m_nDataType = Number(xnParamInfo.getAttribute("DataType"));
	this.m_nDataLength = Number(xnParamInfo.getAttribute("DataLength"));
	this.m_strValue = xnParamInfo.getAttribute("Value");
	this.m_nParamDirection = Number(xnParamInfo.getAttribute("ParamDirection"));
	this.m_bConstant = ("true" == xnParamInfo.getAttribute("Constant"));
}


//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
/**
 * 쿼리에서 InputAtomList, OutputAtomList, LoadFieldAtomList에 들어가는 Atom정보를 관리한다.
 * @author 김지환
 * @since UPS1.0
 */
function AtomVariable (strVarName, strField, strType, bLoadField, strAtomType)
{
	this.m_strVarName = strVarName;
	this.m_strField = strField;
	this.m_strType = strType;
	this.m_bLoadField = bLoadField;
	this.m_strAtomType = strAtomType
}

AtomVariable.prototype.makeRequest = function (xnRequest)
{
	var xnAtomVariable = XmlLib.createChild(xnRequest, "AtomVariable");
	xnAtomVariable.setAttribute("VarName", this.m_strVarName);
	xnAtomVariable.setAttribute("FieldName", this.m_strField);
	xnAtomVariable.setAttribute("FieldType", this.m_strType);
	xnAtomVariable.setAttribute("LoadField", this.m_bLoadField ? "true" : "false");
	xnAtomVariable.setAttribute("AtomType", this.m_strAtomType);
}

AtomVariable.prototype.getVarName = function ()
{
	return this.m_strVarName;
}

AtomVariable.prototype.getAtomType = function ()
{
	return this.m_strAtomType; 
}

AtomVariable.prototype.getFieldType = function ()
{
	return this.m_strType;
}

/**
 * 웹 포탈에서 상세폼을 열기 위한 모듈
 */
function WebConnectionModel ()
{	
}

/**
 * 웹게시판에서 연결모델을 실행한다.
 * @param strPath 연결 주소.
 * @param htConnectionModelInfo 전달값들.
 * @param nTargetType 연결 형태. 0 자신창, 1 새창, 2 부모창.
 * @param strRefAtomVarName 참조아톰명. 
 */
WebConnectionModel.execute = function (strPath, htConnectionModelInfo, nTargetType, strRefAtomVarName)
{
	var strParameter = "";	
	var i = 0;
	for (strItemName in htConnectionModelInfo)
	{
		if (0 == i)
		{
			strParameter += "C="
		}
		else
		{
			strParameter += ",";
		}
		
		var arConnectionInfo = htConnectionModelInfo[strItemName];
		var strItemValue = arConnectionInfo[0];
		strParameter +=  strItemName + ":" + strItemValue;
		
		i += 1;
	}
	
	WebConnectionModel._openProgram(
			strPath, nTargetType, false, 0, 0, strParameter, strRefAtomVarName);
}

/**
 * 연결모델을 엽니다. 
 * @param nRunType 실행형태. 0 프로그램모델, 1 URL.
 * @param strPath 연결 주소.
 * @param nTargetType 연결 형태. 0 자신창, 1 새창, 2 부모창.
 * @param bHideToolbar 도구모음 숨김 여부.
 * @param nWindowHeight 창 높이. 0보다 큰 값만 유효.
 * @param nWindowWidth 창 너비. 0보다 큰 값만 유효.
 * @param strProperVarNames 전달아톰명 값.
 * @param strRefAtomVarName 참조아톰명.
 * @param heAtom 클릭이 일어난 아톰의 태그.
 */
WebConnectionModel.open = function (
	nRunType, strPath, nTargetType, 
	bHideToolbar, nWindowHeight, nWindowWidth,
	strProperVarNames, strRefAtomVarName, heAtom, strScrollName)
{
	if (WebConnectionModel.EXE_PROGRAM == nRunType)
	{
		var strParameter = WebConnectionModel.makeParameter(strProperVarNames, strScrollName, heAtom);
		WebConnectionModel._openProgram(
			strPath, nTargetType, bHideToolbar, nWindowHeight, nWindowWidth, strParameter, strRefAtomVarName);
	}
	else if (WebConnectionModel.EXE_URL == nRunType)
	{		
		WebConnectionModel._openURL(strPath, nTargetType, bHideToolbar, nWindowHeight, nWindowWidth);
	}
}

/**
 * 웹메뉴, 웹하이퍼링크, 웹모델아톰에서 참조변수에 설정된 아톰의 변수와 값을 가지고 링크될 모델에 넘겨줄 인자를 만든다.
 * 형태 -> "C=참조변수명:참조변수값,참조변수명:참조변수값,참조변수명:참조변수값... " 
 */
WebConnectionModel.makeParameter = function (strProperVar, strScrollName, heAtom)
{
	var strParameter = "";
	if (null != strProperVar && 0 < strProperVar.length && (ContainsInputDataAtom() || ContainsRectangleAtom()))
	{
		var arParam = strProperVar.split(",");
		var arValue = new Array(arParam.length);
		
		// 생성조건부분
		for (var i = 0; i < arParam.length; i += 1)
		{
			arParam[i] = Utils.replace(arParam[i], "=", "$");
			
			var arSourceAndDestination = Utils.trim(arParam[i]).split("$");
			
			// 부모폼아톰$자식폼아톰일 경우, 아톰의 값을 가지고 올때는 부모폼아톰으로 찾는다.
			var strProperVarName = arSourceAndDestination[0];
			var arVarName = strProperVarName.split("@");
			var strScrollName;
			
			if (2 == arVarName.length)
			{
				strScrollName = arVarName[0];
				strProperVarName = arVarName[1];
			}
			
			var strDestinationProperVarName = strProperVarName;
			// 부모폼아톰$자식폼아톰일 경우
			if (2 == arSourceAndDestination.length)
			{
				// 파라미터를 만들때는 자식폼아톰의 이름으로 만든다.
				strDestinationProperVarName = arSourceAndDestination[1];
			}
			
			var objProperAtom = Model.getAtom(strProperVarName, strScrollName, heAtom);
			
			var strProperValue = "";
			if (objProperAtom && objProperAtom.getValue)
			{
				strProperValue = objProperAtom.getValue();				
			}
			else if (objProperAtom && objProperAtom.getAtomType && 
					"ReportBrowseAtom" == objProperAtom.getAtomType())
			{
				//검색창의 체크된 행의 값을 세션에 쓴다.
				strProperValue = objProperAtom.getCheckedRowValue();
				PQPortalService.executeSessionService(1, strDestinationProperVarName, strProperValue);
				
				continue;
			}
			else
			{
				if (ContainsReportBrowseAtom())
				{
					var objBrowseAtom = ReportBrowseAtom.getFirstAtom();
					if (objBrowseAtom)
					{
						// 항목명으로 찾는다.
						var nIndex = objBrowseAtom._getItemVarIndexByName(strProperVarName);						
						if (-1 != nIndex)
						{
							strProperValue = objBrowseAtom._getItemValue(objBrowseAtom._getSelectedRow(), nIndex)	
						}
					}					
				}
			}

			if (null != strProperValue && 0 < strProperValue.length)
			{
				if (0 < strParameter.length)
				{
					strParameter += ",";
				}

				strParameter += strDestinationProperVarName + ":" + strProperValue;
			}
		}
		
		if (0 < strParameter.length)
		{
			// C는 생성조건 부분이다.
			strParameter = "C=" + strParameter;
		}
	}
	
	return strParameter;
}

/**
 * 프로그램 모델을 엽니다. 
 * @param strPath 연결 주소.
 * @param nTargetType 연결 형태. 0 자신창, 1 새창, 2 부모창.
 * @param bHideToolbar 도구모음 숨김 여부.
 * @param nWindowHeight 창 높이. 0보다 큰 값만 유효.
 * @param nWindowWidth 창 너비. 0보다 큰 값만 유효.
 * @param strParameter 전달값.
 * @param strRefAtomVarName 참조아톰명.
 */
WebConnectionModel._openProgram = function (
	strPath, nTargetType, bHideToolbar, nWindowHeight, nWindowWidth, strParameter, strRefAtomVarName)
{
	var strRunPath = Utils.removePQPath(Utils.getPathString(strPath));
	
	//일반모델은 솔루션 로그인을 해야 열 수 있다.
	if (!ModelCore.canOpenModel(strRunPath))
	{
		return;
	}
	
	if (0 < strRunPath.indexOf(".QWP"))
	{
		var objModelAtom = Model.getAtom(strRefAtomVarName);
		if (null != objModelAtom && "" != strRefAtomVarName)
		{
			objModelAtom.loadModel(strRunPath, strParameter);
		}
		else
		{
			var strCreateCondition = Utils.getCreateCondition(strRunPath);
			if (null != strParameter && 0 < strParameter.length)
			{
				strParameter = "?" + strParameter + "&D=" + strCreateCondition;
			}
			else
			{
				if (null != strCreateCondition && 0 < strCreateCondition.length)
				{
					strParameter = "?D=" + strCreateCondition;
				}
			}
			
			var strPath = "/ups/" + GetProjectName() + "/";
			if (g_nUPSType == MOBILE_COMMON_UPS)
			{
				strPath = "";
			}
			strPath = strPath + Utils.replace(Utils.getModelName(strRunPath), ".QWP", ".html");
			
			// strPath 에 이미 파라미터가 있을 수 있다.
			if (-1 < strPath.indexOf("?") && 0 == strParameter.indexOf("?"))
			{
				strParameter = "&" + strParameter.substring(1);
			}
						
			strPath = encodeURI(strPath + strParameter);
			
			if (WebConnectionModel.SELF == nTargetType)
			{
				// 현재 윈도우가 임베드된  모델이면 WebModelAtom 정보도 추가한다.
				if (GlobalField.isEmbededModel())
				{
					var strModelAtomName = GlobalField.getWebModelAtomName();
					
					if (null != strParameter && 0 < strParameter.length)
					{
						strPath += "&E=" + encodeURI(strModelAtomName);
					}
					else
					{
						strPath += "?E=" + encodeURI(strModelAtomName);
					}
					
					window.location.href = strPath;
					
					window.parent.WebModelAtom.adjustScroll(strModelAtomName);
					
					//하이퍼 링크 이동시 맨 위로 가게 하기위해.. 추후에 빌더에서 옵션추가 필요 
					window.parent.scrollTo(0,0);
				}
				else
				{
					window.location.href = strPath;
				}
			}
			else if (WebConnectionModel.NEW == nTargetType)
			{					
				Utils.openWindow(strPath, nTargetType, !bHideToolbar, nWindowHeight, nWindowWidth);
			}
			else if (WebConnectionModel.PARENT == nTargetType)
			{
				if (GlobalField.isEmbededModel())
				{
					window.parent.location.href = strPath;
				}
				else
				{
					window.location.href = strPath;
				}
			}
		}
	}
	else if (0 < strRunPath.indexOf(".QMX"))
	{
		var objModelAtom = Model.getAtom(strRefAtomVarName);
		if (null != objModelAtom)
		{
			objModelAtom.changeMenu(strRunPath);
		}
	}
}

/**
 * URL을 엽니다. 
 * @param strRunPath 연결 주소.
 * @param nTargetType 연결 형태. 0 자신창, 1 새창, 2 부모창.
 */
WebConnectionModel._openURL = function (strRunPath, nTargetType, bHideToolbar, nWindowHeight, nWindowWidth)
{
	// PQPath(@path:\\)가 있다면 사용자 프로젝트 폴더가 모든 클라이언트 자원의 root이므로 프로젝트명을 경로에 붙여준다.
	if (-1 < strRunPath.toUpperCase().indexOf("@PATH:\\") || -1 < strRunPath.toUpperCase().indexOf("@PATH:/"))
	{
		strRunPath = "/ups/" + GetProjectName() + "/" + Utils.removePQPath(strRunPath);
	}
	
	// 구글맞춤검색의 URL에 한글이 포함되어 있는 경우 인코딩 해줘야 한다.
	// 이미 인코딩된 URI 일 가능성이 있으므로 디코딩 한번 하고, 인코딩 해준다.
	strRunPath = decodeURI(strRunPath);
	strRunPath = encodeURI(strRunPath); 
	
	if (WebConnectionModel.SELF == nTargetType)
	{
		window.open(strRunPath, "_self");
	}
	else if (WebConnectionModel.NEW == nTargetType)
	{
		if(bHideToolbar)
		{
			window.open(strRunPath,'','height='+nWindowHeight+',width='+nWindowWidth+', titlebar = no , menubar=no, toolbar=no, scrollbars=yes, resizable=yes,scrollbars=yes,status=yes');
		}
		else
		{
			var strSize = "";
			if (0 < nWindowHeight && 0 < nWindowWidth)
			{
				strSize = 'height='+nWindowHeight+',width='+nWindowWidth+', ';
			}
			window.open(strRunPath, '', strSize + 'titlebar = yes , menubar=yes, toolbar=yes, scrollbars=yes, resizable=yes,scrollbars=yes,status=yes');
		}
	}
	else if (WebConnectionModel.PARENT == nTargetType)
	{
		window.open(strRunPath, "_top");
	}
}

WebConnectionModel.EXE_PROGRAM = 0;
WebConnectionModel.EXE_URL = 1;

WebConnectionModel.SELF = 0;
WebConnectionModel.NEW = 1;
WebConnectionModel.PARENT = 2;

/**
 * 웹 아톰의 크기 변화에 의해 크기 및 위치의 영향을 받게 되는 아톰들을 찾아, 
 * 크기 및 위치를 변화시켜 주는 class 입니다 
 *
 * 현재 (2008. 03. 04) ResizableObject 를 가지고 있는 웹 아톰으로 
 * - 웹 게시판
 * - 웹 스크롤 게시판
 * 이 있습니다
 * 
 * ResizableObject에 크기의 변화를 받을수 있는 아톰으로는
 * - 사각형(둥근사각형, 원 포함) 아톰
 * - 직선그리기 아톰
 * - 웹 슬라이드 메뉴
 * - 웹 트리 메뉴
 * 이 있습니다
 *
 * ResizableObject에 의해 위치의 변경을 받을수 있는 아톰으로는 
 * - 사각형(둥근사각형, 원 포함) 아톰
 * - 직선그리기 아톰
 * - 버튼 아톰 
 * - 입력란 아톰
 * - 날짜입력란 아톰
 * - 그림삽입 아톰
 * - 콤보 아톰
 * - 웹 하이퍼링크 아톰
 * 이 있습니다 
 *
 * 위의 사항에 변경이 있을 경우 누락없이 업데이트 해 주세요
 */
function ResizableObject (strBoundsStatusInfos)
{
	this.m_alBoundsStatusInfos = new Array();
	
	// 위치 및 크기 변환 정보를 초기화 합니다
	{
		var arBoundsStatusInfoList = strBoundsStatusInfos.split(";");
		
		for (var i = 0, nLen = arBoundsStatusInfoList.length; i < nLen; i = i + 1)
		{
			var arBoundsStatus = arBoundsStatusInfoList[i].split("$");
			
			if (null != arBoundsStatus && 2 == arBoundsStatus.length)
			{
				var objBoundsStatusInfo = 
				{
					VarName : arBoundsStatus[0],
					BoundStatus : arBoundsStatus[1]
				}
				
				this.m_alBoundsStatusInfos.push(objBoundsStatusInfo);
			}
		}
	}
}

/**
 * 인자로 넘어온 변경 값을 기준으로 
 * 크기를 변경하거나
 * 위치를 변경한다
 * 
 * @param nResizableValue (가변 값)
 */
ResizableObject.prototype.commitBoundsStatus = function (nHeightValue, nWidthValue)
{
	for (var i = 0; i < this.m_alBoundsStatusInfos.length; i += 1)
	{
		var objBoundsStatusInfo = this.m_alBoundsStatusInfos[i];
		var objAtom = Model.getAtom(objBoundsStatusInfo.VarName);
		var nBoundStatus = Utils.parseInt(objBoundsStatusInfo.BoundStatus);
		
		// 스크롤에 묶여 있는 아톰은 연계효과 시키지 않는다. 스크롤 아톰만 연계효과시 이동한다
		if (null != objAtom && null != objAtom.isScroll && objAtom.isScroll())
		{
			continue;
		}
		
		switch (nBoundStatus)
		{
			case 0 : // 상하 크기 변경
				this._resizeHeight(objAtom, nHeightValue);
				break;
			case 1 : // 상하 위치 변경
				this._repositionYPos(objAtom, nHeightValue); 
				break;
			case 2 : // 좌우 크기  변경
				this._resizeWidth(objAtom, nWidthValue);
				break;
			case 3 : // 좌우 위치 변경
				this._repositionXPos(objAtom, nWidthValue);
				break;
		}
	}
	
	// 임베드 모델이고 현재창의 크기가 컨탠츠보다 작은경우  상위폼의 모델삽입 아톰의 크기를 변겨해줘야 한다.
	if (GlobalField.isEmbededModel())
	{
		var nModelResizeHeight = 0; 
		var nModelResizeWidth = 0;
			
		nModelResizeHeight = document.body.scrollHeight - document.body.offsetHeight;
		nModelResizeWidth = document.body.scrollWidth - document.body.offsetWidth;
		
		if (0 != nModelResizeHeight || 0 != nModelResizeWidth)
		{
			this._commitModelBoundsStatus(nModelResizeHeight, nModelResizeWidth);
		}
	}
}

/**
 * 상위폼의 모델삽입 아톰의 크기를 변겨해줘야 한다.
 */
ResizableObject.prototype._commitModelBoundsStatus = function (nHeightValue, nWidthValue)
{
	var strWebModelAtomName = GlobalField.getWebModelAtomName();
	var objOuterWindow = this._getOuterWindow();
	
	if (null != objOuterWindow && 0 < strWebModelAtomName.length)
	{
		if (objOuterWindow.WebModelAtom.resize)
		{
			objOuterWindow.WebModelAtom.resize(strWebModelAtomName, nHeightValue, nWidthValue);
		}
	}
}

/**
 * Embed모델을 품고 있는 윈도우를 찾아온다.
 */
ResizableObject.prototype._getOuterWindow = function (strWebModelAtomName)
{
	if (window.self != window.parent)
	{
		return window.parent;
	}
}

ResizableObject.prototype._resizeHeight = function (objAtom, nResizableValue)
{
	if (null != objAtom)
	{
		var heAtom = objAtom.getHTML();
		
		// 0보다 클 때만
		if (null != heAtom && 0 < heAtom.offsetHeight + nResizableValue)
		{
			objAtom.resizeHeight(nResizableValue);
		}
	}
}

ResizableObject.prototype._resizeWidth = function (objAtom, nResizableValue)
{
	if (null != objAtom)
	{
		var heAtom = objAtom.getHTML();
		
		// 0보다 클 때만
		if (null != heAtom && 0 < heAtom.offsetWidth + nResizableValue)
		{
			objAtom.resizeWidth(nResizableValue);
		}
	}
}

ResizableObject.prototype._repositionYPos = function (objAtom, nResizableValue)
{
	if (null == objAtom || 0 == nResizableValue)
	{
		return;
	}
	
	objAtom.repositionYPos(nResizableValue);
}

ResizableObject.prototype._repositionXPos = function (objAtom, nResizableValue)
{
	if (null == objAtom || 0 == nResizableValue)
	{
		return;
	}
	
	objAtom.repositionXPos(nResizableValue);
}

