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

namespace aka2 {

  template<class L, class T>
  struct  memberdef {
    // Helper class to define serializable member.
    struct _member {
      template<class P, class V> 
      _member(const char *tagname, V P::* m) {
      	new_member(tagname, m, xiso::leaf<V>());
      }
      template<class P, class V, class VL> 
      _member(const char *tagname, V P::* m, const VL&) {
	new_member(tagname, m, VL());
      }
      void set_default(const char *defval) {
	if (mtype_->get_schematype() != simpletype_id)
	  throw internal_error();
      	mtype_->setup_default_value(defval);
      };
      void occurrence(int minOccurs, int maxOccurs = 1) {
        schematype_id id = mtype_->get_schematype();
	if ((id == array_id) || (id == choice_id))
	  mtype_->set_occurrence(aka2::occurrence(minOccurs, maxOccurs));
	else
	  throw internal_error();
      }
      member_type *mtype_;

      void required(bool val) {
	if (id != all_id)
	  throw internal_error();
	if (val) 
	  mtype_->set_occurrence(aka2::occurrence(1, 1));
	else
	  mtype_->set_occurrence(aka2::occurrence(0, 1));
      }

    private:
      template<class P, class V, class VL> 
      void new_member(const char *tagname, V P::* m, const VL&) {
	schematype_id id = VL::dispatcher_.get_schematype();
	if (!L::acceptable(id))
	  throw internal_error();
      	VL::initialize();
	member_getter *mgetter = 
	  create_c_style_getter(&VL::dispatcher_, reinterpret_cast<T*>(0), m);	  
	aka2::member_type mtype = aka2::member_type(mgetter);
	mtype.set_name(tagname);
    	default_op *defop = VL::create_default_op();
	if (defop != 0)
	  mtype.set_default_op(defop);
	mtype_ = L::register_membertype(mtype);
      }
    };
    typedef _member member; // VC6 workaround.


    // Helper class to define serializable member.
    template<class V>
    struct fixed_member { // Default value for complexType or mixed content will not be supported.
      fixed_member(const char *tagname, const char *fixed_value) {
      	new_member(tagname, xiso::leaf<V>());
	mtype_->setup_default_value(fixed_value);
      }
      template<class VL>
      fixed_member(const char *tagname, const char *fixed_value, const VL &) {
      	new_member(tagname, VL());
	mtype_->setup_default_value(fixed_value);
      }
      void occurrence(int minOccurs, int maxOccurs = 1) {
	schematype_id id = mtype_->get_schematype();
	if ((id != array_id) && (id != choice_id))
	  throw internal_error();
	mtype_->set_occurrence(aka2::occurrence(minOccurs, maxOccurs));
      }
      void required(bool val) {
	schematype_id id = mtype_->get_schematype();
	if (id != ptrmember_id)
	  throw internal_error();
	if (val)
	  mtype_->set_occurrence(aka2::occurrence(1, 1));
	else
	  mtype_->set_occurrence(aka2::occurrence(0, 1));
      }
      member_type *mtype_;

    private:
      template<class VL>
      void new_member(const char *tagname, const VL& vl = xiso::leaf<VL>()) {
      	VL::initialize();

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

	aka2::member_type mtype(create_fixed_getter(&VL::dispatcher_));
	mtype.set_name(tagname); 
    	default_op *defop = VL::create_default_op();
	if (defop != 0)
	  mtype.set_default_op(defop);
	mtype_ = L::register_membertype(mtype);
      }
    };


    struct _ptrmember {
      template<class P, class V> 
      _ptrmember(const char *tagname, V* P::* m) {
	new_ptr_member(tagname, m, xiso::leaf<V>());
      }
      template<class P, class V, class VL>
      _ptrmember(const char *tagname, V* P::* m, const VL&) {
      	new_ptr_member(tagname, m, VL());
      }
      void required(bool val) {
      	if (val)
	  mtype_->set_occurrence(aka2::occurrence(1, 1));
      	else
	  mtype_->set_occurrence(aka2::occurrence(0, 1));
      }
      member_type *mtype_;

    private:
      template<class P, class V, class VL> 
      void new_ptr_member(const char *tagname, V* P::* m, const VL&) {
	VL::initialize();
	member_getter *mgetter = 
	  create_c_style_getter(&aka2::ptrmember_op_dispatcher<V, VL>::dispatcher_, 
				reinterpret_cast<T*>(0), m);	  
	
	schematype_id id = VL::dispatcher_.get_schematype();
	if (!L::acceptable(id))
	  throw internal_error();
	
	aka2::member_type mtype(mgetter);
	mtype.set_name(tagname);
	default_op *defop = VL::create_default_op();
	if (defop != 0)
	  mtype.set_default_op(defop);
	mtype_ = L::register_membertype(mtype);
	
      }
    };
    typedef _ptrmember ptrmember; // VC6 workadound.
  };
}

#endif
