//--------------------------------------------------------------------------------------------
unsigned int TSessionManager::GetSessionID( unsigned int ip, unsigned short port )
{
  unsigned int id = INVALID_HANDLE_SESSION;
  if( mNavigateSession == nullptr )
    return id;
  TIP_Port ip_port( ip, port );
  TSession* pSession = mNavigateSession->FindSessionByIP( ip_port );
  if( pSession )
    id = pSession->GetID();
  return id;
}
//--------------------------------------------------------------------------------------------
void TSessionManager::DisconnectHandler( TDisconnectTransportEvent* pEvent )
{
  if( mNavigateSession == nullptr )
    return;

  TSession* pSession = mNavigateSession->FindSessionByIP( pEvent->ip_port );
  if( pSession )
  {
    unsigned int id = pSession->GetID();
    mCallBackDiconnect.Notify( id );
    mNavigateSession->Delete( pSession );
  }
}
//--------------------------------------------------------------------------------------------
void TManagerSession::Recv( INetTransport::TDescRecv* pDescRecv, INetTransport* pTransport)
{
  lockAccessSession();
  if(mNavigateSession==NULL)
  {
    unlockAccessSession();
    return;
  }
  //===================================================================
  // данные, пришедшие от сессии содержат заголовок, учесть при формировании
  TSession::THeader* pHeader = (TSession::THeader*)pDescRecv->data;
  // определить новая сессия или нет
  TSession* pSession = mNavigateSession->FindSessionByIP(pDescRecv->ip_port);
  if(pSession==NULL)
  {
    // новую сессию создавать, только если получен RSA ключ
    if(pHeader->type!=TSession::eKeyRSA)
    {
      unlockAccessSession();
      return;
    }
    pSession = NewSession(pDescRecv->ip_port, pTransport);
  }
  else
    pSession->Recv();// уведомить сессию о приеме
  unsigned int id = pSession->GetID();
  //-----------------------------------------------
  TDescRecvSession descRecvSession;
  *((INetTransport::TDescRecv*)&descRecvSession) = *pDescRecv;
  descRecvSession.id_session = id;
  // данные, пришедшие от сессии содержат заголовок, учесть при формировании
  descRecvSession.use_crypt  = pHeader->use_crypt;
  switch(pHeader->type)
  {
    case TSession::eEcho:
      break;
    case TSession::ePacket:
      RecvPacket(descRecvSession, pSession);
      break;
    case TSession::eKeyRSA:
      RecvKeyRSA(descRecvSession, pSession);
      break;
    case TSession::eKeyAES:
      RecvKeyAES(descRecvSession);
      break;
    default:
      FixHack("Undefined type packet");
  }
  unlockAccessSession();
}
//--------------------------------------------------------------------------------------------
void TSessionManager::ConnectAsync( TIP_Port& ip_port, std::string& login, std::string& password, unsigned char subNet, ConnectResultCallback onResult )
{
  BL_ASSERT( flgNeedAnswerFromUp == false );

  mConnectResult = onResult;
  BeginWaitConnectUp();
  lockConnectUp();

  INetTransport* pTransport = mMngTransport->FindBySubNet( subNet );
  if( pTransport == nullptr )
  {
    unlockConnectUp();
    return mConnectResult( INVALID_HANDLE_SESSION );
  }

  if( mNavigateSession == nullptr )
  {
    unlockConnectUp();
    return mConnectResult( INVALID_HANDLE_SESSION );
  }
  //===================================================================
  // соединиться с сервером (верхнее соединение)
  if( pTransport->Connect( ip_port.ip, ip_port.port ) == false )
  {
    unlockConnectUp();
    return mConnectResult( INVALID_HANDLE_SESSION );// нет такого прослушивающего порта
  }// connect to event
  mIP_PortUp = ip_port; // запомнить параметры верхнего соединения

  TSession* pSession = mNavigateSession->FindSessionByIP( mIP_PortUp );
  if( pSession == nullptr )
    pSession = NewSession( mIP_PortUp, pTransport, true/*connect to*/ );
  else
  {
    unlockConnectUp();
    GetLogger( STR_NAME_MMO_ENGINE )->
      WriteF_time( "TSessionManager::Send(%s) sending to IP with exist session.\n", ip_port.ToString() );
    BL_FIX_BUG();
    return mConnectResult( INVALID_HANDLE_SESSION );
  }
  mSessionID_UP = pSession->GetID();
  pSession->SetLogin( login );
  pSession->SetPassword( password );
  pSession->SetState( TSession::StateWaitKeyAES );
  pSession->SendLogin();

  unlockConnectUp();
  // waiting recv...
}
//--------------------------------------------------------------------------------------------
unsigned int TManagerSession::GetSessionID(unsigned int ip, unsigned short port)
{
    unsigned int id = INVALID_HANDLE_SESSION;
    lockAccessSession();
    if(mNavigateSession==NULL)
    {
        unlockAccessSession();
        return id;
    }
    //===================================================================
    TSession* pSession = mNavigateSession->FindSessionByIP(TIP_Port(ip,port));
    if(pSession)
        id = pSession->GetID();
    unlockAccessSession();
    return id;
}
//--------------------------------------------------------------------------------------------
void TSessionManager::RecvHandler( TRecvTransportEvent* pEvent )
{
  if( mNavigateSession == nullptr )
    return;
  //===================================================================
  // данные, пришедшие от сессии содержат заголовок, учесть при формировании
  auto pHeader = (TSession::THeader*)pEvent->data.GetPtr();
  // определить новая сессия или нет
  TSession* pSession = mNavigateSession->FindSessionByIP( pEvent->ip_port );
  if( pSession == nullptr )
    return;

  TDescRecvSession descRecvSession;
  descRecvSession.c        = pEvent->data;// данные пакета
  descRecvSession.data     = descRecvSession.c.GetPtr();
  descRecvSession.dataSize = descRecvSession.c.GetSize();

  descRecvSession.ip_port   = pEvent->ip_port;
  descRecvSession.type      = pEvent->typeRecv;
  descRecvSession.sessionID = pSession->GetID();
  // данные, пришедшие от сессии содержат заголовок, учесть при формировании
  switch( pHeader->type )
  {
    case TSession::eEcho:
      break;
    case TSession::eData:
      RecvData( descRecvSession, pSession );
      break;
    case TSession::eLogin:
      RecvLogin( descRecvSession, pSession );
      break;
    case TSession::eKeyAES:
      RecvKeyAES( descRecvSession, pSession );
      break;
    case TSession::eIDconfirmation:
      RecvIDconfirmation( descRecvSession, pSession );
      break;
    default:
    {
      BL_FIX_BUG();
      FixHack( "Undefined type packet" );
    }
  }
}
//--------------------------------------------------------------------------------------------
void TManagerSession::Disconnect(TIP_Port* ip_port)
{
    lockAccessSession();
    if(mNavigateSession==NULL)
    {
        unlockAccessSession();
        return;
    }
    //===================================================================
    mMngCtxCrypto.Close(*ip_port);

    TSession* pSession = mNavigateSession->FindSessionByIP(*ip_port);
    if(pSession)
    {
        unsigned int id = pSession->GetID();
        mCallBackDiconnect.Notify(id);
        mNavigateSession->Delete(pSession);
    }
    unlockAccessSession();
}
//--------------------------------------------------------------------------------------------
unsigned int TManagerSession::Send(unsigned int ip, unsigned short port, TBreakPacket bp, unsigned char subNet, bool check)
{
    lockConnectUp();

    INetTransport* pTransport = mMngTransport->FindBySubNet(subNet);
    if(pTransport==NULL)
    {
        unlockConnectUp();
        return INVALID_HANDLE_SESSION;
    }

    lockAccessSession();
    if(mNavigateSession==NULL)
    {
        unlockAccessSession();
        unlockConnectUp();
        return INVALID_HANDLE_SESSION;
    }
    //===================================================================
    // соединиться с сервером
    if(pTransport->Connect(ip, port)==false)
    {
        unlockAccessSession();
        unlockConnectUp();
        //BL_FIX_BUG();
        return INVALID_HANDLE_SESSION;// нет такого прослушивающего порта
    }
    mIP_PortUp.Set(ip,port);  // запомнить параметры верхнего соединения

    TSession* pSession = mNavigateSession->FindSessionByIP(mIP_PortUp);
    if(pSession==NULL)
        pSession = NewSession(mIP_PortUp, pTransport);
    else
    {
        unlockAccessSession();
        unlockConnectUp();
        GetLogger(STR_NAME_MMO_ENGINE)->
        WriteF_time("TManagerSession::Send(0x%X,%u) sending to IP with exist session.\n", ip, port);
        BL_FIX_BUG();
        return INVALID_HANDLE_SESSION;
    }
    unsigned int id_session = pSession->GetID();
    // отсылка запроса на AES ключ
    SendKeyRSA_Up(pSession);

    unlockAccessSession();
    //===================================================================
    // ждем ответа
    bool res = WaitAnswerFromUp();
    CleanFlagsForWaitUp();
    if(res==false)
    {
        unlockConnectUp();
        GetLogger(STR_NAME_MMO_ENGINE)->
        WriteF_time("Wait Answer From Up don't recv answer.\n");
        return INVALID_HANDLE_SESSION;
    }
    //===================================================================
    lockAccessSession();
    if(mNavigateSession==NULL)
    {
        // произошел разрыв соединения
        unlockAccessSession();
        unlockConnectUp();
        return INVALID_HANDLE_SESSION;
    }
    // возможно сессия была удалена, пока ждали ответа
    pSession = mNavigateSession->FindSessionByID(id_session);
    if(pSession)
        Send(pSession, bp, check);
    else
        id_session = INVALID_HANDLE_SESSION;

    unlockConnectUp();
    unlockAccessSession();
    return id_session;
}