/***************************************************************************
                Synchronization
                -----------------------------------------
	begin      : 2012/05/13
	copyright  : (C) 2011 SolutionBox Inc.
	author     : Service 1 Team
	email      : svc1@solbox.com
	version    : 3.1.0

    CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
    Redistribution and use in source and binary forms, with or with out
    modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/

#include "rc_cmove.h"
#include "synchronization.h"
#include "Database.h"
#include "dbconnpool.h"
#include "FtsdSocketControl.h"
#include "parameter.h"

#include "Logger.h"
#include "ReportLog.h"

#define FHS_TRANSFER_DAEMON_PORT	14001
#define EXPIRED_TIME				(1*60*60)
// second
#define MAX_TIMEOUT_PER_FILE		3

#define FTSD_HASH_LEVEL				1

#define ORG_PREFIX		"/stg/nodex"

CSynchronization::CSynchronization(JOB_TYPE::JOB_TYPE type, vector<string>& syncdata)
	: m_type(type), m_syncdata(syncdata), m_exit(false)
{
}

CSynchronization::~CSynchronization()
{
	m_exit = true;
}

void CSynchronization::SetTragetHost(vector<string> &src)
{
	m_vecTargetFHS.clear();
	m_vecTargetFHS.resize(src.size());
	copy( src.begin(), src.end(), m_vecTargetFHS.begin() );
}

DataBase* CSynchronization::GetDB(string & tblname, bool & usedisplay)
{
	ostringstream msg;
	string s = m_syncdata[SYNCFILE_FIELD::slave_tran_id];

	if (s.empty())
	{
		msg << "Service information empty.";
		LOGACERR(LERR, msg);
		return NULL;
	}

	DataBase* db = masterdbpool::getInstance()->GetConnFromPool();
	tblname = masterdbpool::getInstance()->GetMetaTableName(s.c_str());
	usedisplay = masterdbpool::getInstance()->UseDisplayname();

	if (db == NULL)
	{
		msg << "DB POOL doesn't assign a database..";
		LOGACERR(LERR, msg);
		return NULL;
	}

	return db;
}

void CSynchronization::FreeDB(DataBase *db, bool success/* = true*/)
{
	if (db)
	{
		masterdbpool::getInstance()->ReleaseConnToPool(db, success);
		db = NULL;
	}
}

bool CSynchronization::GetTargetFHS(string & targethost)
{
	ostringstream msg;

	string tblname;
	bool usedisplay = true;

	// 해당 파일을 가지고 있는 서버 추출
	string hashost;
	if (GetHostHasFile(hashost) == false)
		return false;

	if (hashost.size())
	{
		if (m_syncdata[SYNCFILE_FIELD::host_name].size())
			hashost = "{" + m_syncdata[SYNCFILE_FIELD::host_name] + "," + hashost + "}";
		else 
			hashost = "{" + hashost + "}";
	}		
	else
	{
		hashost = "{" + m_syncdata[SYNCFILE_FIELD::host_name] + "}";
	}
	
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return false;
	
	vector<string> vechosts = m_vecTargetFHS;
	ostringstream sql;
	
	if (vechosts.empty())
	{
		sql << "SELECT fhs_hostname FROM t_fhs_top_status ";
		sql << "WHERE lastupdate >= (NOW() - interval'01 minute') ";

		sql << "AND NOT fhs_hostname = ANY( $1 ) ";

		const char *paramValues[1];
		paramValues[0] = hashost.c_str();

		msg << "SQL : " << sql.str() << ", value : " << paramValues[0];
		LOGACOUT(LDBG, msg);

		// Query 실행
		db->PgDoExecParams((char*)sql.str().c_str(), 1, paramValues);

		// Query 결과를 가져온다.
		int nResult = db->PgResult(DataBase::NOT_CLEAR);
		if (nResult < 0)
		{
			db->PgClear();
			msg << "Top FHS lookup failed.(" << db->GetErrorMessage() << ") [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACERR(LERR, msg);
			FreeDB(db, false);

			return false;
		}

		for (int i = 0; i < db->GetNoTuples(); i++)
		{
			vechosts.push_back(db->GetValue(i, 0));
		}

		db->PgClear();
	}
	else
	{
		vector<string> tmp = vechosts;
		vechosts.clear();
		while (tmp.size())
		{
			tmp.front();
			string fhs = tmp.front();
			tmp.erase(tmp.begin());

			size_t found = hashost.find(fhs);
			if (found == string::npos)
			{
				if (m_type == JOB_TYPE::MOVE)
				{
					// 동일 RC 체크 : Cloud Storage FHS 도메인 규칙에 따라 5자리 동일 유무 체크 
					// bd-16-fhs002.ktsh.co.kr => bd-16
					if (strncasecmp(fhs.c_str(), m_syncdata[SYNCFILE_FIELD::host_name].c_str(), 5) != 0)
					{
						msg << "Target host : " << fhs << " : RC is not the same." << "[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
						LOGACERR(LWAR, msg);
						continue;
					}
				}

				vechosts.push_back(fhs);
			}
			else
			{
				msg << "Target host : " << fhs << " : File exists." << "[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
				LOGACERR(LWAR, msg);
			}
		}
	}
	FreeDB(db, true);

	if (vechosts.empty())
	{
		msg << "Target Host Empty.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);
		return false;
	}

	targethost = vechosts[rand() % vechosts.size()];

	msg << "Target Host : " << targethost << "[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
	LOGACOUT(LDBG, msg);

	return true;
}

