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

#include <akaxiso/tricklib/tricklib.h>

#ifdef USE_XERCESC
#include <memory.h> /* {BCB6} */
#include <xercesc/util/TransService.hpp>
#include <akaxiso/classes/scoped_ptr.h>
#endif

namespace aka2 {

  class formatter {
  public:
    formatter(std::ostream &ostm) 
      : ostm_(&ostm) {    }
    virtual ~formatter() {
      revert_stream_mode();
    }

    void prepare(const std::string &encoding);

    void write(const std::string &value);
    void write_attribute_entity(const std::string &entity);
    void write_text_entity(const std::string &entity);

    static bool use_xerces_transcoder_;

  private:
    virtual ustring lcp_to_ucs2(const std::string &source) = 0;
    virtual void write(const ustring &entity) = 0;
    void write_entity(const std::string &entity, const int escape_index);

    void set_binary_mode_for_stdio();
    void revert_stream_mode();

  protected:
    virtual void set_encoding(const std::string &encoding) = 0;
    std::ostream *ostm_;
    int saved_stream_mode_;
    int fd_;
  };

  struct bom {
    char chars_[16];
    size_t length_;
  };

  class babel_formatter : public formatter {
  public:
    babel_formatter(std::ostream &ostm) 
      : formatter(ostm), bom_(0) {}
    virtual ~babel_formatter() {}

  private:
    virtual void set_encoding(const std::string &encoding);
    virtual ustring lcp_to_ucs2(const std::string &source);
    virtual void write(const ustring &entity);

    babel::bbl_translater<std::string, ustring> in_translator_;
    babel::bbl_translater<ustring, std::string> out_translator_;

    const bom *bom_;
  };

#ifdef USE_XERCESC
  class xerces_formatter : public formatter {
  public:
    xerces_formatter(std::ostream &ostm) 
      : formatter(ostm), in_transcoder_(0), out_transcoder_(0) {};
    virtual ~xerces_formatter() {}

  private:
    virtual void set_encoding(const std::string &encoding);
    virtual ustring lcp_to_ucs2(const std::string &source);
    virtual void write(const ustring &entity);
    void set_bom(const std::string &encoding);

    scoped_ptr<xercesc::XMLLCPTranscoder> in_transcoder_;
    scoped_ptr<xercesc::XMLTranscoder> out_transcoder_;
    const bom *bom_;
   };
#endif

} // namespace aka2

#endif /* AKAXISO_FORMATTER_H__ */
