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

/** @file akaxiso/classes/simpletype.h */

#include <akaxiso/classes/type_registry.h>
#include <akaxiso/classes/member.h>
#include <akaxiso/classes/traits.h>

namespace aka2 {

  template<class V, class VL>
  struct default_value : public default_op {
    typedef V value_type;

    default_value() : has_default_(false) {}
    virtual ~default_value(){}

    virtual void set_default(const std::string &defval) {
      std::istringstream istm(defval);
      VL::read_text(&default_, istm, system_global_attributes());
      has_default_ = true;
    }

    virtual bool has_default() const {
      return has_default_;
    }

    virtual const void *value() const {
      return &default_;
    }

  private:
    V default_;
    bool has_default_;
  };


  template<class L>
  struct simpletype_op_dispatcher : public simpletype_op {
  public:
    virtual schematype_id get_schematype() const { return simpletype_id; }
    virtual const qname& get_typename() const { return L::typename_; }
    virtual const attribute_types *get_attribute_types() const { return 0; }
    virtual const any_member *get_anyattr_type() const { return 0; }

    virtual void write_text(const void* elm,
                            std::ostream &ostm,
                            const global_attributes &gattrs) const {
      L::write_text(elm, ostm, gattrs);
    }

    virtual void read_text(void* elm, std::istringstream &istm,
                           const global_attributes &gattrs) const {
      L::read_text(elm, istm, gattrs);
    }

    virtual void construct(void *e) const {  L::construct(e); }
    virtual void copy_construct(void *e, const void *src) const { L::copy_construct(e, src); }
    virtual void destruct(void *e) const { L::destruct(e); }
    virtual size_t class_size() const { return L::class_size(); }
    virtual bool equals(const void *lhs, const void *rhs) const { return L::equals(lhs, rhs); }
  };


  template<class L, class V>
  struct simpletype_statics {
    static simpletype_op_dispatcher<L> dispatcher_;
    static qname typename_;
  };

  template<class L, class V>
  simpletype_op_dispatcher<L> simpletype_statics<L, V>::dispatcher_;

  template<class L, class V>
  qname simpletype_statics<L, V>::typename_;




  template<class V, class L=xiso::leaf<V> >
  class simpletype : public simpletype_statics<L, V> {
  public:
    virtual ~simpletype(){}

    static void initialize() {
      system_type_registry().add(L());
    }
    static void uninitialize() {}

    static void write_text(const void *elm, std::ostream &ostm,
                           const global_attributes &gattrs) {
      const V &value = *reinterpret_cast<const V*>(elm);
      ostm << value;
    }

    static void read_text(void *elm, std::istringstream &istm,
                          const global_attributes &gattrs) {
      V &value = *reinterpret_cast<V*>(elm);
      istm >> value;
      if (istm.fail())
        throw parse_exception(__FILE__, __LINE__,
                              "Failed to parse simpletype value.");
    }


    static void construct(void *e) { new (e) V(); }
    static void copy_construct(void *e, const void *src) {
      new (e) V(*static_cast<const V*>(src));
    }
    static size_t class_size() { return sizeof(V); }
    static void destruct(void *elm) { static_cast<V*>(elm)->~V(); }

    static bool equals(const void *lhs, const void *rhs) {
      return *static_cast<const V*>(lhs) == *static_cast<const V*>(rhs);
    }

    static default_op* create_default_op() { return new default_value<V, L>; }
    static simpletype_op_dispatcher<L> *get_attribute_dispatcher() {
      return &dispatcher_;
    }
  };


  struct nill {};

  struct  nill_leaf :  public aka2::simpletype<nill, nill_leaf>  {
    static void initialize() {}
    static void uninitialize() {}
    static bool equals(const void *, const void *) {
      return true;
    }
    static void write_text(const void *e, std::ostream &ostm, const global_attributes &gattrs) {}
    static void read_text(void *e, std::istringstream &istm, const global_attributes &gattrs) { }
    static default_op* create_default_op() { return 0; }
  };

} // namespace aka2

#endif /* AKAXISO_SIMPLETYPE_H__ */
