/*! @file

    @id $Id$
*/
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

#include <mrw/string.hxx>
#include <xml-cxx/xml.hxx>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>

unsigned int MethodTrace::_level(0);

namespace xml {

  //================================================================= EXCEPTIONS

  //----------------------------------------------------------------------------
  exception::exception(std::string reason) throw():
      _what(reason), _node(0) {
  }
  exception::exception(std::string reason, const Node& t) throw():
      _what(reason), _node(t.clone().release()) {
  }
  exception::~exception() throw() {
    delete _node;
  }
  void exception::line(unsigned long line) throw() {
    std::stringstream ss;
    ss<<line;
    _what += "\nat line: "+ss.str();
  }
  const char* exception::what() const throw() {
    static std::string w;
    if (!w.size()) {
      if (_node)
        if (_node->isChild())
          w = _what+"\ntag: "+_node->name()+"\nparent: "+_node->parent().name();
        else
          w = _what+"\ntag: "+_node->name()+" (root element)";
      else
        w = _what;
    }
    return w.c_str();
  }
  //----------------------------------------------------------------------------
  access_error::access_error(const Node& t, const std::string& name) throw():
      exception("child not available", t), _name(name) {
  }
  const char* access_error::what() const throw() {
    static std::string w;
    if (!w.size()) w = std::string(exception::what())+"\nchild name: "+_name;
    return w.c_str();
  }
  //----------------------------------------------------------------------------
  out_of_range::out_of_range(const Node& t, size_t pos) throw():
      exception("child not available", t), _pos(pos) {
  }
  const char* out_of_range::what() const throw() {
    static std::stringstream w;
    if (!w.str().size()) w<<exception::what()<<"\nchild number: "<<_pos;
    return w.str().c_str();
  }
  //----------------------------------------------------------------------------
  cannot_have_children::cannot_have_children(const Node& parent,
                                             const Node& child) throw():
      exception("node does not accept child nodes", parent),
      _child(child.clone().release()) {
                                             }
  cannot_have_children::~cannot_have_children() throw() {
    delete _child;
  }
  const char* cannot_have_children::what() const throw() {
    static std::string w;
    if (!w.size())
      w = std::string(exception::what())+"\nchild name: "+_child->name();
    return w.c_str();
  }
  //----------------------------------------------------------------------------
  stream_error::stream_error(const std::string& reason, const Node& t,
                             std::istream& is, const Tag& tag, char c) throw():
      exception(reason, t), _pos(is.tellg()), _tag(new Tag(tag)), _char(c) {
  }
  stream_error::stream_error(const std::string& reason, const Node& t,
                             std::istream& is) throw():
      exception(reason, t), _pos(is.tellg()), _tag(0), _char(0) {
  }
  stream_error::~stream_error() throw() {
    delete _tag;
  }
  const char* stream_error::what() const throw() {
    static std::string w;
    if (!w.size()) {
      std::stringstream ss;
      ss<<exception::what()
        <<"\nposition in stream: "<<_pos;
      if (_char)
        ss<<"\nactual character: "<<(_char>31?_char:'?')
          <<" (ascii="<<(int)_char<<")";
      if (_tag) {
        ss<<"\ntag type: "<<(_tag->type==START?"START"
                             :(_tag->type==END?"END"
                               :(_tag->type==EMPTY?"EMPTY"
                                 :"???? <UNKNOWN>")));
        if (_tag->name.size()) ss<<"\nnode name read: "<<_tag->name;
        if (_tag->text.size()) ss<<"\ncontained text: "<<_tag->text;
      }
      w = ss.str();
    }
    return w.c_str();
  }

  //============================================================================

