#ifndef __Language_
#define __Language_

#include <string>
#include "const_string.hh"
#include "phonetic.hh"
#include "clone_ptr.hh"

class aspell;

#define to_uchar(c) static_cast<unsigned char>(c)

class AspellConfig;

class SC_Language {
public:
  enum CasePattern {all_lower, first_upper, all_upper};
  enum CharType {letter, space, other};

  struct SpecialChar {
    bool begin;
    bool middle;
    bool end;
    SpecialChar() : begin(false), middle(false), end(false) {}
    SpecialChar(bool b, bool m, bool e) : begin(b), middle(m), end(e) {}
  };

private:
  string   name_;
  string   charset_;

  SpecialChar special_[256];
  char        to_lower_[256];
  char        to_upper_[256];
  char        to_title_[256];
  char        to_sl_[256];
  int         to_uni_[256];
  CharType    char_type_[256];

  string      soundslike_chars_;

  clone_ptr<const SC_Phonetic> phonetic_;

  void setup(string lang, const AspellConfig *);

public:
  SC_Language() {setup("",0);}
  SC_Language(string lang) {setup(lang,0);}
  SC_Language(string lang, const AspellConfig *config) {setup(lang,config);}

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

  CasePattern case_pattern (const char * word) const;
  string fix_case (CasePattern, const char *) const;
  string fix_case (CasePattern p, const_string word) const 
    {return fix_case(p,word.c_str());}

  bool trim_n_try (const aspell &sc, const char * word) const;

  bool trim_n_try (const aspell &sc, const string &word) const
    {return trim_n_try(sc, word.c_str());}
  bool trim_n_try (const aspell &sc, const const_string &word) const
    {return trim_n_try(sc, word.c_str());}

  char to_upper(const char c) const {return to_upper_[to_uchar(c)];}
  bool is_upper(const char c) const {return to_upper(c) == c;}
  string to_upper(const char *word) const {
    string new_word; 
    for (; *word; ++word) 
      new_word += to_upper(*word); 
    return new_word;
  }
  string to_upper(const const_string &word) const
  {
    return to_upper(word.c_str());
  }
  string to_upper(const string &word) const {return to_upper(word.c_str());}

  char to_lower(const char c) const {return to_lower_[to_uchar(c)];}
  bool is_lower(const char c) const {return to_lower(c) == c;}
  string to_lower(const char *word) const {
    string new_word; 
    for (; *word; ++word) 
      new_word += to_lower(*word); 
    return new_word;
  }
  string to_lower(const const_string &word) const 
  {
    return to_lower(word.c_str());
  }
  string to_lower(const string &word) const {return to_lower(word.c_str());}

  char to_title(const char c) const {return to_title_[to_uchar(c)];}
  bool is_title(const char c) const {return to_title(c) == c;}
  string to_title(const char *word) const {
    string new_word; 
    if (*word)
      new_word += to_title(*word);
    ++word;
    for (; *word; ++word) 
      new_word += to_lower(*word); 
    return new_word;
  }
  string to_title (const const_string &word) const 
  {
    return to_title(word.c_str());
  }
  string to_title(const string &word) const {return to_title(word.c_str());}
  
  char to_sl(char c) const {return to_sl_[to_uchar(c)];}
  
  int to_uni(char c) const {return to_uni_[to_uchar(c)];}
  
  SpecialChar special(char c) const {return special_[to_uchar(c)];}
  
  CharType char_type(char c) const {return char_type_[to_uchar(c)];}
  bool is_alpha(char c) const {return char_type(c) == letter;}
  
  bool generic_soundslike() const {return phonetic_->generic_soundslike();}
  string to_soundslike(const char * word) const 
  {
    return phonetic_->to_soundslike(this, word);
  }
  string to_soundslike(const const_string &word) const 
  {
    return to_soundslike(word.c_str());
  }
  string to_soundslike(const string &word) const {
    return to_soundslike(word.c_str());
  }
  
  bool have_phoneme() const {return phonetic_->have_phoneme();}
  string to_phoneme(const char * word) const 
  {
    return phonetic_->to_phoneme(this,word);
  }
  string to_phoneme(const const_string &word)  const  
  {
    return to_phoneme(word.c_str());
  }
  string to_phoneme(const string &word) const 
  {
    return to_phoneme(word.c_str());
  }

  string soundslike_chars() const {return soundslike_chars_;}
};

#endif
