#ifndef LIP_HTTP_SERVER_H
#define LIP_HTTP_SERVER_H

/***************************************************************************//**
 @defgroup lip_http_server HTTP Server
 @ingroup  lip_lvl_app
 @brief Модуль стека @c lip, реализующий HTTP-сервер.\n
  Зависит от: @ref lip_tcp




*******************************************************************************/

#include "lip_http.h"
#include "lip/transport/tcp/lip_tcp.h"

/** Структура, определяющая версию протокола HTTP */
typedef struct {
    uint8_t major; /**< Мажорный номер версии */
    uint8_t minor; /**< Минорный номер версии */
} t_lip_http_ver;

/** Параметры принятого запроса по HTTP */
typedef struct {
    t_lip_http_ver http_version; /**< Версия протокола HTTP клиента, пославшего запрос */
    t_lip_http_method method; /**< Метод HTTP, используемый в запросе */
    const char *target; /**< Цель запроса (пусть к ресурсу внутри сервера).
                             Строка длиной target_len (для облегчения отладки оканивается
                             нулевым символом в (target_len + 1)-ом символе */
    int target_len; /**< Длина строки в поле target (без нулевого символа) */
} t_lip_http_req_params;



typedef struct {
    const char *name;
    int name_len;
    char *value;
    int value_len;
} t_lip_http_hdr_req_field_params;





/** Способ определения длины тела http-запроса */
typedef enum {
    /** Длина тела явно не определена в запросе и установлена исходя из
     * условия по умолчанию */
    LIP_HTTP_BODYLEN_IMPLICIT,
    /** Длина тела задана явно с помощью поля Content-Length */
    LIP_HTTP_BODYLEN_EXPLICIT,
    /** Длина явно не определена, передача идет по блоку, конец определяется по финальному блоку */
    LIP_HTTP_BODYLEN_CHUNKED,
    /** Длина явно не определена, конец передачи определяется по закрытию соединения */
    LIP_HTTP_BODYLEN_ON_CLOSE,
} t_lip_http_body_len_type;

typedef struct {        
    t_lip_http_body_len_type len_type;
    int len;
} t_lip_http_req_body_params;

typedef t_lip_http_status_code (* t_lip_http_server_hdr_field_cb)(t_lsock_id sock, void *ctx, t_lip_http_hdr_req_field_params *params);
typedef t_lip_http_status_code (* t_lip_http_server_data_start_cb)(t_lsock_id sock, void *ctx, t_lip_http_req_body_params *params);
typedef t_lip_http_status_code (* t_lip_http_server_data_block_cb)(t_lsock_id sock, void *ctx, const uint8_t *block, int block_size);
typedef t_lip_http_status_code (* t_lip_http_server_req_finish_cb)(t_lsock_id sock, void *ctx, t_lip_http_status_code err);


typedef int (* t_lip_http_server_get_resp_data_cb)(t_lsock_id sock, void *ctx, int offset, uint8_t *buf, int buf_size);
typedef int (* t_lip_http_server_get_resp_hdrfield_cb)(t_lsock_id sock, void *ctx, const char *name, uint8_t *buf, int buf_size);
typedef void (* t_lip_http_server_resp_finish_cb)(t_lsock_id sock, void *ctx, int total_size);

typedef struct st_lip_http_resp t_lip_http_resp;



typedef struct {
    void *context;
    t_lip_http_server_hdr_field_cb  hdr_field_cb;
    t_lip_http_server_data_start_cb data_start_cb;
    t_lip_http_server_data_block_cb data_block_cb;
    t_lip_http_server_req_finish_cb req_finish_cb;
} t_lip_http_req_proc_params;


typedef t_lip_http_status_code (* t_lip_http_server_req_cb)(t_lsock_id socket, const t_lip_http_req_params *params, t_lip_http_req_proc_params *proc_params);


t_lip_errs lip_http_server_listen_start(uint16_t port, t_lip_http_server_req_cb cb, uint16_t sock_cnt);

t_lip_errs lip_http_srv_get_resp(t_lsock_id socket, t_lip_http_resp **resp);
t_lip_errs lip_http_srv_request_finish(t_lsock_id socket);
t_lip_errs lip_http_srv_close_connection(t_lsock_id socket);
t_lip_errs lip_http_srv_abort_connection(t_lsock_id socket);

void lip_http_resp_set_status_code(t_lip_http_resp *resp, t_lip_http_status_code status);
void lip_http_resp_add_hdrfield(t_lip_http_resp *resp, const char *name, int name_len, const char *value, int value_len);
void lip_http_resp_add_hdrfield_cbval(t_lip_http_resp *resp, const char *name, int name_len, t_lip_http_server_get_resp_hdrfield_cb cb, void *ctx);
void lip_http_resp_add_hdrfield_intval(t_lip_http_resp *resp, const char *name, int name_len, int value);
void lip_http_resp_set_data_buf(t_lip_http_resp *resp, const uint8_t *data, int data_len);
void lip_http_resp_set_data_cb(t_lip_http_resp *resp, t_lip_http_server_get_resp_data_cb cb, int data_len, void *ctx);
void lip_http_resp_set_finish_cb(t_lip_http_resp *resp, t_lip_http_server_resp_finish_cb cb, void *ctx);


#endif // LIP_HTTP_SERVER_H
