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

#include <akaxiso/classes/item.h>
#include <sstream> /* {g++2.96} */

namespace aka2 {

  struct member_types;
  struct member_map;
  class member_type;
  class named_member;


  /** marshalling text/value.  */
  struct value_op {
    virtual ~value_op() {} 
    virtual void write_text(const void* elm, 
                            std::ostream &ostm,
                            const global_attributes &gattrs) const = 0;
    virtual void read_text(void* elm, std::istringstream &istm, 
                           const global_attributes &gattrs) const = 0;
  };


  struct member_types_getter {
    virtual ~member_types_getter() {}
    virtual const member_types &get_member_types() const = 0;
  };

  struct member_map_getter {
    virtual ~member_map_getter() {}
    virtual const member_map &get_member_map() const = 0;
  };


  /** Traits for SchemaTypes */
  struct simpletype_op : public element_op,
                         public value_op {
    virtual ~simpletype_op() {}
  };


  struct simplecontent_op : public element_op {
    virtual ~simplecontent_op() {}
    virtual const member_type& get_valuetype() const = 0;
  };


  struct sequence_op : public element_op, public member_types_getter {
    virtual ~sequence_op() {}
  };

  
  struct all_op : public element_op, public member_map_getter {};


  class item_iterator {
  public:
    virtual ~item_iterator(){}
    virtual bool has_next() const = 0;
    virtual const item *next() = 0;
  };

  struct choice_op : public element_op {
    virtual ~choice_op(){}
    virtual const itemtypes &get_itemtypes() const = 0;
    virtual size_t size(const void *container) const = 0;
    virtual void push(void *container, item &item) const = 0;
    virtual item_iterator* get_iterator(const void *container) const = 0;

    bool empty(const void *container) const {
      return size(container) == 0;
    }
  };


  class array_iterator {
  public:
    virtual ~array_iterator() {}
    virtual bool has_next() const = 0;
    virtual const void *next() = 0;
  };

  struct array_op : public element_op {
    virtual ~array_op(){}
    virtual const element_op& get_item_op() const = 0;
    virtual size_t size(const void *container) const = 0;
    virtual void push(void *container, void *element) const = 0;
    virtual array_iterator* get_iterator(const void *container) const = 0;
    bool empty(const void *container) const {
      return size(container) == 0;
    }
  };


  struct ptrmember_op : public element_op {
    virtual ~ptrmember_op() {}
 
    virtual schematype_id get_schematype() const { return ptrmember_id; }
    virtual size_t class_size() const { assert(!"Must not be called.");  return 0; }
    virtual const attribute_types *get_attribute_types() const { return 0; } 
    virtual const any_member* get_anyattr_type() const { return 0; }
    virtual void construct(void *e) const { set_null(e);  }
    virtual void copy_construct(void *e, const void *src) const;
    virtual void destruct(void *e) const;
    virtual bool equals(const void *lhs, const void *rhs) const;

    virtual const element_op& get_value_op() const = 0;
    virtual void *&dereference(void *elm) const = 0;
    virtual const void *dereference(const void *elm) const = 0;

    void *create_member(void *elm) const {
      void *v = get_value_op().create();
      dereference(elm) = v;
      return v;
    }

    void set_null(void *elm) const { dereference(elm) = 0; }
    bool is_null(const void *elm) const { return dereference(elm) == 0; }
  };

  /**
   * fixed
   */
  struct fixed_op : public element_op {
    virtual ~fixed_op() {}
    virtual schematype_id get_schematype() const { return fixed_id; }
    virtual const qname& get_typename() const = 0;
    virtual bool equals(const void *lhs, const void *rhs) const { return true; }

    virtual void construct(void *e) const { get_value_op().construct(e); }
    virtual void copy_construct(void *e, const void *src) const { 
      get_value_op().copy_construct(e, src);  
    }
    virtual void destruct(void *e) const {
      get_value_op().destruct(e);
    }
    virtual size_t class_size() const { return get_value_op().class_size(); }

    virtual const attribute_types *get_attribute_types() const { return 0; }
    virtual const any_member *get_anyattr_type() const { return 0; }
    virtual const simpletype_op& get_value_op() const = 0;
  };

} // namespace aka2

#endif /* AKAXISO_TRAITS_H__ */
