

#include <iterator>
#include <string>
#include <vector>

//#include "repl.hh"
#include "clone_ptr-t.hh"

namespace autil {
  class ConfigData;
}

namespace afilter {

  using namespace std;
  using namespace autil;

  typedef int unichar;

  struct MapReplData {
    struct Stats {
      string name;
      enum Mapping {m_one, m_many};
      Mapping str_mapping;
      Mapping uni_mapping;
      bool first_same;
      char first_char;
      bool last_same;
      bool unambiguous_last_char;
      char last_char;
      int  max_size;
      bool unambiguous;
      string special;
      string extends;
      string ontop;
    };
    Stats stats;

    typedef pair<string, unichar> ToUniPair;
    typedef pair<unichar, string> FromUniPair;
    typedef vector<ToUniPair>   ToUnicode;
    typedef vector<FromUniPair> FromUnicode;

    ToUnicode   to_unicode;
    FromUnicode from_unicode;
  };

  bool read(const string & name, ConfigData & opts,
	    MapReplData & data, ostream & diag, int verbose_level);

  class MapReplReadError {
  public:
    struct error {
      virtual string mesg() const = 0;
      virtual ~error() {}
      virtual error * clone() const = 0;
      virtual void assign(const error *) = 0;
    };
    string file;
  
  private:
    typedef vector<ClonePtr<error> > Errors;
    Errors errors_;
  public:
    typedef Errors::const_iterator const_iterator;
    typedef Errors::const_iterator iterator;
  
    void add(error * e) {
      errors_.push_back(ClonePtr<error>(e));
    }
    bool empty() const {return errors_.empty();}
    const_iterator begin() const {return errors_.begin();}
    const_iterator end() const {return errors_.end();}

    struct error_w_line : public error {
      int line;
      error_w_line * set_line(int i) {line = i; return this;}
      string line_prefix() const;
      error_w_line() : line(0) {}
    };

#define CLONE_METH(cls) \
  cls * clone() const {return new cls(*this);} \
  void assign(const error * other) {*this = *static_cast<const cls *>(other);} 

    struct expecting_keyword : public error_w_line {
      string keyword;
      string got;
      string mesg() const {return line_prefix()+ "Expecting " + keyword + " got " 
			     + got + ".";}
      expecting_keyword(const string & k, const string & g) 
	: keyword(k), got(g) {}
      CLONE_METH(expecting_keyword)
	};
  
    struct bad_hex_string : public error_w_line {
      string hex_string;
      string mesg() const {return line_prefix() + "Bad hex string: " + hex_string;}
      bad_hex_string(const string &h) : hex_string(h) {}
      CLONE_METH(bad_hex_string)
	};
  
    struct hex_string_improper_size : public bad_hex_string {
      char size;
      string mesg() const {return line_prefix() + "Hex String must be " + size +
			     " characters long: " + hex_string; }
      hex_string_improper_size(const string &h, char s)
	: bad_hex_string(h), size(s) {}
      CLONE_METH(hex_string_improper_size)
	};
  
    struct improper_char_in_hex : public bad_hex_string {
      char chr;
      string mesg() const {return line_prefix() + "Improper character in hex string "
			     + hex_string + ": " + chr;}
      improper_char_in_hex(const string &h, char c) 
	: bad_hex_string(h), chr(c) {}
      CLONE_METH(improper_char_in_hex)
	};
  
    struct invalid_escape_seq : public error_w_line {
      string escape_seq;
      string mesg() const {return line_prefix() + "Improper escape sequence: "
			     + escape_seq;}
      invalid_escape_seq(const string &e) : escape_seq(e) {}
      CLONE_METH(invalid_escape_seq)
	};
  
    struct ambiguous_str_uni : public error {
      string str;
      int    uni_char1;
      int    uni_char2;
      string mesg() const;
      ambiguous_str_uni(const string &s, int u1, int u2) 
	: str(s), uni_char1(u1), uni_char2(u2) {}
      CLONE_METH(ambiguous_str_uni)
	};

    struct ambiguous_uni_str : public error {
      string str1;
      string str2;
      int    uni_char;
      string mesg() const;
      ambiguous_uni_str(const string &s1, const string &s2, int u) 
	: str1(s1), str2(s2), uni_char(u) {}
      CLONE_METH(ambiguous_uni_str)
	};

    struct cant_read_base : public error {
      string name;
      cant_read_base(const string &n) : name(n) {}
      string mesg() const {
	return "I can't read the required base \"" + name + "\".";
      }
      CLONE_METH(cant_read_base);
    };
  };

}  
