/* -*- c++ -*- */
#ifndef AKAXISO_DOCUMENT_H__
#define AKAXISO_DOCUMENT_H__

#include <akaxiso/classes/qname.h>
#include <akaxiso/classes/occurrence.h>
#include <akaxiso/classes/node_ptr.h>
#include <map>

namespace aka2 {

  struct document {
    document() : props_(0) {}
    document(void* root, const element_props &def)
      : root_(node(root, def.op())), props_(&def) {}
    ~document() {}

    node get_root() { return root_.get_node(); }
    node adopt() { return root_.adopt(); }
    const_node get_root() const { return root_.get_node(); }
    const qname &get_name() const { return props_->get_name(); }
    const element_op& get_op() const { return props_->op(); }
    const element_props &get_props() const { return *props_; }

  private:
    node_ptr root_;
    const element_props *props_;
  };


  class document_factory {
  public:
    element_props &register_document_type(const qname &docname,
					  const element_op &op);
    void register_document_type(const qname &docname,
				const element_op &op,
				const aka::occurrence &occ);
    void register_document_type(const qname &docname,
				const element_op &op,
				const std::string &defval);
    document create_named_document(const qname &docname);
    const element_props &get_props(const qname &docname) const;
    void clear() { doctype_map_.clear(); }

  private:
    typedef std::map<qname, element_props, qname_less> doctype_map;
    doctype_map doctype_map_;
  };


  template<class T>
  T* root_cast(aka2::document &doc) {
    return static_cast<T*>(doc.get_root().ptr());
  } 

  template<class T>
  const T* root_cast(const aka2::document &doc) {
    return static_cast<const T*>(doc.get_root().ptr());
  }

  template<class T>
  T* adopt_root(aka2::document &doc) {
    return static_cast<T*>(doc.adopt().ptr());
  }

  bool document_of(const aka2::document &doc, const std::string &tagname);

} // namespace aka2

#endif /* AKAXISO_DOCUMENT_H__ */
