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

#include <akaxiso/classes/member.h>
#include <akaxiso/classes/shared_ptr.h>
#include <functional>

namespace aka2 {

  /** Adaptors */

  
  template<class P, class V>
  struct _ref_getter {
    const V* operator()(const P& p) const {
      return &(p.*getter_)();
    }
    _ref_getter(const V& (P::*g)() const) : getter_(g){}
    const V& (P::*getter_)() const;
  };


  template<class P, class V>
  struct _ref_setter {
    typedef V value_type;
    void operator()(P &p, const V &value) const {
      (p.*setter_)(value);
    }
    _ref_setter(void (P::*s)(const V&)) : setter_(s){}
    void (P::*setter_)(const V&);
  };



  template<class P, class V>
  _ref_getter<P, V> ref_getter(const V& (P::*m)(void) const) {
    return _ref_getter<P, V>(m);
  }
  template<class P, class V>
  _ref_setter<P, V> ref_setter(void (P::*m)(const V& v)) {
    return _ref_setter<P, V>(m);
  }




  template<class T, class G, class S>
  struct general_accessor :  accessor_getter {

    getter_type get_type() const { return accessor_type; }

    general_accessor(element_op &op, const G &g, const S &s) 
      : op_(op), g_(g), s_(s) {}
    
    virtual void get(const void *elm, void *cache) const {
      const T* t = static_cast<const T*>(elm); 
      const void *v = g_(*t);
      op_.copy_construct(cache, v);
    }

    virtual void set(void *elm, const void *cache) const {
      typedef TYPENAME S::value_type value_type;
      T* t = static_cast<T*>(elm); 
      const value_type& v = *static_cast<const value_type*>(cache);
      s_(*t, v);
    }
    const element_op &op_;
    G g_;
    S s_;
  };

  template<class T, class G, class S>
  inline member_getter *create_accessor_getter(const T *,
					       element_op &op, 
					       const G &g,
					       const S &s) {
    return new general_accessor<T, G, S>(op, g, s);
  }
  
}


#endif
