// Pspell implementation header file.
// Applications that just use the pspell library should not include 
// these files as they are subject to change.
// Pspell Modules MUST include some of the implementation files and
// spell checkers MAY include some of these files.
// If ANY of the implementation files are included you also link with
// libaspell-impl to protect you from changes in these files.

// Copyright 2000 by Kevin Atkinson under the terms of the LGPL

#ifndef PSPELL_CONFIG_IMPL__HH
#define PSPELL_CONFIG_IMPL__HH

#include <iostream.h>
#include "config.h"
#include "string_map.h"
#include "string.hh"
#include "error_impl.hh"

// The PspellConfigImpl class is used to hold configuration information.
// it has a set of keys which it will except.  Inserting or even
// trying to look at a key that it does not know will produce
// an error.  Extra accepted keys can be added with the set_extra 
// method.

// An r in the otherdata[0] value means that when merged into
// a config of a different type it will be renamed to
// <config name>_<name>
// A p in the other datavalue means that is is a placeholder
// for when a "r" is merged.  It should start with <config name>_

struct PspellModule {
  const char * name;
  const PspellKeyInfo * begin;
  const PspellKeyInfo * end;
};

class PspellNotifier {
public:
  virtual void item_updated(const PspellKeyInfo *, bool)         {}
  virtual void item_updated(const PspellKeyInfo *, int)          {}
  virtual void item_updated(const PspellKeyInfo *, const char *) {} 
  virtual void item_added  (const PspellKeyInfo *, const char *) {}
  virtual void item_removed(const PspellKeyInfo *, const char *) {}
  virtual void all_removed (const PspellKeyInfo *, const char *) {}
  // the second paramater for all_removed should not be used
};

class PspellPossibleElementsEmul;
class PspellNotifierEmulation;
class PspellGetLine;

struct PspellConfigKeyModuleInfo {
  const PspellKeyInfo * main_begin;
  const PspellKeyInfo * main_end;
  const PspellKeyInfo * extra_begin;
  const PspellKeyInfo * extra_end;
  const PspellModule  * modules_begin;
  const PspellModule  * modules_end;
};

class PspellConfigImpl : public PspellConfig {
private:
  PspellString    name_;
  PspellStringMap * data_;

  bool attached_;    // if attached can't copy
  PspellNotifier * * notifier_list;

  PspellString temp_str;

  friend class PspellPossibleElementsEmul;

  PspellConfigKeyModuleInfo kmi;

  PspellCanHaveErrorImpl error_;

public:
    
  PspellConfigImpl(const char * name,
		   const PspellKeyInfo  * mainbegin, 
		   const PspellKeyInfo * mainend);

  PspellConfigImpl(const PspellConfigImpl &);
  ~PspellConfigImpl();
  PspellConfigImpl & operator= (const PspellConfigImpl &);

  int          error_number() const {return error_.error_number();}
  const char * error_message() const {return error_.error_message();}
  const PspellErrorExtraInfo * error_extra_info() const
  {
    return error_.error_extra_info();
  }

  bool get_attached() const {return attached_;}
  void set_attached(bool a) {attached_ = a;}

  PspellConfig * clone();
  bool assign(const PspellConfig * other);

  const char * name() {return name_.c_str();}

  PspellNotifierEmulation * notifiers() const;
  
  bool add_notifier    (      PspellNotifier *);
  bool remove_notifier (const PspellNotifier *);
  bool replace_notifier(const PspellNotifier *, PspellNotifier *);

  void set_extra(const PspellKeyInfo * begin, const PspellKeyInfo * end);

  void set_modules(const PspellModule * modbegin, const PspellModule * modend);

  static const char * base_name(const char * name);
  
  const PspellKeyInfo * keyinfo(const char * key);

  PspellKeyInfoEmulation * possible_elements(bool include_extra = true);

  PspellStringPairEmulation * elements();
    
  const char * get_default (const char * key);

  const char * retrieve    (const char * key);
  
  bool have (const char * key) const;

  bool retrieve_list (const char * key, PspellMutableContainer &);
  int  retrieve_bool (const char * key);
  int  retrieve_int  (const char * key);
    
  bool replace (const char *, const char *);
  bool remove  (const char *);
    
  void write_to_stream(ostream & out, bool include_extra = false);

  bool read_in(PspellGetLine & in);
  bool read_in_stream(istream & in);
  bool read_in_file(const char * file);
  bool read_in_string(const char * str);

  void merge(PspellConfigImpl &);
  //Note: if the same key is in both config's it is assumed that they
  // have the same data type.
};

class PspellNotifierEmulation {
  PspellNotifier * * i;
public:
  PspellNotifierEmulation(PspellNotifier * * b) : i(b) {}
  const PspellNotifier * next() {
    PspellNotifier * * temp = i;
    if (*i != 0)
      ++i;
    return *temp;
  }
  bool at_end() const {return *i == 0;}
};

extern const PspellKeyInfo * pspell_config_impl_keys_begin;
extern const PspellKeyInfo * pspell_config_impl_keys_end;   

#endif

