/***************************************************************************
                Validation
                -----------------------------------------
	begin      : 2012/05/14
	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 "parameter.h"
#include "validation.h"
#include "Database.h"
#include "dbconnpool.h"

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

#define  RECHK_TIMEOUT	(24*60*60 * 1000000LL) // 1 day

static int64_t convert(string &s)
{
	if (s.size() == 0)
		return 0;

	int64_t v = 0;
	size_t i = 0;
	char sign = (s[0] == '-' || s[0] == '+') ? (++i, s[0]) : '+';
	for (; i < s.size(); ++i)
	{
		if (s[i] < '0' || s[i] > '9')
			return 0;
		v = v * 10 + s[i] - '0';
	}
	return sign == '-' ? -v : v;
}

CValidation::CValidation(JOB_TYPE::JOB_TYPE type, vector<string> & input)
	: m_type(type), m_syncdata(input), m_first(true)
{
}

CValidation::~CValidation()
{
}

DataBase* CValidation::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 CValidation::FreeDB(DataBase *db, bool success/* = true*/)
{
	if (db)
	{
		masterdbpool::getInstance()->ReleaseConnToPool(db, success);
		db = NULL;
	}
}

vector<string> CValidation::Current2Sync(string sflag, vector<string>& curr)
{
	vector<string> r(SYNCFILE_FIELD::MAX_FILED);

	r[SYNCFILE_FIELD::flag] = sflag;
	r[SYNCFILE_FIELD::uri] = curr[CURRENT_FIELD::uri];
	r[SYNCFILE_FIELD::filename_hash] = curr[CURRENT_FIELD::filename_hash];
	r[SYNCFILE_FIELD::resource_type] = curr[CURRENT_FIELD::resource_type];
	r[SYNCFILE_FIELD::file_lastmodified] = curr[CURRENT_FIELD::file_lastmodified];
	r[SYNCFILE_FIELD::deleted_yn] = curr[CURRENT_FIELD::deleted_yn];
	r[SYNCFILE_FIELD::host_name] = curr[CURRENT_FIELD::host_name];
	r[SYNCFILE_FIELD::creation_date] = curr[CURRENT_FIELD::creation_date];
	r[SYNCFILE_FIELD::get_content_length] = curr[CURRENT_FIELD::get_content_length];
	r[SYNCFILE_FIELD::get_content_type] = curr[CURRENT_FIELD::get_content_type];

	r[SYNCFILE_FIELD::src_uri] = m_syncdata[SYNCFILE_FIELD::src_uri];
	r[SYNCFILE_FIELD::slave_tran_id] = m_syncdata[SYNCFILE_FIELD::slave_tran_id];
	r[SYNCFILE_FIELD::uri_ignore_case] = m_syncdata[SYNCFILE_FIELD::uri_ignore_case];

	return r;
}

