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

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

#include <akaxiso/classes/traits.h>
#include <akaxiso/classes/simpletype.h>
#include <akaxiso/classes/global_attributes.h>
#include <akaxiso/classes/attribute.h>
#include <akaxiso/classes/construct.h>

namespace aka2 {

  template<class L>
  class simplecontent_op_dispatcher : public simplecontent_op {
  public:
    virtual schematype_id get_schematype() const { return simplecontent_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_types getter. */
    virtual const attribute_types *get_attribute_types() const {
      return &L::attribute_types_;
    }
    virtual const any_member *get_anyattr_type() const {
      return L::get_anyattr_type();
    }
    virtual const member_type& get_valuetype() const { return L::value_type_; }

  };

  template<class L, class T>
  struct simplecontent_statics {
    static qname typename_;
    static member_type value_type_;
    static simplecontent_op_dispatcher<L> dispatcher_;
  };

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

  template<class L, class T>
  member_type simplecontent_statics<L, T>::value_type_;

  template<class L, class T>
  simplecontent_op_dispatcher<L> simplecontent_statics<L, T>::dispatcher_;


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

    virtual ~simplecontent(){}

    static void initialize() {
      if (!system_type_registry().add(L()))
	return;
      attribute_types_.clear();
      member_getter *getter = new null_getter();
      value_type_ = member_type(getter, nill_leaf::dispatcher_);
      L l; l.model();
    }
    static void uninitialize() {
      attribute_types_.clear();
    }


    static void construct(void *e) {
      new (e) T();
      simplecontent_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 simplecontent_equals(lhs, rhs, dispatcher_);
    }

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

    // Helper class to define serializable member.
    template<class V, class P, class VL>
    static void value(V P::* m, const VL&) {
      VL::initialize();
      member_getter *getter =
	create_ptr_getter(reinterpret_cast<T*>(0), m);
      L::value_type_ = member_type(getter, VL::dispatcher_);
      default_op *defop = VL::create_default_op();
      if (defop != 0)
	value_type_.set_default_op(defop);
    }

    template<class V, class P>
    static void value(V P::* m) {
      value(m, xiso::leaf<V>());
    }

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

    // Helper class to define serializable member.
    struct fixed_value {
      template<class VL>
      fixed_value(const std::string &fixed_value, const VL &) {
      	new_member(tagname, VL());
      }

    private:
      template<class VL>
      void new_member(const std::string &fixed_value, const VL& vl = xiso::leaf<VL>()) {
      	VL::initialize();

	if (VL::dispatcher_.get_schematype() != simpletype_id)
	  throw internal_error();

	aka2::member_type mtype(new null_getter(), fixed<VL>::dispatcher_);
	mtype.set_name(tagname);
    	default_op *defop = VL::create_default_op();
	if (defop != 0)
	  mtype.set_default_op(defop);
	mtype.setup_default_value(fixed_value);
	L::register_membertype(mtype);
      }
    };

    static void set_default(const std::string &defval) {
      if (mtype_.get_schematype() != simpletype_id)
	throw internal_error();
      L::value_type_.set_default(defval);
    }
  };

} // namespace aka2

#endif /* AKAXISO_SIMPLECONTENT_H__ */
