/*
 * Copyright (c) 2001-2005, Adam Dunkels.
 * All rights reserved. 
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 1. Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the distribution. 
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior
 *    written permission.  
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 *
 * This file is part of the uIP TCP/IP stack.
 *
 *
 */

#ifndef __HTTPD_H__
#define __HTTPD_H__
/*
 * The default number of simultaneous server connections is 4. Multiple connections can be triggered
 * by requests for embedded images, style sheets, icons, etc. and a TCP RESET is issued when no more
 * connections are available.
 * The Firefox default connections per server is 15. It can be reduced to 1 in about:config and generally
 * will improve throughput in the half-duplex 6LoWPAN link as embedded files will be requested sequentially.
 * Tictactoe is a good test for multiple connections; it can use as many as 9, but should also work when
 * Firefox network.http.max-connections-per-server is set to a lower number.
 * The RAM needed for each entry depends on script enabling and buffer sizes; see struct httpd_state below.
 * Typical range is 100 - 200 bytes per connection
 * cgi's that use PSOCK_GENERATOR_SEND will have truncated output if UIP_CONF_RECEIVE_WINDOW and UIP_CONF_TCP_MSS
 * are not large enough. The header-menu cgi needs ~340 bytes if all options are enabled, while the file-stats * cgi
 * can exceed any MSS if there are enough files to display (e.g. tic-tac-toe).
 * The advertised MSS is easily seen in wireshark.
 * Some example set a small MSS by default. rpl-border-router for example uses a receive window of 60.
 */
 
 /* Titles of web pages served with the !header cgi can be configured to show characteristics of the node.
  * For example "CD1A:3456" to show the node id and clock time of last access.
  * Change this line and rebuild to make indentifiable instances.
  * Undefine to reduce program size, giving "Contiki-Nano" title on all pages.
  * WAD indexes into the uip destaddr field, which contains the address that we responded to.
  */
#define WEBSERVER_CONF_PAGETITLE sprintf(buf,"[%02x%02x]",WAD[14],WAD[15]);
//#define WEBSERVER_CONF_PAGETITLE sprintf(buf,"Nano[%02x%02x%02x]",WAD[13],WAD[14],WAD[15]);
//#define WEBSERVER_CONF_PAGETITLE sprintf(buf,"Nano[%02x%02x...%02x%02x]",WAD[0],WAD[1],WAD[14],WAD[15]);
//#define WEBSERVER_CONF_PAGETITLE sprintf(buf,"%2x%02x...%2x%02x [%lu]",WAD[0],WAD[1],WAD[14],WAD[15],clock_seconds());

#ifndef WEBSERVER_CONF_NANO
#if CONTIKI_TARGET_SKY || CONTIKI_TARGET_STK500
#define WEBSERVER_CONF_NANO 1
#elif CONTIKI_TARGET_REDBEE_ECONOTAG || CONTIKI_TARGET_AVR_RAVEN || CONTIKI_TARGET_AVR_ATMEGA128RFA1
#define WEBSERVER_CONF_NANO 2
#else
#define WEBSERVER_CONF_NANO 3
#endif
#endif

#if WEBSERVER_CONF_NANO==1
/* nano-size for constrained MCUs */
#define WEBSERVER_CONF_CONNS     2
#define WEBSERVER_CONF_NAMESIZE 16
#define WEBSERVER_CONF_BUFSIZE  40
/* Short tcp timeouts allow new connections sooner */
#define WEBSERVER_CONF_TIMEOUT  20
/* Allow include in .shtml pages, e.g. %!: /header.html */
#define WEBSERVER_CONF_INCLUDE   1
/* Allow cgi in .shtml pages, e.g. %! file-stats . */
#define WEBSERVER_CONF_CGI       1
/* MAX_SCRIPT_NAME_LENGTH should be at least the maximum file name length+2 for %!: includes */
#define MAX_SCRIPT_NAME_LENGTH   WEBSERVER_CONF_NAMESIZE+2
/* Enable specific cgi's */
#define WEBSERVER_CONF_HEADER    1
//#define WEBSERVER_CONF_HEADER_W3C  1 //Proper header
#define WEBSERVER_CONF_HEADER_MENU 1 //with links to other pages
//#define WEBSERVER_CONF_HEADER_ICON 1 //with favicon
#define WEBSERVER_CONF_LOADTIME  0  //show load time in filestats
#define WEBSERVER_CONF_FILESTATS 1
#define WEBSERVER_CONF_TCPSTATS  0
#define WEBSERVER_CONF_PROCESSES 0
#define WEBSERVER_CONF_ADDRESSES 1
#define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_NEIGHBOR_STATUS 0
#define WEBSERVER_CONF_ROUTES    0
#define WEBSERVER_CONF_ROUTE_LINKS  0
#define WEBSERVER_CONF_SENSORS   0
#define WEBSERVER_CONF_STATISTICS   0
#define WEBSERVER_CONF_TICTACTOE 0   //Needs passquery of at least 10 chars 
#define WEBSERVER_CONF_AJAX      0
//#define WEBSERVER_CONF_PASSQUERY 10
#if WEBSERVER_CONF_PASSQUERY
extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
#endif
/* Enable specific file types */
#define WEBSERVER_CONF_JPG       0
#define WEBSERVER_CONF_PNG       0
#define WEBSERVER_CONF_GIF       0
#define WEBSERVER_CONF_TXT       1
#define WEBSERVER_CONF_CSS       0
#define WEBSERVER_CONF_BIN       0

