/*

 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 "thing.h"
#include "strings.h"
#include "utils.h"

using namespace std;


// general case, excepting strings
template <typename T>
struct writeAttribute
{
  ostream & os_;
  // ctor
  writeAttribute (ostream & os, const string & name) : os_ (os) 
    {
    os << "  <" << name << "\n";
    }
    
  // dtor
  ~writeAttribute ()
   {
    os_ << "  />\n";
    }
  
  void operator() (const pair<string, T> & data)
    {
    os_ << "    " << data.first << "=\"" << data.second << "\"\n";  
    }
};  // end of writeAttribute

// strings need to be escaped with FixHTML
// actually I will only replace " by &quot; as the rest appears to work anyway. :)
template <>
struct writeAttribute<string>
{
  ostream & os_;
  // ctor
  writeAttribute (ostream & os, const string & name) : os_ (os) 
    {
    os << "  <" << name << "\n";
    }
    
  // dtor
  ~writeAttribute ()
   {
    os_ << "  />\n";
    }
  
  void operator() (const pair<string, string> & data)
    {
    os_ << "    " << data.first << "=\"" << FindAndReplace (data.second, "\"", "&quot;") << "\"\n";  
    }
};  // end of writeAttribute<string>

ostream& operator<< (ostream & os, const thing & t)
  {
  // I'll put them in separate sections in case they have the same key
  // twice (eg. a bool foo and a string foo), also it makes it easer
  // to read them back in properly
       
 // string data
  if (!t.get_sdata ().empty ())
    for_each_noreturn (ISEQ (t.get_sdata ()), writeAttribute<string> (os, "string"));  

  // int data
  if (!t.get_idata ().empty ())
    for_each_noreturn (ISEQ (t.get_idata ()), writeAttribute<int> (os, "number"));  

  // float data
  if (!t.get_fdata ().empty ())
    for_each_noreturn (ISEQ (t.get_fdata ()), writeAttribute<double> (os, "float"));  

  // bool data
  if (!t.get_bdata ().empty ())
    for_each_noreturn (ISEQ (t.get_bdata ()), writeAttribute<bool> (os, "flag"));  
  } // end of outputting a thing

// combine one thing
template <typename T>
struct concatenateAttribute
{
  string total_;
   
  void operator() (const pair<string, T> & data)
    {
    total_ += data.first + MAKE_STRING (data.second) + ";";  
    }
  
  const string GetTotal () const { return total_; }

};  // end of concatenateAttribute

// hash a thing, to see if someone changed it, or for other purposes
string HashThing (const thing & t)
  {
  string total;

  total += for_each (ISEQ (t.get_sdata ()), concatenateAttribute<string> ()).GetTotal ();  
  total += for_each (ISEQ (t.get_idata ()), concatenateAttribute<int> ()).GetTotal ();  
  total += for_each (ISEQ (t.get_fdata ()), concatenateAttribute<double> ()).GetTotal ();  
  total += for_each (ISEQ (t.get_bdata ()), concatenateAttribute<bool> ()).GetTotal ();  
  
  return SecureHash (total).str ();
  
  } // end of HashThing