string	CValidation::GetFullFilenamehash()
{
	string r;
	ostringstream msg;

	if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
	{
		msg << "[" << m_syncdata[SYNCFILE_FIELD::uri] << "] isn't file.";
		LOGACOUT(LDBG, msg);
		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
		{
			msg << "FHS mount empty.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACOUT(LWAR, msg);

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

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

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

	msg << "Useing SQL filename_hash : " << m_syncdata[SYNCFILE_FIELD::filename_hash]
		<< " => " << r;


	LOGACOUT(LDBG, msg);

	return r;
}

bool CValidation::GetCurrent(DataBase *db, string& tblname, bool useDisyplay /* = true */)
{
	ostringstream sql,msg;

	int index = 1;

	sql << "SELECT ";
	if (useDisyplay)
		sql << "display_name, ";
	else
		sql << "uri, ";
	sql << "filename_hash, resource_type, get_content_length, get_lastmodified, ";
	sql << "file_lastmodified, deleted_yn, host_name, creation_date, get_content_type ";

	sql << "FROM " << tblname << " ";

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

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

	if (m_type == JOB_TYPE::MOVE)
	{
		sql << "AND ";
		sql << "host_name = $" << ++index  << " ";
	}
	else
	{
		sql << "AND ";
		sql << "is_cache = 'N' ";
	}

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

	
	ostringstream t;
	string struri = m_syncdata[SYNCFILE_FIELD::uri];
	string strdepth;
	string strhash = GetFullFilenamehash();

	// depth 값 구하기. path : /tran_id/filename ( tran_id 제거된 count )
	int nDEPTH = StringCount(struri, "/") - 1;

	t << nDEPTH;
	strdepth = t.str(); t.str("");
	
	const char *paramValues[5];

	if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
	{
		index = 1;
		paramValues[0] = strhash.c_str();
		msg << " RCDB GetCurrent value : " << paramValues[0] << ",";
	}
	else
	{
		index = 2;
		paramValues[0] = strdepth.c_str();
		paramValues[1] = struri.c_str();
		msg << paramValues[0] << "," << paramValues[1] << ",";
	}

	if (m_type == JOB_TYPE::MOVE)
	{
		paramValues[index++] = m_syncdata[SYNCFILE_FIELD::host_name].c_str();
		msg << paramValues[index - 1] << ",INDEX (" << index  << ")";
	}
	LOGACOUT(LDBG, msg);

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

	// Query 결과를 가져온다.
	int nResult = db->PgResult(DataBase::NOT_CLEAR);
	if (nResult < 0)
	{
		msg << "RCDB GetCurrent failed : [" << db->GetErrorMessage() << "]";
		LOGACERR(LERR, msg);
		return false;
	}

	for (int i = 0; i < db->GetNoTuples(); ++i)
	{
		vector<string> vectcurr(CURRENT_FIELD::MAX_FILED);

		vectcurr[CURRENT_FIELD::uri] = db->GetValue(i, CURRENT_FIELD::uri);

		if (m_syncdata[SYNCFILE_FIELD::resource_type] == "0")
			vectcurr[CURRENT_FIELD::filename_hash] = db->GetValue(i, CURRENT_FIELD::filename_hash);

		vectcurr[CURRENT_FIELD::host_name] = db->GetValue(i, CURRENT_FIELD::host_name);
		vectcurr[CURRENT_FIELD::resource_type] = db->GetValue(i, CURRENT_FIELD::resource_type);		
		vectcurr[CURRENT_FIELD::creation_date] = db->GetValue(i, CURRENT_FIELD::creation_date);		
		vectcurr[CURRENT_FIELD::get_content_length] = db->GetValue(i, CURRENT_FIELD::get_content_length);
		vectcurr[CURRENT_FIELD::get_content_type] = db->GetValue(i, CURRENT_FIELD::get_content_type);
		vectcurr[CURRENT_FIELD::get_lastmodified] = db->GetValue(i, CURRENT_FIELD::get_lastmodified);
		vectcurr[CURRENT_FIELD::deleted_yn] = db->GetValue(i, CURRENT_FIELD::deleted_yn);
		vectcurr[CURRENT_FIELD::file_lastmodified] = db->GetValue(i, CURRENT_FIELD::file_lastmodified);

		m_current.insert(CCurretMap::value_type(vectcurr[CURRENT_FIELD::uri], vectcurr));
	}

	db->PgClear();
	return true;
}

vector<string> CValidation::MakeFind()
{
	vector<string> r;

	string strtran = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id];
	
	if (m_first && m_type == JOB_TYPE::COPY)
	{
		if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY 
			|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
		{
			// 마스터 망에서 파일 수정일(get_lastmodified)이 해당 파일보다 작은 것이 없을 경우 src_uri 보내지 않음			
			if (m_syncdata[SYNCFILE_FIELD::src_uri].size())
			{
				string srcuri = strtran + m_syncdata[SYNCFILE_FIELD::src_uri];
				r.push_back(srcuri);
			}
		}
	}

	string input = m_syncdata[SYNCFILE_FIELD::uri];
	r.push_back(input);
	return r;
}

int CValidation::IsAllow()
{

	if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_RECHK)
	{ 
		return 1;
	}

	int r = -1;
	switch (m_type)
	{
	case JOB_TYPE::COPY:
		{
			if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC
				|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC
				|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL 
				|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY 
				|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
				r = 0;
		}
		break;
	case JOB_TYPE::MOVE:
		{
			if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
				r = 0;
		}
		break;
	default:
		r =	-2;
		break;
	}

	return r;
}