bool CSynchronization::ReqFileTrans(string & strsrc, vector<string>& vecdest)
{
	ostringstream msg;
	bool ret = false;

	bool bUseInternalIp = false;

	if (m_type == JOB_TYPE::MOVE)
	{
		switch (m_networkmode)
		{
		case 0:
			bUseInternalIp = true;
			break;
		case 1:
			bUseInternalIp = false;
			break;
		case 2:
			bUseInternalIp = (rand() % 2 ? true : false);
			break;
		default:
			bUseInternalIp = false;
			break;
		}
	}

	CFtsdSocketControl sockObj;

	int trycount = 0;
	while (trycount < 3)
	{
		// src FHS connection
		ret = sockObj.ConnectTarget(strsrc, FHS_TRANSFER_DAEMON_PORT);
		if (ret == false)
		{
			if (3 > trycount)
			{
				++trycount;
				solusleep(10000);
				continue;
			}

			msg << "FHS connection fail. host : [" << strsrc << "]["
				<< m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACERR(LERR, msg);

			CReportLog rlog;

			if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
			{
				rlog.Write("ERR", "[%s] [%s]", PROG_NAME, msg.str().c_str());
			}

			return false;
		}

		break;
	}
	

	unsigned long long nsTmp = strtoull(m_syncdata[SYNCFILE_FIELD::get_content_length].c_str(), NULL, 10);
	ret = sockObj.SendFileReplicationRequest(m_syncdata[SYNCFILE_FIELD::filename_hash], nsTmp,
		m_syncdata[SYNCFILE_FIELD::slave_tran_id], FTSD_HASH_LEVEL, bUseInternalIp, vecdest);

	if (ret == false)	{
		msg << "FHS SendFileRequest fail. host : [" << strsrc << "]["
			<< m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);

		return false;
	}


	// check request result 
	// timeout check
	time_t timeStart;
	time_t timeNow;
	timeStart = time(&timeStart);

	map<string, string> mapSuccessFhs;
	map<string, string> mapFailFhs;

	while (!m_exit)
	{
		if (difftime(time(&timeNow), timeStart) > EXPIRED_TIME)
		{ // EXPIRED_TIME
			msg << "FHS SendFileRequest Receive Time Expired : [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACERR(LERR, msg);

			ret = false;
			break;
		}

		bool success = false;
		string errmsg;

		ret = sockObj.GetFileReplicationResult(MAX_TIMEOUT_PER_FILE, success, errmsg, mapSuccessFhs, mapFailFhs);

		if (ret == -1) {
			msg << "FHS SendFileRequest Socket was broken : [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACERR(LERR, msg);

			ret = false;
			break;
		}
		else if (ret == 0) {
			if (sockObj.SendAliveCheck() == false)	{
				sleep(1);
			}
			continue;
		}
		else if (ret == 1) {
			if (success == true) {
				if (mapFailFhs.size() > 0)
				{
					ret = false;
					errmsg += "Host : ";
					errmsg += strsrc;
					errmsg += " => ";
					map<std::string, std::string>::iterator iterFailFhs;
					for (iterFailFhs = mapFailFhs.begin(); iterFailFhs != mapFailFhs.end(); iterFailFhs++) {
						errmsg += iterFailFhs->second;
						errmsg += " | ";
					}

					msg << "FHS SendFileRequest fail Result : (" << errmsg << ").[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";

					CReportLog rlog;

					if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
					{
						rlog.Write("ERR", "[%s] [%s]", PROG_NAME, msg.str().c_str());
					}
					LOGACERR(LERR, msg);
				}
				else
				{
					msg << "FHS SendFileRequest OK : [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
					_LOGACOUT(LDEV2, msg);

					ret = true;
					m_syncdata[SYNCFILE_FIELD::filename_hash].clear();
					map<std::string, std::string>::iterator iterSuccessFhs;
					for (iterSuccessFhs = mapSuccessFhs.begin(); iterSuccessFhs != mapSuccessFhs.end(); iterSuccessFhs++) 
					{
						m_syncdata[SYNCFILE_FIELD::filename_hash] = iterSuccessFhs->second;
					}
				}
			}
			else {
				msg << "FHS SendFileRequest BAD Result : (Host :" << strsrc 
					<< "," << errmsg << ").[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
				CReportLog rlog;

				if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
				{
					rlog.Write("ERR", "[%s] [%s]", PROG_NAME, msg.str().c_str());
				}
				LOGACERR(LERR, msg);

				ret = false;
			}
			break;
		}
		else if (ret == 2) {
			// Ignore it
			msg << "FHS SendFileRequest Ignore it.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACOUT(LDBG, msg);
			continue;
		}
		else {
			msg << "FHS SendFileRequest Unknown Result : [Host :" << strsrc << "," << ret << "]";
			LOGACERR(LERR, msg);

			ret = false;
			break;
		}

	}

	return ret;
}

