////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 2012-2019 (c) Baical                                                        /
//                                                                             /
// This library is free software; you can redistribute it and/or               /
// modify it under the terms of the GNU Lesser General Public                  /
// License as published by the Free Software Foundation; either                /
// version 3.0 of the License, or (at your option) any later version.          /
//                                                                             /
// This library is distributed in the hope that it will be useful,             /
// but WITHOUT ANY WARRANTY; without even the implied warranty of              /
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           /
// Lesser General Public License for more details.                             /
//                                                                             /
// You should have received a copy of the GNU Lesser General Public            /
// License along with this library.                                            /
//                                                                             /
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// This header file provide server functionality                               /
////////////////////////////////////////////////////////////////////////////////
#ifndef P7_SERVER_H
#define P7_SERVER_H

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>Server status enumerator</summary>
enum eServer_Status
{
    ESERVER_STATUS_OK                   = 0,
    ESERVER_STATUS_INTERNAL_ERROR          ,

    //Temporary statuses             

    ESERVER_STATUS_COUNT
};

#define REMOTE_PROCESS_NAME_MAX_LEN 128

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>Connection base information structure</summary>
struct sP7S_Connection_Info
{
    /// <summary>Client network address</summary>
    sockaddr_storage sAddress;
    /// <summary>Protocol version</summary>
    tUINT16          wProtocol_Version;
    /// <summary>Remote process ID</summary>
    tUINT32          dwProcess_ID;
    /// <summary>Remote process time (last 32 bits)</summary>
    tUINT32          dwProcess_Time_Hi;
    /// <summary>Remote process time (first 32 bits)</summary>
    tUINT32          dwProcess_Time_Low;
    /// <summary>Remote process name</summary>
    tXCHAR           pProcess_Name[REMOTE_PROCESS_NAME_MAX_LEN];
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>Connection status information structure</summary>
struct sP7S_Connection_Status
{
    /// <summary>Is connection a live (ping packets or data packets are coming)</summary>
    tBOOL   bConnected;
    /// <summary>Is connection is closed by remote side</summary>
    tBOOL   bClosed;
    /// <summary>Has connection data coming</summary>
    tBOOL   bHas_Data;
    /// <summary>Was connection reinitialized by server</summary>
    tBOOL   bReinitialized;
    /// <summary>Time in milliseconds passed since connection was established</summary>
    tUINT32 dwDuration_Life;
    /// <summary>Time in milliseconds passed since receiving last data/ping packet</summary>
    tUINT32 dwDuration_Off;
    /// <summary>amount of bytes waiting to be read</summary>
    tUINT32 dwPending_Size;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>Connection interface</summary>
class IP7S_Connnection
{
public:
    /// <summary>Get connection information</summary>
    /// <param name="o_pInfo">output. connection information</param>
    /// <returns>TRUE: ok, FALSE: error</returns>
    virtual tBOOL Get_Info(sP7S_Connection_Info *o_pInfo) = 0;

    /// <summary>Get connection statu</summary>
    /// <param name="o_pStatus">output. connection status</param>
    /// <returns>TRUE: ok, FALSE: error</returns>
    virtual tBOOL Get_Status(sP7S_Connection_Status *o_pStatus) = 0;

    /// <summary>Pull incoming data packet</summary>
    /// <returns>data packet pointer</returns>
    virtual CTPacket *Pull_Packet() = 0;

    /// <summary>Release incoming data packet</summary>
    /// <param name="i_pPacket">packet, obtained by Pull_Packet</param>
    virtual void Release_Packet(CTPacket *i_pPacket) = 0;

    /// <summary>Return information about remote side endianesses</summary>
    /// <returns>TRUE: big endian, FALSE: little endian</returns>
    virtual tBOOL Is_BigEndian() = 0;

    /// <summary>Get connection ID</summary>
    /// <returns>ID</returns>
    virtual tUINT32 Get_ID() = 0;
   
    /// <summary>
    /// Function allow you to send to client control packets, because this protocol is optimized to deliver data in
    /// Client->Server direction. Function Push_Packet has slow speed and data size limitation = 490 bytes max.
    /// It can fails by 3 reasons:
    ///  - data cell is busy
    ///  - wrong arguments
    ///  - data is to large
    /// </summary>
    /// <param name="o_pInfo">output. packet information</param>
    /// <returns>data packet pointer, NULL if nothing to read</returns>
    virtual tBOOL  Push_Data(tUINT32 i_dwChannel_ID, const tUINT8 *i_pData, tUINT32 i_dwSize) = 0;

   virtual void  Set_User_Data(void *i_pData) = 0;
   virtual void *Get_User_Data() = 0;

   //to release connection you should use IP7S_Address::Del_Conn()
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>Network address interface</summary>
class IP7S_Address
{
public:
    /// <summary>Get address status</summary>
    /// <returns>eServer_Status enum values</returns>
    virtual eServer_Status Get_Status() = 0;

    /// <summary>Get network address</summary>
    /// <returns>network address (IPv4/IPv6)</returns>
    virtual sockaddr_storage *Get_Socket_Address() = 0;

    //func. get retransmission statistics & reset internal counters, to be used
    //periodically, once per second for example
    virtual tBOOL Get_Stat(tUINT32 &o_rBytesIn, tUINT32 &o_rBytesOut) = 0;

    /// <summary>
    /// Enumerate connections, return connection next to current one i_pConn, if there is no next - return NULL.
    /// If NULL == i_pConn -> returns first one 
    /// </summary>
    /// <param name="i_pConn">current connection, next to this one will be returned</param>
    /// <returns>P7 connection interface</returns>
    virtual IP7S_Connnection *Get_Next_Conn(IP7S_Connnection *i_pConn) = 0;

    /// <summary> Returns new connection </summary>
    /// <returns>P7 connection interface</returns>
    virtual IP7S_Connnection *Get_New_Conn() = 0;

    /// <summary> Delete connection </summary>
    /// <param name="i_pConn">connection to be removed</param>
    /// <returns>TRUE: connection was deleted, FALSE: not found</returns>
    virtual tBOOL Del_Conn(IP7S_Connnection *i_pConn) = 0;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>P7 server interface, entry point</summary>
class IP7_Server
{
public:
    /// <summary> Get next network address comparing to i_pAddress</summary>
    /// <param name="i_pAddress">current address</param>
    /// <returns>P7 Network address</returns>
    virtual IP7S_Address *Get_Next_Address(IP7S_Address *i_pAddress) = 0;

    /// <summary>Get server status</summary>
    /// <returns>status</returns>
    virtual eServer_Status Get_Status() = 0;

    /// <summary>Get server memory consumption information</summary>
    /// <param name="o_rBusy">output. Amount of busy memory in bytes</param>
    /// <param name="o_rAllocated">output. Amount of allocated memory in bytes</param>
    virtual void Get_MemStat(size_t &o_rBusy, size_t &o_rAllocated) = 0;

    /// <summary>Increase object's reference count</summary>
    /// <returns>new reference counter value</returns>
    virtual tINT32 Add_Ref() = 0;

    /// <summary>
    /// Decrease object's reference count, when reference counter will reach 0 - object will be self destroyed
    /// </summary>
    /// <returns>new reference counter value</returns>
    virtual tINT32 Release() = 0;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary> Create P7 server instance</summary>
/// <param name="i_pLog"> interface for internal logging </param>
/// <param name="i_pProp"> parameters </param>
/// <returns>IP7_Server interface</returns>
extern "C" P7_EXPORT IP7_Server* __cdecl P7_Create_Server(IJournal *i_pLog, CProperty *i_pProp);

#endif //P7_SERVER_H
