/*

 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.
 
*/

// standard library includes ...

#include <iterator>
#include <stdexcept>
#include <fstream>

#ifdef WIN32
#include <time.h>
#endif

using namespace std; 

#include "utils.h"
#include "object.h"
#include "regexp.h"
#include "globals.h"
#include "exceptions.h"
#include "save.h"

ostream& operator<< (ostream & os, const Object & obj)
{
  os << "\n<item>\n";
  // the object itself
  os << static_cast <thing> (obj);  // need to do this to avoid infinite recursion
  // and its contents_
  copy (ISEQ (obj.contents_), ostream_iterator<Object> (os));
  os << "</item>" << endl;
  return os;
}

ostream& writeList (ostream & os, const string & name, const ObjectList & contents_)
  {
  os << "\n<!-- " << name << " -->\n\n";
  os << "<" << name << ">\n";   // eg. <inventory>
  copy (ISEQ (contents_), ostream_iterator<Object> (os));
  os << "</" << name << ">\n";   // eg. </inventory>
  return os;
  } // end of writeList
  
struct fWriteMap
  {
  ostream & os_;
  // ctor
  fWriteMap (ostream & os) : os_ (os) {}
  void operator() (const pair<const string, const ObjectList> & obj)
     {
     writeList (os_, obj.first, obj.second);
     }  
  };  // end of fWriteMap

// output a top-level thing (eg. a player, room, etc.)
ostream& operator<< (ostream & os, const TopThing & obj)
{
  os << static_cast <thing> (obj);  // output the main attributes
  for_each (ISEQ (obj.items_), fWriteMap (os)); // and all owned items
  return os;
}

// create a file, write a top-level thing, include XML headers
void WriteTopThing (const string & filename, 
                    const string & name, 
                    const TopThing & obj)
  {
  
  ofstream f (filename.c_str (), ios::out);
  if (!f)
    throw runtime_error ("Could not open file: " + filename + " for writing.");

  f << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
  f << "<!DOCTYPE " << name << ">\n\n";
  f << "<!-- Saved on " << stringDate (time (NULL)) << " -->\n\n";
  f << "<" << name << ">\n";  // eg. <player>
  f << obj;   // the actual data (see operator<< above)
  f << "</" << name << ">" << endl;   // eg. </player>
  
  } // end of WriteTopThing

void WriteObjectList (ObjectList & which, const string & filename, const string & doctype)
  {
  ofstream f (filename.c_str (), ios::out);
  if (!f)
    throw runtime_error ("Could not open file: " + filename + " for writing.");

  f << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
  f << "<!DOCTYPE " << doctype << ">\n\n";
  f << "<!-- Saved on " << stringDate (time (NULL)) << " -->\n\n";
  f << "<" << doctype << ">\n";  // all <whatever>
  // now output all of it
  for (ObjectList::const_iterator i = which.begin ();
       i != which.end ();
        ++i)
    f << *i;
  
  f << "</" << doctype << ">" << endl; 
  
  } // end of WriteObjectList


// this is the old WriteRooms function

// I'm not using it yet but is should work to save the current world position
// (if we want to)

void WriteWorld ()
  {
  string filename = WORLD_DIR + "world.xml";
  ofstream f (filename.c_str (), ios::out);
  if (!f)
    throw runtime_error ("Could not open file: " + filename + " for writing.");

  f << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
  f << "<!DOCTYPE rooms>\n\n";
  f << "<!-- Saved on " << stringDate (time (NULL)) << " -->\n\n";
  f << "<world>\n";  // all rooms
  // now output all rooms
  for (WorldMapIterator i = world ().begin ();
       i != world ().end ();
        ++i)
    {
    f << "\n<!-- Room vnum " << i->first << " -->\n\n";
    f << "<room>\n";
    f << i->second;
    f << "</room>\n";
    }

  f << "</world>" << endl;

  } // end of WriteWorld