  //----------------------------------------------------------------------------
  //! Copy an attribute.
  Attributes::Value::Value(const value_type& o) throw():
      Attributes::value_type(o) {
  }
  //! Construct an empty attribute.
  Attributes::Value::Value(const std::string& name) throw():
      Attributes::value_type(name, std::string()) {
  }
  //! Construct an attribute with name an value.
  Attributes::Value::Value(const std::string& name,
                           const std::string& value) throw():
      Attributes::value_type(name, value) {
  }
  //! Assign a value.
  Attributes::Value& Attributes::Value::operator=(const std::string& value)
      throw() {
    second = value;
    return *this;
  }
  //! Get the attribute name.
  const std::string& Attributes::Value::name() const throw() {
    return first;
  }
  //! Get the attribute value.
  const std::string& Attributes::Value::value() const throw() {
    return second;
  }
  //! Get the attribute value.
  std::string& Attributes::Value::value() throw() {
    return second;
  }
  //! Convert the attribute to a boolean.
  /*! @return @c true if the value is set and not equal to one of:
      @c false @c no @c 0. */
  Attributes::Value::operator bool() const throw() {
    return bool();
  }
  //! Convert the attribute to a boolean.
  /*! @return @c true if the value is set and not equal to one of:
      @c false @c no @c 0. */
  bool Attributes::Value::toBool() const throw() {
    return !(!second.size()||second=="false"||second=="no"||second=="0");
  }
  //! Convert the attribute to a number.
  Attributes::Value::operator unsigned long() const throw() {
    return toNumber();
  }
  //! Convert the attribute to a number.
  unsigned long Attributes::Value::toNumber() const throw() {
    std::stringstream ss(second);
    int i(0);
    ss>>i;
    return i;
  }
  //! Convert the attribute to a space separated list.
  Attributes::Value::operator List() const throw() {
    return toList();
  }
  //! Convert the attribute to list.
  /*! @param separators a string containing a list of valid separators */
  Attributes::List Attributes::Value::toList(const std::string& separators)
      const throw() {
    List l;
    for (std::string::size_type it(0), pos(0);
         it!=std::string::npos &&
           ((pos=second.find_first_of(separators, it)), true);
         it=pos!=std::string::npos?++pos:std::string::npos)
      if (pos==std::string::npos)
        l.push_back(second.substr(it));
      else
        l.push_back(second.substr(it, pos-it));
    return l;
  }
  //! Get the first value of an attribute containing a list of values.
  /*! @copydoc xml::Attributes::Value::toList
      @return the first element of the list. */
  std::string Attributes::Value::front(const std::string& separators) const
      throw(empty_attribute_list) {
    List l(toList(separators));
    if (!l.size()) throw empty_attribute_list(first);
    return l.front();
  }
  //----------------------------------------------------------------------------
  //! Empty attribute list
  Attributes::Attributes() throw() {}
  //! Attribute list with first one empty attribute given.
  Attributes::Attributes(const std::string& empty) throw() {
    insert(Value(empty));
  }
  //! Attribute list with first attribute given.
  Attributes::Attributes(const std::string& key,
                         const std::string& value) throw() {
    insert(Value(key, value));
  }
  //! Add a new key-value pair to the attribute list.
  Attributes& Attributes::operator<<(const Attributes::Value& v) throw() {
    insert(v);
    return *this;
  }
  //! Add a new empty key to the attribute list.
  Attributes& Attributes::operator<<(const std::string& key) throw() {
    insert(Value(key));
    return *this;
  }
  //----------------------------------------------------------------------------
  //! Nodes must be given a name.
  /*! Unnamed nodes are not allowed, therefore there's no default
      constructor.
      @copydoc xml::Node::limits */
  Node::Node(std::string name,
             Node::size_type min, Node::size_type max) throw():
      _name(name), _parent(0), _min(min), _max(max) {
  }
  //! Copy node, reset parent.
  /*! The parent is reset, the node does not belong to the same parent
      as the source of the copy.
      @see xml::Node::clone() for more information on the parenting. */
  Node::Node(const Node& o) throw():
      _attributes(o._attributes), _name(o.name()), _parent(0),
      _min(o._min), _max(o._max) {
    for (Contents::const_iterator it(o._contents.begin());
         it!=o._contents.end(); ++it)
      _contents.push_back((*it)->clone(this).release());
  }
  Node::~Node() throw() {
    clear();
  }
  //! Assign new node, keep parent.
  /*! The parent remains unchanged, the node does not belong to the
      same parent as the source of the copy.
      @see xml::Node::clone() for more information on the parenting. */
  Node& Node::operator=(const Node& o) throw() {
    clear();
    _attributes=o._attributes;
    _name = o.name();
    _min = o._min;
    _max = o._max;
    for (Contents::const_iterator it(o._contents.begin());
         it!=o._contents.end(); ++it)
      _contents.push_back((*it)->clone(this).release());
    return *this;
  }
  //! Clones But resets the parent reference.
  /*! You get a new instance of the node, but detached from the
      parent. It is then ready to be inserted below a new parent.
      
      If you clone (or copy) a node, the parent is not copied. This is
      because otherwise the new now would need to be appended to the
      parent's child list. That's most probably not
      intended. Therefore, in a normal copy construction the parent is
      set to @c 0 (no parent). Then the new node can be appended to a
      parent if needed. In a copy assignment, the parent remains
      uncanged and the other data is copied.

      The user of this library doesn't have to and is not able to care
      about the parenting. */
  std::unique_ptr<Node> Node::clone() const throw() {
    std::unique_ptr<Node> res(new Node(*this));
    res->_parent = 0;
    return res;
  }
  //! Stream XML.
  /*! Streams the node including all attributes and children. It is
      formatted with new-lines and tabulator indentation for human
      readability. */
  std::ostream& Node::out(std::ostream& o, unsigned int level) const throw() {
    if (_contents.size()) {
      o<<std::string(level, '\t')<<'<'<<name();
      for (Attributes::const_iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        o<<' '<<it->first<<"=\""<<it->second<<'"';
      o<<'>'<<std::endl;
      for (Contents::const_iterator it(_contents.begin());
           it!=_contents.end(); ++it)
        (*it)->out(o, level+1)<<std::endl;
      o<<std::string(level, '\t')<<"</"<<name()<<'>';
    } else {
      o<<std::string(level, '\t')<<'<'<<name();
      for (Attributes::const_iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        o<<' '<<it->first<<"=\""<<it->second<<'"';
      o<<"/>";
    }
    return o;
  }
  //! Get the textual contents of a node.
  /*! By default this is the concatenation of all child nodes' texts. */
  std::string Node::text() const throw() {
    std::string s;
    for (Contents::const_iterator it(_contents.begin());
         it!=_contents.end(); ++it)
      s+=***it;
    return s;
  }
  //! Set a text (forbidden in xml::Node)
  /*! This method is only useful for child nodes, where it is
      reimplemented. In xml::Node, the parent of all nodes, it throws
      xml::tag_expected, since a xml::Node may only contain sub-nodes
      (formatted as xml-tags) and no plain text. */
  Node& Node::text(const std::string& txt) throw(tag_expected, type_mismatch) {
    throw tag_expected(*this, txt);
  }
  //! Appends a new node at the end of all children.
  Node& Node::append(const Node& o) throw(cannot_have_children) {
    _contents.push_back(o.clone(this).release());
    return *this;
  }
  //! Removes a given child node.
  Node& Node::remove(Node& n) throw(access_error) {
    Contents::iterator it(std::find(_contents.begin(), _contents.end(), &n));
    if (it==_contents.end()) throw access_error(*this, n.name());
    _contents.erase(it);
    return *this;
  }
  //! Removes the first child node of a given name.
  Node& Node::remove(const std::string& n) throw(access_error) {
    Node* t(find(n));
    if (!t) throw access_error(*this, n);
    return remove(*t);
  }
  //! Removes the child node of a given position.
  Node& Node::remove(size_type n) throw(out_of_range) {
    if (n>=children()) throw out_of_range(*this, n);
    _contents.erase(_contents.begin()+n);
    return *this;
  }
  //! Set a list of attributes.
  /*! Existing attributes with the same name are overwritten. */
  Node& Node::set(const Attributes& o) throw() {
    _attributes.clear();
    _attributes.insert(o.begin(), o.end());
    return *this;
  }
  //! Clears content and attributes.
  Node& Node::clear() throw () {
    for (Contents::const_iterator it(_contents.begin());
         it!=_contents.end(); ++it)
      delete *it;
    _contents.clear();
    _attributes.clear();
    return *this;
  }
  //! Get the node's tag name.
  std::string Node::name() const throw() {
    return _name;
  }
  //! Set a new node's tag name.
  Node& Node::name(const std::string& n) throw() {
    _name = n;
    return *this;
  }
  //! Set minimum number of instances (in a xml::Factory).
  /*! @copydoc limits */
  Node& Node::min(Node::size_type m) throw() {
    _min = m;
    return *this;
  }
  //! Get minimum number of instances (in a xml::Factory).
  /*! @copydoc limits */
  Node::size_type Node::min() const throw() {
    return _min;
  }
  //! Set maximum number of instances (in a xml::Factory).
  /*! @copydoc limits */
  Node& Node::max(Node::size_type m) throw() {
    _max = m;
    return *this;
  }
  //! Get maximum number of instances (in a xml::Factory).
  /*! @copydoc limits */
  Node::size_type Node::max() const throw() {
    return _max;
  }
  //! @c true if node has a parent.
  bool Node::isChild() const throw() {
    return _parent;
  }
  //! Get the parent node.
  Node& Node::parent() const throw(no_parent) {
    if (!_parent) throw no_parent(*this);
    return *_parent;
  }
  //! Check if a specific attribute is set or not.
  bool Node::hasAttr(const std::string& name) const throw() {
    return _attributes.find(name)!=_attributes.end();
  }
  //! Declare an attribute template and specify whether it is mandatory
  /*! Used for setting up attributes in xml::Factory:
      @code
      xml::Factory f(xml::Node("root").attr("aname", xml::mandatory);
      @endcode
      If a factory reads from a stream, it verifies that only optional
      or mandatory attributes are given and that mandatory attributes
      are specified. Otherwise reading throws an exception. */
  Node& Node::attr(const std::string& name, bool mandatory) throw() {
    _attributes[name] = mandatory?"xml::mandatory":"xml::optional";
    return *this;
  }
  //! Declare an attribute with given value.
  /*! When used for setting up attributes in xml::Factory, it
      specifies an optional attribute with given default value:
      @code
      xml::Factory f(xml::Node("root").attr("aname", "avalue");
      @endcode
      If a factory reads from a stream and the specified attribute is
      not given, it is set to @c deflt. */
  Node& Node::attr(const std::string& name, const std::string& deflt) throw() {
    _attributes[name] = deflt;
    return *this;
  }
  //! Get an attribute.
  /*! Returns the attribute's value (empty if the attribute is not set) */
  std::string Node::attr(const std::string& name) const throw() {
    Attributes::const_iterator it(_attributes.find(name));
    if (it!=_attributes.end()) return it->second;
    return std::string();
  }
  //! Get an attribute.
  /*! Returns the attribute's value (empty if the attribute is not set) */
  std::string& Node::attr(const std::string& name) throw() {
    return _attributes[name];
  }
  //! Get an attribute.
  /*! Returns an attribute class or throws an exception if the
      attribute is not set. This method is useful when you need
      conversions or other methods as specified in
      xml::Attributes::Value. */
  const Attributes::Value Node::attribute(const std::string& name)
      const throw(attribute_not_available) {
    Attributes::const_iterator it(_attributes.find(name));
    if (it!=_attributes.end()) return *it;
    throw attribute_not_available(*this, name);
  }
  //! Get the list of attributes.
  const Attributes& Node::attributes() const throw() {
    return _attributes;
  }
  //! Get the list of attributes.
  Attributes& Node::attributes() throw() {
    return _attributes;
  }
  //! Get the first child node
  /*! Returns the first child node or throws an exception, if there are
      no children. */
  Node& Node::first() throw(out_of_range) {
    Contents::iterator it(_contents.begin());
    if (it==_contents.end()) throw out_of_range(*this, 0);
    return **it;
  }
  //! Get the first child node
  /*! Returns the first child node or throws an exception, if there are
      no children. */
  const Node& Node::first() const throw(out_of_range) {
    Contents::const_iterator it(_contents.begin());
    if (it==_contents.end()) throw out_of_range(*this, 0);
    return **it;
  }
  //! Get the last child node
  /*! Returns the last child node or throws an exception, if there are
      no children. */
  const Node& Node::last() const throw(out_of_range) {
    Contents::const_reverse_iterator it(_contents.rbegin());
    if (it==_contents.rend()) throw out_of_range(*this, 0);
    return **it;
  }
  //! Get the last child node
  /*! Returns the last child node or throws an exception, if there are
      no children. */
  Node& Node::last() throw(out_of_range) {
    Contents::reverse_iterator it(_contents.rbegin());
    if (it==_contents.rend()) throw out_of_range(*this, 0);
    return **it;
  }
  //! Pass a minimal and maximal number for this node in a xml file.
  /*! Minimal and maximal values are verified when you use the node as
      a template in a xml::Factory. When the factory reads a stucture
      from a stream through xml::Factory::read, then all the limits
      are verified.

      There are several ways to declare the limits.
      - in the constructor xml::Node::Node
      - minimum and maximum using method xml::Node::limits
      - using methods xml::Node::min and xml::Node::max separately

      It is recommended not to use the constructor, but the methods
      xml::Node::limits, xml::Node::min and xml::Node::max, simply for
      code readability.

      The number @c 0 means unlimited: xml::Node::min(0) means the
      value is optional and xml::Node::max(0) means that there is no
      upper limit. The only exception for this rule is the root
      element of a structure passed to a xml::Factory which must exist
      exactly once.

      Default is no limits: <code>0..n</code>,
      which means that the node is optional and may be instatiated
      multiple (infinite, unlimited) times. */
  Node& Node::limits(size_type min, size_type max) throw() {
    _min = min;
    _max = max;
    return *this;
  }
  //! Get all immediate children of a given node name.
  Node::List Node::list(const std::string& name) const throw() {
    List res;
    for (Contents::const_iterator it(_contents.begin());
         it!=_contents.end(); ++it)
      if ((*it)->_name==name) res.push_back(*it);
    return res;
  }
  //! Check if at least one child node of a given name exists.
  bool Node::operator()(const std::string& child) const throw() {
    return find(child);
  }
  //! Append a child at the end.
  /*! @copydoc xml::Node::append */
  Node& Node::operator<<(const Node& o) throw(cannot_have_children) {
    return append(o);
  }
  //! Add an empty attribute.
  /*! @copydoc xml::Node::set */
  Node& Node::operator<<(const Attributes& o) throw() {
    return set(o);
  }
  //! Get the number of children.
  Node::size_type Node::children() const throw() {
    return _contents.size();
  }
  //! Get a child by child-number (the n-th child).
  /*! @param child number of the child to return: <code>child&gt;=0</code> and
             <code>child&lt;xml::Node::children()</code> */
  const Node& Node::operator[](Node::size_type child) const
      throw(out_of_range) try {
    return *_contents.at(child);
  } catch (...) {
    throw out_of_range(*this, child);
  }
  /*! @copydoc xml::Node::operator[](Node::size_type child) const */
  Node& Node::operator[](Node::size_type child) throw(out_of_range) try {
    return *_contents.at(child);
  } catch (...) {
    throw out_of_range(*this, child);
  }
  //! Get the first child of a given node name.
  /*! @return the first child with matching node name */
  const Node& Node::operator[](const std::string& child) const
      throw(access_error) {
    const Node* const t(find(child));
    if (!t) throw access_error(*this, child);
    return *t;
  }
  /*! @copydoc xml::Node::operator[](const std::string& child) const */
  Node& Node::operator[](const std::string& child) throw(access_error) {
    Node* const t(find(child));
    if (!t) throw access_error(*this, child);
    return *t;
  }
  //! Get the textual contents of a node.
  /*! @copydoc xml::Node::text() */
  std::string Node::operator*() const throw() {
    return text();
  }
  //! Set a text (forbidden in xml::Node)
  /*! @copydoc xml::Node::text(const std::string& txt) */
  Node& Node::operator=(const std::string& contents) throw(tag_expected,
                                                           type_mismatch) {
    return text(contents);
  }
  //! Write node in XML format to a stream.
  /*! @copydoc xml::Node::out */
  std::ostream& operator<<(std::ostream& o, const Node& t) throw() {
    return t.out(o);
  }
  //! Get a pointer to the first child of a given node name.
  /*! This method does not throw an exception if the element does not
      exist, but returns @c 0. */
  Node* Node::find(const std::string& child) const throw() {
    for (Contents::const_iterator it(_contents.begin());
         it!=_contents.end(); ++it) {
      if ((*it)->name()==child) return *it;
    }
    return 0;
  }
  //! Clone a node, but assign a new parent.
  std::unique_ptr<Node> Node::clone(Node* p) const throw() {
    std::unique_ptr<Node> c(clone());
    c->_parent = p;
    return c;
  }

  //----------------------------------------------------------------------------
  /*! @copydoc Node::Node(std::string name,
                          Node::size_type min, Node::size_type max) */
  String::String(std::string name,
                 Node::size_type min, Node::size_type max) throw():
      Node(name, min, max) {
  }
  //! Pass the text in the node.
  /*! @copydoc Node::Node(std::string name,
                          Node::size_type min, Node::size_type max) */
  String::String(std::string name, const std::string& text,
                 Node::size_type min, Node::size_type max) throw():
      Node(name, min, max), _text(text) {
  }
  std::unique_ptr<Node> String::clone() const throw() {
    return std::unique_ptr<Node>(new String(*this));
  }
  std::string String::text() const throw() {
    return _text;
  }
  //! An xml::String contains text: Set the text.
  /*! Never throws an exception. */
  String& String::text(const std::string& txt) throw(tag_expected,
                                                     type_mismatch) {
    _text = txt;
    return *this;
  }
  std::ostream& String::out(std::ostream& o, unsigned int level) const throw() {
    if (_text.size()) {
      o<<std::string(level, '\t')<<'<'<<name();
      for (Attributes::const_iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        o<<' '<<it->first<<"=\""<<it->second<<'"';
      o<<'>'<<_text<<"</"<<name()<<'>';
    } else {
      o<<std::string(level, '\t')<<'<'<<name();
      for (Attributes::const_iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        o<<' '<<it->first<<"=\""<<it->second<<'"';
      o<<"/>";
    }
    return o;
  }
  //! An xml::String has no child nodes: Always throws an exception.
  String& String::append(const Node& o) throw(cannot_have_children) {
    throw cannot_have_children(*this, o);
  }
  //! An xml::String contains text: Set the text.
  Node& String::operator=(const std::string& contents) throw() {
    return text(contents);
  }
  String::operator std::string() const throw() {
    return text();
  }
  String::operator bool() const throw() {
    bool res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator char() const throw() {
    char res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator signed char() const throw() {
    signed char res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator unsigned char() const throw() {
    unsigned char res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator signed short() const throw() {
    signed short res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator unsigned short() const throw() {
    unsigned short res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator signed int() const throw() {
    signed int res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator unsigned int() const throw() {
    unsigned int res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator signed long() const throw() {
    signed long res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator unsigned long() const throw() {
    unsigned long res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator float() const throw() {
    float res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }
  String::operator double() const throw() {
    double res;
    std::stringstream ss(text());
    ss>>res;
    return res;
  }

  //----------------------------------------------------------------------------
  /*! @copydoc Node::Node(std::string name,
                          Node::size_type min, Node::size_type max) */
  UnsignedInteger::UnsignedInteger(std::string name, unsigned long i,
                                   size_type min, size_type max) throw():
      String(name, mrw::string(i), min, max) {
  }
  std::unique_ptr<Node> UnsignedInteger::clone() const throw() {
    return std::unique_ptr<Node>(new UnsignedInteger(*this));
  }
  //! An xml::UnsignedInteger must only contain an number.
  /*! En exception is thrown, if the contents does not match a number. */
  UnsignedInteger& UnsignedInteger::text(const std::string& txt)
      throw(tag_expected, type_mismatch) {
    std::string::size_type
      start(txt.find_first_not_of(" \t\n\r")),
      last(txt.find_last_not_of(" \t\n\r"));
    if (start==std::string::npos) { // empty - set to 0
      _text = "0";
      return *this;
    }
    std::string::size_type pos(txt.find_first_not_of("0123456789", start));
    if (pos<last || (pos==last && last==start))
      throw type_mismatch(*this, txt,
                          "unsigned integer may only contain numbers");
    unsigned long i(0);
    std::stringstream(txt)>>i;
    std::stringstream ss;
    ss<<i;
    _text = ss.str();
    return *this;
  }
  //! Returns the contents as number.
  unsigned long UnsignedInteger::number() const throw() {
    return number(*this);
  }
  //! Returns the contents as number.
  unsigned long UnsignedInteger::number(const Node& node) throw() {
    unsigned long i(0);
    std::stringstream ss(node.text());
    ss>>i;
    return i;
  }

  //----------------------------------------------------------------------------
  //! To instanciate a factory, a template must be given.
  Factory::Factory(const Node& t) throw():
      _template(xml::Node("<xml::start>")<<t), _line(0) {
    _template[0].min(1);
    _template[0].max(1);
  }
  //! Instanciates an invalid factory. A template must be assigned later.
  Factory::Factory() throw():
      _template(xml::Node("<xml::start>")), _line(0) {
  }
  //! Assign a template.
  /*! If you don't pass a template at instanciation, you must call
      this method later, or you will get xml::factory_not_valid
      exceptions when you try to use the factory. */
  Factory& Factory::operator=(const Node& t) throw() {
    _template = xml::Node("<xml::start>")<<t;
    _template[0].min(1);
    _template[0].max(1);
  }
  //! Get the template.
  const Node& Factory::operator*() const throw(factory_not_valid) try {
    return _template[0];
  } catch (...) {
    throw factory_not_valid();
  }
  //! Access the (root node of the) template.
  const Node*const Factory::operator->() const throw(factory_not_valid) try {
    return &_template[0];
  } catch (...) {
    throw factory_not_valid();
  }
  //! Check whether the factory has been given a valid template.
  Factory::operator bool() const throw() {
    return _template.children()>0;
  }
  //! Print the factory template's schema in human readable format.
  /*! Calls xml::Factory::print */
  std::ostream& operator<<(std::ostream& os, const Factory& factory)
      throw(factory_not_valid) {
    return factory.print(os, *factory);
  }
  //! Print a node's schema description in human readable format.
  /*! @todo May be changed to a XML Schema output later. */
  std::ostream& Factory::print(std::ostream& os, const Node& node,
                               unsigned int level) throw() {
    if (node.children()) {
      os<<std::string(level, '\t')<<'<'<<node.name();
      for (Attributes::const_iterator it(node.attributes().begin());
           it!=node.attributes().end(); ++it)
        os<<' '<<it->first<<"=\""<<it->second<<'"';
      os<<'>';
      if (dynamic_cast<const UnsignedInteger*>(&node))
        os<<" (Unsigned Integer";
      else if (dynamic_cast<const String*>(&node))
        os<<" (String";
      else
        os<<" (Node";
      if (node.min()==1 && node.max()==1)
        os<<", required exactly once)";
      else if (node.min()==1 && node.max()==0)
        os<<", required at least once)";
      else if (node.min()==0 && node.max()==0)
        os<<", 0..n)";
      else if (node.min()==0 && node.max()==1)
        os<<", optional)";
      else
        os<<", "<<node.min()<<".."<<node.max()<<")";
      os<<std::endl;
      for (Node::size_type i(0); i<node.children(); ++i)
        print(os, node[i], level+1);
      os<<std::string(level, '\t')<<"</"<<node.name()<<'>'<<std::endl;
    } else {
      os<<std::string(level, '\t')<<'<'<<node.name();
      for (Attributes::const_iterator it(node.attributes().begin());
           it!=node.attributes().end(); ++it)
        os<<' '<<it->first<<"=\""<<it->second<<'"';
      os<<"/>";
      if (dynamic_cast<const UnsignedInteger*>(&node))
        os<<" (Unsigned Integer";
      else if (dynamic_cast<const String*>(&node))
        os<<" (String";
      else
        os<<" (Node";
      if (node.min()==1 && node.max()==1)
        os<<", required exactly once)";
      else if (node.min()==1 && node.max()==0)
        os<<", required at least once)";
      else if (node.min()==0 && node.max()==0)
        os<<", 0..n)";
      else if (node.min()==0 && node.max()==1)
        os<<", optional)";
      else
        os<<", "<<node.min()<<".."<<node.max()<<")";
      os<<std::endl;
    }
    return os;
  }
  //! Restore a xml::Node tree from a stream, according to the given schema.
  std::unique_ptr<Node> Factory::read(std::istream& is)
      throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
            second_slash_in_tag,
            character_after_slash, missing_end_tag, attribute_value_not_quoted,
            access_error, duplicate_attribute,
            attributes_in_end_tag,
            illegal_attribute, mandatory_attribute_missing,
            wrong_node_number, factory_not_valid) {
    if (_template.children()==0) throw factory_not_valid();
    try {
      _line=1;
      _open=0;
      std::unique_ptr<Node> node(read(is, _template));
      if (node->children()==0)
        throw tag_expected(_template[0],
                           "nothing found, possibly empty stream");
      return (*node)[0].clone();
    } catch (exception& e) {
      e.line(_line);
      throw;
    }
  }
  void Factory::reset() throw() {
    _line = 0;
    _open = 0;
    _template = xml::Node("<xml::start>");
  }
  Node& Factory::operator*() throw(factory_not_valid) try {
    return _template[0];
  } catch (...) {
    throw factory_not_valid();
  }
  Node*const Factory::operator->() throw(factory_not_valid) try {
    return &_template[0];
  } catch (...) {
    throw factory_not_valid();
  }
  bool Factory::ws(char c) throw() {
    static char last(0);
    if ((c=='\n'||c=='\r')&&last!='\n'&&last!='\r') ++_line;
    last = c;
    return c==' '||c=='\t'||c=='\n'||c=='\r';
  }
  std::unique_ptr<Node> Factory::read(std::istream& is, const Node& node)
      throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch,
            second_slash_in_tag,
            character_after_slash, missing_end_tag, attribute_value_not_quoted,
            access_error, duplicate_attribute, attributes_in_end_tag,
            illegal_attribute, mandatory_attribute_missing,
            wrong_node_number) {
    std::unique_ptr<Node> result(node.clone());
    result->clear();
    while (true) {
      Tag res(tag(is, node));
      if (!res.found) return result;
      if (res.text.size()) result->text(res.text);
      switch (res.type) {
        case END: {
          --_open;
          if (res.attributes.size()) throw attributes_in_end_tag(node, is, res);
          if (res.name!=node.name()) throw wrong_end_tag(node, is, res);
        } return result;
        case EMPTY: {
          std::unique_ptr<Node> current(node[res.name].clone());
          current->clear()<<res.attributes;
          *result<<*checkChildren(node[res.name], std::move(current), is);
        } break;
        case START: {
          ++_open;
          *result<<(*checkChildren(node[res.name], read(is, node[res.name]), is)
                    <<res.attributes);
        } break;
        case SPECIAL: break; //! @todo ignored could be stored
      }
    }
  }
  std::unique_ptr<Node> Factory::checkChildren(const xml::Node& tpl,
                                               std::unique_ptr<Node> node,
                                               std::istream& is) const
      throw(wrong_node_number) {
    for (Node::size_type i(0); i<tpl.children(); ++i)
      if ((tpl[i].min()>0 && node->list(tpl[i].name()).size()<tpl[i].min())
          || (0<tpl[i].max() && tpl[i].max()<node->list(tpl[i].name()).size()))
        throw wrong_node_number(*node, is, tpl[i].name(),
                                node->list(tpl[i].name()).size(),
                                tpl[i].min(), tpl[i].max());
    return std::move(node);
  }
  Tag Factory::tag(std::istream& is, const Node& position)
      throw(second_slash_in_tag, character_after_slash, tag_expected,
            missing_end_tag, attribute_value_not_quoted,
            access_error, duplicate_attribute, attributes_in_end_tag,
            illegal_attribute, mandatory_attribute_missing,
            wrong_start_tag) {
    char c(0);
    Tag tag((Tag){"", START, "", Attributes(), "", false});
    while (is && is.get(c) && ws(c)); // skip ws
    if (is.eof()) {
      if (_open>0)
        throw missing_end_tag(position, is, tag);
      else
        return tag;
    }
    tag.found = true;
    if (c!='<') do tag.text+=c; while (is && is.get(c) && c!='<');
    bool nameRead(false);
    for (char last(c); is && is.get(c) && c!='>'; last=c) switch (c) {
      case '\n': case '\r':
        if (last!='\n'&&last!='\r') ++_line;
      case ' ': case '\t':
        if (!nameRead && tag.name.size()) nameRead=true;
        break;
      case '/':
        if (!nameRead && tag.name.size()) nameRead=true;
        if (tag.type!=START) throw second_slash_in_tag(position, is, tag, c);
        tag.type = nameRead?EMPTY:END;
        break;
      case '!': case '?':
        if (last=='<') { // <! tag or <?xml.. starts
          tag.special+=last;
          do tag.special+=c; while (c!='>' && is && is.get(c));
          tag.type=SPECIAL;
          return tag;
        }
      default:
        if (tag.type==EMPTY) throw character_after_slash(position, is, tag, c);
        if (nameRead) { // read attribute
          if (tag.type!=START) throw attributes_in_end_tag(position, is, tag);
          std::string attrname(1, c), attrvalue;
          while (is && is.get(c) && c!='=' && c!='>' && c!='/'
                 && !ws(c)) attrname+=c;
          while (ws(c) && is && is.get(c)); // skip ws, search '='
          if (c=='=') { // get the value
            while (is && is.get(c) && ws(c)); // skip ws
            if (c!='"')
              throw attribute_value_not_quoted(position, is, tag, c, attrname);
            while (is && is.get(c) && c!='"') attrvalue+=c;
            if (c!='"')
              throw attribute_value_not_quoted(position, is, tag, c, attrname);
          } else is.unget(); // read too far
          if (tag.attributes.find(attrname)!=tag.attributes.end())
            throw duplicate_attribute(position, is, tag, attrname);
          if (!position(tag.name)) {
            if (tag.name.size())
              throw wrong_start_tag(position, is, tag);
            else
              throw tag_expected(position, tag.text);
          }
          if (position[tag.name].attributes().find(attrname)
              ==position[tag.name].attributes().end())
            throw illegal_attribute(position, is, tag, attrname);
          tag.attributes[attrname] = attrvalue;
        } else { // part of a tag name
          tag.name+=c;
        }
    }
    if (tag.type==START||tag.type==EMPTY) {
      if (!position(tag.name)) {
        if (tag.name.size())
          throw wrong_start_tag(position, is, tag);
        else
          throw tag_expected(position, tag.text);
      }
      const xml::Node& node(position[tag.name]);
      for (Attributes::const_iterator it(node.attributes().begin());
           it!=node.attributes().end(); ++it)
        if (tag.attributes.find(it->first)==tag.attributes.end()) {
          if (it->second=="xml::mandatory")
            throw mandatory_attribute_missing(position, is, tag, it->first);
          else if (it->second!="xml::optional")
            tag.attributes.insert(*it);
        }
    }
    return tag;
  }

  //============================================================== Serialization


  //----------------------------------------------------------------------------
  Serialize::Serialize() throw() {}
  Serialize::Serialize(const std::string& className) throw():
      _xmlFactory(xml::Node(xml::String(className).limits(1,1))) {
  }
  Serialize::Serialize(const Serialize& other) throw() {
    copy(other);
  }
  Serialize::~Serialize() {
    reset();
  }
  Serialize& Serialize::operator=(const Serialize& other) throw() {
    copy(other);
    return *this;
  }
  Serialize& Serialize::className(const std::string& name) throw() {
    xml::Node node(xml::Node(xml::String(name).limits(1,1)));
    if (_xmlFactory) {
      for (xml::Node::size_type i(0); i<_xmlFactory->children(); ++i)
        node<<(*_xmlFactory)[i];
    }
    _xmlFactory=node;
    return *this;
  }
  Serialize& Serialize::persist(Serialize& ser,
                                const std::string& name) throw() {
    if (ser.optional()) {
      _xmlNames[name] = &ser;
      ser.className(name);
      *_xmlFactory<<*ser._xmlFactory;
      std::stringstream ss;
    } else {
      ser.checkInit();
      _xmlNames[name] = &ser;
      xml::Node schema(*_xmlFactory);
      xml::Node node(xml::Node(name).limits(1,1));
      for (xml::Node::size_type i(0); i<ser._xmlFactory->children(); ++i)
        node<<(*ser._xmlFactory)[i];
      _xmlFactory = schema<<node;
      return *this;
     }
    return *this;
  }
  Serialize& Serialize::persist(bool& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(char& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(unsigned char& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(signed char& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(unsigned short& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(signed short& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(unsigned int& member,
                               const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(signed int& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(unsigned long& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(signed long& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(float& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(double& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  Serialize& Serialize::persist(std::string& member,
                                const std::string& name) throw() {
    return persistSimpleType(member, name);
  }
  std::ostream& Serialize::saveXml(std::ostream& os,
                                   const std::string& name) const throw() {
    checkInit();
    xml::Node node(*_xmlFactory);
    if (name.size()) node.name(name);
    for (std::map<std::string, Any>::const_iterator
           it(_xmlNames.begin());
         it!=_xmlNames.end(); ++it)
      toNode(it->second, node[it->first]);
    os<<node;
    return os;
  }
  std::istream& Serialize::loadXml(std::istream& is, const std::string& name) {
    checkInit();
    xml::Factory factory(_xmlFactory);
    if (name.size()) factory->name(name);
    std::unique_ptr<xml::Node> node(factory.read(is));
    for (std::map<std::string, Any>::const_iterator
           it(_xmlNames.begin());
         it!=_xmlNames.end(); ++it)
      if ((*node)(it->first))
        fromNode(it->second, (*node)[it->first]);
      else
        clear(it->second);
    return is;
  }
  std::string Serialize::schema() const throw() {
    checkInit();
    std::stringstream ss;
    ss<<*_xmlFactory;
    return ss.str();
  }

  void Serialize::registerFromNode(Serialize::FromNodeFunc fromNodeFunc) {
    _fromNode.insert(fromNodeFunc);
  }
  void Serialize::registerToNode(Serialize::ToNodeFunc toNodeFunc) {
    _toNode.insert(toNodeFunc);
  }
  void Serialize::registerClear(Serialize::ClearFunc clearFunc) {
    _clear.insert(clearFunc);
  }
  void Serialize::initXmlMembers() {}
  void Serialize::clear() throw() {
    for (std::map<std::string, Any>::const_iterator
           it(_xmlNames.begin());
         it!=_xmlNames.end(); ++it)
      clear(it->second);
  }
  void Serialize::reset() throw() {
    _xmlFactory.reset();
    _xmlNames.clear();
  }
  void Serialize::copy(const Serialize& o) throw() {
    reset();
    initXmlMembers();
  }
  void Serialize::fromNode(Any member, const xml::Node& node) {
    for (std::set<FromNodeFunc>::const_iterator it(_fromNode.begin());
         it!=_fromNode.end(); ++it)
      if ((**it)(member, node)) return; // found match
    throw type_not_registered(member.type().name(), node.name(), node);
  }
  void Serialize::toNode(const Any member, xml::Node& node) const {
    for (std::set<ToNodeFunc>::const_iterator it(_toNode.begin());
         it!=_toNode.end(); ++it)
      if ((**it)(member, node)) return; // found match
    throw type_not_registered(member.type().name(), node.name(), node);
  }
  void Serialize::clear(Any member) throw() {
    for (std::set<ClearFunc>::const_iterator it(_clear.begin());
         it!=_clear.end(); ++it)
      if ((**it)(member)) return; // found match
    throw type_not_registered(member.type().name());
  }
  bool Serialize::optional() const throw() {
    return false;
  }
  
  std::set<Serialize::FromNodeFunc> Serialize::_fromNode;
  std::set<Serialize::ToNodeFunc> Serialize::_toNode;
  std::set<Serialize::ClearFunc> Serialize::_clear;
  
  //=============================================================== Assign Types
  template<typename TYPE> bool assignFromNode(Any member,
                                              const xml::Node& node) {
    if (!any_cast<TYPE>(&member)) return false;
    *any_cast<TYPE>(member) =
      (TYPE)dynamic_cast<const xml::String&>(node);
    return true;
  }
  template<typename TYPE> bool assignToNode(const Any member,
                                            xml::Node& node) {
    if (!any_cast<TYPE>(&member)) return false;
    std::stringstream ss;
    ss<<*any_cast<TYPE>(member);
    node.text(ss.str());
    return true;
  }
  template<> bool assignFromNode<bool>(Any member,
                                       const xml::Node& node) {
    if (member.type()!=typeid(bool)) return false;
    std::string s(*dynamic_cast<const xml::String&>(node));
    std::string::size_type
      start(s.find_first_not_of(" \t\n\r")),
      end(s.find_last_not_of(" \t\n\r"));
    if (start==std::string::npos) {
      *any_cast<bool>(member) = false;
    } else {
      s = s.substr(start, end-start+1);
      *any_cast<bool>(member) = 
        s!="0" && s!="false" && s!="no" && s!="off";
    }
    return true;
  }
  template<> bool assignToNode<bool>(const Any member,
                                     xml::Node& node) {
    if (member.type()!=typeid(bool)) return false;
    node.text(*any_cast<bool>(member)?"true":"false");
    return true;
  }
  template<> bool assignFromNode<Serialize>(Any member,
                                            const xml::Node& node) {
    if (!any_cast<Serialize>(&member)) return false;
    if (any_cast<Serialize>(member)->optional()) {
      (*any_cast<Serialize>(member)).fromNode(member, node);
      return true;
    }
    //! @todo improve this (inefficient)
    std::stringstream ss; // simple but inefficient: rewrite and reread
    ss<<node;
    any_cast<Serialize>(member)->loadXml(ss, node.name());
    /*
    Serialize* ser(any_cast<Serialize>(member));
    for (xml::Node::size_type i(0); i<node.children(); ++i)
        ser->fromNode(ser->_xmlNames[*node[i]], node[i]);*/
    return true;
  }
  template<> bool assignToNode<Serialize>(const Any member,
                                          xml::Node& node) {
    if (!any_cast<Serialize>(&member)) return false;
    if (any_cast<Serialize>(member)->optional()) {
      any_cast<Serialize>(member)->toNode(member, node);
      return true;
    }
    std::stringstream ss;
    any_cast<Serialize>(member)->saveXml(ss, node.name());
    xml::Factory factory(node);
    node = *factory.read(ss);
    return true;
  }
  //================================================================ Clear Types
  template<typename TYPE> bool clearMember(Any member) {
    if (!any_cast<TYPE>(&member)) return false;
    *any_cast<TYPE>(member) = 0;
    return true;
  }
  template<> bool clearMember<bool>(Any member) {
    if (member.type()!=typeid(bool)) return false;
    *any_cast<bool>(member) = false;
    return true;
  }
  template<> bool clearMember<std::string>(Any member) {
    if (member.type()!=typeid(bool)) return false;
    any_cast<std::string>(member)->clear();
    return true;
  }
  template<> bool clearMember<Serialize>(Any member) {
    if (!any_cast<Serialize>(&member)) return false;
    any_cast<Serialize>(member)->clear();
    return true;
  }
  // Init To and From Node ---------------------------------------------------
  namespace {
    template<int NUM=MAX_NUM> struct RegisterTemplateForStdTypes {
        RegisterTemplateForStdTypes<NUM-1> next; // recurse to next until 0
        RegisterTemplateForStdTypes() {
          Serialize::registerToNode
            (&assignToNode<typename ToType<NUM>::Type>);
          Serialize::registerFromNode
            (&assignFromNode<typename ToType<NUM>::Type>);
          Serialize::registerClear
            (&clearMember<typename ToType<NUM>::Type>);
        }
    };
    template<> struct RegisterTemplateForStdTypes<0> {}; // stop recursion
    static RegisterTemplateForStdTypes<> init; // execute initialisation
  }
  // ===========================================================================
  
}
