/*******************************************************************\
 
Module:
 
Author: Daniel Kroening, kroening@cs.cmu.edu
 
\*******************************************************************/

#ifndef XML_H
#define XML_H

#include <list>
#include <map>
#include <string>
#include <iostream>

class xmlt
{
public:
  xmlt()
  {}

  xmlt(const std::string &_name):name(_name)
  {}

  typedef std::list<xmlt> elementst;
  typedef std::map<std::string, std::string> attributest;

  static std::string escape(const std::string &s);
  static std::string escape_attribute(const std::string &s);
  static std::string unescape(const std::string &s);

  std::string name, data;

  attributest attributes;
  elementst elements;

  elementst::const_iterator find(const std::string &name) const;
  elementst::iterator find(const std::string &name);

  void set(
    const std::string &attribute,
    unsigned value);

  void set(
    const std::string &attribute,
    const std::string &value)
  {
    if ((value[0]=='\"' && value[value.size()-1]=='\"') ||
        (value[0]=='\'' && value[value.size()-1]=='\''))
    {
      attributes[attribute]=value.substr(1,value.size()-2);
    }
    else
    {
      attributes[attribute]=value;
    }
  }

  std::string get(
    const std::string &attribute) const
    {
      attributest::const_iterator i=attributes.find(attribute);
      if(i!=attributes.end())
        return i->second;                    
      return "";
    }

  void set_bool(
    const std::string &attribute,
    bool value)
  {
    set(attribute, value?"true":"false");
  }

  bool get_bool(const std::string &attribute) const
  {
    attributest::const_iterator i=attributes.find(attribute);
    if (i!=attributes.end())
      return (i->second=="true");
    return false;
  }

  xmlt &new_element(const std::string &name)
  {
    elements.push_back(xmlt());
    elements.back().name=name;
    return elements.back();
  }

  xmlt &new_element()
  {
    elements.push_back(xmlt());
    return elements.back();
  }

  void swap(xmlt &xml)
  {
    xml.data.swap(data);
    xml.attributes.swap(attributes);
    xml.elements.swap(elements);
    xml.name.swap(name);
  }

  void clear()
  {
    data.clear();
    name.clear();
    attributes.clear();
    elements.clear();
  }

  friend std::ostream& operator <<(
    std::ostream &out,
    const xmlt &xml)
  {
    xml.output(out);
    return out;
  }

  void output(
    std::ostream &out,
    unsigned indent=0) const;

protected:
  static void do_indent(
    std::ostream &out,
    unsigned indent);
};

#endif
