/***************************************************************************
                   Service Change Class (ServiceChange.cpp)
                -----------------------------------------

	begin      : 2013/03/14
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/03/14 - 1st dadamin
	email      : dev1@solbox.com
	version    : 3.2.0

	CopyRight(C) 2005 Solbox Inc. All Rights reserved.
	Redistribution and use in source and binary forms, with or with out
	modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "rc_mngd.h"
#include "Job.h"
#include "ServiceChange.h"
#include "RcMngdControl.h"
#include "JobData.h"
#include "Logger.h"

#define  RCTX_XML_SSL_PORT 13112

CServiceChange::CServiceChange()
{

}

CServiceChange::~CServiceChange()
{

}

int CServiceChange::run( CJobDataMap &jobData )
{
	int r = JOB_SUCCESS;
	_LOG( LDBG, "Job Service Change running...");

	// rcdb
	CRCDBControl rcdb;

	if( rcdb.Init() != 0 )
	{
		LOG( LERR, "RCDB Initialization failed.");
		return JOB_ERR_CREATION_FAIL;
	}
	
	while ( 1 )
	{
		int t = 0;
		bool userexist = true;
		bool productexist = true;

		// check user info : Must have.		
		t = ExistUser(rcdb, jobData);
		if ( t < 0 )
		{	
			r = t;
			LOG(LERR, "user information check error.");
			break;
		}

		if(t == 0) 
		{
			r = JOB_ERR_USER_EMPTY;
			LOG(LERR, "In order to change the service information, user information is required.");
			break;
		}

		// check product info 
		if( FindInSubKey(jobData, JOB_SERVICE_CHG_USER) == false)
		{
			t = ExistProduct(rcdb, jobData);
			if( t < 0 )
			{
				r = t;
				LOG(LERR, "Service Product check error.");
				break;
			}

			if ( t == 0 )
			{
				r = JOB_ERR_PRODUCT_EMPTY;
				LOG(LERR, "In order to change the service information, basic service information is required.");
				break;
			}
		}

		// change user
		if( FindInSubKey(jobData, JOB_SERVICE_CHG_USER))
		{
			// check subkey
			if(IsSubKey(jobData, JOB_SERVICE_CHG_USER_PW))
			{
				// change user info
			}
			else 
			{
				r = JOB_ERR_NOT_FOUND_JOB;
			}

			if(r != JOB_ERR_NOT_FOUND_JOB)
			{
				r = SetUser(rcdb, jobData);
			}

			break;
		}
		
		// change product
		if( FindInSubKey(jobData, JOB_SERVICE_CHG_PRODUCT))
		{
			if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_STORAGE))
			{
				// change storage 
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_BANDWIDTH))
			{
				// change bandwidth
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_PERIOD))
			{
				// change period
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_AUTHINFO))
			{
				// change auth 
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_REPLICATION))
			{
				// change replication_count
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_STORAGE_CAL))
			{
				// change cal_used_depth
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_IGNORE_CASE))
			{
				// change uri_ignore_case
				// 2014.06.16 dadamin
				// 정책 체크하여 t_sms_sp_svc_product 값을 변경함
				r = ChkPolicyIgnoreCase(rcdb, jobData);
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_IGNORE_CASE_FROCE))
			{
				// change uri_ignore_case
				// 2014.06.16 dadamin
				// 정책 체크 없이 t_sms_sp_svc_product 값을 변경함
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_PRODUCT_DEL_FILE_KEEP_TIME))
			{
				// change del_file_keep_time
			}
			else 
			{
				r = JOB_ERR_NOT_FOUND_JOB;
			}

			if(r == JOB_SUCCESS)
			{
				r = SetProduct(rcdb, jobData);
			}

			break;
		}

		// change extension auth
		if ( FindInSubKey(jobData, JOB_SERVICE_CHG_EXAUTH) )
		{
			if (IsSubKey(jobData, JOB_SERVICE_CHG_EXAUTH_MODE))
			{

			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_EXAUTH_INFO))
			{
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_EXAUTH_REFERER_CHK))
			{

			}
			else 
			{
				r = JOB_ERR_NOT_FOUND_JOB;
			}

			if (r == JOB_SUCCESS)
			{
				if(jobData[KEY_REQ_EXT_AUTH_SET].compare("1") == 0 )
				{
					jobData[KEY_VALIDATE_SP_SESSION_ID_YN] = "Y";
				}
				else if ( jobData[KEY_REQ_EXT_AUTH_UNSET].compare("1") == 0 )
				{
					jobData[KEY_VALIDATE_SP_SESSION_ID_YN] = "N";
				}
				else
				{

				}

				r = SetExtAuth(rcdb, jobData);
			}
			break;
		}

		// change bandwidth control
		if ( FindInSubKey(jobData, JOB_SERVICE_CHG_BAND) )
		{
			if (IsSubKey(jobData, JOB_SERVICE_CHG_BAND_MODE))
			{

			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_BAND_VOLUME_LIMIT))
			{

			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_BAND_SESSION_LIMIT))
			{

			}
			else 
			{
				r = JOB_ERR_NOT_FOUND_JOB;
			}

			if (r == JOB_SUCCESS)
			{
				if(jobData[KEY_REQ_BAND_LIMIT_SET].compare("1") == 0 )
				{
					jobData[KEY_BANDWIDTH_CTRL_YN] = "Y";
				}
				else if ( jobData[KEY_REQ_BAND_LIMIT_UNSET].compare("1") == 0 )
				{
					jobData[KEY_BANDWIDTH_CTRL_YN] = "N";
				}
				else
				{

				}

				r = SetBandCtl(rcdb, jobData);
			}

			break;
		}

		// change status
		if (FindInSubKey(jobData, JOB_SERVICE_CHG_STATUS))
		{
			if (jobData[KEY_REQ_SVC_STATUS].compare(SERVICE_STATUS_REMOVE) == 0)
			{
				r = RemoveService(rcdb, jobData);
			}
			else
			{
				r = JOB_SUCCESS;
				LOG(LWAR, "Service Change(%s|%s) job SKIP & SUCCESS.[%s@%s][code:%s]",
					jobData[KEY_JOBSUB_TYPE].c_str(), jobData[KEY_REQ_SVC_STATUS].c_str(),
					jobData[KEY_SP_SVC_ID].c_str(), jobData[KEY_SP_USER_ID].c_str(),
					jobData[KEY_REQ_SVC_STATUS].c_str());
			}

			break;
		}

		// change sync
		if (FindInSubKey(jobData, JOB_SERVICE_CHG_SYNC))
		{
			jobData[KEY_REQ_SVC_STATUS] = jobData[KEY_REQ_LINK_CODE];
			r = SetSyncLink(rcdb, jobData);
			break;
		}

		// change rcts
		if (FindInSubKey(jobData, JOB_SERVICE_CHG_MOVE))
		{
			if (IsSubKey(jobData, JOB_SERVICE_CHG_MOVE_RQE))
			{
	
			}
			else if (IsSubKey(jobData, JOB_SERVICE_CHG_MOVE_COMP))
			{

			}
			else
			{
				r = JOB_ERR_NOT_FOUND_JOB;
			}

			if (r == JOB_SUCCESS)
			{
				r = SetSvcMove(rcdb, jobData);
			}

			break;
		}

		break;
	}

	if (r == JOB_SKIP)
	{
		LOG(LNOT, "Service Change(%s|%s) SKIP.[%s@%s]",
			jobData[KEY_JOBSUB_TYPE].c_str(), jobData[KEY_REQ_SVC_STATUS].c_str(),
			jobData[KEY_SP_SVC_ID].c_str(), jobData[KEY_SP_USER_ID].c_str());
	}
	else if (r != JOB_SUCCESS)
	{
		// pgpool 3.0.9 이전 버전 경우 다이나믹 쿼리 수행 후 동일 세션을 사용 시
		// pgpool 비정상 종료 현상이 발생하기 때문에 사용한 Pool을 강제 종료 시킴
		rcdb.ForceClose();
		LOG(LERR, "Service Change(%s|%s) error.[%d][%s@%s]", 
				jobData[KEY_JOBSUB_TYPE].c_str(), jobData[KEY_REQ_SVC_STATUS].c_str(), r,
				jobData[KEY_SP_SVC_ID].c_str(),	jobData[KEY_SP_USER_ID].c_str());
	}
	else 
	{
		_LOG(LINF, "Service Change(%s|%s) success.[%s@%s]",
				jobData[KEY_JOBSUB_TYPE].c_str(), jobData[KEY_REQ_SVC_STATUS].c_str(),
				jobData[KEY_SP_SVC_ID].c_str(),	jobData[KEY_SP_USER_ID].c_str());
	}

	rcdb.Final();

	_LOG( LDBG, "Job Service Change End.");
	return r ;
}

int CServiceChange::SetUser(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;

	bool userexist = true;
	do
	{		
		// set		
		if( rcdb.SetUserInfo(jobData, userexist) == false)
		{
			r = JOB_ERR_SET_USER;
		}

	} while (false);

	return r;
}

int	CServiceChange::SetProduct(CRCDBControl &rcdb, CJobDataMap &jobData)
{

	int r = JOB_SUCCESS;

	bool product = true;
	do
	{		
		// set

		if ( rcdb.SetProductInfo(jobData, product) == false )
		{
			r = JOB_ERR_SET_PRODUCT;
		}
	} while (false);

	return r;
}

int CServiceChange::SetExtAuth(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;

	bool product = true, exist = true;
	do
	{		
		// check info
		if( rcdb.CheckProductExtAuth(jobData, exist) == false)
		{
			r= JOB_ERR_CHK_PRODUCT_EXTAUTH;
			break;
		}

		// set
		if( !rcdb.BeginTrans() )
		{
			r = JOB_ERR_RCDB_BEGIN_TRANS;
			break;
		}

		if ( rcdb.SetProductInfo(jobData, product) == false )
		{
			r = JOB_ERR_SET_PRODUCT;
		}

		if ( r == 0 )
		{
			if( rcdb.SetProductExtAuth(jobData, exist) == false )
			{
				r = JOB_ERR_SET_PRODUCT_EXTAUTH;
			}			
		}

		rcdb.SetSuccess( (r == 0) );
		if( !rcdb.EndTrans() )
		{
			r = JOB_ERR_RCDB_END_TRANS;
			break;
		}
	} while (false);

	return r;
}

int CServiceChange::SetBandCtl(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;
	bool product = true, exist = true;
	do
	{
		// check info
		if( rcdb.CheckProductExtBand(jobData, exist) == false)
		{
			r= JOB_ERR_CHK_PRODUCT_BAND;
			break;
		}

		// set
		if( !rcdb.BeginTrans() )
		{
			r = JOB_ERR_RCDB_BEGIN_TRANS;
			break;
		}

		if ( rcdb.SetProductInfo(jobData, product) == false )
		{
			r = JOB_ERR_SET_PRODUCT;
		}

		if ( r == 0 && rcdb.SetProductBand(jobData, exist) == false )
		{
			r = JOB_ERR_SET_PRODUCT_EXTAUTH;
		}

		rcdb.SetSuccess((r == JOB_SUCCESS));
		if( !rcdb.EndTrans() )
		{
			r = JOB_ERR_RCDB_END_TRANS;
			break;
		}
	} while (false);

	return r;
}

int CServiceChange::SetSyncLink(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;
		
	if (jobData[KEY_REQ_LINK_ONE_WAY] == SYNC_LINK_ONE_WAY)
	{
		bool exist = false;
		if (rcdb.CheckProductSync(jobData, exist) == true)
		{
			if (rcdb.SetProductSync(jobData, exist) == false)
				r = JOB_ERR_SET_PRODUCT_SYNC;
		}
		else 
			r = JOB_ERR_SET_PRODUCT_SYNC;
	}
	else
	{
		CRcMngdControl ctl;
		if (ctl.Connect(jobData[KEY_LINK_RCTS].c_str(), RCTX_XML_SSL_PORT))
		{
			struct LinkInfo s, t;

			s.master = (jobData[KEY_LINK_MASTER_YN] == "Y" ? true : false);
			s.linkuserseq = jobData[KEY_LINK_USER_SEQ];
			s.linksvcseq = jobData[KEY_LINK_SP_SVC_TRAN_ID];
			s.linkrcts = jobData[KEY_LINK_RCTS];

			t.master = (jobData[KEY_LINK_MASTER_YN] == "Y" ? false : true);
			t.linkuserseq = jobData[KEY_SP_USER_SEQ];
			t.linksvcseq = jobData[KEY_SP_SVC_TRAN_ID];
			t.linkrcts = jobData[KEY_SELF_RCTS];

			if (ctl.LinkRequest(s, t, jobData[KEY_REQ_LINK_CODE].c_str()) == false)
				r = JOB_ERR_SET_PRODUCT_SYNC;
		}
		else 
			r = JOB_ERR_SET_PRODUCT_SYNC;
	}

	return r;
}

int CServiceChange::SetSvcMove(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;
	CRcMngdControl ctl;
	if (ctl.Connect(jobData[KEY_REQ_MOVE_NEW_RCTS].c_str(), RCTX_XML_SSL_PORT))
	{
		if (IsSubKey(jobData, JOB_SERVICE_CHG_MOVE_RQE))
		{
			if (ctl.MoveRequest(jobData[KEY_SP_USER_SEQ].c_str(),
						jobData[KEY_SP_SVC_TRAN_ID].c_str(), 
						jobData[KEY_REQ_MOVE_NOW_RCTS].c_str()) == false)
				r = JOB_ERR_SET_PRODUCT_MOVE;
		}
		else if (IsSubKey(jobData, JOB_SERVICE_CHG_MOVE_COMP))
		{
			if (ctl.MoveCompleted(jobData[KEY_SP_USER_SEQ].c_str(),
					jobData[KEY_SP_SVC_TRAN_ID].c_str(),
					jobData[KEY_REQ_MOVE_NOW_RCTS].c_str()) == false)
				r = JOB_ERR_SET_PRODUCT_MOVE;
		}
	}
	else 
		r = JOB_ERR_SET_PRODUCT_MOVE;

	return r;
}

int	CServiceChange::RemoveService(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;
	bool exist = true, another = true;
	jobData[KEY_DEL_DIR_USED] = "Y";
	jobData[KEY_DEL_ROOT] = "Y";
	jobData[KEY_BANDWIDTH_CTRL_YN] = "N";
	jobData[KEY_VALIDATE_SP_SESSION_ID_YN] = "N";
	jobData[KEY_DEL_PRODUCT] = "Y";
	jobData[KEY_DEL_USER_INFO] = "Y";
	jobData[KEY_REQ_LINK_CODE] = SYNC_LINK_CODE_UNLINK;
		
	if (rcdb.HasFile(jobData, exist))
	{
		if (!exist)
		{
			exist = true;
			do
			{
				if (!rcdb.CheckAnotherProduct(jobData, another))
				{
					r = JOB_ERR_CHK_ANOTHER_PRODUCT;
					break;
				}

				if (!rcdb.BeginTrans())
				{
					r = JOB_ERR_RCDB_BEGIN_TRANS;
					break;
				}

				// del root
				if (!rcdb.SetRootInfo(jobData, exist))
				{
					r = JOB_ERR_DEL_ROOT_INFO;
				}

				// del volume info
				if (r == 0 && !rcdb.SetVolumeInfo(jobData, exist))
				{
					r = JOB_ERR_DEL_VOLUME_INFO;
				}

				// del product band
				if (r == 0 && !rcdb.SetProductBand(jobData, exist))
				{
					r = JOB_ERR_DEL_PRODUCT_BAND;
				}

				// del product  extension auth
				if (r == 0 && !rcdb.SetProductExtAuth(jobData, exist))
				{
					r = JOB_ERR_DEL_PRODUCT_EXTAUTH;
				}

				// del product sync
				if (r == 0 && !rcdb.SetProductSync(jobData, exist))
				{
					r = JOB_ERR_DEL_PRODUCT_SYNC;
				}

				// del product
				if (r == 0 && !rcdb.SetProductInfo(jobData, exist))
				{
					r = JOB_ERR_DEL_PRODUCT;
				}

				// del user
				if (r == 0 && another == false && !rcdb.SetUserInfo(jobData, exist))
				{
					r = JOB_ERR_DEL_USER;
				}

				rcdb.SetSuccess((r == 0));
				if (!rcdb.EndTrans())
				{
					r = JOB_ERR_RCDB_END_TRANS;
					break;
				}
			} while (false);
		}
		else
			r = JOB_ERR_HAS_FILE;
	}
	else
		r = JOB_ERR_CHK_HAS_FILE;

	return r;
}

#define  POLICY_IGNORECASE_LIMIT 500
int CServiceChange::ChkPolicyIgnoreCase(CRCDBControl &rcdb, CJobDataMap &jobData)
{
	int r = JOB_SUCCESS;

	bool ignorecase = false;
	bool b = rcdb.CheckUriIgnoreCase(jobData, ignorecase);

	if (b == false)
		return JOB_ERR_CHK_POLICY_IGNORECASE;

	// 메타 정보 체크
	uint64_t total = 0;
	uint64_t limit = POLICY_IGNORECASE_LIMIT + 1;
	b = rcdb.GetTotalCntFiles(jobData, total, limit);

	if (b == false)
		return JOB_ERR_CHK_POLICY_IGNORECASE;
	
	if (ignorecase)
	{
		// 무시 => 구분(가능)
		if (jobData[KEY_URI_IGNORE_CASE] == "N")
		{			
			// 메타 정보 500 rows 초과 : 변경 허용되지 않음
			if (total == limit)
			{
				LOG(LWAR, "Ignore case does not allow for change(%d over).[%s: Y => N]"
					, POLICY_IGNORECASE_LIMIT, jobData[KEY_SP_SVC_TRAN_ID].c_str());
				r = JOB_SKIP;
			}				
			else
			{
				//r = JOB_SUCCESS;
				// 메타 변경 작업
				if (rcdb.SetMetaIgnoreCase(jobData, false) == true)
					r = JOB_SUCCESS;
				else
					r = JOB_ERR_CHK_POLICY_IGNORECASE;
			}				
		}			
	}
	else
	{
		// 구분 => 무시(불가능)
		if (jobData[KEY_URI_IGNORE_CASE] == "Y")
		{
			// 메타 정보 0 : 변경 허용
			if (total == 0)
				// tran_id 숫자이므로 메타 정보 변경 필요 없음
				r = JOB_SUCCESS;
			else
			{
				r = JOB_SKIP;
				LOG(LWAR, "Ignore case does not allow for change.[%s: N => Y]"
					, jobData[KEY_SP_SVC_TRAN_ID].c_str());
			}
				
		}
	}
	
	return r;
}
