/*
Serval DNA Rhizome HTTP interface
Copyright (C) 2013-2014 Serval Project Inc.
 
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
 
This program 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 General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef __SERVAL_DNA__HTTPD_H
#define __SERVAL_DNA__HTTPD_H

#include "rhizome.h"
#include "meshms.h"
#include "http_server.h"

int is_httpd_server_running();

#define HTTPD_PORT 4110
#define HTTPD_PORT_MAX 4210

extern uint16_t httpd_server_port;
extern unsigned int httpd_request_count;

enum list_phase { LIST_HEADER = 0, LIST_ROWS, LIST_END, LIST_DONE };

struct form_buf_malloc {
  char *buffer;
  size_t size_limit; // == 0 means no limit
  size_t buffer_alloc_size;
  size_t length;
};

struct httpd_request;

int form_buf_malloc_init(struct form_buf_malloc *, size_t size_limit);
int form_buf_malloc_accumulate(struct httpd_request *, const char *partname, struct form_buf_malloc *, const char *, size_t);
void form_buf_malloc_release(struct form_buf_malloc *);

typedef struct httpd_request
{
  struct http_request http; // MUST BE FIRST ELEMENT

  /* Identify request from others being run.  Monotonic counter feeds it.  Only
   * used for debugging when we write post-<uuid>.log files for multi-part form
   * requests.
   */
  unsigned int uuid;

  /* For requests/responses that pertain to a single manifest.
   */
  rhizome_manifest *manifest;
  enum rhizome_payload_status payload_status;
  enum rhizome_bundle_status bundle_status;

  /* For requests/responses that contain one or two SIDs.
   */
  sid_t sid1;
  sid_t sid2;

  /* For requests/responses that contain a Rhizome Bundle ID.
   */
  rhizome_bid_t bid;

  /* For requests/responses that contain a 64-bit unsigned integer (eg, SQLite ROWID, byte offset).
   */
  uint64_t ui64;

  /* Finaliser for union contents (below).
   */
  void (*finalise_union)(struct httpd_request *);

  /* Mutually exclusive response arguments.
   */
  union {

    /* For receiving Rhizome Direct import request
     */
    struct {
      // Which part is currently being received
      const char *current_part;
      // Temporary file currently current part is being written to
      int part_fd;
      // Which parts have already been received
      bool_t received_manifest;
      bool_t received_data;
      // Name of data file supplied in part's Content-Disposition header, filename
      // parameter (if any)
      char data_file_name[MIME_FILENAME_MAXLEN + 1];
    }
      direct_import;

    /* For receiving RESTful Rhizome insert request
     */
    struct {
      // Which part is currently being received
      const char *current_part;
      // Which parts have already been received
      bool_t received_author;
      bool_t received_secret;
      bool_t received_manifest;
      bool_t received_payload;
      // For storing the "bundle-author" hex SID as we receive it
      char author_hex[SID_STRLEN];
      size_t author_hex_len;
      sid_t author;
      // For storing the "bundle-secret" hex as we receive it
      char secret_hex[RHIZOME_BUNDLE_KEY_STRLEN];
      size_t secret_hex_len;
      rhizome_bk_t bundle_secret;
      // The "force-new" parameter
      char force_new_text[5]; // enough for "false"
      size_t force_new_text_len;
      bool_t force_new;
      // For storing the manifest text (malloc/realloc) as we receive it
      struct form_buf_malloc manifest;
      // For receiving the payload
      uint64_t payload_size;
      struct rhizome_write write;
    }
      insert;

    /* For responses that send part or all of a payload.
    */
    struct rhizome_read read_state;

    /* For responses that list manifests.
    */
    struct {
      enum list_phase phase;
      uint64_t rowid_highest;
      size_t rowcount;
      time_ms_t end_time;
      struct rhizome_list_cursor cursor;
    }
      rhlist;

    /* For responses that list MeshMS conversations.
    */
    struct {
      enum list_phase phase;
      size_t rowcount;
      struct meshms_conversations *conv;
      struct meshms_conversation_iterator iter;
    }
      mclist;

    /* For responses that list MeshMS messages in a single conversation.
    */
    struct {
      enum meshms_which_ply token_which_ply;
      uint64_t token_offset;
      enum meshms_which_ply latest_which_ply;
      uint64_t latest_offset;
      time_ms_t end_time;
      uint64_t highest_ack_offset;
      enum list_phase phase;
      size_t rowcount;
      struct meshms_message_iterator iter;
      int finished;
    }
      msglist;

    /* For responses that send a MeshMS message.
    */
    struct {
      // Which part is currently being received
      const char *current_part;
      // Which parts have already been received
      bool_t received_message;
      // The text of the message to send
      struct form_buf_malloc message;
    }
      sendmsg;

  } u;

} httpd_request;

int httpd_server_start(uint16_t port_low, uint16_t port_high);

typedef int HTTP_HANDLER(httpd_request *r, const char *remainder);

int is_http_header_complete(const char *buf, size_t len, size_t read_since_last_call);
int authorize_restful(struct http_request *r);
int http_response_content_type(httpd_request *r, const char *what, const struct mime_content_type *ct);
int http_response_content_disposition(httpd_request *r, const char *what, const char *type);
int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen);
int accumulate_text(httpd_request *r, const char *partname, char *textbuf, size_t textsiz, size_t *textlenp, const char *buf, size_t len);

int rhizome_response_content_init_filehash(httpd_request *r, const rhizome_filehash_t *hash);
int rhizome_response_content_init_payload(httpd_request *r, rhizome_manifest *);
HTTP_CONTENT_GENERATOR rhizome_payload_content;

struct http_response_parts {
  uint16_t code;
  char *reason;
  uint64_t range_start;
  uint64_t content_length;
  char *content_start;
};

#define HTTP_RESPONSE_CONTENT_LENGTH_UNSET UINT64_MAX

int unpack_http_response(char *response, struct http_response_parts *parts);

#endif // __SERVAL_DNA__HTTPD_H