string CSynchronization::ChgFilenamehash()
{
	string r;

	if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
	{
		LOG(LDBG, "[%s] isn't file.",
			m_syncdata[SYNCFILE_FIELD::uri].c_str());
		return r;
	}

	if (m_type == JOB_TYPE::COPY)
	{
		//m_syncdata[SYNCFILE_FIELD::filename_hash]
		unsigned found = m_syncdata[SYNCFILE_FIELD::filename_hash].find_last_of("/");
		string hash = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] +
			m_syncdata[SYNCFILE_FIELD::filename_hash].substr(found);
		if (m_fhsmount.size())
		{
			for (vector<string>::size_type i = 0; i < m_fhsmount.size(); ++i)
			{
				if (i > 0)
					r += ",";
				r += m_fhsmount[i] + hash;
			}
		}
		else
		{
			LOG(LWAR, "FHS mount empty.[%s]", m_syncdata[SYNCFILE_FIELD::uri].c_str());

			r = m_syncdata[SYNCFILE_FIELD::filename_hash];
		}
	}
	else
	{
		r = m_syncdata[SYNCFILE_FIELD::filename_hash];
	}

	r = StringReplace(r, "{", "\\{");
	r = StringReplace(r, "}", "\\}");

	r = "{" + r + "}";

	LOG(LDBG, "Useing SQL filename_hash : %s => %s",
		m_syncdata[SYNCFILE_FIELD::filename_hash].c_str(),
		r.c_str());

	return r;

}

string CSynchronization::MakeFilenameorg()
{
	string r;

	if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
	{
		LOG(LDBG, "[%s] isn't file.",
			m_syncdata[SYNCFILE_FIELD::uri].c_str());
		return r;
	}

	unsigned found;
	string filename;
	if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY 
		|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
	{
		found = m_syncdata[SYNCFILE_FIELD::src_uri].find_last_of("/");
		filename = m_syncdata[SYNCFILE_FIELD::src_uri].substr(found);
	}
	else
	{
		found = m_syncdata[SYNCFILE_FIELD::uri].find_last_of("/");
		filename = m_syncdata[SYNCFILE_FIELD::uri].substr(found);
	}

	// fixed prefix : /stg/nodex/...
	r = ORG_PREFIX;
	r += "/";
	r += m_syncdata[SYNCFILE_FIELD::slave_tran_id];
	r += filename;
		
	LOG(LDBG, "Make filename org [%s:%s].", 
				m_syncdata[SYNCFILE_FIELD::uri].c_str(),
				r.c_str());

	return r;
}

bool CSynchronization::GetSource(string & srchost, string & srchash)
{
	ostringstream msg;
	string tblname;
	bool usedisplay = true;

	string filehash = ChgFilenamehash();
	string srcuri = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] + m_syncdata[SYNCFILE_FIELD::src_uri];

	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return false;
	
	int index = 1;
	ostringstream sql;

	sql << "SELECT ";

	if (usedisplay)
		sql << "display_name, ";
	else
		sql << "uri, ";

	sql << "filename_hash, host_name ";
	sql << "FROM " << tblname << " ";
	sql << "WHERE ";

	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
		sql << " uri = lower($1) ";
	else 
		sql << " uri = $1 ";

	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		index = 2;
		sql << "AND ";
		sql << "filename_hash = ANY ($2) ";
	}

	sql << "AND ";
	sql << "resource_type = " << m_syncdata[SYNCFILE_FIELD::resource_type] << " ";

	sql << "AND ";
	sql << "get_content_length = " << m_syncdata[SYNCFILE_FIELD::get_content_length] << " ";

	sql << "AND ";
	sql << "deleted_yn = 'N' ";

	sql << "AND ";
	sql << "is_cache = 'N' ";

	const char *paramValues[2];

	paramValues[0] = srcuri.c_str();
	paramValues[1] = filehash.c_str();

	msg << "SQL : " << sql.str() << ", value : " << paramValues[0] << "," << paramValues[1];
	LOGACOUT(LDEV1, msg);

	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	int nResult = db->PgResult(DataBase::NOT_CLEAR);
	if (nResult < 0)
	{	
		msg << "Get Source lookup failed.(" << db->GetErrorMessage() << ") [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);
		db->PgClear();
		FreeDB(db, false);

		return false;
	}

	bool r = false;
	if (db->GetNoTuples() > 1)
	{
		msg << "The duplicate files.[uri:" << srcuri << "]";
		LOGACERR(LERR, msg);
	}
	else if (db->GetNoTuples() == 1)
	{
		r = true;
		srchash = db->GetValue(0, 1);
		srchost = db->GetValue(0, 2);
	}
	else
	{
		msg << "Source Not Found.[uri:" << srcuri << "]";
		LOGACERR(LERR, msg);		
	}
	
	db->PgClear();
	FreeDB(db, true);

	return r;
}

