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

#include "schema.h"
#include "type_registry.h"
#include <set>

namespace osixaka {

  class contents;
  typedef std::set<aka::qname, aka::qname_less> qname_set;
  typedef std::map<aka::qname, contents*, aka::qname_less> contents_map;
  typedef std::vector<const contents*> contents_array;

  class contents {
  public:
    contents(const aka::qname &name, const aka::occurrence &occ)
      : name_(name), occ_(occ) {}

    aka::qname name_;
    aka::occurrence occ_;

    virtual ~contents(){};
    virtual void generate_element(std::ostream &ostm) const = 0;
    virtual void generate_xiso(std::ostream &ostm) const = 0;
    virtual void generate_xiso_impl(std::ostream &ostm) const = 0;
    virtual bool is_resolved(const qname_set &resolved) const = 0;
 };

  struct content_less_by_name : std::binary_function<bool, 
				const contents*, const contents*> {
    bool operator()(const contents* &lhs, const contents* &rhs) const {
      return aka::qname_less()(lhs->name_, rhs->name_);
    }
  };

  struct content_eq_by_name : std::binary_function<bool, 
			      const contents*, const contents*> {
    bool operator()(const contents* &lhs, const contents* &rhs) const {
      return aka::qname_less()(lhs->name_, rhs->name_);
    }
  };

  /* Sequence */
  struct sequence_member {
    aka::qname name_;
    aka::qname type_;
    aka::occurrence occ_;
  };

  typedef std::vector<sequence_member> sequence_members;

  typedef sequence_member attribute_member;
  typedef std::vector<attribute_member> attribute_members;


  class attribute_contents {
  public:
    bool push_attribute(const aka::qname &name, const aka::qname &type);
    void write_attributes_header(const attribute_members &members, std::ostream &ostm) const;
    void write_attributes_leaf(const attribute_members &members, 
			       const cppname &type, std::ostream &ostm) const;
    bool is_resolved() const;
  protected:
    attribute_members attributes_;
  };


  class sequence_class : public contents, public attribute_contents {
  public:
    sequence_class(const aka::qname &name) 
      : contents(name, aka::occurrence()) {}
    virtual ~sequence_class() {}
    virtual void generate_element(std::ostream &ostm) const;
    virtual void generate_xiso(std::ostream &ostm) const;
    virtual void generate_xiso_impl(std::ostream &ostm) const;
     
    bool push_member(const aka::qname &name, const aka::qname &xmltype,
		     const aka::occurrence &occ);
   
    virtual bool is_resolved(const qname_set &resolved) const;
  private:
    sequence_members members_;
  };


  /** Choice */
  class choice_item {
  public:
    aka::qname name_;
    aka::qname type_;
    aka::occurrence occ_;
  };


  typedef std::vector<choice_item> choice_items;

  class choice_class : public contents {
  public:
    choice_class(const aka::qname &name, const aka::occurrence &occ)
      : contents(name, occ) {}
    virtual void generate_element(std::ostream &ostm) const;
    virtual void generate_xiso(std::ostream &ostm) const;
    virtual void generate_xiso_impl(std::ostream &ostm) const;

    bool push_item(const aka::qname &name, const aka::qname &xmltype,
		   const aka::occurrence &occ);
    
    virtual bool is_resolved(const qname_set &resolved) const;
  private:
    choice_items items_;
  };

  class simplecontent_class : public contents, public attribute_contents {
  public:
    simplecontent_class(const aka::qname &name)
      : contents(name, aka::occurrence()) {}
    aka::qname value_type_;
    virtual void generate_element(std::ostream &ostm) const;
    virtual void generate_xiso(std::ostream &ostm) const;
    virtual void generate_xiso_impl(std::ostream &ostm) const;
    virtual bool is_resolved(const qname_set &resolved) const;
 };

  class array_class : public contents {
  public:
    array_class(const aka::qname &name)
      : contents(name, aka::occurrence()){}
    aka::qname item_type_; 
    virtual void generate_element(std::ostream &ostm) const;
    virtual void generate_xiso(std::ostream &ostm) const;
    virtual void generate_xiso_impl(std::ostream &ostm) const;
    virtual bool is_resolved(const qname_set &resolved) const;
  };

  class document_class {
  public:
    aka::qname document_name_;
    aka::qname element_type_;
  };
  typedef std::vector<document_class> document_contents;


  struct document_less_by_type : std::binary_function<bool, 
				 const document_class, const document_class> {
    bool operator()(const document_class &lhs, const document_class &rhs) const {
      return aka::qname_less()(lhs.element_type_, rhs.element_type_);
    }
  };

  void write_occurrence(const aka::occurrence &occ, std::ostream &ostm);

} // namespace osixaka

#endif /* CLASSCONTENTS_H__ */