/* Log page accesses */
#define WEBSERVER_CONF_LOG       0
/* Include referrer in log */
#define WEBSERVER_CONF_REFERER   0
/*-----------------------------------------------------------------------------*/
#elif WEBSERVER_CONF_NANO==2
/* webserver-mini having more content */
#define WEBSERVER_CONF_CONNS     2
#define WEBSERVER_CONF_NAMESIZE 20
#define WEBSERVER_CONF_BUFSIZE  40
#define WEBSERVER_CONF_TIMEOUT  20
/* Allow include in .shtml pages, e.g. %!: /header.html */
#define WEBSERVER_CONF_INCLUDE   1
/* Allow cgi in .shtml pages, e.g. %! file-stats . */
#define WEBSERVER_CONF_CGI       1
/* MAX_SCRIPT_NAME_LENGTH should be at least the maximum file name length+2 for %!: includes */
#define MAX_SCRIPT_NAME_LENGTH   WEBSERVER_CONF_NAMESIZE+2
/* Enable specific cgi's */
#define WEBSERVER_CONF_HEADER    1
//#define WEBSERVER_CONF_HEADER_W3C  1 //Proper header
#define WEBSERVER_CONF_HEADER_MENU 1 //with links to other pages
//#define WEBSERVER_CONF_HEADER_ICON 1 //with favicon
#define WEBSERVER_CONF_LOADTIME  1
#define WEBSERVER_CONF_FILESTATS 1
#define WEBSERVER_CONF_TCPSTATS  1
#define WEBSERVER_CONF_PROCESSES 1
#define WEBSERVER_CONF_ADDRESSES 1
#define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_NEIGHBOR_STATUS 1
#define WEBSERVER_CONF_ROUTES    1
#define WEBSERVER_CONF_ROUTE_LINKS  1
#define WEBSERVER_CONF_SENSORS   1
#define WEBSERVER_CONF_STATISTICS   1
//#define WEBSERVER_CONF_TICTACTOE 1   //Needs passquery of at least 10 chars 
#define WEBSERVER_CONF_AJAX      1
#define WEBSERVER_CONF_SHOW_ROOM 0
#define WEBSERVER_CONF_PASSQUERY 10
#if WEBSERVER_CONF_PASSQUERY
extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
#endif
/* Enable specific file types */
#define WEBSERVER_CONF_JPG       0
#define WEBSERVER_CONF_PNG       0
#define WEBSERVER_CONF_GIF       0
#define WEBSERVER_CONF_TXT       1
#define WEBSERVER_CONF_CSS       0
#define WEBSERVER_CONF_BIN       0

/* Log page accesses */
#define WEBSERVER_CONF_LOG       0
/* Include referrer in log */
#define WEBSERVER_CONF_REFERER   1

/*-----------------------------------------------------------------------------*/
#elif WEBSERVER_CONF_NANO==3
/* webserver-mini having all content */
#define WEBSERVER_CONF_CONNS     6
#define WEBSERVER_CONF_NAMESIZE 20
#define WEBSERVER_CONF_BUFSIZE  40
#define WEBSERVER_CONF_TIMEOUT  20
/* Allow include in .shtml pages, e.g. %!: /header.html */
#define WEBSERVER_CONF_INCLUDE   1
/* Allow cgi in .shtml pages, e.g. %! file-stats . */
#define WEBSERVER_CONF_CGI       1
/* MAX_SCRIPT_NAME_LENGTH should be at least the maximum file name length+2 for %!: includes */
#define MAX_SCRIPT_NAME_LENGTH   WEBSERVER_CONF_NAMESIZE+2
/* Enable specific cgi's */
#define WEBSERVER_CONF_HEADER    1
//#define WEBSERVER_CONF_HEADER_W3C  1 //Proper header
#define WEBSERVER_CONF_HEADER_MENU 1 //with links to other pages
//#define WEBSERVER_CONF_HEADER_ICON 1 //with favicon
#define WEBSERVER_CONF_LOADTIME  1
#define WEBSERVER_CONF_FILESTATS 1
#define WEBSERVER_CONF_TCPSTATS  1
#define WEBSERVER_CONF_PROCESSES 1
#define WEBSERVER_CONF_ADDRESSES 1
#define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_ROUTES    1
#define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_NEIGHBOR_STATUS 1
#define WEBSERVER_CONF_ROUTES    1
#define WEBSERVER_CONF_ROUTE_LINKS  1
#define WEBSERVER_CONF_SENSORS   1
#define WEBSERVER_CONF_STATISTICS   1
#define WEBSERVER_CONF_TICTACTOE 1   //Needs passquery of at least 10 chars 
#define WEBSERVER_CONF_AJAX      1
#define WEBSERVER_CONF_PASSQUERY 10
#if WEBSERVER_CONF_PASSQUERY
extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
#endif
/* Enable specific file types */
#define WEBSERVER_CONF_JPG       1
#define WEBSERVER_CONF_PNG       1
#define WEBSERVER_CONF_GIF       1
#define WEBSERVER_CONF_TXT       1
#define WEBSERVER_CONF_CSS       1
#define WEBSERVER_CONF_BIN       1