bool CSynchronization::GetHostHasFile(string & srchosts)
{
	ostringstream msg;
	string tblname;
	bool usedisplay = true;

	string filehash;

	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		unsigned found = m_syncdata[SYNCFILE_FIELD::filename_hash].find_last_of("/");
		string hash = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] +
			m_syncdata[SYNCFILE_FIELD::filename_hash].substr(found);
		filehash += "{";
		if (m_fhsmount.size())
		{
			for (vector<string>::size_type j = 0; j < m_fhsmount.size(); ++j)
			{
				if (j > 0)
					filehash += ",";
				filehash += m_fhsmount[j] + hash;
			}
		}
		else
		{
			LOG(LWAR, "FHS mount empty.[%s]", m_syncdata[SYNCFILE_FIELD::uri].c_str());

			filehash = m_syncdata[SYNCFILE_FIELD::filename_hash];
		}
		filehash += "}";
	}

	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return false;

	int index = 1;
	ostringstream sql;

	sql << "SELECT ";
	sql << "host_name ";
	sql << "FROM " << tblname << " ";

	sql << "WHERE ";
	const char *paramValues[2];
	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		sql << "filename_hash = ANY ($1) ";
		paramValues[0] = filehash.c_str();
	}
	else
	{
		if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
			sql << " uri = lower($1) ";
		else
			sql << " uri = $1 ";

		paramValues[0] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	}

	sql << "AND ";
	sql << "deleted_yn = 'N' ";

	msg << "SQL : " << sql.str() << ", value : " << paramValues[0] ;
	LOGACOUT(LDEV1, msg);

	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	int nResult = db->PgResult(DataBase::NOT_CLEAR);
	if (nResult < 0)
	{
		msg << "Find a server that has a file failed.(" << db->GetErrorMessage() << ") [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);
		db->PgClear();
		FreeDB(db, false);

		return false;
	}

	for (int i = 0; i < db->GetNoTuples(); ++i)
	{
		if (i > 0)
			srchosts += ",";
		srchosts += db->GetValue(i, 0);
	}

	db->PgClear();
	FreeDB(db, true);

	return true;
}

int CSynchronization::Deleted()
{
	int r = 0;
	ostringstream msg;
	msg << "		URI = "	<< m_syncdata[SYNCFILE_FIELD::uri] << ", HASH = " << m_syncdata[SYNCFILE_FIELD::filename_hash];
	LOGACOUT(LDBG, msg);

	string tblname;
	bool usedisplay = true;
	int index = 2;
	
	DataBase *db = GetDB(tblname, usedisplay);
	if (db == NULL)
		return -311;

	ostringstream sql;

	sql << "UPDATE " << tblname << " ";
	sql << "SET deleted_yn = 'Y', get_lastmodified = $1 ";
	sql << "WHERE ";

	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case]== "Y")
	{
		sql << "uri = lower($2) ";
	}
	else
	{
		sql << "uri = $2 ";
	}

	// use hash 
	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		index = 3;
		sql << "AND ";
		sql << "filename_hash = ANY($3) ";
	}

	sql << "AND ";
	sql << "resource_type = " << m_syncdata[SYNCFILE_FIELD::resource_type] << " ";

	sql << "AND ";
	sql << "deleted_yn = 'N' ";

	const char *paramValues[3];

	ostringstream tmp;
	tmp << longtime_now();
	
	string strNow, strhash; 
	strNow = tmp.str(); tmp.str("");
	strhash = ChgFilenamehash();

	paramValues[0] = strNow.c_str();
	paramValues[1] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	paramValues[2] = strhash.c_str();

	msg << "SQL - " << sql.str();
	msg << ", Value - " << paramValues[0] << "," << paramValues[1] << "," << paramValues[2];

	LOGACOUT(LDEV1, msg);
	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::CLEAR) < 0)
	{
		FreeDB(db, false);
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);

		return -312;
	}
	
	FreeDB(db, true);

	msg << "DELETE SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";	
	LOGACOUT(LINF, msg);
	
	return r;
}

