/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
#if !defined(NET_WANDERINGHORSE_CWAL_S2_CGI_H_INCLUDED)
#define NET_WANDERINGHORSE_CWAL_S2_CGI_H_INCLUDED
/**
   This file houses the s2_cgi API, a far-from-complete CGI
   application framework based on s2.
*/
#if defined(S2_AMALGAMATION_BUILD)
#  include "s2_amalgamation.h"
#else
#  include "s2.h"
#endif

#if defined(__cplusplus)
extern "C" {
#endif

/**
   State container for the s2 CGI module. It holds all kinds of
   stuff related to CGI state.
*/
struct s2_cgi {
  cwal_engine * e;
  s2_engine * se;
  /**
     Holds info related to the request.
  */
  struct {
    /**
       POST data. The library handles JSON and transforms
       form/url-encoded input to a JSON form here.
    */
    cwal_value * post;
    /**
       An Object holding values from the HTTP GET parameters
       (i.e. from getenv("QUERY_STRING")).
    */
    cwal_value * get;
    /**
       An Object holding values from the HTTP cookies
       (i.e. from getenv("HTTP_COOKIE")).
    */
    cwal_value * cookies;
    /**
       An Object holding the raw (currently not unencoded)
       values from the environ(7) environment
       (i.e. from getenv(3) and friends).
    */
    cwal_value * env;
    /**
       stdin for reading POST data. Currently hard-wired
       to stdin.
    */
    FILE * input;
  } request;
  struct {
    /**
       Object of HTTP headers as key/value pairs.
    */
    cwal_value * headers;
    /**
       Object of HTTP cookies as key/value pairs.
    */
    cwal_value * cookies;
    /**
       Response content type.
    */
    char const * contentType;
    /**
       Response HTTP code type.
    */
    int httpCode;
    /**
       Response HTTP status message:

       Status: httpCode httpStatus
    */
    char * httpStatus;
    /**
       Specifies whether or not HTTP headers (including cookies)
       should be output.
        
       0==no header output

       >0==output headers

       <0==determine automatically if headers
       should be output.
    */
    char headerMode;
  } response;
  /**
     The scope under which this object was originally
     initialized. It MUST NOT wander up to a higher scope than this.
  */
  cwal_scope * topScope;
  /**
     TODO. Config file (JSON).
  */
  cwal_value * config;
  /**
     Scratchpad buffer.
  */
  cwal_buffer tmpBuf;
  /**
     Second scratchpad buffer, for when tmpBuf is currently being
     used.
  */
  cwal_buffer tmpBuf2;
  /**
     Holds non-HTTP error information.
  */
  struct {
    /**
       Underlying result code. Hopefully one
       of the CWAL_RC_xxx values.
    */
    int rc;
    /**
       _Might_ hold an error string in the first msg.used bytes of
       msg.mem.
    */
    cwal_buffer msg;
  } err;
};
typedef struct s2_cgi s2_cgi;
/**
   "Empty" s2_cgi object, intended for use
   in copy-constructing.
*/
#define s2_cgi_empty_m {                                \
      NULL/*e*/,                                          \
      NULL/*se*/,                                       \
      {/*request*/                                      \
        NULL/*post*/,                                   \
          NULL/*get*/,                                  \
          NULL/*cookies*/,                              \
          NULL/*input*/                                 \
          },                                            \
      {/*response*/                                     \
        NULL/*headers*/,                                \
          NULL/*cookies*/,                              \
          NULL/*contentType*/,                          \
          200/*httpCode*/,                              \
          NULL/*httpStatus*/,                           \
          1/*headerMode*/                               \
          },                                            \
        NULL/*topScope*/,                               \
          NULL/*config*/,                               \
          cwal_buffer_empty_m/*tmpBuf*/,                \
          cwal_buffer_empty_m/*tmpBuf2*/,               \
          {/*err*/ 0/*rc*/, cwal_buffer_empty_m/*msg*/} \
  }

/**
   "Empty" s2_cgi object, intended for use
   in copy-constructing.
*/
extern const s2_cgi s2_cgi_empty;

/** @def S2_CGI_GETENV_DEFAULT

    The default environment name(s) to use for cwal_cgi_getenv().
*/
#define S2_CGI_GETENV_DEFAULT "gpc"

/**
   Initializes tgt to use ie as its interpreter/engine and
   sets up tgt's state based on the contents of the CGI-related
   environment variables.

   tgt must be a cleanly-initialized s2_cgi instance,
   and it may be stack allocated (copy s2_cgi_empty over
   it to cleanly initialize it).

   Ownership of ie and tgt are not changed and ie must live tgt.

   Returns 0 on success.

   On error, if either ie or tgt are NULL then there are no side
   effects, otherwise tgt might be partially initialized, so the
   client must eventually pass tgt to s2_cgi_cleanup() before ie
   is cleaned up.
*/
int s2_cgi_init( s2_engine * se, s2_cgi * tgt );

