/* -*- 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>
#include <akaxiso/classes/any_attributes.h>

namespace aka2 {


  // For typed attributes.
  template<class L, class T>
  class  attributes {
  public:
    struct _attribute {
      template<class P, class V>
      _attribute(const std::string &tagname, V P::*member) {
      	new_attribute(tagname, member, xiso::leaf<V>());
      }
      template<class P, class V, class VL>  
      _attribute(const std::string &tagname, V P::* member, const VL&) {
	new_attribute(tagname, member, VL());
      }

      void set_default(const std::string &defval) {
	if (attr_ == 0)
	  throw internal_error(); // attribute already specified.
	attr_->setup_default_value(defval);
	attr_->set_required(false); // When default is specified, '@use' should be "optional". 
	attr_ = 0;
      }
      void required(bool required) {
	if (attr_ == 0)
	  throw internal_error(); // attribute already specified.
	attr_->set_required(required);
	attr_ = 0;
      }

    private:
      template<class P, class V, class VL>
      void new_attribute(const std::string &tagname, V P::*member, const VL) {
	VL::initialize();
	member_getter *getter = 
	  create_ptr_getter(reinterpret_cast<T*>(0), member);
	const simpletype_op &sop = VL::dispatcher_;
	attribute_type attr = aka2::attribute_type(getter, sop); 
	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 std::string &tagname, const std::string &fixed_value) {
	new_attribute(tagname, fixed_value, xiso::leaf<V>());
      }
      template<class VL>
      fixed_attribute(const std::string &tagname, const std::string &fixed_value, const VL &) {
	new_attribute(tagname, fixed_value, VL());
      }
      void required(bool val) { attr_->set_required(val); }
    private:
      template<class VL>
      void new_attribute(const std::string &tagname, const std::string &fixed_value, const VL&) {
	VL::initialize();
	member_getter *mg = new null_getter();
	attribute_type attr = aka2::attribute_type(mg, fixed<VL>::dispatcher_); 
	attr.set_name(tagname);
	
	default_op *defop = VL::create_default_op();
	assert(defop != 0);
	attr.set_default_op(defop);
	attr.setup_default_value(fixed_value);
	
	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 P>
    void any_attribute(wc_attributes P::*member)  {
      member_getter *mgetter = 
	create_ptr_getter(reinterpret_cast<T*>(0), member);
      any_attributes_ = aka2::any_member(mgetter, any_attributes_op::dispatcher_);
    }
    
    static const any_member* get_anyattr_type() {
      if (any_attributes_.empty())
	return 0;
      return &any_attributes_;
    }
    
    typedef _attribute attribute;
    static attribute_types attribute_types_;
    static any_member any_attributes_;
  };
  
  template<class L, class T>
  attribute_types attributes<L, T>::attribute_types_;
  
  template<class L, class T>
  any_member attributes<L, T>::any_attributes_;

}


#endif