int CSynchronization::Syned()
{
	int r = 0;
	ostringstream msg,tmp;
	msg << "		URI = " << m_syncdata[SYNCFILE_FIELD::uri] << ", HASH = " << m_syncdata[SYNCFILE_FIELD::filename_hash];
	LOGACOUT(LDBG, msg);

	if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
	{
		msg << FLAG_SYNC << " is only supported only file.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]"; 
		LOGACERR(LERR, msg);
		return -321;
	}

	string srcfhs, destfhs;
	srcfhs = m_syncdata[SYNCFILE_FIELD::host_name];
	if (GetTargetFHS(destfhs) == false)
	{
		return -322;
	}

	string fileorg = MakeFilenameorg();

	int depth = StringCount(m_syncdata[SYNCFILE_FIELD::uri], "/") - 1;
	tmp << depth;	
	string strdepth = tmp.str(); tmp.str("");

	vector<string> vecdestfhs;
	vecdestfhs.push_back(destfhs);
	
	string srchash, desthash;
	srchash = m_syncdata[SYNCFILE_FIELD::filename_hash];	
	if (ReqFileTrans(srcfhs, vecdestfhs) == false)
	{
		return -323;
	}

	desthash = m_syncdata[SYNCFILE_FIELD::filename_hash];

	if (srchash.empty() || desthash.empty())
	{
		CReportLog rlog;
		if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
		{
			rlog.Write("ERR", "[%s] [failed SYNC filename_hash empty caution.[uri :%s(src:%s,dest:%s)]]"
				, PROG_NAME, m_syncdata[SYNCFILE_FIELD::uri].c_str()
				, srchash.c_str(), destfhs.c_str()
				);
		}

		return -326;
	}

	msg << "SYNC : " << srchash << " => " << desthash;
	LOGACOUT(LDBG, msg);

	string tblname;
	bool usedisplay = true;
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return -324;

	ostringstream sql;
	sql << "INSERT INTO " << tblname << " ";
	sql << "(";
	sql << "sp_user_seq, ";
	sql << "sp_svc_tran_id, host_name, resource_type, display_name, ";
	sql << "uri, ";
	sql << "filename_org, filename_hash, depth, ";
	sql << "creation_date, get_content_length, get_content_type, ";
	sql << "get_lastmodified, source, deleted_yn, is_cache ";
	sql << ", file_lastmodified ";
	sql << ") ";

	sql << "SELECT ";
	sql << "(SELECT sp_user_seq FROM t_sms_sp_svc_product WHERE sp_svc_tran_id = $1)";
	sql << ", $2, $3, $4, $5";
	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
		sql << ", lower($6)";
	else 
		sql << ", $6";
	sql << ", $7, $8, $9";
	sql << ", $10, $11, $12";
	sql << ", $13, $14, $15, $16";
	sql << ", $17 ";

	tmp << longtime_now();

	string strNow;
	strNow = tmp.str(); tmp.str("");

	int index = 17;
	const char *paramValues[17];

	//sql << "sp_user_seq, "
	paramValues[0] = m_syncdata[SYNCFILE_FIELD::slave_tran_id].c_str();
	//sql << "sp_svc_tran_id, host_name, resource_type, display_name, ";
	paramValues[1] = m_syncdata[SYNCFILE_FIELD::slave_tran_id].c_str();
	paramValues[2] = destfhs.c_str();
	paramValues[3] = m_syncdata[SYNCFILE_FIELD::resource_type].c_str();
	paramValues[4] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	//sql << "uri, "
	paramValues[5] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	//sql << "filename_org, filename_hash, depth, ";
	paramValues[6] = fileorg.c_str();
	paramValues[7] = desthash.c_str();
	paramValues[8] = strdepth.c_str();
	//sql << "creation_date, get_content_length, get_content_type, ";
	paramValues[9] = m_syncdata[SYNCFILE_FIELD::creation_date].c_str();
	paramValues[10] = m_syncdata[SYNCFILE_FIELD::get_content_length].c_str();
	paramValues[11] = m_syncdata[SYNCFILE_FIELD::get_content_type].c_str();
	//sql << "get_lastmodified, source, deleted_yn, is_cache ";
	paramValues[12] = strNow.c_str();
	// fixed 
	paramValues[13] = "0";
	paramValues[14] = "N";
	paramValues[15] = "N";
	//sql << ", file_lastmodified ";
	paramValues[16] = m_syncdata[SYNCFILE_FIELD::file_lastmodified].c_str();
	
	msg << "SQL - " << sql.str() << endl;
#ifdef _DEBUG
	msg << "Value 1 - " << paramValues[0] << "," << paramValues[1] << "," << paramValues[2];
	msg << "Value 2 - " << paramValues[1] << "," << paramValues[2] << "," << paramValues[3];
	msg << "Value 3 - " << paramValues[4] << "," << paramValues[5] << "," << paramValues[6];
	msg << "Value 4 - " << paramValues[7] << "," << paramValues[8] << "," << paramValues[9];
	msg << "Value 5 - " << paramValues[10] << "," << paramValues[11] << "," << paramValues[12];
	msg << "Value 6 - " << paramValues[13] << "," << paramValues[14] << "," << paramValues[15];
	msg << "Value 7 - " << paramValues[16] ;
#endif // _DEBUG

	LOGACOUT(LDEV1, msg);
	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::CLEAR) < 0)
	{
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);
		FreeDB(db, false);
		return -325;	
	}

	FreeDB(db, true);

	msg << "SYNC SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
	LOGACOUT(LINF, msg);
	
	return r;
}

