/***************************************************************************
                   rc_mngd Worker ( Worker.cpp )
                -----------------------------------------

	begin      : 2013/02/15
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/02/15 - 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 "Worker.h"
#include "Signals.h"
#include "Logger.h"
#include "Configs.h"
#include "Service.h"
#include "DbConnPool.h"
#include "UtilFn.h"

#include <unistd.h>


#define		DBPOOL_KEEPALIVE_TIMEOUT	300  // 5 min

static int _isExit = 0;

/// @brief Worker Process 생성(fork) 처리 함수
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool MakeProcessWorker( bool isDaemon )
{
	pid_t processId;

	// Worker 프로세스 fork
	processId = fork();
	if( processId < 0 ) // Fork fail
	{
		int errorNum = errno;
		LOG( LERR, "Worker Process create failed. [%d][%s]", errorNum, strerror(errorNum) );
		return false;
	}
	else if( processId == 0 ) // Child Process => Worker Process
	{
		// Worker Process Main 함수 호출 및 종료처리.
		WorkerMain( isDaemon );
		exit( EXIT_SUCCESS );
	}
	else
	{
		// Parent Process => Logging
		LOG( LWAR, "Worker Process create success. PID[%d]" , processId);
		// 잠시 대기
		solusleep(100000);
	}

	return true;
}

static void SigTermWorker( int nSignalNumber )
{
	if(_isExit)	return;
	_isExit = 1;

	ostringstream msg;
	// Signal Number 에 따른 로깅처리.
	if( nSignalNumber == SIGTERM )
	{
		msg << "Worker Process [" << getpid() << "] exit job start by user signal [SIGTERM]";
	}
	else
	{
		msg << "Worker Process [" << getpid() << "] exit job start by user signal ["<< nSignalNumber <<"]";
	}

	cout << msg.str() << endl;
	_LOG(LWAR, msg.str().c_str());
}

/// @brief Worker Process 의 main 함수
int WorkerMain( bool isDaemon )
{
	// Set Signal Handler
	SetIgnoreSignal(isDaemon);
	SetSIGTERM(isDaemon, SigTermWorker);

	// create DB connection
	CMasterDBpool::init(CMyConfig::GetInstance()->GetDBInfo());
	if (CMasterDBpool::getInstance()->CreatePool(CMyConfig::GetInstance()->GetDBPoolCnt()) <= 0)
	{
		LOG(LERR, "database connection pool created fail.");
		_isExit = 3;
	}
	else
	{
		CMasterDBpool::getInstance()->SetKeepAliveTimeout(DBPOOL_KEEPALIVE_TIMEOUT);
		CMasterDBpool::getInstance()->SetRecreted(true);
	}

	_LOG(LINF, "RCDB : %s Type.", CMasterDBpool::getInstance()->GetTargetTableType() == 1 ? "NEW" : "OLD");

	// Start Service
	list<CServiceInfo> infos = 
		CMyConfig::GetInstance()->GetServiceList();
	
	CSericeFactory servicefactory;
	list<CService *> services;
	for (list<CServiceInfo>::iterator it= infos.begin(); it != infos.end(); ++it)
	{
		CServiceInfo info = *it;
#ifdef _DEBUG
		cout << "Service : " ; info.PrintInfo();
#endif //_DEBUG
		CService *d = servicefactory.CreateSerice(info);
		if(d && d->init() == 0)
		{
			services.push_back(d);
		}
		else
		{
			LOG(LERR, "Service initialization failed.[%d,%d]",info.m_type,info.m_port);
			_isExit = 2;
		}
	}

	for (list<CService*>::iterator it= services.begin(); it != services.end(); ++it)
	{
		(*it)->Start();
	}	

	// signal wait
	while ( _isExit == 0 )
	{
#ifdef _DEBUG
		cout << "Working ..." << endl;
#endif //_DEBUG
		pause();
	}

	if(_isExit > 1 )
	{
		 LOG( LERR, "Worker process create failed. Exit...");
		 kill(0, SIGTERM);
	}

	// Process 종료 처리.
	while(!services.empty())
	{
		CService* pService = services.front();
		pService->Stop();

		if(pService)
			delete pService;
		services.pop_front();
	}

	_LOG( LWAR, "Worker Process[%d] exit.. Good Bye..", getpid());
	CMasterDBpool::release();
	CLogger::Exit();
	CMyConfig::Exit();

	// 잠시 대기 후 종료처리.
	solusleep(500000);

	return EXIT_SUCCESS;
}

