#include "ExecCall.h"
#include "ServiceConfig.h"
#include "Logger.h"


#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <spawn.h>

static int getCommand(string cmd, string & out)
{
	string data;
	FILE *stream;
	int MAX_BUFFER = 256;
	char buffer[MAX_BUFFER];
	cmd.append(" 2>&1");
	LOG(LDEV1, "[POPNE] OPEN %s ", cmd.c_str());

	stream = popen(cmd.c_str(), "r");
	if (!stream)
	{
		LOG(LERR, "[POPNE] popen error. [%s] ", cmd.c_str());
		return -1;
	}

	LOG(LDEV1, "[POPNE] READ %s ", cmd.c_str());
	memset(buffer, 0, MAX_BUFFER);
	while (fgets(buffer, MAX_BUFFER, stream))
	{
		LOG(LDEV1, "[POPNE] READING.. %s|%s ", cmd.c_str(), buffer);
		data.append(buffer);
		memset(buffer, 0, MAX_BUFFER);
	}
	LOG(LDEV1, "[POPNE] READ END %s ", cmd.c_str());

	if (ferror(stream))
	{
		// Handle error.
		LOG(LERR, "[POPNE] Handle error. [%s] ", cmd.c_str());
		return -2;
	}

	out = data;
	
	pclose(stream);
	//if (status == -1)
	//{
	//	LOG(LERR, "[POPNE] popen run error(%s). [%s] ", data.c_str(),cmd.c_str());
	//	return -3;
	//}
		
	return 0;
}

static int callAnother(char *argv[])
{

	//pid_t processID;
	
	//int status = -1;
	//status = posix_spawn(&processID, argv[0], NULL, NULL, argv, environ);
	
	//if (status == 0)
	//	LOG(LDBG, "%s Launching Application", argv[0]);
	//else
	//	LOG(LDBG, "%s Launching application Failed", argv[0]);

	///*
	pid_t pid = fork();
	
	// 실해된 프로세스 좀비 프로스세 막기 위해서
	signal(SIGCHLD, SIG_IGN);
	switch (pid)
	{
	case -1:
		LOG(LERR, "Command fork failed.[%s]", argv[0]);
		return -1;
		break;
	case 0:
	{
		// exec ... call
		// close-exec 
		int flags;
		for (int i = getdtablesize(); i-- > 3;) {
			if ((flags = fcntl(i, F_GETFD)) != -1)
				fcntl(i, F_SETFD, flags | FD_CLOEXEC);
		}
		execvp(argv[0], const_cast<char**>(argv));
		LOG(LERR, "Command exec failed.[%s]", argv[0]); // //check for error in execl
		exit(EXIT_FAILURE);
		return -2;
	}
		break;
	default:
		// wait((int*)0);// child 종료 될 때까지 기다림; block 됨
		LOG(LDBG, "%s completed", argv[0]);
		return 0;
		break;
	}
	//*/
	return 0;
}

CExecCall::CExecCall(CSyncInfo & info)
	: m_info(info)
{
}

CExecCall::~CExecCall()
{
}

int CExecCall::Call(Call_TYPE t, bool called /*= true*/)
{
	int r = -1 ;
	switch (t)
	{
	case CExecCall::DIFF_SCRIPT:
		r = DIFF(called);
		break;
	case CExecCall::RC_CMOVE:
		r = RCCMove(called);
		break;
	default:
		r = -1;
		break;
	}

	return r;
}

int CExecCall::GetFileLine(const char * filename)
{
	int64_t r = -1;
	string out;
	ostringstream cmd, msg;

	cmd << "cat " << filename << " | wc -l";
	if(getCommand(cmd.str(), out) == 0)
	{ 
		r = atoll(out.c_str());
	}
	
	msg << "file lines : " << filename << " => " << r;
	_LOG(LDBG, msg.str().c_str());

	return r;
}

int CExecCall::DIFF(bool called /*= true*/)
{
	int r = 0;

	// /user/service/etc/svcsync_diff.sh [master data] [slave data] [output file]
	string strCmd = CServiceConfig::GetInstance()->GetDiffCommand();
	
	struct stat fileStat;
	if (stat(strCmd.c_str(), &fileStat) < 0)
	{
		LOG(LERR, "Diff Commnad not found.[%s]", strCmd.c_str());
		if (getppid() > 1)
		{
			kill(getppid(), SIGTERM);
		}
		return -101;
	}
	
	strCmd = strCmd + " " + m_info.file_master_name + " " + m_info.file_slave_name + " " + m_info.file_diff_name;

	if (called)
	{
		string out;
		r = getCommand(strCmd, out);

		if (r != 0)
			LOG(LERR, "Fialed diff script.[%s]", strCmd.c_str());
	}
	else
	{
		r = -100;
		LOG(LNOT, "Only block run diff script.[%s]", strCmd.c_str());
	}

	return r;
}

int CExecCall::RCCMove(bool called /*= true*/)
{
	int r = 0;

	// /user/service/bin/rc_cmove -m copy -f [sync file]
	string strCmd = CServiceConfig::GetInstance()->GetRCCMoveCommand();

	struct stat fileStat;
	if (stat(strCmd.c_str(), &fileStat) < 0)
	{
		LOG(LERR, "RC MOVE Commnad not found.[%s]", strCmd.c_str());
		if (getppid() > 1)
		{
			kill(getppid(), SIGTERM);
		}
		return -101;
	}

	if (called)
	{
		strCmd = strCmd + " -m copy -f " + m_info.file_sync_name;
		string out;
		r = getCommand(strCmd, out);
	}
	else
	{
		char *argv[8];
		argv[0] = (char *)strCmd.c_str();
		argv[1] = (char *)"-m";
		argv[2] = (char *)"copy";
		argv[3] = (char *)"-f";
		argv[4] = (char *)m_info.file_sync_name.c_str();
		argv[5] = (char *)"2>&1";
		argv[6] = (char *)"&";
		argv[7] = NULL;

		r = callAnother(argv);		
	}

	if (r != 0)
		LOG(LERR, "Fialed rc_cmove.[%s]", strCmd.c_str());

	return 0;
}
