#include "rcdu.h"
#include "Database.h"
#include "Logger.h"
#include "parammanager.h"
#include "infomanager.h"
#include "syncmanager.h"


#include <unistd.h>


static void Trim( string & str )
{
	if( str.length() == 0 )
		return ;
	// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
	string::size_type pos = str.find_last_not_of(" \a\b\f\n\r\t\v");
	if( pos != string::npos )
		str.erase( pos + 1 );
	// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
	pos = str.find_first_not_of(" \a\b\f\n\r\t\v");
	if( pos != string::npos )
		str.erase( 0, pos );
}

static bool IsCurrentProcessRun()
{
	char tempBuffer[512];
	FILE * fd = NULL;
	bool bRun = false;
	snprintf( tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", PROG_NAME );
	fd = popen( tempBuffer, "r" );
	if( fd == NULL )
	{
		cerr << "[error] Process duplication check failed.[popen error][" << strerror(errno) << "]" << endl;
		// 오류 발생시 true 반환하여 프로세스 실행 방지처리
		return true;
	}
	else
	{
		memset( tempBuffer, 0x00, sizeof(tempBuffer) );
		while( fgets( tempBuffer, sizeof(tempBuffer)-1, fd) != NULL )
		{
			string tempPid( tempBuffer );
			Trim(tempPid);
			if( atoi( tempPid.c_str() ) != getpid() )
			{
				cout << "[info] Process duplication found. pid[" << atoi( tempPid.c_str() ) << "]" << endl;
				bRun = true;
				break;
			}
		}
		pclose( fd );
		return bRun;
	}
}

// main function
int main( int argc, char * argv[] )
{
	// 프로그램 중복 실행 체크
	if( IsCurrentProcessRun() == true )
	{
		cerr << "[warning] Process[" << PROG_NAME << "] is already running...." << endl;
		return EXIT_FAILURE;
	}

	// 입력된 정보 분석 및 config load
	CParamManager paramter;

	if( paramter.inputparamAnalysis( argc, argv ) != 0 )
		return EXIT_FAILURE;

	// database connect
	DataBase db;

	if( db.PgOpenDB( paramter.getDBHost(), paramter.getDBPort(), paramter.getDBName(),
			paramter.getDBUser(),paramter.getDBPasswd() )  == NULL)
	{
		cerr << "[error] Database connection fail." << endl;
		return EXIT_FAILURE;
	}

	// initialized Log object
	if( CLogger::Init( PROG_NAME, paramter.getLogPath(), paramter.getLogLevel()) == false )
	{
		cerr << "[error] Failed to initialize the log object." << endl;
		return EXIT_FAILURE;
	}

	// load  calculation depth
	CInfoManager infomanger;
	if( !infomanger.loadInfo( db, paramter.getServiceid() ) )
	{
		LOG(LERR, "load calculation depth failed.");
		cerr << "[error] load calculation depth failed." << endl;
		return EXIT_FAILURE;
	}

#ifdef _DEBUG
	time_t  time_start = time(0);
#endif // _DEBUG	
	// 각 모드별 작업
	switch( paramter.getMode() )
	{
	case CParamManager::REGMODE:
		{
			cout << "Mode : REG " << endl;
			_LOG(LINF, "Mode : REG - start.");
			infomanger.changDepth( db, paramter.getCaldepth() );
			_LOG(LINF, "Mode : REG - end.");
		}
		break;
	case CParamManager::SYNCMODE:
		{
			cout << "Mode : SYNC " << endl;
			_LOG(LINF, "Mode : SYNC - start.");
			CSyncManager syncmanager;
			syncmanager.sync( db, infomanger.getInfolist() );
			_LOG(LINF, "Mode : SYNC - end.");
		}
		break;
	}
#ifdef _DEBUG
	cout << "run-time : " << time(0) - time_start << " sec" <<endl;
#endif // _DEBUG
	return EXIT_SUCCESS;
}
