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

#include <akaxiso/classes/qname.h>
#include <akaxiso/classes/occurrence.h>
#include <akaxiso/classes/element_ptr.h>

namespace aka2 {

  struct docdef {
    docdef(const element_op *op = 0, const aka2::occurrence &occurs = aka2::occurrence())
      : op_(op), occurrence_(occurs) {}
    const element_op *op_;
    aka2::occurrence occurrence_;
  };


  struct document {
    document() : def_(0) {}
    document(const qname &name, void* root, const docdef &def)
      : name_(name), root_(root, *def.op_), def_(&def) {}
    ~document() {}

    void *get_root() { return root_.get_ptr(); }
    void *adopt() { return root_.adopt(); }
    const void *get_root() const { return root_.get_ptr(); }
    const qname &get_name() const { return name_; }
    const element_op& get_op() const { return *def_->op_; }
    const occurrence &get_occurrence() const { return def_->occurrence_; }

  private:
    qname name_;
    element_ptr root_;
    const docdef *def_;
  };


  class document_factory {
  public:
    void register_document_type(const qname &docname,
                                const element_op &op, const occurrence &occurs);
    document create_named_document(const qname &docname);
    const docdef * get_docdef(const qname &docname) const;
    void clear() { doctype_map_.clear(); }
    void initialize() {}
    void uninitialize() {}

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


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

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

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

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

} // namespace aka2

#endif /* AKAXISO_DOCUMENT_H__ */
