#ifndef __CHANNEL__
#define __CHANNEL__

#ifdef _WIN32
    #include "WinSock2.h"
    #define SHUT_RDWR SD_BOTH
    #define SHUT_WR   SD_SEND
    #define SHUT_RD   SD_RECEIVE
#endif


#include "lwintypes.h"
#include "ltrapi.h"
#include "ltimer.h"
#include "stdlib.h"
#include "ltrd_protocol_defs.h"
#include "config.h"


#define EXPORT_SEND_RECV    0

/*================================================================================================*/
/*================================================================================================*/

/*================================================================================================*/

#ifdef __cplusplus
extern "C" {
#endif

#define LTR_CHANNEL_PRIV_BUF_MAX  4

/** стркуктура с даннми канала связи с сервером -
  внутренние данные описателя TLTR */
typedef struct LTR_CHANNEL {
    DWORD default_tout; /**< таймаут по-умолчанию. Реально каналом самим не
                            используется, а просто поле для хранения и получения,
                            т.к. размер TLTR менять нельзя */
    SOCKET sock;        /**< сокет для связи с сервером */

    LARGE_INTEGER unixtime;

    DWORD recv_part_wrd; /**< принятое неполностью слово */
    DWORD send_part_wrd; /**< переданное неполностью слово */
    BYTE  recv_part_size;  /**< кол-во принятых байт в последнем неполном слове */
    BYTE  send_part_size;  /**< кол-во неотправленных байт в последнем переданном не полностью слове */
#ifdef LTRAPI_USE_WSA_SOCKS
    WSAOVERLAPPED ovRead;
    WSAOVERLAPPED ovWrite;
#endif

    // для обработки ESC-последовательностей
    struct st_internal_esc {
        DWORD type;                     // сохраненный тип сигнала (из ESCAPE-слова)
        WORD data_count;                // количество принятых слов данных
        WORD data_len;                  // количество слов данных всего
        DWORD data[LTR_SIG_MAX_DWORDS]; // буфер для приема данных esc-последовательности
    } esc;

    void* priv_buf[LTR_CHANNEL_PRIV_BUF_MAX]; /**< приватный буфер для скрытых данных API верхнего уровня */
} TLTR_CHANNEL, *PTLTR_CHANNEL;

static LINLINE BOOL ltr_ch_is_open(const TLTR_CHANNEL *ch) {
    return ch && ch->sock != INVALID_SOCKET;
}

static LINLINE void ltr_ch_set_def_tout(TLTR_CHANNEL *ch, DWORD tout) {
    if (ch)
        ch->default_tout = tout;
}

static LINLINE DWORD ltr_ch_get_def_tout(const TLTR_CHANNEL *ch) {
    return ch ? ch->default_tout : 0;
}








INT ltr_ch_priv_alloc(TLTR_CHANNEL* ch, DWORD id, DWORD size);
INT ltr_ch_priv_free(TLTR_CHANNEL* ch, DWORD id);
static LINLINE void* ltr_ch_priv_get(TLTR_CHANNEL* ch, DWORD id) {
    return id < LTR_CHANNEL_PRIV_BUF_MAX ? ch->priv_buf[id] : NULL;
}



TLTR_CHANNEL* ltr_ch_create(void);
void ltr_ch_free(TLTR_CHANNEL* ch);

INT ltr_ch_open(TLTR_CHANNEL *ch, DWORD addr, WORD port, t_ltimer *ptmr);
void ltr_ch_close(TLTR_CHANNEL *ch);
void ltr_ch_tx_shutdown(TLTR_CHANNEL *ch);
/** Прием блока данных по каналу (сокету)
    @return <0 - Код ошибки, >=0 - количество принятых данных */
INT ltr_ch_recv(TLTR_CHANNEL *ch, LPBYTE buf, DWORD size, t_ltimer *ptmr);
/** Передача блока данных по каналу (сокету)
    @return <0 - Код ошибки, >=0 - количество переданных данных */
INT ltr_ch_send(TLTR_CHANNEL *ch, LPCBYTE buf, DWORD size, t_ltimer *ptmr);


#ifdef __cplusplus
}
#endif
/*================================================================================================*/
#endif
