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

#include <akaxiso/classes/membertype.h>
#include <akaxiso/classes/document.h>
#include <akaxiso/formatter.h>
#include <akaxiso/classes/scoped_ptr.h>
#include <set>
#include <stack>

namespace aka2 {

  class serializer  {
  public:
    serializer(int tab, const std::string &encoding);
    virtual ~serializer();

    void using_prefix(const std::string &prefix);
    void using_uri(const std::string &uri);

    void serialize(const document &doc, std::ostream &ostm);
    
    template <class R>
    void serialize(const R &root, const std::string &name, std::ostream &ostm) {
      const element_props &props = system_document_factory().get_props(name);
      do_serialize(&root, props, name, ostm);
    }

  private:
    void create_formatter(std::ostream& ostm);
    void do_serialize(const void *e, const element_props &props, const qname &name, std::ostream &ostm);
    virtual void serialize_internal(const void *e, const element_props &props,
				    const qname &name) = 0;

    int indent_;
    std::string indent_str_;

    int any_depth_;

  protected:
    void inc_indent_level() { ++indent_; }
    void dec_indent_level() { --indent_; }
    void new_line();

    void inc_ns_depth();
    void dec_ns_depth();
    bool is_new_ns(id_type id) const;
    void use_temp_nsdecl(id_type id);

    static bool is_sequence_empty(const void *e, const member_types &mtypes);
    static bool is_all_empty(const void *e, const member_map &mmap);
    static bool is_member_empty(const void *e, const member_type &mtype);

    std::string encoding_;
    scoped_ptr<formatter> formatter_;
    bool is_root_;

    typedef std::vector<id_type> ids;
    ids nsids_;
   
    typedef std::set<id_type> ns_set;
    typedef std::stack<ns_set> ns_stack;
    ns_stack ns_stack_;
  };

} // namespace aka2

#endif  /* AKAXISO_SERIALIZER_H__ */
