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

#ifndef __aspell_manager__
#define __aspell_manager__

#include <string>
#include <vector>
#include "exception.hh"
#include "emulation.hh"
#include "copy_ptr.hh"
#include "clone_ptr.hh"
#include "data.hh"

class PspellConfigImpl;

namespace autil {
  class StringMap;
}

// The manager class is responsible for keeping track of the
// dictionaries coming up with suggestions and the like. Its methods
// are NOT meant to be used my multiple threads and/or documents.

namespace aspell {

  using namespace autil;

  class Language;
  class SensitiveCompare;
  class Config;
  class Suggest;
  class SuggestionList;
  
  class DataSet;
  class BasicWordSet;
  class WritableWordSet;
  class WritableReplacementSet;

  class Manager {
  public:
    Manager(const string & override);
    Manager(const Config & override);
    Manager(PspellConfigImpl & override);

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

    void init_config();
    void setup(const string & override = "");
    void setup(PspellConfigImpl & override);
    void setup(const Config & override);

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

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

  public:

    enum SpecialId {main_id, personal_id, session_id, 
		    personal_repl_id, none_id};

    typedef Emulation<DataSet *> WordLists;

    WordLists wordlists() const;
    int  num_wordlists() const;

    //these functions are undefined if the requesed wl doesn't exist
    WritableWordSet &        personal_wl();
    WritableWordSet &        session_wl();
    WritableReplacementSet & personal_repl();

    const WritableWordSet &        personal_wl() const;
    const WritableWordSet &        session_wl() const;
    const WritableReplacementSet & personal_repl() const;

    bool have(const DataSet::Id &) const;
    bool have(SpecialId) const;
    LocalWordSet locate (const DataSet::Id &);
    bool attach(DataSet *, const LocalWordSetInfo * li = 0);
    bool steal(DataSet *, const LocalWordSetInfo * li = 0);
    bool detach(const DataSet::Id &);
    bool destroy(const DataSet::Id &);
  
    SpecialId check_id(const DataSet::Id &) const;
    void change_id(const DataSet::Id &, SpecialId);
  
    bool use_to_check(const DataSet::Id &) const;
    void use_to_check(const DataSet::Id &, bool);
    bool use_to_suggest(const DataSet::Id &) const;
    void use_to_suggest(const DataSet::Id &, bool);
    bool save_on_saveall(const DataSet::Id &) const;
    void save_on_saveall(const DataSet::Id &, bool);
    bool own(const DataSet::Id &) const;
    void own(const DataSet::Id &, bool);
  
    //
    // Language methods
    //

    const char * lang_name() const;

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

    //
    // Spelling methods
    //
  
    bool check(char * word, char * word_end, /* it WILL modify word */
	       unsigned int run_together_limit,
	       CompoundInfo::Position pos,
	       SingleWordInfo * words) const;

    BasicWordInfo check_simple(const char * word) const;
    BasicWordInfo check_simple(const string & w) const 
    {
      return check_simple(w.c_str());
    }
    
    bool check(const string & word, WordInfo & wi) const
    {
      vector<char> w(word.size()+1);
      strncpy(&*w.begin(), word.c_str(), w.size());
      return check(&*w.begin(), 
		   &*w.begin() + w.size() - 1, 
		   run_together_limit_,
		   CompoundInfo::Orig,
		   wi.words);
    }
    bool check(const string & word) const { 
      WordInfo wi;
      bool s =  check(word,wi); 
      //cerr << "::"; wi.write(cerr,lang(),WordConvertInfo()); cerr << endl;
      return s;
    }
    bool check(const char * word, WordInfo & wi) const
    {
      vector<char> w(strlen(word)+1);
      strncpy(&*w.begin(), word, w.size());
      return check(&*w.begin(), 
		   &*w.begin() + w.size() - 1, 
		   run_together_limit_,
		   CompoundInfo::Orig,
		   wi.words);
    }
    bool check(const char * word) const { 
      WordInfo wi;
      bool s =  check(word,wi); 
      //cerr << "::"; wi.write(cerr,lang(),WordConvertInfo()); cerr << endl;
      return s; 
    }
    

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

    void add_to_personal(const string & word);
    void add_to_session(const string & word);

    void save_all_wls();

    void clear_session();

    SuggestionList & suggest(const string & word);
    // the suggestion list and the elements in it are only 
    // valid until the next call to suggest.

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

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

    class DataSetCollection;
    class ConfigNotifier;

  private:

    friend class ConfigNotifier;

    void real_setup();
    void populate();

    CopyPtr<Language>          lang_;
    CopyPtr<SensitiveCompare>  sensitive_compare_;
    CopyPtr<Config>            config_;
    CopyPtr<DataSetCollection> wls_;
    CopyPtr<ConfigNotifier>    config_notifier_;
    ClonePtr<Suggest>       suggest_;
    ClonePtr<Suggest>       intr_suggest_;
    unsigned int            ignore_count;
    bool                    ignore_repl;
    bool                    unconditional_run_together_;
    bool                    run_together_specified_;
    unsigned int            run_together_limit_;
    const char *            run_together_middle_;
    unsigned int            run_together_min_;
    unsigned int            run_together_start_len_;
    string                  prev_mis_repl_;
    string                  prev_cor_repl_;

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

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

    const DataSetCollection & data_set_collection() const {return *wls_;}

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

  struct DontOwnWordlist : public Exception {
    const DataSet * data_set;
    DontOwnWordlist(const DataSet *wl);
  };
  
  struct ChangeIdException : public Exception {
    Manager::SpecialId try_id;
    DataSet *          data_set;
    ChangeIdException(Manager::SpecialId id, DataSet * ws, const string & m)
      : Exception(m), try_id(id), data_set(ws) {}
  };
  
  struct AlreadyHaveType : public ChangeIdException {
    AlreadyHaveType(Manager::SpecialId id, DataSet * ws);
  };
  
  struct DataSetNotCompatible : public ChangeIdException {
    DataSetNotCompatible(Manager::SpecialId id, DataSet * ws);
  };
}

#endif
