// Aspell main C++ include file
// Copyright 1998 by Kevin Atkinson under the terms of the LGPL.

#ifndef aspell__
#define aspell__

#include <string>
#include <vector>
#include "error.hh"
#include "data.hh"
#include "copy_ptr.hh"

class SC_WordList;
class SC_Soundslikes;
class SC_Language;
class AspellConfig;
class StringMap;

class aspell : public aspell_object {
public:
  typedef vector<string>      Suggestions;

public:
  aspell(const string & override);
  aspell(const StringMap & override);

  aspell(); // does not set anything up. 
  ~aspell();

  void setup(const StringMap & override);

  const AspellConfig & config () const {return *config_;}

  //
  // Low level Word List Management methods
  // (implementation in spell_data.cc)
  //

public:
  enum SpecialId {main_id, personal_id, session_id, per_repl_id, none_id};

  class WL {
      friend class aspell;
    public:
      WL(WordList_Base *w) : wl_(w), 
	use_to_check_(false), use_to_suggest_(false), 
        save_on_saveall_(false), own_(false), special_id_(none_id)     {}

// AER: made a null intializer, cuz it wanted that. Hope it doesn't mess anything up
WL() : wl_(NULL), 
	use_to_check_(false), use_to_suggest_(false), 
        save_on_saveall_(false), own_(false), special_id_(none_id)     {}

      WordList_Base *wl() const {return wl_;}
      WL&  wl(WordList_Base *w) {wl_ = w; return *this;}
      bool use_to_check() const {return use_to_check_;}
      WL&  use_to_check(bool val) {use_to_check_ = val; return *this;}
      bool use_to_suggest() const {return use_to_suggest_;}
      WL&  use_to_suggest(bool val) {use_to_suggest_ = val; return *this;}
      bool save_on_saveall() const {return save_on_saveall_;}
      WL&  save_on_saveall(bool val) {save_on_saveall_ = val; return *this;}
      bool own() const {return own_;}
      WL&  own(bool val) {own_ = val; return *this;}
    private:
      WordList_Base  *wl_;
      bool            use_to_check_;
      bool            use_to_suggest_;
      bool            save_on_saveall_;
      bool            own_;
      SpecialId       special_id_;
  };

  typedef vector<WL> WordLists; 
  // do not relay on word lists being a vector!
  // relay only on the fact that it is a forward container
  
  WordLists::size_type wl_size() const;
  bool wl_empty() const;
  WordLists::iterator wl_begin();
  WordLists::const_iterator wl_begin() const;
  WordLists::iterator wl_end();
  WordLists::const_iterator wl_end() const;
  
  WordLists::iterator locate_wl(SpecialId);
  WordLists::const_iterator locate_wl(SpecialId) const;
  WordLists::iterator locate_wl(WordList_Base *);
  WordLists::const_iterator locate_wl(WordList_Base *) const;
  
  //these functions are undefined if the requesed wl doesn't exist
  StandardWL_Base & main_wl();
  const StandardWL_Base & main_wl() const;
  WritableWL_Base & personal_wl();
  const WritableWL_Base & personal_wl() const;
  WritableWL_Base & session_wl();
  const WritableWL_Base & session_wl() const;
  ReplacementsWL_Base & personal_repl();
  const ReplacementsWL_Base & personal_repl() const;
  
  bool have_wl(WordList_Base *) const;
  bool have_wl(SpecialId) const;
  WordLists::iterator attach(WordList_Base *);
  bool detach(WordList_Base *);
  bool detach(WordLists::iterator);
  bool destroy(WordList_Base *);
  bool destroy(WordLists::iterator);
  
  WordLists::iterator set_id(WordList_Base *, SpecialId);
  WordLists::iterator set_id(WordLists::iterator, SpecialId);
  WordLists::iterator change_id(WordList_Base *, SpecialId);
  WordLists::iterator change_id(WordLists::iterator, SpecialId);
  
  bool check_raw (const char *w) const;
  bool check_raw (const string &w) const;

  typedef SC_MWordList        SWordList;
  typedef SC_MReplList        SReplList;

  const SWordList words_w_soundslike(const char *word) const;
  const SWordList words_w_soundslike(const string &word) const 
    {return words_w_soundslike(word.c_str());}

  const SReplList repls_w_soundslike(const char *word) const;
  const SReplList repls_w_soundslike(const string &word) const
    {return repls_w_soundslike(word.c_str());}

  //
  // Language methods
  //

  const char * lang_name() const;

  const SC_Language & lang() const {return *lang_;}

  //
  // Spelling methods
  //  

  Suggestions suggest(const string &word) const;
  const Suggestions suggest_ultra(const string &word) const;

  bool check(const string &word) const;
  bool check(const char *word) const;
  bool check_notrim(const string &word) const;
  bool check_notrim(const char *word) const;

  //
  // High level Word List management methods
  //

  void add_personal(const string &word);
  void add_session(const string &word);

  void save_all_wls();

  void clear_session();

  const string to_soundslike(const string &word) const;
  const SWordList soundslike(const string &word) const;

  const string to_phoneme(const string &word) const;

  double score(const char *word1, const char *word2) const;

  bool ignore_repls();
  bool ignore_repls(bool);
  
  void store_repl(const string& mis, const string &cor,
		  bool memory = true);

  //
  // Private Stuff (from here to the end of the class)
  //

private:

  void populate();

  copy_ptr<const SC_Language> lang_;
  copy_ptr<AspellConfig>      config_;
  bool                    ignore_repl;
  string                  prev_mis_repl_;
  string                  prev_cor_repl_;

  void operator= (const aspell &other);
  aspell(const aspell &other);

public:
  // these are public so that other classes and functions can use them, 
  // DO NOT USE

  void set_check_lang(const string& lang, const string &lang_dir="");
  
  double distance (const char *, const char *, const char *, const char *) const;

private:
  WordLists       word_lists_;
  void destroy();
};

struct ae_change_id_problem : public aspell_error {
  aspell::SpecialId try_id;
  aspell::WordLists::iterator word_list;
  ae_change_id_problem(aspell::SpecialId id, aspell::WordLists::iterator wl,
		       const aspell_object *o) 
    : aspell_error(o), try_id(id), word_list(wl) {}
};

struct ae_already_have_type : public ae_change_id_problem {
  string message() const;
  ae_already_have_type(aspell::SpecialId id, aspell::WordLists::iterator wl, 
		       const aspell_object *o)
    : ae_change_id_problem(id, wl, o) {}
};

struct ae_word_list_not_compellable : public ae_change_id_problem {
  string message() const;
  ae_word_list_not_compellable(aspell::SpecialId id, 
			       aspell::WordLists::iterator wl, 
			       const aspell_object *o)
    : ae_change_id_problem(id, wl, o) {}
};

#define SpellChecker aspell

#endif
