/***************************************************************************
                   Parser Class (Parser.cpp)
                -----------------------------------------

	begin      : 2013/02/19
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/02/19 - 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 "Parser.h"
#include "Service.h"
#include "SocketControl.h"
#include "Convert.h"
#include "Logger.h"

// CParser
CParser::CParser()
	: m_sock(NULL), m_resp(JOB_ERR_UNKNOWN)
{

}

CParser::~CParser()
{
	if(m_sock)
		delete m_sock;
}

int CParser::SetSocket(int sfd, SSL* ssl)
{
	ostringstream msg;
	
	if(m_sock != NULL)
	{
		msg << "The socket is already assigned." ;
		LOGACONSOLE(LERR, msg);
		return -1;	
	}

	m_sock = new CSocketControl(sfd, ssl);
	if( m_sock == NULL)
	{
		msg << "Socket allocation failed.[errno:" << errno << "]";
		LOGACONSOLE(LERR, msg);
		return -1;	
	}

	m_sock->SetOption();

	return 0;
}

// CXMLParser
CXMLParser::CXMLParser()
	: m_pBodyData(NULL), m_Job(NULL)
{

}

CXMLParser::~CXMLParser()
{
	if(m_pBodyData)
		delete [] m_pBodyData;
}

int CXMLParser::ReadHeader()
{
	ostringstream msg;
	msg << "XML Parser : ReadHeader()";
	LOGACONSOLE(LDBG, msg);

	int n = m_sock->ReadData(&m_header, sizeof m_header);

	if( n < 0 )
	{
		msg << "XML Parser : GetHeader() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}
	else if ( n == 0 )
	{
		return -2;
	}
	else
	{
		m_header.ulBodyLength = ntohl(m_header.ulBodyLength);
	}
	
	msg << "XML Parser ReadHeader Data: " << m_header.ulBodyLength;
	LOGACONSOLE(LDBG, msg);

	return 0;
}

int	CXMLParser::Parsering(const char * pstrxml)
{
	ostringstream msg;

	try
	{
		m_xmlparser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
		m_xmlparser.parse_memory(pstrxml);
		if (m_xmlparser)
		{
			// check xml verify and get job
			if (!GetXMJobLNode())
			{
				msg << "Failure to acquire a job of requests.";
				LOGACONSOLE(LDBG, msg);
				return -2;
			}

			return 0;
		}
	}
	catch (const std::exception& ex)
	{
		msg << "XML Parsing Exception caught: " << ex.what();
		LOGACONSOLE(LERR, msg);
		return -3;
	}

	msg << "XML Parsing unknown error.";
	LOGACONSOLE(LERR, msg);
	return -1;
}

int CXMLParser::ReadBody()
{
	ostringstream msg;
	msg << "XML Parser : ReadBody()";
	LOGACONSOLE(LDBG, msg);

	m_pBodyData = new BYTE [m_header.ulBodyLength +1];

	int n = m_sock->ReadData(m_pBodyData, m_header.ulBodyLength);

	if( n < 0 )
	{
		msg << "XML Parser : ReadBody() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}
	else if (n == 0)
	{
		return -2;
	}
	else 
	{
		m_pBodyData[m_header.ulBodyLength]= '\0';
	}

	msg << "XML Parser : Body Data [" << m_sock->GetMyIPString() << "]";
	LOGACONSOLE(LINF, msg);
	msg << "################ Data Start ################";
	LOGACONSOLE(LDBG, msg);
	msg << "################ Text ################" << endl;
	msg << (char*) m_pBodyData;
	LOGACONSOLE(LINF, msg);
	msg << "################ Binary ################";
	LOGACONSOLE(LDBG, msg);
	_LOG_HEX_(LDBG, m_pBodyData, m_header.ulBodyLength);
	msg << "################ Data End ################";
	LOGACONSOLE(LDBG, msg);
		
	return Parsering((char*)m_pBodyData);
}

bool CXMLParser::GetXMJobLNode()
{
	bool r = true;

	ostringstream msg;
	try
	{
		xmlpp::Document *doc = m_xmlparser.get_document();
		xmlpp::Element *root = doc->get_root_node();

		// check root
		if(root->get_name() != XML_STR_ROOT)
		{
			r = false;
			msg << "XML root node different.[" << root->get_name() << "," 
				<< PROG_NAME <<"]";
			LOGACONSOLE(LERR, msg);
			return false;
		}
		
		xmlpp::Node::NodeList request = root->get_children(XML_STR_JOB);
		
		// check value
		if( request.size() != 1 )
		{
			r = false;
			msg << "Request empty or 1 over.[size :"<< request.size()  << "]";
			LOGACONSOLE(LERR, msg);
			return false;
		}
		else 
		{
			msg << "Request size.[" << request.size() << "]" ;
			LOGACONSOLE(LDBG, msg);
			m_Job = request.front();
		}
	}
	catch(const std::exception& ex)
	{
		r = false;
		msg << "XML Parsing Exception caught: " << ex.what();	
		LOGACONSOLE(LERR, msg);
	}

	return r;
}

int CXMLParser::ConvertJobData(void *pData)
{
	ostringstream msg;
	msg << "XML Parser : Convert Job Data";
	LOGACONSOLE(LDBG, msg);

	CConvertFactory f;

	// Body type	
	CConvert * convert = f.CreateConvert(const_cast<xmlpp::Node*>(m_Job), pData);
	if(convert == NULL)
	{
		// error
		msg << "Convert Object creation fail.";
		LOGACONSOLE(LERR, msg);
		return JOB_ERR_CREATION_FAIL;
	}

	int r = convert->ToJobData(CServiceInfo::XML, m_Job, pData);

	delete convert;

	return (r >= 0 ?  0 : -1 );
}

int CXMLParser::ConvertClient(void *pData, int nCode/* = 0*/)
{
	int r = 0;
	CConvertFactory f;
	ostringstream msg;

	CConvert * convert = f.CreateConvert(m_Job, pData);
	if(convert == NULL)
	{
		// error
		msg << "Convert Object creation fail.";
		LOGACONSOLE(LERR, msg);
		return JOB_ERR_CREATION_FAIL;
	}

	if(m_pBodyData)
	{
		 delete [] m_pBodyData;
		 m_pBodyData = NULL;
	}

	m_resp = convert->ToClientResult(CServiceInfo::XML, nCode);
	m_pBodyData = (BYTE *) convert->ToClientData(CServiceInfo::XML, nCode, pData, r);

	delete convert;
	
	return r;
}

