/*

 BabbleMud - A MUD server

 Author:  Nick Gammon 
          http://www.gammon.com.au/ 

(C) Copyright Nick Gammon 2004. Permission to copy, use, modify, sell and
distribute this software is granted provided this copyright notice appears
in all copies. This software is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.
 
*/

#include "commands.h"
#include "webclient.h"

//~ PLAYER (number):
  
const string ROOM = "room";     // current room
const string COINS = "coins";   // coins s/he is carrying

//~ PLAYER (string):

const string NAME = "name";     // player name

const string DoHeader (WebClient & w,           // which client
                      const int messageType,  // type, eg, 200, 404
                      const string & title,         // what to put into title
                      const bool sendBody)    // if true, start a message body
  {
  w.inbuf_.clear ();
  
  w.connstate_ = eSendingResponse;
  
  string message = SendMessage (w, messageType);
  w << "Date: " << GetBrowserTime () << "\n";
  w << "Server: " << MUDNAME << " " << VERSION << "\n";
  w << "Connection: close\n";
  w << "X-Powered-By: BabbleMUD/" << VERSION << "\n";  
  
  if (sendBody)
    {
    // if the title is empty use the message type (eg. 404 error) as the title
    if (!title.empty ())
      message = title;
    
    string header = FindAndReplace (control ().gets ("html_header"), "~", message);
    
    w << "Content-Type: text/html; charset=iso-8859-1\n";
    w << "\n" << header << "\n";
    } // end of body wanted
  
  return message;
  } // end of DoHeader

// show things 
template <typename T>
struct showWebAttribute
{
  WebClient & w_;
  // ctor
  showWebAttribute (WebClient & w, const string & name) : w_ (w) 
    {
    w_ << "<tr bgcolor=\"#99C49B\">" <<
          "<th colspan=\"2\">" << FixHTML (name) << "</th>\n";
    }
   
  void operator() (const pair<string, T> & data)
    {
    w_ << "<tr><th>" << FixHTML (data.first) << "</th>" <<
          "<td>" << FixHTML (MAKE_STRING (data.second)) << "</td></tr>\n";  
    }
};  // end of showWebAttribute

// general thing-shower - used for displays (not XML-writing)
static void ShowWebThing (WebClient & w, const thing & o)
  {
  
  w << "<p><table>\n";
  // string data
  if (!o.get_sdata ().empty ())
    for_each_noreturn (ISEQ (o.get_sdata ()), showWebAttribute<string> (w, "Strings"));  
  
  // int data
  if (!o.get_idata ().empty ())
    for_each_noreturn (ISEQ (o.get_idata ()), showWebAttribute<int> (w, "Numbers"));  
  
  // float data
  if (!o.get_fdata ().empty ())
    for_each_noreturn (ISEQ (o.get_fdata ()), showWebAttribute<double> (w, "Floats"));  
  
  // bool data
  if (!o.get_bdata ().empty ())
    for_each_noreturn (ISEQ (o.get_bdata ()), showWebAttribute<bool> (w, "Flags"));  

  w << "</table></p>\n";
  
  } // end of ShowWebThing

struct fWebShowThing
{
  WebClient & w_;
  int count_;
  const string & name_;

  // ctor
  fWebShowThing (WebClient & w, const string & name) : w_ (w), count_ (0), name_ (name) {}
  
  void operator() (const Object & thing)
    {
    w_ << "<li><b> " << name_ << " " << ++count_ << "</b>\n";
    ShowWebThing (w_, thing); 
    w_ << "<p></p><hr>\n";

    if (!thing.contents_.empty ())
      {
      w_ << "<p><b>Contents</b></p><ul>\n";
      for_each (ISEQ (thing.contents_), fWebShowThing (w_, "Contents item"));
      w_ << "</ul>\n";
      }
  
    }
};  // end of fWebShowThing

void WebShowOnePlayer (WebClient & w)
  {
  string name = w.getData_ ["name"];
  
  DoHeader (w, 200, "Player " + name);
    
  Character * p = FindPlayer (name);
  
  if (!p)
    throw runtime_error (name + " is not playing.");
  
  ShowWebThing (w, *p);
  
  w << "<hr><h2>Inventory</h2><ul>\n";
  
  for_each (ISEQ (p->inventory ()), fWebShowThing (w, "Inventory item"));
  
  w << "</ul>\n";
  
  w << "<p><a href=\"/who.php\">";
  w << "Show who list</a>\n";
      
  }

void WebWhoList (WebClient & w)
  {
  
  if (!w.getData_ ["name"].empty ())
    {
    WebShowOnePlayer (w);
    return;
    }
  
  DoHeader (w, 200, "Who List");
  
  w << "<h2>Who list</h2>\n";
  w << "<ul>\n";
  
  int count = 0;
  for (PlayerListIterator iter = playerlist ().begin ();
       iter != playerlist ().end ();
       ++iter)
    {
    Player * pTarget = *iter;    // the player  
    if (pTarget->IsPlaying ())
      {
      w << "<li><a href=\"who.php?name=" << pTarget->gets (NAME) << "\">"
            << FixHTML (pTarget->gets (NAME)) << 
            "</a> in room " << pTarget->geti (ROOM) << "\n";
      ++count;
      } // end of if playing
    } // end of doing each player
  
  w << "</ul>\n";
  
  w << "<p>" << count << " player(s)</p>\n";    
  
  } // end of WebWhoList

