// -*- mode: c++ -*-

#ifndef MiX_SAXPARSER_H_
#define MiX_SAXPARSER_H_

#include <map>
#include <stack>

#include "classes.h"
#include "DefaultXMLTraits.h"
#include "misc.h"
#include "Tokenizer.h"
#include "SAX_EventHandler.h"
#include "XMLString.h"
#include "AttrMap.h"

namespace MiX{
  template <class charT,class char_traits,class xml_traits>
  class SAX_Parser{
  public:
    MiX_Template_Typedef(charT,char_traits,xml_traits);
    typedef SAX_Parser<charT,char_traits,xml_traits> this_type;
    typedef XMLToken<charT,char_traits,xml_traits> token_type;
    typedef SAX_EventHandler<charT,char_traits,xml_traits> handler_type;
    typedef Tokenizer<charT,char_traits,xml_traits> tokenizer_type;
  private:
    enum State{
      STATE_Text,
      STATE_Tag,
      STATE_Reference,
      STATE_Comment,
      STATE_Complete,
      STATE_Declaration,
      STATE_XMLDeclaration,
      STATE_Escape,
      STATE_Exception
    };
    State state_;
    tokenizer_type tokenizer_;
    handler_type* handler_;
    std::stack<string_type> validator_;

    bool ignore_space_;

    void skipSpaceTokens();

    bool parsingLoop();

    State parseText();
    State parseTag();
    State parseComment();
    State parseDeclaration();
    State parseXMLDeclaration();

    attrmap_type parseAttributes();
    string_type parseReference();

    void trimRight(string_type& str);
  public:
    ///コンストラクタ
    SAX_Parser(){ handler_ = NULL; ignore_space_ = false; }
    /**
     * イベントハンドラを指定します
     *
     * \param handler 
     *   イベントを受け取るハンドラを表すオブジェクトへのポインタ
     */
    void setEventHandler(handler_type* handler){
      handler_ = handler;
    };
    /**
     * 文字列の前後にある空白(インデント)を無視するかどうか設定します
     *
     * setIgnoreSpace(true)をした場合、インデント等によって整形された
     * XMLドキュメントを簡単に処理することができます
     */
    void setIgnoreSpace(bool flag) { ignore_space_ = flag; };
    /**
     * 与えられた文字列を解析しSAX_EventHandlerに適切なイベントを起こします
     *
     * handlerを指定していなかった場合ParsingExceptionを投げます
     * \param text 解析する文字列
     */
    bool parse(const string_type& text);
    /**
     * 与えられたストリームを解析し、SAX_EventHandlerに適切なイベントを起こします
     *
     * handlerを指定していなかった場合ParsingExceptionを投げます
     * \param is 入力ストリーム
     */
    bool parse(std::basic_istream<charT, char_traits>& is);
  };
}

#ifndef MiX_SAXPARSER_CPP_
#include "SAX_Parser.cpp"
#endif

#endif
