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

#include <akaxiso/classes/qname.h>
#include <akaxiso/classes/namespaces.h>
#include <akaxiso/classes/member.h>
#include <akaxiso/classes/traits.h>
#include <akaxiso/classes/membertype.h>
#include <akaxiso/classes/fixed.h>

namespace aka2 {


  // For typed attributes.
  template<class L, class T>
  class  attributes {
  public:
    struct _attribute {
      template<class P, class V>
      _attribute(const char *tagname, V P::*member) {
      	new_attribute(tagname, member, xiso::leaf<V>());
      }
      template<class P, class V, class VL>  
      _attribute(const char *tagname, V P::* member, const VL&) {
	new_attribute(tagname, member, VL());
      }
      void set_default(const char *defval) {
      	// Don't have to think of value types other than simpletype,
	if (attr_->get_schematype() != simpletype_id)
	  throw internal_error();
      	attr_->setup_default_value(defval);
      };

      void set_required(bool val) { attr_->set_required(val); }

    private:
      template<class P, class V, class VL>
      void new_attribute(const char *tagname, V P::*member, const VL&) {
      	VL::initialize();
	member_getter *op = 
	  create_c_style_attribute_getter(&VL::dispatcher_, 
					  reinterpret_cast<T*>(0), member);
	attribute_type attr = aka2::attribute_type(op); 
	attr.set_name(tagname);
	
      	default_op *defop = VL::create_default_op();
      	if (defop != 0)
	  attr.set_default_op(defop);

      	std::pair<attribute_types::iterator, bool> 
	  res = L::attribute_types_.insert(attribute_types::value_type(qname(tagname), attr));
	if (!res.second)
	  throw internal_error();
	attr_ = &res.first->second;
      }
      attribute_type *attr_;
    };

    template<class V>
    struct fixed_attribute {
      fixed_attribute(const char *tagname, const char *fixed_value) {
	new_attribute(tagname, xiso::leaf<V>());
	attr_->setup_default_value(fixed_value);
      }
      template<class VL>
      fixed_attribute(const char *tagname, const char *fixed_value, const VL &) {
	new_attribute(tagname, VL());
	attr_->setup_default_value(fixed_value);
      }
      void set_required(bool val) { attr_->set_required(val); }
      
    private:
      template<class VL>
      void new_attribute(const char *tagname, const VL&) {
      	VL::initialize();
	member_getter *mg = create_fixed_getter(&VL::dispatcher_);
	attribute_type attr = aka2::attribute_type(mg); 
	attr.set_name(tagname);
	
      	default_op *defop = VL::create_default_op();
      	assert(defop != 0);

	attr.set_default_op(defop);
      	std::pair<attribute_types::iterator, bool> 
	  res = L::attribute_types_.insert(attribute_types::value_type(qname(tagname), attr));
	if (!res.second)
	  throw internal_error();
	attr_ = &res.first->second;
      }
      attribute_type *attr_;
    };

    typedef _attribute attribute;
    static attribute_types attribute_types_;
  };
  
  template<class L, class T>
  attribute_types attributes<L, T>::attribute_types_;


}


#endif