int CXMLParser::WriteHeader(int32_t bodylen /* = 0 */)
{
	int r = 0;
	ostringstream msg;

	m_header.ulBodyLength = htonl(bodylen) ;

	if( m_sock->WriteData(&m_header , sizeof m_header) < 0 )
	{
		msg << "XML Parser : WriteHeader() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

int CXMLParser::WriteBoad(int32_t bodylen)
{
	int r = 0;
	ostringstream msg;

	if( m_sock->WriteData(m_pBodyData , bodylen) < 0 )
	{
		msg << "XML Parser : WriteBoad() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

// CSDKParser
CSDKParser::CSDKParser()
	: m_pBodyData(NULL)
{

}

CSDKParser::~CSDKParser()
{
	if(m_pBodyData)
		delete [] m_pBodyData;
}

int CSDKParser::ReadHeader()
{
	ostringstream msg;
	msg << "SDK Parser : ReadHeader()";
	LOGACONSOLE(LDBG, msg);

	int n = m_sock->ReadData(&m_header, sizeof m_header) ;
	if( n < 0 )
	{
		msg << "SDK Parser : ReadHeader() Error.";
		LOGACONSOLE(LERR, msg);
		return -1;
	}
	else if( n == 0 )
	{
		return -2;
	}
	else 
	{
		m_header.ulMode = ntohl(m_header.ulMode);
		m_header.ulResult = ntohl(m_header.ulResult);
		m_header.ulBodyLength = ntohl(m_header.ulBodyLength);
	}


	msg << "SDK Parser ReadHeader Data: " << m_header.szTransactionID << ","
		<< m_header.ulMode << "," << m_header.szIssuer << "," 
		<< m_header.szServiceID  << "," << m_header.ulResult << "," 
		<< m_header.ulBodyLength;
	LOGACONSOLE(LDBG, msg);

	return 0;
}

int CSDKParser::ReadBody()
{
	ostringstream msg;
	msg << "SDK Parser : ReadtBoad()";
	LOGACONSOLE(LDBG, msg);

	m_pBodyData = new BYTE[m_header.ulBodyLength+1];
	
	int n = m_sock->ReadData(m_pBodyData, m_header.ulBodyLength);
	if( n < 0 )
	{
		msg << "SDK Parser : ReadtBoad() Error.";
		LOGACONSOLE(LERR, msg);
		return -1;
	}
	else if (n == 0)
	{
		return -2;
	}
	else 
	{
		m_pBodyData[m_header.ulBodyLength] = '\0';
	}		

	

	return 0;
}

int CSDKParser::ConvertJobData(void *pData)
{
	ostringstream msg;
	msg << "SDK Parser : Convert Job Data";
	LOGACONSOLE(LDBG, msg);

	CConvertFactory f;
	
	// Body type
	CConvert * convert = f.CreateConvert(m_header.ulMode);
	if(convert == NULL)
	{
		// error
		msg << "Convert Object creation fail.";
		LOGACONSOLE(LERR, msg);
		return JOB_ERR_CREATION_FAIL;
	}

	int r = convert->ToJobData(CServiceInfo::SDK, m_pBodyData, pData);

	delete convert;

	return (r >= 0 ?  0 : -1 );
}

int CSDKParser::ConvertClient(void *pData, int nCode /*= 0*/)
{
	int r = 0;

	ostringstream msg;
	msg << "SDK Parser : Convert Client Data";
	LOGACONSOLE(LDBG, msg);

	CConvertFactory f;

	// Body type
	CConvert * convert = f.CreateConvert(m_header.ulMode);
	if(convert == NULL)
	{
		// error
		msg << "Convert Object creation fail.";
		LOGACONSOLE(LERR, msg);
		return JOB_ERR_CREATION_FAIL;
	}

	if(m_pBodyData)
	{
		delete [] m_pBodyData;
		m_pBodyData = NULL;
	}

	m_resp = convert->ToClientResult(CServiceInfo::SDK, nCode);
	m_pBodyData = (BYTE*) convert->ToClientData(CServiceInfo::SDK, nCode, pData ,r);

	if( r > 0 && m_pBodyData )
	{
		LOG(LDBG, "ConvertClient : %s, %d", (char *)m_pBodyData, r);
	}

	delete convert;	

	return r;
}

int CSDKParser::WriteHeader(int32_t bodylen /* = 0 */)
{	
	int r = 0;
	ostringstream msg;

	m_header.szTransactionID;
	m_header.ulMode = htonl(m_header.ulMode);
	strcpy(m_header.szIssuer, PROG_NAME);
	m_header.szServiceID;
	
	m_header.ulResult = htonl(m_resp);

	m_header.ulBodyLength = htonl(bodylen);

	LOG(LDBG, "WriteHeader : %s, 0X%0X, %d",m_header.szTransactionID, 
							ntohl(m_header.ulResult), bodylen );

	if( m_sock->WriteData(&m_header , sizeof m_header) < 0 )
	{
		msg << "SDK Parser : WriteHeader() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

int CSDKParser::WriteBoad(int32_t bodylen)
{
	int r = 0;
	ostringstream msg;

	LOG(LDBG, "WriteBoad : %s",(char *) m_pBodyData);

	if( m_sock->WriteData(m_pBodyData, bodylen) < 0 )
	{
		msg << "SDK Parser : WriteBoad() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

// CEtcParser
CEtcParser::CEtcParser()
	: m_pBodyData(NULL)
{

}

CEtcParser::~CEtcParser()	
{
	if(m_pBodyData)
		delete [] m_pBodyData;
}

int CEtcParser::ReadHeader()
{
	ostringstream msg;
	msg << "Etc Parser : ReadHeader()";
	LOGACONSOLE(LDBG, msg);

	int n = m_sock->ReadData(&m_header, sizeof m_header) ;
	if( n < 0 )
	{
		msg << "Etc Parser : ReadHeader() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}
	else if ( n == 0 )
	{
		return -2;
	}
	else 
	{
		m_header.op_num = ntohl(m_header.op_num);
		m_header.op_ret_code = ntohl(m_header.op_ret_code);
	}


	msg << "SDK Parser ReadHeader Data: " << m_header.op_num << ","
		<< m_header.op_ret_code;
	LOGACONSOLE(LDBG, msg);

	return 0;
}

int CEtcParser::ReadBody()
{
	ostringstream msg;
	msg << "Etc Parser : ReadBoyd()";
	LOGACONSOLE(LDBG, msg);

	size_t len = 0;
	switch(m_header.op_num)
	{
	case ETC_REQ_GETFILE_HASH_MD5_10MB:
		len = sizeof(EtcReqBodyMD5_10MB);
		break;
	default:
		msg << "Etc Parser : Body type is unknown.";
		LOGACONSOLE(LERR, msg);
		return -1;
		break;
	}

	m_pBodyData = new BYTE[len+1];
	int n = m_sock->ReadData(m_pBodyData, len);
	if( n < 0 )
	{
		msg << "Etc Parser : ReadBody() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}
	else if (n == 0)
	{
		return -2;
	}
	else 
	{
		m_pBodyData[len] = '\0';
	}	

	return 0;
}

int CEtcParser::ConvertJobData(void *pData)
{
	ostringstream msg;
	msg << "Etc Parser : Convert Job Data";
	LOGACONSOLE(LDBG, msg);

	CConvertFactory f;

	// Body type
	CConvert * convert = f.CreateConvert(m_header.op_num);
	if(convert == NULL)
	{
		// error
		msg << "Convert Object creation fail.";
		LOGACONSOLE(LERR, msg);
		return JOB_ERR_CREATION_FAIL;
	}

	int r = convert->ToJobData(CServiceInfo::ETC, m_pBodyData, pData);

	delete convert;

	return (r >= 0 ?  0 : -1 );
}

int CEtcParser::ConvertClient(void *pData, int nCode /*= 0*/)
{
	int r = 0;

	ostringstream msg;
	msg << "ETC Parser : Convert Client Data";
	LOGACONSOLE(LDBG, msg);

	CConvertFactory f;

	// Body type
	CConvert * convert = f.CreateConvert(m_header.op_num);
	if(convert == NULL)
	{
		// error
		msg << "Convert Object creation fail.";
		LOGACONSOLE(LERR, msg);
		return JOB_ERR_CREATION_FAIL;
	}

	if(m_pBodyData)
	{
		delete [] m_pBodyData;
		m_pBodyData = NULL;
	}

	m_resp = convert->ToClientResult(CServiceInfo::ETC, nCode);
	m_pBodyData = (BYTE*) convert->ToClientData(CServiceInfo::ETC, nCode, pData ,r);

	if( r > 0 && m_pBodyData )
	{
		LOG(LDBG, "ConvertClient : %s, %d", (char *)m_pBodyData, r);
	}

	delete convert;	

	return r;
}

int CEtcParser::WriteHeader(int32_t bodylen /* = 0 */)
{
	int r = 0;
	ostringstream msg;

	m_header.op_num = htonl(m_header.op_num);

	m_header.op_ret_code = htonl(m_resp);

	LOG(LDBG, "WriteHeader : %d, %d", htonl(m_header.op_num), ntohl(m_header.op_ret_code));

	if( m_sock->WriteData(&m_header , sizeof m_header) < 0 )
	{
		msg << "Etc Parser : WriteHeader() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

int CEtcParser::WriteBoad(int32_t bodylen)
{
	int r = 0;
	ostringstream msg;

	LOG(LDBG, "WriteBoad : %s",(char *) m_pBodyData);

	if( m_sock->WriteData(m_pBodyData, bodylen) < 0 )
	{
		msg << "ETC Parser : WriteBoad() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

// CStrXMLParser
CStrXMLParser::CStrXMLParser()
{
}

CStrXMLParser::~CStrXMLParser()
{
}

int CStrXMLParser::ReadHeader()
{
	return 0;
}

int CStrXMLParser::ReadBody()
{
	ostringstream msg;

	const size_t buffsize = 1024;
	char buff[buffsize+1] = { 0 };
	ssize_t r = 0;
	
	string::size_type offset = 0;

	// 통신 종단 메시지
	string findString = "\\n\\n";
	string findString2 = "\n\n";
	while ((r = m_sock->ReadDataEx(buff, buffsize)) > 0)
	{
		buff[r] = '\0';
		m_readdata.append(buff);
		
		// 2016.05.11 토토디스트 ASP와 통신 종단 메세지 처리		
		offset = m_readdata.find(findString);
		if (offset != string::npos)
		{
			m_readdata.replace(offset, findString.length(), "\n");
			break;
		}

		offset = m_readdata.find(findString2);
		if (offset != string::npos)
		{
			m_readdata.replace(offset, findString2.length(), "\n");
			break;
		}

	}

	msg << "XML Parser : Body Data [" << m_sock->GetMyIPString() << "]";
	LOGACONSOLE(LINF, msg);
	msg << "################ Data Start ################";
	LOGACONSOLE(LDBG, msg);
	msg << "################ Text ################" << endl;
	msg << m_readdata;
	LOGACONSOLE(LINF, msg);
	msg << "################ Data End ################";
	LOGACONSOLE(LDBG, msg);


	return Parsering(m_readdata.c_str());
}

int CStrXMLParser::ConvertJobData(void *pData)
{
	return CXMLParser::ConvertJobData(pData);
}

int CStrXMLParser::ConvertClient(void *pData, int nCode /* = 0 */)
{
	return CXMLParser::ConvertClient(pData, nCode);
}

int CStrXMLParser::WriteHeader(int32_t bodylen /* = 0 */)
{
	//return 0;
	return CXMLParser::WriteBoad(bodylen);
}

int CStrXMLParser::WriteBoad(int32_t bodylen /* = 0 */)
{
	//return CXMLParser::WriteBoad(bodylen);
	int r = 0;
	ostringstream msg;

	string s = "\n";

	if (m_sock->WriteData((void*)s.c_str(), s.size()) < 0)
	{
		msg << "XML Parser : WriteBoad() Error.";
		LOGACONSOLE(LDBG, msg);
		return -1;
	}

	return r;
}

// Abstract Factory returning a Parser
CParser* CParserFactory::CreateParser(CServiceInfo &info)
{
	switch(info.m_type)
	{
	case CServiceInfo::XML:
		_LOG( LDBG, "Parser Factory [type:XML,Port:%d]", info.m_port );
		return new CXMLParser();
		break;
	case CServiceInfo::SDK:
		_LOG( LDBG, "Parser Factory [type:SDK,Port:%d]", info.m_port );
		return new CSDKParser();
		break;
	case CServiceInfo::ETC:
		_LOG( LDBG, "Parser Factory [type:ETC,Port:%d]", info.m_port );
		return new CEtcParser();
		break;
	case CServiceInfo::STR:
		_LOG(LDBG, "Parser Factory [type:STR,Port:%d]", info.m_port);
		return new CStrXMLParser();
		break;
	default:
		LOG(LERR, "Parser type is unknown.");
		break;
	}

	return NULL;
}
