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

#include <akaxiso/classes/simpletype.h>
#include <akaxiso/classes/container_methods.h>
#include <akaxiso/classes/equals.h>

namespace aka2 {

  template<class C>
  class typed_array_iterator : public array_iterator {
  public:
    typed_array_iterator(const C& container) : 
      container_(container), current_(container.begin()) {}
    virtual ~typed_array_iterator(){}

    const C &container_;
    TYPENAME C::const_iterator current_;

    virtual bool has_next() const { return current_ != container_.end(); }
    virtual const void *next() { 
      assert(has_next());
      const TYPENAME C::value_type &v = *current_;
      ++current_;
      return &v;
    }
  };

  template<class L, class VL>
  class array_op_dispatcher : public array_op {
  public:
    virtual schematype_id get_schematype() const {  return array_id;  }
    virtual const qname& get_typename() const {  return L::typename_; }
    virtual const attribute_types *get_attribute_types() const { return 0; } 

    virtual void *create() const { return L::create(); }
    virtual void destroy(void *elm) const { L::destroy(elm); }
    virtual bool equals(const void *lhs, const void *rhs) const {
      return L::equals(lhs, rhs);
    }
    virtual void copy(void *dest, const void *src) const {
      L::copy(dest, src);
    }

    virtual size_t size(const void *container) const { return L::size(container); }
    virtual void push(void *container, void *item) const {
      L::push_method(container, item);
    }
    virtual const element_op& get_item_op() const {
      return VL::dispatcher_;
    }
    virtual array_iterator* get_iterator(const void *e) const {
      return L::get_iterator(e);
    } 
  };

  template<class VL, class L> 
  struct array_statics {
    static qname typename_;
    static array_op_dispatcher<L, VL> dispatcher_;
  };

  template<class VL, class L>
  qname array_statics<VL, L>::typename_;

  template<class VL, class L>
  array_op_dispatcher<L, VL> array_statics<VL, L>::dispatcher_;

  
  template<class T, class L, class VL>
  class array : public array_statics<VL, L> { 
  public:
    virtual ~array(){}
    typedef TYPENAME T::value_type value_type;

    static void initialize() {  
      if (!system_type_registory().add(L()))
	return;
      VL::initialize();
    }
    static void uninitialize() {  }

    // To define model.
    static void push_method(void *container, const void *item) {
      L().methods.push(*static_cast<T*>(container), 
		       *static_cast<const TYPENAME T::value_type*>(item));
    }

    static T* create() { return new T; }
    static void destroy(void *elm) { delete static_cast<T*>(elm); }
    static bool equals(const void *lhs, const void *rhs) {
      return array_equals(lhs, rhs, dispatcher_, VL::dispatcher_);
    }
    static void copy(void *dest, const void *src) {
      array_copy(dest, src, dispatcher_, VL::dispatcher_);
    }

    static size_t size(const void *container) { 
      return static_cast<const T*>(container)->size(); 
    }

    static typed_array_iterator<T> * get_iterator(const void *e) {
      return new typed_array_iterator<T>(*static_cast<const T*>(e));
    }
    static default_op *create_default_op() { return 0; }
  };




  template<class T, class VL=xiso::leaf<TYPENAME T::value_type> >
  class sequential_array : public array<T, sequential_array<T, VL> , VL> { 
  public:
    sequential<T> methods;
  };


  template<class T, class VL=xiso::leaf<TYPENAME T::value_type> >
  class associative_array : public array<T, associative_array<T, VL>, VL> { 
  public:
    associative<T> methods;
  };


}

#endif