/**
   Cleans up memory owned by the given cgi instance but does not free
   cgi. The caller is responsible for deallocating cgi in a manner
   complementary to its allocation mechanism.
*/
void s2_cgi_cleanup( s2_cgi * cgi );

/**
   Sets the HTTP response code and message string. The msg bytes
   are copied by this function, and need not be static. The default
   response code is 200. If msg is NULL or empty then some built-in
   string is used, depending on the value of httpCode.
*/
int s2_cgi_response_status_set(s2_cgi * cx, int httpCode,
                               char const * msg);


/**
   
 */
cwal_value * s2_cgi_env_get( s2_cgi * cgi,
                             char which,
                             char createIfNeeded );

/**
   
 */
cwal_value * s2_cgi_getenv( s2_cgi * cx,
                            char const * fromWhere,
                            char const * key,
                            cwal_size_t keyLen);

/**
   
 */
char const * s2_cgi_getenv_cstr( s2_cgi * cx, char const * where,
                                 char const * key, cwal_size_t keyLen,
                                 cwal_size_t* strLen );
/**
   Sets a variable in one of cx's environment objects.

   whichEnv must be the conventional character representation
   (case-insensitive) for on of the following environment objects:

   - g = GET
   - p = POST
   - e = ENV (i.e. getenv(3))
   - c = COOKIE
   - r = REQUEST (==GET, POST, COOKIE)

   On success 0 is returned and ownership of v is transfered to (or
   shared with) the appropriate environment object. On error non-zero
   is returned and ownership of v is not modified.
*/
int s2_cgi_setenv_v( s2_cgi * cx, char whichEnv,
                     char const * key,
                     cwal_size_t keyLen,
                     cwal_value * v );

/**
   Convenience form of s2_cgi_setenv_v() which sets
   the property in the 'e' environment.
*/
int s2_cgi_setenv( s2_cgi * cx, char const * key,
                   cwal_size_t keyLen, cwal_value * v );

/**
   
 */
int s2_cgi_cookie_set( s2_cgi * cx,
                       char const * key,
                       cwal_size_t keyLen,
                       cwal_value * v );

/**
   
 */
int s2_cgi_cookie_set2( s2_cgi * cx,
                        char const * key, cwal_size_t keyLen,
                        cwal_value * v,
                        char const * domain, char const * path,
                        unsigned int expires, char secure,
                        char httponly );

/**
   
 */
int s2_cgi_response_header_add( s2_cgi * cx, char const * key,
                                cwal_size_t keyLen, cwal_value * v );

/**
   This outputs cx's HTTP headers, flushes all pending output (buffered via
   the api.ob API), and cleans up any cleans up any output buffers
*/
int s2_cgi_response_output_all(s2_cgi * cx);
/**
   URL-decodes a string inline. sLen may be NULL, but if it is not
   then *sLen must initially be the length of str which should be
   decoded. On returning, if sLen is not NULL then it will contain the
   new virtual length of str (which may be shorter than its original
   length but never longer). str will be NUL-terminated by this
   function. If sLen is NULL then the equivalent of strlen() is used
   to determine how many bytes to decode.

   The only error conditions are if the arguments are invalid, in
   which case it returns without side effects (if it can determine the
   arguments are in error) or invokes undefined behaviour (if *sLen is
   longer than str's valid memory).

*/
void s2_cgi_urldecode_inline( char * str, cwal_size_t * sLen );

#if 0
/* broken by removal of request.ENV object... */
/**
   If the environment variable PATH_INFO is found during
   initialization, it is split into its component dir/file parts as an
   array. This routine returns the Nth element in that array, or NULL
   if out of bounds or no PATH_INFO is availble. The array itself is
   available via s2_cgi_getenv(cx,"e","PATH_INFO_SPLIT", 15).
*/
cwal_value * s2_cgi_path_part( s2_cgi * cx,
                               unsigned short ndx );
/**
   Convenience form of s2_cgi_path_part() with fetches the value
   as a C-string. If strLen is not NULL then it will be set to the
   length (in bytes) of the returned string pointer.  Returns NULL on
   error or if it can't figure out what to do.
*/
char const * s2_cgi_path_part_cstr( s2_cgi * cx, unsigned short ndx,
                                    cwal_size_t * strLen );
#endif

/**
   URL-encodes src to dest and NUL-terminates it. dest is expanded as
   needed.

   Returns 0 on success. On error dest might be partially populated.
*/
int s2_cgi_urlencode( s2_cgi * cx, char const * src,
                      cwal_size_t srcLen,
                      cwal_buffer * dest );

    
#if defined(__cplusplus)
} /*extern "C"*/
#endif

#endif
/* NET_WANDERINGHORSE_CWAL_S2_CGI_H_INCLUDED */
