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

#include <akaxiso/classes/qname.h>
#include <vector>


namespace aka2 {


  template<class V>
  V* get_member_ptr(const void *element, int offset) {
    return reinterpret_cast<V*>(reinterpret_cast<int>(element) + offset);
  }

  template <class P, class T, class V>
  int get_member_offset(V T::* member) {
    P* p = reinterpret_cast<P*>(1024);
    return reinterpret_cast<int>(& (p->*member)) - reinterpret_cast<int>(p);
  }


  struct element_op;

  struct default_op { 
    virtual void set_default(const char *defval) = 0;
    virtual bool has_default() const = 0;
    virtual void init_value(void *element) const = 0;
    virtual bool is_default(const void *element) const = 0;
    virtual bool is_default_string(const std::string &val) const = 0;
    virtual void write_default(std::ostream &ostm) const = 0;
 };



  struct memberpair {
    memberpair(void *e, const element_op& op) : e_(e), op_(op){}
    void* e_;
    const element_op& op_; 
  };

  struct const_memberpair {
    const_memberpair(const void *e, const element_op& op) : e_(e), op_(op){}
    const void* e_;
    const element_op& op_; 
  };

  struct member_getter {
    virtual ~member_getter(){}
    virtual void* get_member(void *element) const = 0;
    virtual const void* get_member(const void* element) const = 0;

    // Return type must be pointer, because 0 could be returned.
    virtual const element_op* get_op() const = 0;
  };


  struct c_style_getter : public member_getter {
    c_style_getter(int offset, element_op *et) : offset_(offset), et_(et) {}
    virtual void* get_member(void *element) const {
      return get_member_ptr<void>(element, offset_);
    }
    virtual const void* get_member(const void* element) const {
      return get_member_ptr<const void>(element, offset_);
    }
    virtual const element_op* get_op() const { return et_; }
  protected:
    int offset_;
    element_op *et_;
  };


  template<class P, class T, class V>
  struct cpp_member_getter : public member_getter {
    typedef V& (T::*getter)();
    typedef const V& (T::*const_getter)() const;
    cpp_member_getter(getter m, const_getter mc, element_op *et) : m_(m), et_(et) {}
    virtual void* get_member(void *element) const {
      static_cast<P*>(element)->*m_();
    }
    virtual const void* get_member(const void* element) const {
      static_cast<const P*>(element)->*mc_();
    }
    virtual const element_op* get_op() const { return et_; }
  protected:
    getter m_;
    const_getter mc_;
    element_op *et_;
  };



  template<class P, class T, class V>
  inline member_getter *create_c_style_getter(element_op *et, const P *, V T::* m) {
    int offset = get_member_offset<P, T, V>(m);
    return new c_style_getter(offset, et);
  }
}



#endif

