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

/** @file akaxiso/classes/all.h */

#include <akaxiso/classes/simpletype.h>
#include <akaxiso/classes/attribute.h>
#include <akaxiso/classes/memberdef.h>

namespace aka2 {

  template<class L>
  class all_op_dispatcher : public all_op {
  public:
    virtual schematype_id get_schematype() const { return all_id; }
    virtual const qname& get_typename() const { return L::typename_; }
    /** creatable */
    virtual void construct(void *e) const {  L::construct(e); }
    virtual void copy_construct(void *e, const void *src) const { L::copy_construct(e, src); }
    virtual void destruct(void *e) const { L::destruct(e); }
    virtual size_t class_size() const { return L::class_size(); }
    virtual bool equals(const void *lhs, const void *rhs) const {
      return L::equals(lhs, rhs);
    }

    /** attribute_info getter. */
    virtual const attribute_types *get_attribute_types() const {
      return &L::attribute_types_;
    }
    virtual const any_member *get_anyattr_type() const { return 0; }
    /** all_info getter. */
    virtual const member_map &get_member_map() const {
      return L::member_map_;
    }
  };


  template<class T, class L=xiso::leaf<T> >
  class all : public attributes<L, T>,
	      public memberdef<L, T> {
  public:
    typedef T value_type;

    virtual ~all(){}

    static member_type* register_membertype(const member_type &mtype) {
      std::pair<member_map::iterator, bool> res =
    	member_map_.insert(member_map::value_type(mtype.get_name(), mtype));
      if (!res.second)
	      throw internal_error();
      return &res.first->second;
    }

    static void initialize() {
      if (!system_type_registry().add(L()))
      	return;
      member_map_.clear();
      attribute_types_.clear();
      L l; l.model(); // VC6 does not accept L().model();
    }

    static void uninitialize() {
      member_map_.clear();
      attribute_types_.clear();
    }

    static void construct(void *e) {
      new (e) T();
      all_construct(e, dispatcher_);
    }
    static void copy_construct(void *e, const void *src) {
      new (e) T(*static_cast<const T*>(src));
    }
    static size_t class_size() { return sizeof(T); }
    static void destruct(void *elm) { static_cast<T*>(elm)->~T(); }

    static bool equals(const void *lhs, const void *rhs) {
      return all_equals(lhs, rhs, dispatcher_);
    }

    static element_op* get_attribute_dispatcher() { return &dispatcher_; }
    static default_op* create_default_op() { return 0; }

    static member_map member_map_;
    static qname typename_;
    static all_op_dispatcher<L> dispatcher_;

    static void xmltype(const std::string &name) {
      typeinfo_.set_name(qname(name));
    }

    static bool acceptable(schematype_id id) {
      return
	(id == sequence_id) ||
	(id == choice_id) ||
	(id == simpletype_id) ||
	(id == ptrmember_id) ||
	(id == simplecontent_id);
    }
  };

  template<class T, class L>
  member_map all<T, L>::member_map_;

  template<class T, class L>
  qname all<T, L>::typename_;

  template<class T, class L>
  all_op_dispatcher<L> all<T, L>::dispatcher_;

} // namespace aka2

#endif /* AKAXISO_ALL_H__ */
