#include "WorkerRebalance.h"

#include "Logger.h"
#include "ProcessRename.h"
#include "ProcessConfig.h"


#include "RebalanceData.h"
#include "DataQueue.hpp"
#include "ProcessMonitoringThread.h"
#include "ShmInfoThread.h"
#include "TargetSelectThread.h"
#include "CopyControlThread.h"
#include "RcdbUpdateThread.h"
#include "PhysicalDeleteThread.h"


#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <time.h>

/////////////////////////////////////////////////




////////////////////////////////////////////////


// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerRebalance()
{
	// Logger 객체 종료 처리.
	CLogger::Exit();

	return;
}

// Worker Rebalance 프로세스에 대한 대한 종료 처리 수신시.
static void SignalWorkerRebalanceTerminate( int nSignalNumber )
{
	// Signal Number 에 따른 로깅처리.
	if( nSignalNumber == SIGTERM )
	{
		_LOG( LINF, "[Rebalance:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
	}
	else
	{
		_LOG( LWAR, "[Rebalance:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
	}

	ReadyToExitWorkerRebalance();

	// 종료전 잠시 대기
	struct timespec sleep;
	sleep.tv_sec = 0;
	sleep.tv_nsec = 500000000;  // 0.5 sec
	nanosleep( &sleep, NULL );
	
	exit( EXIT_SUCCESS );
}

// Worker::Rebalance Process 의 signal 처리기...
void SetWorkerRebalanceSignalHandler()
{
	sigset_t set;
	struct sigaction act;

	memset( &act, 0x00, sizeof( act ) );
	sigfillset( &set );
	sigprocmask( SIG_SETMASK, &set, NULL );
	sigfillset( &act.sa_mask );

	// 무시 처리 signal
	act.sa_handler = SIG_IGN;
	sigaction( SIGPIPE, &act, NULL );	/* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
	sigaction( SIGHUP, &act, NULL );	/* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
	sigaction( SIGINT, &act, NULL );	/* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
	sigaction( SIGQUIT, &act, NULL );	/* 키보드에 의한  Abort 신호 처리 => ? */

	// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
	act.sa_handler = SIG_IGN;
	sigaction( SIGCHLD, &act, NULL );

	/* 각종 에러나 사용자의 종료 신호 처리 */
	act.sa_handler = SignalWorkerRebalanceTerminate;
	sigaction( SIGTERM, &act, NULL );	/* kill -TERM 에 의한 프로세스 종료시 */

	// 나머지 신호는 default 처리.

	sigemptyset( &set );                  /* 신호 처리기 처리 설정 위한 블록 해제 */
	sigprocmask( SIG_SETMASK, &set, NULL );

	return;
}


// Worker::Rebalance 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerRebalanceMain()
{
	// Process Rename..
	set_ps_display( PROG_NAME": Rebalance init.", false );
	
	// Set Signal Handler
	SetWorkerRebalanceSignalHandler();


	// 1. 사용할 객체 초기화 처리

	// Move 처리할 대상 content 를 저장할 Queue 객체
	CDataQueue<CRebalanceData> queueMoveStandby;
	queueMoveStandby.SetMaxSize( CProcessConfig::GetInstance()->GetMaxQueueSize() );

	// Move 대상 conent 를 다른 FHS 에 Copy 완료한 후 RCDB 업데이트 수행할 content 정보를 저장하기 위한 queue.
	CDataQueue<CRebalanceData> queueUpdateStandby;
	queueUpdateStandby.SetMaxSize( CProcessConfig::GetInstance()->GetMaxQueueSize() );

	// RCDB UPDATE 처리 후 delete(unlink) 처리 대상 content 를 저장하기 위한 queue
	CDataQueue<CRebalanceData> queueDeleteStandby;
	queueDeleteStandby.SetMaxSize( CProcessConfig::GetInstance()->GetMaxQueueSize() );

	// Shared memory 접근 및 주요 정보 추출 관련 thread 객체 생성
	CShmInfoThread objShmInfoThread;

	// Rebalance 처리 대상 FHS, content 선정을 수행하는 thread 객체 생성
	CTargetSelectThread objTargetSelectThread( &queueMoveStandby, &objShmInfoThread );

	// Content Copy 처리를 수행할 thread 객체 생성
	CCopyControlThread objCopyControlThread( &queueMoveStandby, &queueUpdateStandby, &objShmInfoThread );

	// RCDB update 처리를 수행할 thread 객체 생성
	CRcdbUpdateThread objRcdbUpdateThread( &queueUpdateStandby, &queueDeleteStandby );

	// Process Monitoring thread 객체 생성
	CProcessMonitoringThread objProcessMonitoringThread( &queueMoveStandby, &queueUpdateStandby, &queueDeleteStandby, &objCopyControlThread );

	// 물리 파일 삭제(unlink) 처리 thread 객체 생성
	CPhysicalDeleteThread objPhysicalDeleteThread( &queueDeleteStandby, &objProcessMonitoringThread );



	// 2. 각 모듈 기동 처리
	// - 최종 작업 모듈부터 기동 처리

	set_ps_display( PROG_NAME": Rebalance start.", false );

	// 공유메모리 접근 및 Rebalance 처리 대상, Copy 수신 대상 FHS 정보 수집을 담당하는 Thread 기동 처리
	// - 정상 기동시 공유메모리 정보를 scan 해 올 수 있도록 잠시 대기한다.
	if( objShmInfoThread.Start() == false )
	{
		_LOG( LWAR, "[Rebalance:%d] Shm info thread start failed. => Process Exit", getpid() );

		ReadyToExitWorkerRebalance();
		return EXIT_FAILURE;	// EXIT_FAILURE 를 반환하여 재생성 처리 방지...
	}
	else
	{
		sleep( 3 );		// 성공시 3 sec 대기
	}


	// 물리 파일 삭제(unlink) 처리를 수행할 thread 기동 처리.
	if( objPhysicalDeleteThread.Start() == false )
	{
		_LOG( LWAR, "[Rebalance:%d] Physical delete thread start failed. => Process Exit", getpid() );

		ReadyToExitWorkerRebalance();
		return EXIT_FAILURE;	// EXIT_FAILURE 를 반환하여 재생성 처리 방지...
	}

	// RCDB update 처리를 수행할 thread 기동 처리.
	if( objRcdbUpdateThread.Start() == false )
	{
		_LOG( LWAR, "[Rebalance:%d] Rcdb update thread start failed. => Process Exit", getpid() );

		ReadyToExitWorkerRebalance();
		return EXIT_FAILURE;	// EXIT_FAILURE 를 반환하여 재생성 처리 방지...
	}

	// Content copy 처리를 수행할 thread 기동 처리.
	if( objCopyControlThread.Start() == false )
	{
		_LOG( LWAR, "[Rebalance:%d] Content copy control thread start failed. => Process Exit", getpid() );

		ReadyToExitWorkerRebalance();
		return EXIT_FAILURE;	// EXIT_FAILURE 를 반환하여 재생성 처리 방지...
	}

	// rebalance 처리 대상 FHS, content 선정을 수행하는 thread 기동 처리
	if( objTargetSelectThread.Start() == false )
	{
		_LOG( LWAR, "[Rebalance:%d] Target select thread start failed. => Process Exit", getpid() );

		ReadyToExitWorkerRebalance();
		return EXIT_FAILURE;	// EXIT_FAILURE 를 반환하여 재생성 처리 방지...
	}

	// 프로세스 모니터링 thread 기동 처리.
	if( objProcessMonitoringThread.Start() == false )
	{
		_LOG( LWAR, "[Rebalance:%d] Process monitoring thread start failed. => Process Exit", getpid() );

		ReadyToExitWorkerRebalance();
		return EXIT_FAILURE;	// EXIT_FAILURE 를 반환하여 재생성 처리 방지...
	}
		
	// 대기
	while( 1 )
	{
		// 할일 없어서.. 시그널 수신까지 대기 한다.
		pause();
	}

	// 종료시 정리 작업 수행
	// - 실제로는 동작하지 않는 code 
	ReadyToExitWorkerRebalance();
	return EXIT_SUCCESS;
}

