#ifndef BABBLEMUD_WEBCLIENT_H
#define BABBLEMUD_WEBCLIENT_H

#include <set>
#include <list>
#include <stack>
#include <iostream>   // for cerr in dtor

#ifdef unix
#include <unistd.h>   // for close
#endif

#include "strings.h"  // for ciLess
#include "constants.h"  // for NO_SOCKET
#include "object.h"   // player inventory_
#include "character.h"  // player is based on character
#include "regexp.h"   // for regexps in commands

// connection states - add more to have more complex connection dialogs 
typedef enum
{
  eAwaitingCommand,   /* 0 = waiting for GET/POST etc. */
  eAwaitingHeaders,   /* 1 = accepting header lines */
  eAwaitingData,			/* 2 = waiting for POST data */
  eSendingResponse,   /* 3 = we are replying to the client (ie. reading from disk) */
  eAwaitingFinish     /* 4 = we have sent everything and are waiting to close him */
} tWebConnectionStates;

/*

Note: There are five types of information you get from a web browser request ...

Here is an example:

POST /mypage.htm?aaa=bbb&ccc=ddd HTTP/1.1
Host: bacall.gammon:4080
Cookie: session=2b4997d8156431dcf42e90887369177a
[other headers here]
[blank line here]
formdata1=xxx&formdata2=yyy

The five things above are:

1. The URL: /mypage.htm
2. The parameters after the URL: aaa=bbb, ccc=ddd
3. Header information: Host: bacall.gammon:4080
4. Cookies: session=2b4997d8156431dcf42e90887369177a
5. Form data (for a POST): formdata1=xxx, formdata2=yyy

Since there is only one URL that is stored in a string.
The others, of which there may be many are stored in name/value pairs in lists:
       
Thus, you can extract them by a scan.
       
   headers     <-- all headers (including cookies)
   GetData     <-- the parameters after the URL
   PostData    <-- the form POST data
   CookieData  <-- cookies (values only) if present

Also, the version (probably HTTP/1.0 or HTTP/1.1) is stored in the version string.

Headers, parameters and form data are URL-encoded which means that special characters
are converted into %xx and then spaces are turned into + signs.

*/

typedef list <pair<string, string> > HeaderList;

//  WebClient - for incoming HTTP connections

class WebClient
{

private:
  
  int s_;             // socket they connected on
 
  string outbuf_;     // pending output

// copy construction is probably an error.

  WebClient (const WebClient &);  // do not allow copy construction!!!

public:

  string inbuf_;      // pending input

  tWebConnectionStates connstate_;   // connection state
  string address_;                // IP address they came from
  bool closing_;      // true if they are about to leave us

 // HTTP header stuff

  string command_;     /* command (eg. GET, POST) */
  string URL_;         /* URL from the command line */
  string version_;     /* HTTP version given on first line (eg. HTTP/1.0) */
  int data_wanted_  ;  /* amount of POST data wanted */
  int data_received_;  /* amount of POST data received */

  Object user_;        // user identification (from cookie)
  bool  verified_;     // true if user found

  HeaderList headers_;  // the headers

  StringMap postData_,
            getData_,
            cookieData_;

  string ifModifiedSince; // what was in the If-Modified-Since field
  
  FILE * file_;
  
  // ctor
  WebClient (const int sock) 
    : s_ (sock), closing_ (false), connstate_ (eAwaitingCommand), verified_ (false), file_ (NULL)
      {  } 
  
  ~WebClient (); // dtor
        
  virtual WebClient & operator<< (const string & s)  
    {     
    outbuf_ += s;
    return *this; 
    };  

  virtual WebClient & operator<< (const int & i)  
    {     
    outbuf_ += MAKE_STRING (i); 
    return *this; 
    };  

  virtual WebClient & operator<< (const unsigned int & i)  
    {     
    outbuf_ += MAKE_STRING (i); 
    return *this; 
    };  

  virtual WebClient & operator<< (const double & f)  
    {     
    outbuf_ += MAKE_STRING (f); 
    return *this; 
    };  
    
  virtual WebClient & operator<< (const bool & i)  
    {     
    outbuf_ += MAKE_STRING (i); 
    return *this; 
    };  
  
  virtual WebClient & operator<< (const char * p)  
    {     
    outbuf_ += MAKE_STRING (p);
    return *this; 
    };  
  
  // what's our socket?
  int GetSocket () const { return s_; }
  // true if connected at all
  bool Connected () const { return s_ != NO_SOCKET; }
  // true if we have something to send them
  bool PendingOutput () const { return !outbuf_.empty (); }
  // get rid of this guy
  void CloseClient () 
    { 
    closing_ = true; 
    if (file_)
      cerr << "Warning - closing client with file open" << endl;
    }    
 
  // TCP/IP read/write/exception routines
  void ProcessRead ();    // get player input
  void ProcessWrite ();   // output outstanding text
  void ProcessException (); // exception on socket

  void CloseFile ();    // close file if open
     
};  // end of class WebClient 

typedef void (*tWebHandler)  (WebClient & w);
typedef map<string, tWebHandler> WebHandlerMap;

// for generating command handlers
#define WEBPAGE(arg) webmap [#arg] = arg

// player list type
typedef std::list <WebClient*> WebClientList;
typedef WebClientList::iterator WebClientListIterator;

const string SendMessage (WebClient & w, int iWhich);
const string GetBrowserTime (const long whichtime = 0);
const string DoHeader (WebClient & w,           // which client
                        const int messageType = 200,  // type, eg, 200, 404
                        const string & title = "",         // what to put into title
                        const bool sendBody = true);   // if true, start a message body
void ShowError (WebClient & w, const string & what);
void WebDebugVars (WebClient & w);    // debugging what we get from the client

void Button (WebClient & w, const string & name, const string & label);
void Hidden (WebClient & w, const string & name, const string & contents);
void InputField (WebClient & w, const string & name, const string & contents,
                 const int size, const int maxlength, const bool right = false,
                 const bool password = false);
void InputBox (WebClient & w, const string & name, const string & contents,
                 const int lines);
void ComboBox (WebClient & w, const string & name, const string & contents,
                 const string matchlist);
void CheckBox (WebClient & w, const string & name, const bool contents);


bool verifyWebUser (WebClient & w, Object & page);

#endif // BABBLEMUD_WEBCLIENT_H