int CSynchronization::NSyned()
{
	int r = 0;
	ostringstream msg, tmp;
	msg << "        URI = " << m_syncdata[SYNCFILE_FIELD::uri] << ", HASH = " << m_syncdata[SYNCFILE_FIELD::filename_hash];
	LOGACOUT(LDBG, msg);

	string srcfhs, destfhs;

	ostringstream sql;

	bool is_lastmodified = true;

	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_DIR)
	{
		srcfhs = m_syncdata[SYNCFILE_FIELD::host_name];
		if (srcfhs.empty())
		{
			if (GetTargetFHS(destfhs) == false)
			{
				return -331;
			}

			is_lastmodified = false;
		}
	}

	string filehash = ChgFilenamehash();
	string fileorg = MakeFilenameorg();

	string tblname;
	bool usedisplay = true;
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return -332;

	int index = 0;
	const char *paramValues[17];

	tmp << longtime_now();

	string strNow;
	strNow = tmp.str(); tmp.str("");

	int depth = StringCount(m_syncdata[SYNCFILE_FIELD::uri], "/") - 1;
	tmp << depth;
	string strdepth = tmp.str(); tmp.str("");

	if (is_lastmodified)
	{
		sql << "UPDATE " << tblname << " ";
		sql << "SET file_lastmodified = $1, get_lastmodified = $2 ";
		sql << "WHERE ";

		if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
		{
			sql << "uri = lower($3) ";
		}
		else
		{
			sql << "uri = $3 ";
		}

		index = 3;
		if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
		{ 
			sql << "AND  filename_hash = ANY($4) ";
			index = 4;
		}

		sql << "AND resource_type = " << m_syncdata[SYNCFILE_FIELD::resource_type] << " ";
		sql << "AND deleted_yn = 'N' ";

		paramValues[0] = m_syncdata[SYNCFILE_FIELD::file_lastmodified].c_str();
		paramValues[1] = strNow.c_str();
		paramValues[2] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
		paramValues[3] = filehash.c_str();
	}
	else
	{
		// insert ??? 
		sql << "INSERT INTO " << tblname << " ";
		sql << "(";
		sql << "sp_user_seq, ";
		sql << "sp_svc_tran_id, host_name, resource_type, display_name, ";
		sql << "uri, ";
		sql << "depth, ";
		sql << "creation_date, get_content_length, get_content_type, ";
		sql << "get_lastmodified, source, deleted_yn, is_cache ";
		sql << ", file_lastmodified ";
		sql << ") ";

		sql << "SELECT ";
		sql << "(SELECT sp_user_seq FROM t_sms_sp_svc_product WHERE sp_svc_tran_id = $1)";
		sql << ", $2, $3, $4, $5";
		if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
			sql << ", lower($6)";
		else
			sql << ", $6";
		sql << ", $7";
		sql << ", $8, $9, $10";
		sql << ", $11, $12, $13, $14";
		sql << ", $15 ";

		index = 15;
		//sql << "sp_user_seq, ";
		paramValues[0] = m_syncdata[SYNCFILE_FIELD::slave_tran_id].c_str();
		//sql << "sp_svc_tran_id, host_name, resource_type, display_name, ";
		paramValues[1] = m_syncdata[SYNCFILE_FIELD::slave_tran_id].c_str();
		paramValues[2] = destfhs.c_str();
		paramValues[3] = m_syncdata[SYNCFILE_FIELD::resource_type].c_str();
		paramValues[4] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
		//sql << "uri, ";
		paramValues[5] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
		//sql << "depth, ";
		paramValues[6] = strdepth.c_str();
		//sql << "creation_date, get_content_length, get_content_type, ";
		paramValues[7] = m_syncdata[SYNCFILE_FIELD::creation_date].c_str();
		paramValues[8] = m_syncdata[SYNCFILE_FIELD::get_content_length].c_str();
		paramValues[9] = m_syncdata[SYNCFILE_FIELD::get_content_type].c_str();
		//sql << "get_lastmodified, source, deleted_yn, is_cache ";
		paramValues[10] = strNow.c_str();;
		paramValues[11] = "0";
		paramValues[12] = "N";
		paramValues[13] = "N";
		//sql << ", file_lastmodified ";
		paramValues[14] = m_syncdata[SYNCFILE_FIELD::file_lastmodified].c_str();
	}

	msg << "SQL - " << sql.str() << endl;
	LOGACOUT(LDEV1, msg);

	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::CLEAR) < 0)
	{
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);
		FreeDB(db, false);
		return -333;
	}

	FreeDB(db, true);

	msg << "NSYNC SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
	LOGACOUT(LINF, msg);
		
	return r;
}