void WebShowOneRoom (WebClient & w)
  {
  DoHeader (w, 200, "Room");
  
  w << "<h2>Room " << FixHTML (w.getData_ ["room"]) << "</h2>\n";
  
  int vnum = convertString<int>  (w.getData_ ["room"], "bad numeric value");
  
  RoomMap::const_iterator iter = rooms ().find (vnum);
  
  if (iter == rooms ().end ())
    throw runtime_error ("Room " + w.getData_ ["room"] + " does not exist.");

  Room * r = iter->second;
  
  ShowWebThing (w, *r);
  
  w << "<hr><h2>Exits</h2><ul>\n";
  
  for_each (ISEQ (r->exits ()), fWebShowThing (w, "Exit"));
  
  w << "</ul>\n";
  
  w << "<p><a href=\"/room.php\">";
  w << "Show rooms list</a>\n";
    
  } // end of WebShowOneRoom

struct fWebShowOneRoom
{
  WebClient & w_;
  int count_;

  // ctor
  fWebShowOneRoom (WebClient & w) : w_ (w), count_ (0) {}
  
  void operator() (const pair<int, Room*> item)
    {
    w_ << "<li>";
    w_ << "<a href=\"/room.php?room=" << item.first << "\">";
    w_ << "vnum: " << item.first << "</a> " << 
      item.second->gets (FixHTML ("short")) << "\n";
    ++count_; 
    }
  
  const int GetCount () { return count_; }

};  // end of fWebShowOneRoom

void WebRoomList (WebClient & w)
  {
  if (!w.getData_ ["room"].empty ())
    {
    WebShowOneRoom (w);
    return;
    }
  
  DoHeader (w, 200, "Room List");
  w << "<h2>Room list</h2>\n";
  w << "<ul>\n";
  int count = for_each (ISEQ (rooms ()), fWebShowOneRoom (w)).GetCount ();
  w << "</ul>\n";
  w << "<p>" << count << " room(s)</p>\n";    
  } // end of WebRoomList

void WebControlList (WebClient & w)
  {
  DoHeader (w, 200, "Control data");
  ShowWebThing (w, control ());
  } // end of WebControlList

void WebShowOneSpell (WebClient & w)
  {
  DoHeader (w, 200, "Spell");
  
  w << "<h2>Spell " << FixHTML (w.getData_ ["spell"]) << "</h2>\n";

  ObjectList & spells = control ().items_ ["spells"];
  ObjectIter iSpell = FindObject (spells, "name", w.getData_ ["spell"]);
  if (iSpell == spells.end ())
    throw runtime_error ("There is no spell " + w.getData_ ["spell"]);
 
  ShowWebThing (w, *iSpell);
  
  w << "<hr><h2>Affects</h2><ul>\n";
  
  for_each (ISEQ ((*iSpell).contents_), fWebShowThing (w, "Affect"));
  
  w << "</ul>\n";
  
  w << "<p><a href=\"/spell.php\">";
  w << "Show spells list</a>\n";
    
  } // end of WebShowOneSpell

struct fWebShowOneSpell
{
  WebClient & w_;
  int count_;

  // ctor
  fWebShowOneSpell (WebClient & w) : w_ (w), count_ (0) {}
  
  void operator() (const Object & spell)
    {
    w_ << "<li>";
    w_ << "<a href=\"/spell.php?spell=" << spell.gets ("name") << "\">";
    w_ << spell.gets ("name") << "</a> " << 
       spell.gets  (FixHTML ("summary")) << "\n";
    ++count_; 
    }
  
  const int GetCount () { return count_; }

};  // end of fWebShowOneSpell

void WebSpellList (WebClient & w)
  {
  
  if (!w.getData_ ["spell"].empty ())
    {
    WebShowOneSpell (w);
    return;
    }

  ObjectList & spells = control ().items_ ["spells"];

  DoHeader (w, 200, "Spell List");
  w << "<h2>Spell list</h2>\n";
  w << "<ul>\n";
  int count = for_each (ISEQ (spells), fWebShowOneSpell (w)).GetCount ();
  w << "</ul>\n";
  w << "<p>" << count << " spell(s)</p>\n";    
  } // end of WebSpellList

void WebSend (WebClient & w)
  {
  
  DoHeader (w, 200, "Send message");
  w << "<h2>Send message</h2>\n";
 
  if (w.postData_ ["action"] == "send_to_all" &&
      !w.postData_ ["message"].empty ())
    {
    SendToAll ("\n`^** `WMessage from web client: `R" + w.postData_ ["message"] + "`v\n");
    w << "<p>Message <b>" << FixHTML (w.postData_ ["message"]) 
      << "</b> sent to everybody.</p>";    
    }
  else
    throw runtime_error ("No message");
    
  } // end of WebSend

static int LoadWebMap ()
  {
static WebHandlerMap & webmap = getWebHandlerMap ();

  cout << "Loading web handlers in " __FILE__ << endl;
    
  WEBPAGE (WebWhoList);       // who is on
  WEBPAGE (WebRoomList);      // list of rooms
  WEBPAGE (WebControlList);   // control data
  WEBPAGE (WebSpellList);     // list of spells
  WEBPAGE (WebSend);          // send a message

  return 0;
  } // end of LoadWebMap

static int loadThemUp = LoadWebMap ();