/* Log page accesses */
#define WEBSERVER_CONF_LOG       1
/* Include referrer in log */
#define WEBSERVER_CONF_REFERER   1

#else
#error Specified WEBSERVER_CONF_NANO configuration not supported.
#endif /* WEBSERVER_CONF_NANO */

/* Address printing used by cgi's and logging, but it can be turned off if desired */
#if WEBSERVER_CONF_LOG || WEBSERVER_CONF_ADDRESSES || WEBSERVER_CONF_NEIGHBORS || WEBSERVER_CONF_ROUTES
extern uip_ds6_netif_t uip_ds6_if;
#define WEBSERVER_CONF_PRINTADDR 1
#endif
#if WEBSERVER_CONF_PRINTADDR
uint8_t httpd_cgi_sprint_ip6(uip_ip6addr_t addr, char * result);
#else
#define httpd_cgi_sprint_ip6(...) 0
#endif

#include "contiki-net.h"
#include "httpd-fs.h"

#if defined(__AVR__)
/* When using non-ram storage httpd-fsdata.c must be generated with the HTTPD_STRING_ATTR, eg
 *        ../../tools/makefsdata -A HTTPD_STRING_ATTR
 */
#include <avr/pgmspace.h>
#define HTTPD_STRING_ATTR PROGMEM
#define PRINTA(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
/* These will fail if the server strings are above 64K in program flash */
#define httpd_memcpy         memcpy_P
#define httpd_strcpy         strcpy_P
#define httpd_strcmp         strcmp_P
#define httpd_strncmp        strncmp_P
#define httpd_strlen         strlen_P
#define httpd_snprintf       snprintf_P
#define httpd_fs_cpy         memcpy_P
#define httpd_fs_strcmp      strcmp_P
#define httpd_fs_strchr      strchr_P
#define httpd_fs_getchar(x)  pgm_read_byte(x)

#else /* All storage in RAM */
#define HTTPD_STRING_ATTR
#define PRINTA(FORMAT,args...) printf(FORMAT,##args)
#define httpd_snprintf       snprintf
#define httpd_fs_cpy         memcpy
#define httpd_memcpy         memcpy
#define httpd_strcpy         strcpy
#define httpd_strcmp         strcmp
#define httpd_strncmp        strncmp
#define httpd_strlen         strlen
#define httpd_fs_strchr      strchr
#define httpd_fs_strcmp      strcmp
#define httpd_fs_getchar(c)  *(c)
#endif

struct httpd_state {
  unsigned char timer;
  struct psock sin, sout;
  struct pt outputpt;
#if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
  struct pt scriptpt;
#endif
  char inputbuf[WEBSERVER_CONF_BUFSIZE];
  char filename[WEBSERVER_CONF_NAMESIZE];
  char state;
  struct httpd_fs_file file;  
  int len;
#if WEBSERVER_CONF_INCLUDE || WEBSERVER_CONF_CGI
  char *scriptptr;
  int scriptlen;
#endif
#if WEBSERVER_CONF_LOADTIME
  clock_time_t pagetime;
#endif
#if WEBSERVER_CONF_AJAX
  uint16_t ajax_timeout;
#endif
#if WEBSERVER_CONF_NEIGHBORS || WEBSERVER_CONF_ROUTES
  uint8_t starti,savei,startj,savej;
#endif
#if WEBSERVER_CONF_CGI
  union {
    unsigned short count;
    void *ptr;
  } u;
#endif
};

void httpd_init(void);
void httpd_appcall(void *state);

/* DEBUGLOGIC is a convenient way to debug without a tcp/ip connection.
 * After initialization, break the program and set the program counter
 * to the beginning of httpd.c::httpd_appcall:
 *   s = sg = (struct httpd_state *)memb_alloc(&conns);
 * The global sg points to the s data to get around "not in scope" optimization.
 * The input file is forced to /index.html and the output directed to TCPBUF.
 * However the socket will hang on acknowledgement when any data is sent.
 * To prevent this just add a break to /core/net/psock.c::psock_generator_send
 * ...
 * // Wait until all data is sent and acknowledged.
 * break;                            //<---add this line
 * PT_YIELD_UNTIL(&s->psockpt, uip_acked() || uip_rexmit());
 * ...
 */
#define DEBUGLOGIC 0
#if DEBUGLOGIC
struct httpd_state *sg;
#define uip_mss(...) 512
#define uip_appdata TCPBUF
char TCPBUF[512];
#endif


#endif /* __HTTPD_H__ */