int CSynchronization::Copy()
{
	int r = 0;
	ostringstream msg, tmp;
	msg << "		URI = " << m_syncdata[SYNCFILE_FIELD::uri] << ", HASH = " << m_syncdata[SYNCFILE_FIELD::filename_hash];
	LOGACOUT(LDBG, msg);

	if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
	{
		msg << FLAG_COPY << " is only supported only file.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);
		return -341;
	}

	string srchost, srchash;
	if (GetSource(srchost, srchash) == false)
	{
		return -342;
	}

	string fileorg = MakeFilenameorg();
	
	string tblname;
	bool usedisplay = true;
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return -343;

	int index = 0;
	const char *paramValues[17];

	tmp << longtime_now();

	string strNow;
	strNow = tmp.str(); tmp.str("");

	int depth = StringCount(m_syncdata[SYNCFILE_FIELD::uri], "/") - 1;
	tmp << depth;
	string strdepth = tmp.str(); tmp.str("");

	ostringstream sql;
	// insert ??? 
	sql << "INSERT INTO " << tblname << " ";
	sql << "(";
	sql << "sp_user_seq, ";
	sql << "sp_svc_tran_id, host_name, resource_type, display_name, ";
	sql << "uri, ";
	sql << "filename_org, filename_hash, depth, ";
	sql << "creation_date, get_content_length, get_content_type, ";
	sql << "get_lastmodified, source, deleted_yn, is_cache ";
	sql << ", file_lastmodified ";
	sql << ") ";

	sql << "SELECT ";
	sql << "(SELECT sp_user_seq FROM t_sms_sp_svc_product WHERE sp_svc_tran_id = $1)";
	sql << ", $2, $3, $4, $5";
	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
		sql << ", lower($6)";
	else
		sql << ", $6";
	sql << ", $7, $8, $9";
	sql << ", $10, $11, $12";
	sql << ", $13, $14, $15, $16";
	sql << ", $17 ";

	index = 17;
	//sql << "sp_user_seq, ";
	paramValues[0] = m_syncdata[SYNCFILE_FIELD::slave_tran_id].c_str();
	//sql << "sp_svc_tran_id, host_name, resource_type, display_name, ";
	paramValues[1] = m_syncdata[SYNCFILE_FIELD::slave_tran_id].c_str();
	paramValues[2] = srchost.c_str();
	paramValues[3] = m_syncdata[SYNCFILE_FIELD::resource_type].c_str();
	paramValues[4] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	//sql << "uri, ";
	paramValues[5] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	// sql << "filename_org, filename_hash, depth, ";
	paramValues[6] = fileorg.c_str();
	paramValues[7] = srchash.c_str();
	paramValues[8] = strdepth.c_str();
	//sql << "creation_date, get_content_length, get_content_type, ";
	paramValues[9] = m_syncdata[SYNCFILE_FIELD::creation_date].c_str();
	paramValues[10] = m_syncdata[SYNCFILE_FIELD::get_content_length].c_str();
	paramValues[11] = m_syncdata[SYNCFILE_FIELD::get_content_type].c_str();
	//sql << "get_lastmodified, source, deleted_yn, is_cache ";
	paramValues[12] = strNow.c_str();
	paramValues[13] = "0";
	paramValues[14] = "N";
	paramValues[15] = "N";
	//sql << ", file_lastmodified ";
	paramValues[16] = m_syncdata[SYNCFILE_FIELD::file_lastmodified].c_str();

	LOGACOUT(LDEV1, msg);
	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::CLEAR) < 0)
	{
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);
		FreeDB(db, false);
		return -344;
	}

	FreeDB(db, true);

	msg << "COPY SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
	LOGACOUT(LINF, msg);

	return r;
}
int CSynchronization::MoveTypeCopy()
{
	int r = 0;
	ostringstream msg, tmp;
	if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
	{
		msg << FLAG_MOVE << " is only supported only file.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);
		return -351;
	}

	string srchost, srchash;
	if (GetSource(srchost, srchash) == false)
	{
		return -352;
	}

	string fileorg = MakeFilenameorg();
	string fullhash = ChgFilenamehash();

	string tblname;
	bool usedisplay = true;
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return -353;

	int index = 0;
	const char *paramValues[6];

	ostringstream sql;

	sql << "UPDATE " << tblname << " ";
	sql << "SET get_lastmodified = $1";
	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
		sql << ", uri = lower($2) ";
	else 
		sql << ", uri = $2 ";
	sql << ", display_name = $2 ";
	sql << ", depth = $3 ";

	sql << "WHERE ";

	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
	{
		sql << "uri = lower($4) ";
	}
	else
	{
		sql << "uri = $4 ";
	}

	// rc_rmcd와 충돌을 막기 위해서 host 제거
	//sql << "AND ";
	//sql << "host_name = $5 ";
	
	// use hash 
	index = 4;
	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		index = 5;
		sql << "AND ";
		sql << "filename_hash = ANY($" << index << ") ";
	}

	sql << "AND ";
	sql << "resource_type = " << m_syncdata[SYNCFILE_FIELD::resource_type] << " ";

	sql << "AND ";
	sql << "deleted_yn = 'N' ";

	tmp << longtime_now();

	string strNow;
	strNow = tmp.str(); tmp.str("");

	int depth = StringCount(m_syncdata[SYNCFILE_FIELD::uri], "/") - 1;
	tmp << depth;
	string strdepth = tmp.str(); tmp.str("");
	string srcuri = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] + m_syncdata[SYNCFILE_FIELD::src_uri];

	// update value : get_lastmodified, uri, depth
	paramValues[0] = strNow.c_str();
	paramValues[1] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	paramValues[2] = strdepth.c_str();

	// where value : uri, host_name, filename_hash
	paramValues[3] = srcuri.c_str();
	//paramValues[4] = srchost.c_str();
	// 해당 파일 복제본도 동일하게 변경하기 위해서 fhs mount별 hash 사용
	paramValues[4] = fullhash.c_str();

	msg << "SQL - " << sql.str();
	LOGACOUT(LDEV1, msg);

	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::CLEAR) < 0)
	{
		FreeDB(db, false);
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);

		return -354;
	}

	FreeDB(db, true);

	msg << "Move(COMMAND:COPY) SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
	LOGACOUT(LINF, msg);

	return r;
}

int CSynchronization::MoveTypeMove()
{
	int r = 0;

	ostringstream msg, tmp;

	string srcfhs, destfhs;
	srcfhs = m_syncdata[SYNCFILE_FIELD::host_name];
	if (GetTargetFHS(destfhs) == false)
	{
		return -361;
	}

	vector<string> vecdestfhs;
	vecdestfhs.push_back(destfhs);

	string srchash, desthash;
	srchash = m_syncdata[SYNCFILE_FIELD::filename_hash];
	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		if (ReqFileTrans(srcfhs, vecdestfhs) == false)
		{
			return -362;
		}
	

		desthash = m_syncdata[SYNCFILE_FIELD::filename_hash];

		if (srchash.empty() || desthash.empty())
		{
			CReportLog rlog;
			if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
			{
				rlog.Write("ERR", "[%s] [failed MOVE(COMMAND) filename_hash empty caution.[uri :%s(src:%s,dest:%s)]]"
					, PROG_NAME, m_syncdata[SYNCFILE_FIELD::uri].c_str()
					, srchash.c_str(), destfhs.c_str()
					);
			}

			return -366;
		}
	}

	msg << "MOVE(COMMAND:MOVE) : " << srchash << " => " << desthash;
	LOGACOUT(LDBG, msg);

	string tblname;
	bool usedisplay = true;
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return -363;


	int index = 0;
	const char *paramValues[5];

	ostringstream sql;

	sql << "UPDATE " << tblname << " ";
	sql << "SET ";
	sql << "host_name = $1 ";
	sql << ", filename_hash = $2 ";

	sql << "WHERE ";

	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
	{
		sql << "uri = lower($3) ";
	}
	else
	{
		sql << "uri = $3 ";
	}

	sql << "AND ";
	sql << "host_name = $4";

	// use hash 
	index = 4;
	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		index = 5;
		sql << "AND ";
		sql << "filename_hash = $5 ";
	}

	sql << "AND ";
	sql << "resource_type = " << m_syncdata[SYNCFILE_FIELD::resource_type] << " ";

	sql << "AND ";
	sql << "deleted_yn = 'N' ";

	tmp << longtime_now();
	string strNow;
	strNow = tmp.str(); tmp.str("");

	// update value :  host_name, filename_hash
	//paramValues[0] = strNow.c_str();
	paramValues[0] = destfhs.c_str();
	paramValues[1] = desthash.c_str();

	// where value : uri, host_name, filename_hash
	paramValues[2] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	paramValues[3] = srcfhs.c_str();
	paramValues[4] = srchash.c_str(); 

	msg << "SQL - " << sql.str();
	LOGACOUT(LDEV1, msg);

	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::NOT_CLEAR) < 0)
	{
		FreeDB(db, false);
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);

		return -364;
	}

	if (db->GetCmdTuples() == 0)
	{
		msg << "Zero rows affected by the SQL command. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACOUT(LERR, msg);
		r = -365;
	}
	else
	{
		msg << "Move(COMMAND:MOVE) SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACOUT(LINF, msg);
	}
	db->PgClear();
	FreeDB(db, true);

	return r;
}

