//---------------------------------------------------------------------------


#pragma hdrstop

#include "ClientSessionManagerF.h"
#include "VMSCommLibF.h"
//---------------------------------------------------------------------------

#pragma package(smart_init)

//---------------------------------------------------------------------------
TClientSessionManager *ClientSessionManager = NULL;
//---------------------------------------------------------------------------

TClientSessionManager::TClientSessionManager()
{
    FLastTick = 0;
}
//---------------------------------------------------------------------------
TClientSessionManager::~TClientSessionManager()
{
}
//---------------------------------------------------------------------------
TClientSession* TClientSessionManager::CreateClientSession(SOCKET ASock, SOCKADDR_IN* ASockAddr)
{
	TClientSession *pSession = NULL;
#if USE_POOL
    FLists.Lock();
    try
    {
        FOR_STL(TClientSession*, pObj, FLists)
        {
            if (pObj->Socket == INVALID_SOCKET && pObj->State == eSS_none)
            {
                pObj->Create(ASock, ASockAddr);
                pSession = pObj;
                break;
            }
        }
        if (!pSession)
        {
            pSession = new TClientSession();
            if (pSession)
            {
                pSession->Create(ASock, ASockAddr);
                FLists.Push(FLists.Size(), pSession);
            }
        }
    }
    __finally
    {
        FLists.UnLock();
    }
#else
	pSession = new TClientSession(ASock, ASockAddr);
    if (pSession)
    {
	    FClientSessionList.insert(TClientSessionList::value_type(ASock, pSession));
    }
#endif
	return pSession;
}
//---------------------------------------------------------------------------
void TClientSessionManager::SendFlushAllClient()
{
#if USE_POOL
    FLists.Lock();
    try
    {
        FOR_STL(TClientSession*, pSession, FLists)
        {
            if (pSession->Socket != INVALID_SOCKET && pSession->State >= eSS_OnConnect)
            {
                if (false == pSession->SendFlush())
                {
                    pSession->Disconnect();
                }
            }
        }
    }
    __finally
    {
        FLists.UnLock();
    }
#else
	for (TClientSessionList::const_iterator it=FClientSessionList.begin(); it!=FClientSessionList.end(); ++it)
	{
		TClientSession *pSession = it->second;

		if (false == pSession->SendFlush())
		{
			pSession->Disconnect();
		}
	}
#endif
}
//---------------------------------------------------------------------------
void TClientSessionManager::OnPeriodWork()
{
	/// 접속이 끊긴 세션들 주기적으로 정리 (1초 정도 마다 해주자)
	DWORD currTick = GetTickCount();
	if (currTick - FLastTick >= 1000)
	{
		CollectGarbageSessions();
		FLastTick = currTick;
	}
}
//---------------------------------------------------------------------------
void TClientSessionManager::CollectGarbageSessions()
{
	std::vector<TClientSession*> disconnectedSessions;

	for (TClientSessionList::const_iterator it=FClientSessionList.begin(); it!=FClientSessionList.end(); ++it)
	{
		TClientSession *pSession = it->second;

        if (!pSession->IsConnected)
        {
            if (pSession->FCloseTick++ > 10)
            {
                //연결종료후 10초후에 메모리 삭제
                disconnectedSessions.push_back(pSession);
            }
        }
	}

    // 메모리에서 삭제하지 전까지 Socket은 최초 접속했을때의 값을 유지해야 한다.
	for (int ii = 0; ii < (int)disconnectedSessions.size(); ii++)
	{
		TClientSession *pSession = disconnectedSessions[ii];
		FClientSessionList.erase(pSession->Socket);
		delete pSession;
	}
}
//---------------------------------------------------------------------------
TClientSession* TClientSessionManager::FindClientSession(SOCKET ASock)
{
#if USE_POOL
    FLists.Lock();
    try
    {
        FOR_STL(TClientSession*, pSession, FLists)
        {
            if (pSession->Socket == ASock) return pSession;
        }
    }
    __finally
    {
        FLists.UnLock();
    }
    return NULL;
#else
	TClientSessionList::const_iterator it = FClientSessionList.find(ASock);
    if (it == FClientSessionList.end()) return NULL;

	return it->second;
#endif
}
//---------------------------------------------------------------------------
void TClientSessionManager::Init(int APoolSize)
{
#if USE_POOL
    for (int ii = 0; ii < APoolSize; ii++)
    {
        TClientSession *pSession = new TClientSession();
        if (pSession)
        {
            FLists.Push(FLists.Size(), pSession);
        }
    }
#endif
}
//---------------------------------------------------------------------------
void TClientSessionManager::CloseAll()
{
#if USE_POOL
    FLists.Lock();
    try
    {
        FOR_STL(TClientSession*, pSession, FLists)
        {
            if (pSession->Socket != INVALID_SOCKET && pSession->State >= eSS_OnConnect)
            {
                pSession->Disconnect();
            }
        }
    }
    __finally
    {
        FLists.UnLock();
    }
#else
	for (TClientSessionList::const_iterator it=FClientSessionList.begin(); it!=FClientSessionList.end(); ++it)
	{
		TClientSession *pSession = it->second;
        pSession->Disconnect();
	}
#endif
}
//---------------------------------------------------------------------------
void TClientSessionManager::CheckCommandTimeoutSessions()
{
    int nTimeout;

#if USE_POOL
    FLists.Lock();
    try
    {
        FOR_STL(TClientSession*, pSession, FLists)
        {
            if (pSession->Socket != INVALID_SOCKET && pSession->State >= eSS_OnConnect)
            {
                if (pSession->CDSCtlr != NULL && pSession->FChkRecvTO)
                {
                    nTimeout = COMM_TimeDiff(pSession->FTmrRecv);
                    if (nTimeout > 10)
                    {
                        MERROR("+CLIM Session Command timeout: %s,%s. will be closed.", pSession->IpAddress.c_str(), pSession->CDSCtlr->CTLR_NMBR.c_str());
                        pSession->Disconnect();
                    }
                    else
                    if (nTimeout > 5)
                    {
                        if (3 <= COMM_TimeDiff(pSession->FTmrSend))
                        {
                            MERROR("+CLIM Session Command timeout: %s,%s. request parameter.", pSession->IpAddress.c_str(), pSession->CDSCtlr->CTLR_NMBR.c_str());
                            IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
                            pMsg->Type   = eVmsParamReq;
                            pMsg->ObjPtr = (DWORD)pSession;
                            g_jobQ.PushBlocking((DWORD)pMsg);
                        }
                    }
                }
            }
        }
    }
    __finally
    {
        FLists.UnLock();
    }
#else
	for (TClientSessionList::const_iterator it=FClientSessionList.begin(); it!=FClientSessionList.end(); ++it)
	{
		TClientSession *pSession = it->second;

        if (pSession->IsConnected && pSession->CDSCtlr != NULL && pSession->FChkRecvTO)
        {
            nTimeout = COMM_TimeDiff(pSession->FTmrRecv);
            if (nTimeout > 10)
            {
                MERROR("+CLIM Session Command timeout: %s,%s. will be closed.", pSession->IpAddress.c_str(), pSession->CDSCtlr->CTLR_NMBR.c_str());
                pSession->Disconnect();
            }
            else
            if (nTimeout > 5)
            {
                if (3 <= COMM_TimeDiff(pSession->FTmrSend))
                {
                    MERROR("+CLIM Session Command timeout: %s,%s. request parameter.", pSession->IpAddress.c_str(), pSession->CDSCtlr->CTLR_NMBR.c_str());
                    IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
                    pMsg->Type   = eVmsParamReq;
                    pMsg->ObjPtr = (DWORD)pSession;
                    g_jobQ.PushBlocking((DWORD)pMsg);
                }
            }
        }
	}
#endif
}
//---------------------------------------------------------------------------