void CValidation::FindZero(string & input, CSyncData & outSync)
{
	ostringstream msg;

	msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> FIND ZERO";
	LOGACOUT(LDBG, msg);

	string synctranid = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id];
	string src = synctranid + m_syncdata[SYNCFILE_FIELD::src_uri];

	// 다른 uri로 파일 존재하므로 검출된 데이터에 대해서 RECHK flag 설정
	if (m_type == JOB_TYPE::COPY && m_first && m_current.size())
	{
		// RECHK 
		for (CCurretMap::iterator it = m_current.begin(); it != m_current.end(); ++it)
		{
			vector<string> 	newsync = Current2Sync(FLAG_RECHK, it->second);
			
			if (input == newsync[SYNCFILE_FIELD::uri])
				continue;

			//  input : destination 
			if (src == newsync[SYNCFILE_FIELD::uri])
				continue;

			// input : source 
			if (src == input)
				continue;

			if (m_syncdata[SYNCFILE_FIELD::src_uri].empty())
			{
				if (m_syncdata[SYNCFILE_FIELD::get_content_length] == newsync[SYNCFILE_FIELD::get_content_length])
				{
					string newsrc = newsync[SYNCFILE_FIELD::uri];
					m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
				}
			}

			//int64_t d = convert(it->second[CURRENT_FIELD::get_lastmodified]);
			
			//if (longtime_now() - d > RECHK_TIMEOUT)
			{
				outSync.push_back(newsync);

				msg << "Set RECHK....[" << newsync[SYNCFILE_FIELD::uri] << "]";
				LOGACOUT(LDBG, msg);
			}
		}
	}

	// check
	if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
	{
		msg << "Does not process a request to delete a file because it does not exist currently. [" << input << "]";
		LOGACOUT(LINF, msg);
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
	{
		// 해당 파일과 동일한 파일 존재 확인		
		if (m_first)
		{
			for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
			{
				if ((*it)[SYNCFILE_FIELD::flag] == FLAG_RECHK)
				{
					if ((*it)[SYNCFILE_FIELD::get_content_length] == m_syncdata[SYNCFILE_FIELD::get_content_length])
					{
						string newsrc = (*it)[SYNCFILE_FIELD::uri];
						m_syncdata[SYNCFILE_FIELD::flag] = FLAG_COPY;
						m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
						break;
					}
				}
			}
		}

		outSync.push_back(m_syncdata);
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
	{
		if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
		{
			msg << "Because the file does not exist, "
				<< "change the physical synchronization from the logical synchronization. [" 
				<< input << "]";

			LOGACOUT(LINF, msg);
			m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
		}

		if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_DIR)
		{
			msg << "Create DIR. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACOUT(LDBG, msg);

			m_syncdata[SYNCFILE_FIELD::host_name] = "";
		}

		outSync.push_back(m_syncdata);
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY )
	{
		if (input == src)
		{
			vector<string> 	newsync = m_syncdata;
			newsync[SYNCFILE_FIELD::flag] = FLAG_SYNC;
			newsync[SYNCFILE_FIELD::uri] = src;

			outSync.push_back(newsync);
		}
		else
		{
			if (m_syncdata[SYNCFILE_FIELD::src_uri].empty())
				m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;

			outSync.push_back(m_syncdata);
		}			
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
	{
		if (m_type == JOB_TYPE::MOVE)
		{
			msg << "Because the file does not exist, can not be transferred. [" << input << "]";
			LOGACOUT(LINF, msg);
		}
		else
		{
			if (input == src)
			{
				// Nothing
				msg << "The source file does not exist, Nothing... [" << input << "]";
				LOGACOUT(LDBG, msg);
			}
			else
			{	
				if (m_first)
				{
					
					bool findsrc = false;
					for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
					{
						if ((*it)[SYNCFILE_FIELD::flag] == FLAG_RECHK)
						{
							if ((*it)[SYNCFILE_FIELD::uri] == src)
							{
								findsrc = true;
								outSync.erase(it);
								break;
							}

							// 해당 소스와 동일한 uri 존재하지 하지 않지만 동일한 파일로 다른 uri 존재할 수 있으므로
							// 해당 파일을 소스 파일로 하는 copy 본 생성함
							// 소스로 선정된 파일은 RECHK 옵션에 의해서 재처리됨
							if ((*it)[SYNCFILE_FIELD::get_content_length] == m_syncdata[SYNCFILE_FIELD::get_content_length])
							{
								findsrc = true;
								string newsrc = (*it)[SYNCFILE_FIELD::uri];
								m_syncdata[SYNCFILE_FIELD::flag] = FLAG_COPY;
								m_syncdata[SYNCFILE_FIELD::host_name] = (*it)[SYNCFILE_FIELD::host_name];
								m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
								break;
							}
						}
					}

					// 소스 존재 하지 않을 경우 SYNC로 변경
					if (findsrc == false)
					{
						m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
					}
					
					outSync.push_back(m_syncdata);
				}
				else
				{
					outSync.push_back(m_syncdata);
				}
			}
		}
	}
	else
	{
		msg << "Unknown flag.[" << m_syncdata[SYNCFILE_FIELD::flag] << ":";
		msg << input;
		msg << "]";

		LOGACERR(LERR, msg);
		return;
	}
}

void CValidation::FindOne(vector<string> f, CSyncData & outSync)
{
	ostringstream msg;

	string input = f[CURRENT_FIELD::uri];
	string src = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] + m_syncdata[SYNCFILE_FIELD::src_uri];

	msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> FIND IT";
	LOGACOUT(LDBG, msg);

	// 다른 uri로 파일 존재하므로 검출된 데이터에 대해서 RECHK flag 설정
	if (m_type == JOB_TYPE::COPY && m_first && m_current.size() > 1)
	{
		// RECHK 
		for (CCurretMap::iterator it = m_current.begin(); it != m_current.end(); ++it)
		{
			vector<string> 	newsync = Current2Sync(FLAG_RECHK, it->second);
			if (input == newsync[SYNCFILE_FIELD::uri])
				continue;
			
			//  input : destination 
			if (src == newsync[SYNCFILE_FIELD::uri])
				continue;
			
			// input : source 
			if (src == input)
				continue;

			//int64_t d = convert(it->second[CURRENT_FIELD::get_lastmodified]);

			//if (longtime_now() - d > RECHK_TIMEOUT)
			{
				outSync.push_back(newsync);

				msg << "Set RECHK(1)....[" << newsync[SYNCFILE_FIELD::uri] << "]";
				LOGACOUT(LDBG, msg);
			}
		}
	}

	bool in2sync = false;
	// check
	if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
	{
		in2sync = true;
		if (m_first && m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
		{			
			msg << "uri same but size different. change flag(RECHK).[" << input << "]";
			LOGACOUT(LDBG, msg);
			m_syncdata[SYNCFILE_FIELD::flag] = FLAG_RECHK;
		}
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
	{
		in2sync = true;
		
		if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
		{
			if (m_first)
			{
				msg << "uri same but size different. new syncdata(DEL) create.[" << input << "]";
				LOGACOUT(LINF, msg);
				vector<string> 	newsync = Current2Sync(FLAG_DEL, f);
				outSync.push_back(newsync);
			}
		}
		else if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
		{
			if (m_first)
			{
				msg << "uri same but file_lastmodified  different. new syncdata(NSYNC) create.[" << input << "]";
				LOGACOUT(LINF, msg);
				vector<string> 	newsync = Current2Sync(FLAG_NSYNC, f);
				newsync[SYNCFILE_FIELD::file_lastmodified] = m_syncdata[SYNCFILE_FIELD::file_lastmodified];
				outSync.push_back(newsync);
			}
		}
		else
		{
			in2sync = false;
			msg << "Information all same. not synchronized.[" << input << "]";
			LOGACOUT(LDBG, msg);
		}
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
	{
		if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
		{
			in2sync = true;
			if (f[CURRENT_FIELD::resource_type] == TYPE_DIR)
				m_syncdata[SYNCFILE_FIELD::host_name] = f[CURRENT_FIELD::host_name];
		}

		if (f[CURRENT_FIELD::resource_type] == TYPE_FILE)
		{
			if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
			{
				if (m_first)
				{
					msg << "uri same but size(or file_lastmodified) different. new syncdata(DEL) create.["
						<< input << "]";
					LOGACOUT(LINF, msg);
					vector<string> 	newsync = Current2Sync(FLAG_DEL, f);
					outSync.push_back(newsync);
				}
				else
				{
					msg << "Change flag NSYNC to SYNC. [" << input << "]";
					LOGACOUT(LDBG, msg);
					m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
				}
			}
		}
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY)
	{
		if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
		{
			if (m_first)
			{
				msg << "uri same but size different. new syncdata(DEL) create.["
					<< input << "]";
				LOGACOUT(LINF, msg);
				vector<string> 	newsync = Current2Sync(FLAG_DEL, f);
				outSync.push_back(newsync);
			
				if (input == src)
				{
					msg << "uri same but size different. new syncdata(SYNC) create.["
						<< input << "]";
					LOGACOUT(LINF, msg);
					newsync = Current2Sync(FLAG_SYNC, f);
					outSync.push_back(newsync);
				}
				else 
					in2sync = true;
			}
			else
				in2sync = true;
		}
		else if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
		{
			if (m_first)
			{
				if (input != src)
				{
					vector<string> 	newsync = Current2Sync(FLAG_NSYNC, f);
					newsync[SYNCFILE_FIELD::file_lastmodified] = m_syncdata[SYNCFILE_FIELD::file_lastmodified];
					outSync.push_back(newsync);
				}
			}
		}
		else
		{
			// nothing
		}
	}
	else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
	{
		if (m_type == JOB_TYPE::MOVE)
		{
			in2sync = true;
		}
		else
		{
			if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
			{
				if (m_first)
				{
					msg << "uri same but size different. new syncdata(DEL) create.["
						<< input << "]";
					LOGACOUT(LINF, msg);
					vector<string> 	newsync = Current2Sync(FLAG_DEL, f);
					outSync.push_back(newsync);
				}

				if (input != src)
				{
					msg << "uri same but size different. new syncdata(SYNC) create.["
						<< input << "]";
					LOGACOUT(LINF, msg);
					vector<string> newsync = Current2Sync(FLAG_SYNC, f);
					outSync.push_back(newsync);
				}
			}
			else
			{
				if (input == src)
				{
					vector<string> newsync = Current2Sync(FLAG_RECHK, f);
					outSync.push_back(newsync);
				}
				else
				{
					for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
					{
						if ((*it)[SYNCFILE_FIELD::uri] == src )
						{
							// 소스 존재하고 복사된 파일도 존재하면 소스 삭제 처리
							(*it)[SYNCFILE_FIELD::flag] = FLAG_DEL;
							break;
						}
					}
				}
			}
		}
	}
	else
	{
		msg << "Unknown flag.[" << m_syncdata[SYNCFILE_FIELD::flag] << ":";
		msg << input;
		msg << "]";

		LOGACERR(LERR, msg);
		return;
	}

	// input to sync data
	if (in2sync)
	{
		outSync.push_back(m_syncdata);
	}
}

void CValidation::FindOver(pair<CCurretMap::iterator, CCurretMap::iterator> &f, CSyncData & outSync)
{
	ostringstream msg;

	//f.first
	CCurretMap::iterator vf = f.first;

	string input = (*vf).second[CURRENT_FIELD::uri];

	msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> DUPLICATE";
	LOGACOUT(LDBG, msg);

	CReportLog rlog;

	if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
	{
		rlog.Write("NOT", "[%s] [The duplicate files.[uri :%s]]", PROG_NAME, input.c_str());
	}

}

bool CValidation::CompareData(DataBase *db, string& tblname,
							vector<string> & vecFind, CSyncData & outSync)
{
	bool r = true;
	ostringstream msg;

	msg << "FIND vector Size : " << vecFind.size();
	LOGACOUT(LDBG, msg);
	
	while (vecFind.size())
	{
		string input = vecFind.front();
		msg << "FIND input : " << input;
		LOGACOUT(LDEV1, msg);

		pair<CCurretMap::iterator, CCurretMap::iterator> f = m_current.equal_range(input);
		CCurretMap::const_iterator ff = f.first;

		if (f.first == m_current.end())
		{
			// find zero
			FindZero(input, outSync);
		}
		else if (++ff == f.second)
		{
			// find one 
			CCurretMap::iterator v = f.first;
			FindOne((*v).second, outSync);
		}
		else
		{
			// find one over
			FindOver(f, outSync);
			return false;
		}

		vecFind.erase(vecFind.begin());
	}

	return r;
}

int CValidation::CheckData(bool first, CSyncData & outSync)
{	
	DataBase* db = NULL;
	string tblname;
	bool usedisp = true;
	ostringstream msg;
	
	m_first = first;

	// check allow
	switch (IsAllow())
	{
	case 0: // Allow
		msg << "ALLOW Validation.["	<< m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACOUT(LDEV2, msg);
		break;
	case 1: // SKIP
		msg << "SIKP Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";		
		LOGACOUT(LDBG, msg);

		outSync.push_back(m_syncdata);
		return 0;
		break;
	default: // Deny
		msg << "DENY Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
		LOGACOUT(LERR, msg);
		return -10;
		break;
	}

	// Get DB 
	db = GetDB(tblname, usedisp);
	if (db == NULL)
		return -1;

	int r = 0;
	do 
	{
		// Get Current 
		if (GetCurrent(db, tblname, usedisp) == false)
		{
			r = -2;
			break;
		}

		// Make Find URI
		vector<string> vecfind = MakeFind();
		if (vecfind.empty())
		{
			r = -3;
			msg << "Not Found 'FIND URI'.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
			LOGACOUT(LERR, msg);
			break;
		}

		// compare			
		if (CompareData(db, tblname, vecfind, outSync) == false)
		{
			r = -4;
			break;
		}
	
	} while (false);
	

	// Free DB
	FreeDB(db, (r != -2));
	return r;
}
