/*****************************************************************************
   file         : $Id: stream.h,v 1.11 2006/09/19 14:04:36 nils Exp $
   description  :
   ------------------------------------------------------------------------

   copyright    : (C) 2006 by Nils Springob, Aachen, GERMANY
   email        : nils.springob@nicai-systems.de
   project      : nicai-systems library

 *****************************************************************************/

#ifdef CVS_INCLUDE_ID
CVS_ID_INC(CVS_INCLUDE_ID, "$Header: /home/cvs/repository/base_nicai_lib/src/nicai/xml/stream.h,v 1.11 2006/09/19 14:04:36 nils Exp $")
#undef CVS_INCLUDE_ID
#endif

#ifndef _NICAI_XML_STREAM_H_
#define _NICAI_XML_STREAM_H_

#include <iosfwd>
#include "xml/nodes.h"


namespace nicai {
namespace xml {

enum
{
  STATE_PREDOC,
  STATE_NORMAL,
  STATE_INTAG,
  STATE_POSTDOC,
  STATE_ERROR
};

/*****************************************************************************/

class failure : public std::exception
{
  private:
    std::string msg;
  public:
    failure(const std::string & _msg) : msg(_msg) {}
    virtual const char * what () const throw() {return msg.c_str();}
    virtual ~failure () throw() {}
};


class ixmlbasestream
{
  protected:
    int state;
    bool doIgnoreComments;
    int pos;
    std::vector<std::string> nodes;
    node * nextNode;

    ixmlbasestream() : state(0), doIgnoreComments(false), pos(0), nextNode(0) {}
    void prefetchNode();
    void dropNode();
    virtual node * getNextInternal() = 0;

  public:
    virtual ~ixmlbasestream() {}
    void ignoreComments(bool value) {doIgnoreComments=value;}
    node * getNext();
    node * peekNext();
    bool expectNode(const node & expected);
    bool expectTag(const std::string & name);
    bool expectTagReadAttributes(const std::string & name, attributemap & attributes);

    bool readTag(std::string & name);
    bool readAttributes(attributemap & attributes, bool clear=true);
    bool readText(std::string & str);
    bool readArray(std::vector<std::string> & /*data*/) {return false;}
    bool ignoreContent();
};

class oxmlbasestream
{
  protected:
    int state;
    std::vector<std::string> nodes;

    virtual oxmlbasestream & outputNode(const node & node) = 0;

  public:
    oxmlbasestream() : state(0) {}
    virtual ~oxmlbasestream() {}
    oxmlbasestream & operator<< (const node & node) {return outputNode(node);}
    oxmlbasestream & operator<< (const std::string & str) {return outputNode(text(str));}
    oxmlbasestream & operator<< (const char * str) {return outputNode(text(str));}
    virtual oxmlbasestream & flush() {return *this;}
};

/*****************************************************************************/

class ixmlstream : public ixmlbasestream
{
  private:
    std::istream & in;
    bool doCollapseWhitespace;
    std::string readEscaped(char until);
    std::string readString(const std::string & until);
    std::string readName();
    bool readAttribute(std::string & name, std::string & val);
    node * activateError(const std::string & msg);

  protected:
    virtual node * getNextInternal();
  public:
    ixmlstream(std::istream & _in) : ixmlbasestream(), in(_in), doCollapseWhitespace(true) {}
    int getPos();
    void collapseWhitespace(bool value) {doCollapseWhitespace=value;}
    std::istream & getStream() {return in;}
};


class oxmlstream : public oxmlbasestream
{
  private:
    std::ostream & out;
    bool doCollapseWhitespace;
    bool doInlineText;
    void outString(const std::string & str, bool attribute=true);
    std::string indent(int offset = 0);
    std::string finish_state();
  protected:
    virtual oxmlstream & outputNode(const node & node);

  public:
    oxmlstream(std::ostream & _out) : oxmlbasestream(), out(_out), doCollapseWhitespace(false) {}
    virtual ~oxmlstream() {}
    void collapseWhitespace(bool value) {doCollapseWhitespace=value;}
    void inlineText(bool value) {doInlineText=value;}
    // optimizations:
    oxmlstream & operator<< (const document & node);
    oxmlstream & operator<< (const tag & node);
    oxmlstream & operator<< (const attribute & node);
    oxmlstream & operator<< (const endtag & node);
    oxmlstream & operator<< (const enddocument & node);
    oxmlstream & operator<< (const comment & node);
    oxmlstream & operator<< (const instruction & node);
    oxmlstream & operator<< (const cdata & node);
    oxmlstream & operator<< (const text & node);
    // inherited
    oxmlstream & operator<< (const node & node) {return outputNode(node);}
    oxmlstream & operator<< (const std::string & str) {return outputNode(text(str));}
    oxmlstream & operator<< (const char * str) {return outputNode(text(str));}
    oxmlstream & flush();
};

} // namespace
} // namespace

#endif