int CSynchronization::Move()
{
	int r = 0;
	ostringstream msg;
	msg << "		URI = " << m_syncdata[SYNCFILE_FIELD::uri] << ", HASH = " << m_syncdata[SYNCFILE_FIELD::filename_hash];
	LOGACOUT(LDBG, msg);

	if (m_type == JOB_TYPE::COPY)
	{
		r = MoveTypeCopy();
	}
	else
	{
		r = MoveTypeMove();
	}
	
	return r;
}

int CSynchronization::Rechk()
{
	int r = 0;
	ostringstream msg, tmp;
	msg << "		URI = " << m_syncdata[SYNCFILE_FIELD::uri] << ", HASH = " << m_syncdata[SYNCFILE_FIELD::filename_hash];
	LOGACOUT(LDBG, msg);

	string tblname;
	bool usedisplay = true;
	DataBase *db = GetDB(tblname, usedisplay);

	if (db == NULL)
		return -371;

	int index = 0;
	const char *paramValues[4];

	tmp << longtime_now();
	string strNow, strHash;
	strNow = tmp.str(); tmp.str("");
	strHash = ChgFilenamehash();

	ostringstream sql;
	sql << "UPDATE " << tblname << " ";
	sql << "SET ";
	sql << "get_lastmodified = $1 ";


	sql << "WHERE ";

	if (usedisplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
	{
		sql << "uri = lower($2) ";
	}
	else
	{
		sql << "uri = $2 ";
	}

	// 중복 리플리케이션 방지를 위해서 제거
	//sql << "AND ";
	//sql << "host_name = $3 ";

	// use hash 
	index = 2;
	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		// 리플리케이션 업데이트 되어야함(중복 리플리케이션 방지)
		index = 3;
		sql << "AND ";
		sql << "filename_hash = ANY($" << index <<") ";
	}

	// 등록한지 하루 이상된 것에 대해서 RECHK 수행함
	sql << "AND ";
	sql << "(get_lastmodified + (24::bigint*60::bigint*60::bigint*1000000::bigint)::bigint) < " << strNow << " ";

	sql << "AND ";
	sql << "resource_type = " << m_syncdata[SYNCFILE_FIELD::resource_type] << " ";

	sql << "AND ";
	sql << "deleted_yn = 'N' ";

	// update value :  host_name, filename_hash
	paramValues[0] = strNow.c_str();
	
	// where value :  uri, host_name, filename_hash
	paramValues[1] = m_syncdata[SYNCFILE_FIELD::uri].c_str();
	//paramValues[2] = m_syncdata[SYNCFILE_FIELD::host_name].c_str();
	//paramValues[3] = m_syncdata[SYNCFILE_FIELD::filename_hash].c_str();
	paramValues[2] = strHash.c_str();

	msg << "SQL - " << sql.str();
	LOGACOUT(LDEV1, msg);

	// Query 실행
	db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);

	// Query 결과를 가져온다.
	if (db->PgResult(DataBase::CLEAR) < 0)
	{
		FreeDB(db, false);
		msg << "Query failed. errmsg : [" << db->GetErrorMessage() << "] / Query : [" << sql.str() << "]";
		LOGACERR(LERR, msg);

		return -372;
	}

	FreeDB(db, true);

	msg << "RECHK SUCCESS. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
	LOGACOUT(LINF, msg);

	return r;
}

int  CSynchronization::Execute()
{
	int r = 0;
	ostringstream msg;

	msg << "[" << m_syncdata[SYNCFILE_FIELD::flag] << "] Synchronization..... ";

	LOGACOUT(LDBG, msg);

	if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
	{
		r = Deleted();
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
	{
		r = Syned();
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
	{
		r = NSyned();
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY)
	{
		r = Copy();
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
	{
		r = Move();
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_RECHK)
	{
		r = Rechk();
	}
	else
	{
		msg << "This flag isn't supported.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACERR(LERR, msg);
		r = -300;
	}

	return r;
}
