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

#include <akaxiso/classes/types.h>
#include <akaxiso/classes/qname.h>
#include <akaxiso/classes/traits.h>

namespace aka2 {


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

  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 occurence &get_occurence() const { return def_->occurence_; }

  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 occurence &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);

}



#endif
