/**************************************************************************************************
 * File Name	: RegMgr.cpp
 * Created		: 08/09/15
 * Author		: ChenWei
 * Model			: TSD
 * Description	: Register Manager.
 **************************************************************************************************/
#include "RegMgr.h"
#include "StudentMgr.h"
#include "Student.h"
#include "libsesdata.h"
#include "NetSSLClientWrapper.h"
#include "SSL_Context.h"
using namespace LibSESData;

/**************************************************************************************************
 * Function Name	: RegMgr
 * Description		: Construct RegMgr
 * Date				: 08/09/15
 * Parameter		:
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
RegMgr::RegMgr()
{
	mp_COperationManager = NULL;
	m_Errno = 0;
	m_pContext = NULL;
	mp_ACE_Reactor = NULL;
	m_bFirst = 1;
	m_Password = "";
	ACE_OS::thread_mutex_init(&mc_mgr_lock);
}

/**************************************************************************************************
 * Function Name	: instance
 * Description		: Get RegMgr's singleton.
 * Date				: 08/09/15
 * Parameter		:
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
RegMgr * RegMgr::instance(void)
{

	return ACE_Singleton<RegMgr, ACE_SYNCH_MUTEX>::instance();

}

/**************************************************************************************************
 * Function Name	: ~RegMgr
 * Description		: Destroy RegMgr
 * Date				: 08/09/15
 * Parameter		:
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
RegMgr::~RegMgr()
{

	ACE_OS::thread_mutex_lock(&mc_mgr_lock);

	int size = m_StuVector.size();
	for (int i = 0; i < size; i++)
	{
		delete m_StuVector[i];
	}
	m_StuVector.clear();
	if (NULL != m_pContext)
	{
		delete m_pContext;
	}
	if (NULL != mp_ACE_Reactor)
	{
		delete mp_ACE_Reactor;
	}
	mp_ACE_Reactor = NULL;
	m_pContext = NULL;
	ACE_OS::thread_mutex_unlock(&mc_mgr_lock);

}

/**************************************************************************************************
 * Function Name	: StartOpen
 * Description		: Start Accept.
 * Date				: 08/09/15
 * Parameter		:
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
void RegMgr::StartOpen()
{
	int iEvent = 0;
	//	while (bStart)
	//	{
	//		iEvent = ACE_Reactor::instance()->handle_events();
	iEvent = ACE_Reactor::instance()->run_event_loop();//reactor_
	if (iEvent < 0)
	{
		CSESLog::WriteLine("ACE_Reactor->handle_events(&iTime):",
				CSESLog::FATAL);
		CSESLog::WriteLine(ACE_OS_String::strerror(errno), CSESLog::FATAL);

		CSESLog::WriteLine(CSESLogData::LOG_NETWORK_ERROR,
				"ACE_Reactor::instance()->handle_events(); err");
		//}
		//		else
		//		{
		//			CSESLog::WriteLine(iEvent, "ACE_Reactor->handle_events(&iTime):");
		//		}
		//		}

	}
	CSESLog::WriteLine("RegMgr::StatOpen Close");
}
//
//	int nret;
//	do
//	{
//		while (bStart)
//		{
//
//			ACE_Time_Value timeout(1);
//			ACE_Handle_Set temp = handle_set;
//
//			int result = ACE_OS::select(int(cNetSSLServerWrapper.GetHandle())
//					+ 1, (fd_set *) temp, 0, 0, timeout);
//
//			if (result > 0)
//			{
//				if (temp.is_set(cNetSSLServerWrapper.GetHandle()))
//				{
//					// if ssl still err   then reset  cNetSSLServerWrapper
//					nret = cNetSSLServerWrapper.Accept(*cNetSSLClientWrapper);//, &timeout);
//					CSESLog::WriteLine(ACE_OS_String::strerror(errno),
//							CSESLog::WARNING);
//					if (!nret)
//					{
//						CSESLog::WriteLine("RegMgr Accept ERR",
//								CSESLog::WARNING);
//						CSESLog::WriteLine(ACE_OS_String::strerror(errno),
//								CSESLog::WARNING);
//						delete cNetSSLClientWrapper;
//						cNetSSLClientWrapper = new CNetSSLClientWrapper();
//						continue;
//					}
//					else
//					{
//						//cNetSSLClientWrapper->SetOption();
//						nret = cNetSSLClientWrapper->Recv(buff, RECVTIMEOUT);
//						if (nret > 0)
//						{
//							// add err handle
//							RegMgr::instance()->AddStudent(buff,
//									cNetSSLClientWrapper);
//							cNetSSLClientWrapper = new CNetSSLClientWrapper();
//						}
//						else
//						{
//							CSESLog::WriteLine("RegMgr Accept >>Recv",
//									CSESLog::WARNING);
//							CSESLog::WriteLine(ACE_OS_String::strerror(errno),
//									CSESLog::WARNING);
//							delete cNetSSLClientWrapper;
//							cNetSSLClientWrapper = new CNetSSLClientWrapper();
//						}
//					}
//				}
//			}
//			//0 don't have message
//			if (result < 0)
//			{
//				CSESLog::WriteLine(ACE_OS_String::strerror(errno),
//						CSESLog::WARNING);
//			}
//		}
//		delete cNetSSLClientWrapper;
//		cNetSSLServerWrapper.Close();
//	} while (0);
//cNetSSLServerWrapper.Close();


/**************************************************************************************************
 * Function Name	: AddStudent
 * Description		: for CNetSSLServerWrapper Accept
 * Date				: 08/09/15
 * Parameter		: std::string &strIntfData,CNetSSLClientWrapper* cNetSSLClientWrapper
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
void RegMgr::AddStudent(std::string &strIntfData,
		CNetSSLClientWrapper* cNetSSLClientWrapper)
{

	CIntfData cIntfData;
	std::string studentId;
	Student* pStudent = new Student();
	//bool bReturn = false;
	if (cIntfData.load(strIntfData))
	{

		std::string messageName;
		cIntfData.GetMessage(messageName);
		//		if (0 == messageName.compare(TEACHER_ROOTCA))
		//		{
		//
		//		}
		cIntfData.GetStudentID(studentId);

		pStudent->SetStudentID(studentId);
		std::list<StudentInfo_t> studentInfo_tList;

		cIntfData.ParaXmlDoc.getStudentInfoList(studentInfo_tList);

		int iTime;
		time((time_t*) &iTime);
		StudentInfo_t si = studentInfo_tList.front();
		si.start_time = iTime;

		//pStudent->SetStudentInfo_t(studentInfo_tList.front());

		pStudent->SetStudentInfo_t(si);

		pStudent->SetConn(*cNetSSLClientWrapper);
		pStudent->SetStudentID(studentId);

		bool isOnlyOne = CStudentMgr::instance()->AddNewStudent(pStudent);
		if (true == isOnlyOne)
		{
			RegMgrCallback();
			return;
		}
	}
	else
	{
		delete cNetSSLClientWrapper;
	}
	// low message worng
	//		ACE_OS::thread_mutex_lock(&mc_mgr_lock);
	//
	//		int stuVectorSize = m_StuVector.size();
	//		std::string temp;
	//
	//		for (int var = 0; var < stuVectorSize; ++var)
	//		{
	//			((Student*) m_StuVector[var])->GetStudentID(temp);
	//
	//			if (studentId.compare(temp) == 0)
	//			{
	//
	//				delete m_StuVector[var];
	//				m_StuVector[var] = pStudent;
	//
	//				bReturn = true;
	//				break;
	//
	//			}
	//		}
	//		if (!bReturn)
	//		{
	//			m_StuVector.push_back(pStudent);
	//
	//		}
	//
	//		ACE_OS::thread_mutex_unlock(&mc_mgr_lock);

	//		if (!bReturn)
	//		{
	//			RegMgrCallback(cIntfData);
	//		}

	//RegMgrCallback(cIntfData);

}

/**************************************************************************************************
 * Function Name	: RegMgrThread
 * Description		: RegMgrThread.
 * Date				: 08/09/15
 * Parameter		: void *arg
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
void* RegMgr::RegMgrThread(void *arg)
{
	RegMgr::instance()->StartOpen();
	return NULL;
}

/**************************************************************************************************
 * Function Name	: Accept
 * Description		: Accept connect.
 * Date				: 08/09/15
 * Parameter		:
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
int RegMgr::Accept(int iPort, int iDownloadPort)
{
	//CSESLog::WriteLine(" RegMgr::Accept()>>Start");
	bStart = true;
	int iReturn = SES_API_SUCCESS;
	//ACE_SSL_Context::instance()->~ACE_SSL_Context();
	//new ACE_SSL_Context();
	m_iPort = iPort;
	do
	{
		//m_pContext = ACE_SSL_Context::instance();
		//		if (context->certificate(CERTIFICATE, SSL_FILETYPE_PEM) < 0)
		//		{
		//			CSESLog::WriteLine("Verifycertificate", CSESLog::ERROR);
		//			CSESLog::WriteLine(ACE_OS_String::strerror(errno), CSESLog::WARNING);
		//			iReturn = SES_API_FAILURE;
		//			break;
		//		}
		//		context->context()->default_passwd_callback_userdata
		//				= (void*) m_Password.c_str();
		//context->context()->default_passwd_callback_userdata= (void*) m_Password.c_str();
		//		if (context->private_key(PRIVATE_KEY, SSL_FILETYPE_PEM) < 0)
		//		{
		//			CSESLog::WriteLine("context->private_key", CSESLog::ERROR);
		//			CSESLog::WriteLine(ACE_OS_String::strerror(errno), CSESLog::WARNING);
		//			iReturn = SES_API_FAILURE;
		//			break;
		//		}
		CSESLog::WriteLine(iPort, "Tcp port");
		//		for (int i = 0; i < 2147483699; i++)
		//		{
		//			iPort = i;
		m_cNetSSLServerWrapper.SetLlisten_port(iPort);
		if (!m_cNetSSLServerWrapper.Open())
		{
			CSESLog::WriteLine(iPort, ACE_OS_String::strerror(errno));
			//			CSESLog::WriteLine(, CSESLog::WARNING);
			m_Errno = errno;
			iReturn = errno;
			//break;
		}
		//		}
		//m_cNetSSLServerWrapper.priority(MAX_PRIORITY);
		CSESLog::WriteLine(iDownloadPort, "Download port");
		m_cNetSSLServerWrapper2.SetLlisten_port(iDownloadPort);
		if (!m_cNetSSLServerWrapper2.Open())
		{
			CSESLog::WriteLine(ACE_OS_String::strerror(errno), CSESLog::WARNING);
			m_Errno = errno;
			iReturn = errno;
			m_cNetSSLServerWrapper.Close();
			break;
		}
		//m_cNetSSLServerWrapper2.priority(MAX_PRIORITY);

		CSESLog::WriteLine(ACE_OS_String::strerror(errno), CSESLog::WARNING);

		CNetSSLServerWrapper* cNetSSLServerWrapper1 = &m_cNetSSLServerWrapper;
		CNetSSLServerWrapper* cNetSSLServerWrapper2 = &m_cNetSSLServerWrapper2;
		cNetSSLServerWrapper1->SetOption();
		cNetSSLServerWrapper2->SetOption();
		int iRegister1 = ACE_Reactor::instance()->register_handler(
				cNetSSLServerWrapper1, ACE_Event_Handler::ACCEPT_MASK);
		CSESLog::WriteLine(iRegister1, "register_handler(cNetSSLServerWrapper1");
		int iRegister2 = ACE_Reactor::instance()->register_handler(
				cNetSSLServerWrapper2, ACE_Event_Handler::ACCEPT_MASK);
		CSESLog::WriteLine(iRegister2, "register_handler(cNetSSLServerWrapper2");
		m_bFirst = 0;
		//iReturn = m_Errno;
		//CSESLog::WriteLine(ACE_Reactor::instance()->register_handler(
		//				&m_cNetSSLServerWrapper, ACE_Event_Handler::ACCEPT_MASK),
		//				"register_handler(&m_cNetSSLServerWrapper");
	} while (0);
	CSESLog::WriteLine(iReturn, " RegMgr::Accept()<<End");
	return iReturn;
}

/**************************************************************************************************
 * Function Name	: StopAccept
 * Description		: Stop accept.
 * Date				: 08/09/15
 * Parameter		:
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
bool RegMgr::StopAccept()
{
	CSESLog::WriteLine(" RegMgr::StopAccept()>>Start");
	//#ifndef OPENSSL_NO_COMP
	//	STACK_OF(SSL_COMP) * ssl_comp_methods = SSL_COMP_get_compression_methods();
	//	if (ssl_comp_methods)
	//		sk_SSL_COMP_free(ssl_comp_methods);

	//CRYPTO_cleanup_all_ex_data();
	//	ERR_remove_state(0);
	//	ERR_free_strings();
	//#endif
	//SSL_CTX_free(ACE_SSL_Context::instance()->context());
	//***
	//SSL_CTX_flush_sessions(ACE_SSL_Context::instance()->context(), 0);

	bool bReturn = true;
	bStart = false;
	///*** if you want to wait_grp please set bStart = false; after ACE_Reactor::instance()->remove_handler
	//so ACE_Reactor::instance()->remove_handler will occurs handle_event return .
	//int iResult = 0;

	//	iResult = ACE_Reactor::instance()->end_event_loop();//reactor_
	//	if (1> iResult)
	//	{
	//
	//		CSESLog::WriteLine(iResult,
	//				" ACE_Reactor::instance()->end_event_loop():");
	//
	//	}
	//	iResult = ACE_Reactor::instance()->event_loop_done();//reactor_
	//	if (1> iResult)
	//	{
	//
	//		CSESLog::WriteLine(iResult,
	//				" ACE_Reactor::instance()->event_loop_done():");
	//	}
	if (m_cNetSSLServerWrapper.IsOpen())
	{
		ACE_Reactor::instance()->remove_handler(&m_cNetSSLServerWrapper,
				ACE_Event_Handler::ACCEPT_MASK);
	}
	//	sleep(1);
	//	iResult = ACE_Reactor::instance()->end_event_loop();//reactor_
	//	if (1 > iResult)
	//	{
	//
	//		CSESLog::WriteLine(iResult,
	//				" ACE_Reactor::instance()->end_reactor_event_loop():");
	//
	//	}
	//	iResult = ACE_Reactor::instance()->event_loop_done();//reactor_
	//	if (1 > iResult)
	//	{
	//
	//		CSESLog::WriteLine(iResult,
	//				" ACE_Reactor::instance()->reactor_event_loop_done():");
	//	}
	if (m_cNetSSLServerWrapper2.IsOpen())
	{
		ACE_Reactor::instance()->remove_handler(&m_cNetSSLServerWrapper2,
				ACE_Event_Handler::ACCEPT_MASK);
	}

	//ACE_Thread_Manager::instance()->close();
	ACE_OS::thread_mutex_lock(&mc_mgr_lock);
	CSESLog::WriteLine(" RegMgr::StopAccept()>>thread_mutex_lock");
	int size = m_StuVector.size();
	for (int i = 0; i < size; i++)
	{
		delete m_StuVector[i];
	}
	m_StuVector.clear();

	ACE_OS::thread_mutex_unlock(&mc_mgr_lock);
	if (NULL != mp_ACE_Reactor)
	{
		delete mp_ACE_Reactor;
	}
	m_pContext = NULL;
	m_cNetSSLServerWrapper.Close();
	m_cNetSSLServerWrapper2.Close();
	SSL_CTX_flush_sessions(ACE_SSL_Context::instance()->context(), 0);
	//ACE_SSL_Context::instance()->
	CSESLog::WriteLine(" RegMgr::StopAccept()<<End");
	return bReturn;

}

/**************************************************************************************************
 * Function Name	: RegisterCOperationManager
 * Description		: RegisterC OperationManager.
 * Date				: 08/09/15
 * Parameter		: COperationManager *cOperationManager
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
bool RegMgr::RegisterCOperationManager(COperationManager *cOperationManager)
{

	mp_COperationManager = cOperationManager;
	return true;
}

/**************************************************************************************************
 * Function Name	: RegMgrCallback
 * Description		: RegMgr Callback.
 * Date				: 08/09/15
 * Parameter		: CIntfData& intfData
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
//void RegMgr::RegMgrCallback(CIntfData& intfData)
//{
//	CSESLog::WriteLine(" RegMgr::RegMgrCallback>>Start");
//	if (mp_COperationManager != NULL)
//	{
//		mp_COperationManager->RegMgrCallback(intfData);
//	}
//	CSESLog::WriteLine(" RegMgr::RegMgrCallback<<End");
//	return;
//}
void RegMgr::RegMgrCallback()
{
	CSESLog::WriteLine(" RegMgr::RegMgrCallback>>Start");
	if (mp_COperationManager != NULL)
	{
		mp_COperationManager->RegMgrCallback();
	}
	CSESLog::WriteLine(" RegMgr::RegMgrCallback<<End");
	return;
}

/**************************************************************************************************
 * Function Name	: UpdateStudent
 * Description		: UpdateStudent
 * Date				: 08/09/15
 * Parameter		: std::string& studentID,StudentInfo_t& studentInfo_t, bool bAllow
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
bool RegMgr::UpdateStudent(std::string& studentID,
		StudentInfo_t& studentInfo_t, bool bAllow)
{
	CSESLog::WriteLine(" RegMgr::RegMgrCallback>>Start");
	bool bReturn = false;

	ACE_OS::thread_mutex_lock(&mc_mgr_lock);

	std::vector<Student*>::iterator startIterator;

	std::string existStudentID;
	startIterator = m_StuVector.begin();
	int size = m_StuVector.size();

	for (int i = 0; i < size; i++)
	{

		m_StuVector[i]->GetStudentID(existStudentID);

		if (0 == existStudentID.compare(studentID))
		{

			if (bAllow)
			{
				m_StuVector[i]->SetStudentInfo_t(studentInfo_t);

			}

			else
			{
				delete (*startIterator);
				m_StuVector.erase(startIterator);
			}

			bReturn = true;
			break;
		}
		startIterator++;

	}

	ACE_OS::thread_mutex_unlock(&mc_mgr_lock);
	CSESLog::WriteLine(" RegMgr::RegMgrCallback<<End");
	return bReturn;
}

/**************************************************************************************************
 * Function Name	: ControlNewStudent
 * Description		: Control NewStudent
 * Date				: 08/09/15
 * Parameter		: std::string& studentID, bool bAllow, CIntfData& cIntfData
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
//bool RegMgr::ControlNewStudent(std::string& studentID, bool bAllow,
//		CIntfData& cIntfData)
//{
//	CSESLog::WriteLine(" RegMgr::ControlNewStudent>>Start");
//	bool bReturn = false;
//
//	ACE_OS::thread_mutex_lock(&mc_mgr_lock);
//
//	std::vector<Student*>::iterator startIterator;
//
//	std::string existStudentID;
//	startIterator = m_StuVector.begin();
//	int size = m_StuVector.size();
//
//	for (int i = 0; i < size; i++)
//	{
//
//		((Student*) m_StuVector[i])-> GetStudentID(existStudentID);
//
//		if (0 == existStudentID.compare(studentID))
//		{
//			if (bAllow)
//			{
//				std::string msg;
//				cIntfData.toString(msg);
//				m_StuVector[i]->Send(msg);
//
//				if (CStudentMgr::instance()->AddNewStudent(
//						(Student*) m_StuVector[i]))
//				{
//					bReturn = true;
//				}
//
//			}
//			else
//			{
//				delete (*startIterator);
//			}
//			m_StuVector.erase(startIterator);
//
//			break;
//		}
//		startIterator++;
//
//	}
//
//	ACE_OS::thread_mutex_unlock(&mc_mgr_lock);
//	CSESLog::WriteLine(" RegMgr::ControlNewStudent>>End");
//	return bReturn;
//}

/**************************************************************************************************
 * Function Name	: AddNewStudent
 * Description		: Add NewStudent old for CStudentMgr
 * Date				: 08/09/15
 * Parameter		: Student* student, const std::string& studentId
 * Return Code		:
 * Author			: ChenWei
 **************************************************************************************************/
bool RegMgr::AddNewStudent(Student* student, const std::string& studentId)
{

	ACE_OS::thread_mutex_lock(&mc_mgr_lock);
	std::vector<Student*>::iterator startIterator;
	bool bReturn = false;
	startIterator = m_StuVector.begin();
	int size = m_StuVector.size();
	for (int i = 0; i < size; i++)
	{
		std::string temp;
		((Student*) m_StuVector[i])-> GetStudentID(temp);
		if (temp.compare(studentId) == 0)
		{

			student = m_StuVector[i];
			m_StuVector.erase(startIterator);

			bReturn = true;
			break;
		}
		startIterator++;

	}

	ACE_OS::thread_mutex_unlock(&mc_mgr_lock);
	return bReturn;

}
