
//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  Copyright (C) 2005-2006 Ianos Gnatius
//  Copyright (C) 2011 Max Vasilyev
//  Copyright (C) 2011 Stas Degteff
//  ------------------------------------------------------------------
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307, USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  SpellChecker Structures and Classes declarations.
//  ------------------------------------------------------------------

#ifndef __GESPELL_H__
#define __GESPELL_H__


//  ------------------------------------------------------------------

#if defined(GCFG_SPELL_INCLUDED)

#if defined (__WIN32__)
    #include <windows.h>
#else
    #include <sys/param.h>
#endif

#ifndef _MAX_PATH
    #define _MAX_PATH 256
#endif

#ifndef PATH_MAX
    #define PATH_MAX _MAX_PATH
#endif

const uint SCHECKET_TYPE_UNKNOWN = 0;
const uint SCHECKET_TYPE_MSSPELL = 1;
const uint SCHECKET_TYPE_MYSPELL = 2;


//  ------------------------------------------------------------------

typedef std::vector<std::string > CSpellSuggestV;
struct Chs;

class CSpellLang
{

protected:
    uint mSpellType;

    bool mIsMdrLoaded;
    bool mIsUdrLoaded;
    char mLangCode[100];

    char mEngine[PATH_MAX];
    char mDictionary[PATH_MAX];

    Chs  *mToDicTable;
    Chs  *mToLocTable;

    std::string userDicPath;

public:
    CSpellLang()
    {
        mSpellType = SCHECKET_TYPE_UNKNOWN;
        mIsMdrLoaded = mIsUdrLoaded = false;
        mToDicTable = mToLocTable = NULL;
    }
    virtual ~CSpellLang() {};

    virtual bool Load(const char *codeset, const char *userdic) = 0;
    virtual void UnLoad() = 0;

    virtual void BuildSuggest(const char *text, CSpellSuggestV &suggest) = 0;

    virtual bool SpellCheck(const char *text) = 0;
    virtual bool AddWord(const char *text) = 0;

    bool IsMdrLoaded()
    {
        return mIsMdrLoaded;
    }
    bool IsUdrLoaded()
    {
        return mIsUdrLoaded;
    }

    const char *GetLangCode()
    {
        return mLangCode;
    }
    uint GetSpellType()
    {
        return mSpellType;
    }

protected:
    // Translate encoding:
    // flag=true: translate to charset of dictionnary, flag=false: translate to charset of locale
    std::string RecodeText(const char *srcText, bool flag);
};


//  ------------------------------------------------------------------

#if !defined(GCFG_NO_MSSPELL)

typedef uint32_t MDR;   // Main Dictionary Reference
typedef uint32_t UDR;   // User Dictionary Reference
typedef uint16_t SEC;   // Spell Error Code
typedef uint16_t LIDC;  // Language Identifier Code
typedef uint16_t SCCC;  // Spell Check Command Code
typedef uint32_t SLID;  // Spell Id type
typedef uint16_t SCIS;  // Spell Check Input Status
typedef uint16_t SCRS;  // Spell Check Return Status

typedef struct WizSpecChars
{
    byte bIgnore;
    byte bHyphenHard;
    byte bHyphenSoft;
    byte bHyphenNonBreaking;
    byte bEmDash;
    byte bEnDash;
    byte bEllipsis;
    byte rgLineBreak[2];
    byte rgParaBreak[2];
} WSC;

typedef struct SpellInputBuffer
{
    word cChr;        // Total characters in buffer area
    word cMdr;        // Count of MDR's specified in lrgMdr
    word cUdr;        // Count of UDR's specified in lrgUdr
    word wSpellState; // State relative to previous SpellCheck call
    char *lrgChr;     // Pointer to text to be spell checked
    MDR  *lrgMdr;     // List of main dicts to use when spelling the buffer
    UDR  *lrgUdr;     // List of user dicts to use when spelling the buffer
} SIB;

typedef struct SpellReturnBuffer
{
    // These fields are set by the SpellCheck() function
    word iChrErr;   // Position in the SIB
    word cChrErr;   // Length of error "word" in SIB
    SCRS scrs;      // Spell check return status
    word cSZ;       // Count of sz's put in buffer
    word cChrMac;   // Current total of chars in buffer

    // These fields MUST be set by the app, NULL pointers are invalid
    word cChr;      // Total space in lrgSZ
    char *lrgSZ;    // Ptr to alternatives format: word\0word\0...word\0\0
    byte *lrgbRate; // Ptr to Rating value for each suggest returned
    word cbRate;    // Number of elements in lrgbRate
} SRB;

typedef struct mdrs
{
    MDR  mdr;
    LIDC lidc;
    UDR  udr;
} MDRS;

typedef SEC (*SpellVer_fn         ) (word*, word*, word*);
typedef SEC (*SpellInit_fn        ) (SLID*, WSC*);
typedef SEC (*SpellOptions_fn     ) (SLID, dword);
typedef SEC (*SpellCheck_fn       ) (SLID, SCCC, SIB*, SRB*);
typedef SEC (*SpellTerminate_fn   ) (SLID, BOOL);
typedef SEC (*SpellOpenMdr_fn     ) (SLID, char*, char*, BOOL, BOOL, LIDC, MDRS*);
typedef SEC (*SpellCloseMdr_fn    ) (SLID, MDRS*);
typedef SEC (*SpellOpenUdr_fn     ) (SLID, char*, BOOL, word, UDR*, BOOL*);
typedef SEC (*SpellAddUdr_fn      ) (SLID, UDR, char*);
typedef SEC (*SpellCloseUdr_fn    ) (SLID, UDR, BOOL);
typedef SEC (*SpellAddChangeUdr_fn) (SLID, UDR, char*, char*);
typedef SEC (*SpellDelUdr_fn      ) (SLID, UDR, char*);
typedef SEC (*SpellClearUdr_fn    ) (SLID, UDR);
typedef SEC (*SpellGetSizeUdr_fn  ) (SLID, UDR, word*);
typedef SEC (*SpellGetListUdr_fn  ) (SLID, UDR, word, SRB*);
typedef SEC (*SpellVerifyMdr_fn   ) (char*, LIDC, LIDC*);


//  ------------------------------------------------------------------

class CMSSpellLang: public CSpellLang
{

private:
    LIDC mLIDC;
    SLID mSLID;
    MDRS mMDRS;
    UDR  mUDR;
    SIB  mSIB;
    SRB  mSRB;

    char mSZ[1024];
    byte mRate[1024];

    HINSTANCE mLibrary;

    SpellVer_fn           mSpellVer;
    SpellInit_fn          mSpellInit;
    SpellOptions_fn       mSpellOptions;
    SpellCheck_fn         mSpellCheck;
    SpellTerminate_fn     mSpellTerminate;
    SpellOpenMdr_fn       mSpellOpenMdr;
    SpellCloseMdr_fn      mSpellCloseMdr;
    SpellOpenUdr_fn       mSpellOpenUdr;
    SpellAddUdr_fn        mSpellAddUdr;
    SpellCloseUdr_fn      mSpellCloseUdr;
    SpellAddChangeUdr_fn  mSpellAddChangeUdr;
    SpellDelUdr_fn        mSpellDelUdr;
    SpellClearUdr_fn      mSpellClearUdr;
    SpellGetSizeUdr_fn    mSpellGetSizeUdr;
    SpellGetListUdr_fn    mSpellGetListUdr;
    SpellVerifyMdr_fn     mSpellVerifyMdr;

private:
    bool SpellSuggest(const char *text, bool more);
    void BuildRTable(const char *codeset);

public:
    CMSSpellLang()
    {
        mLibrary = NULL;
        mSpellType = SCHECKET_TYPE_MSSPELL;
    }
    virtual ~CMSSpellLang()
    {
        UnLoad();
    }

    bool Init(HKEY hKey, const char *name);

    virtual bool Load(const char *codeset, const char *userdic);
    virtual void UnLoad();

    virtual void BuildSuggest(const char *text, CSpellSuggestV &suggest);

    virtual bool SpellCheck(const char *text);
    virtual bool AddWord(const char *text);
};

#endif  //#if !defined(GCFG_NO_MSSPELL)


#if !defined(GCFG_NO_MYSPELL)

class gdirentry;
class Hunspell;

class CMYSpellLang: public CSpellLang
{

private:
    Hunspell *mMSpell;

public:
    CMYSpellLang()
    {
        mMSpell = NULL;
        mSpellType = SCHECKET_TYPE_MYSPELL;
    }
    virtual ~CMYSpellLang()
    {
        UnLoad();
    }

    bool Init(const gdirentry *entry);

    virtual bool Load(const char *codeset, const char *);
    virtual void UnLoad();

    virtual void BuildSuggest(const char *text, CSpellSuggestV &suggest);

    virtual bool SpellCheck(const char *text);
    virtual bool AddWord(const char *);

private:
    void BuildRTable(const char *codeset);
    bool LoadUserDictionary(const char *userDic);
};

#endif  //#if !defined(GCFG_NO_MYSPELL)


typedef std::vector<CSpellLang*> CSpellLangV;

class CSpellChecker
{
private:
    bool mInited;

    char mXlatLocalset[256];

    CSpellLangV    mLangsLoaded;
    CSpellLangV    mLangs;
    CSpellSuggestV mSuggest;

public:
    CSpellChecker();
    ~CSpellChecker()
    {
        Close();
    }

    bool Init(const char *codeset, const char *dicPath);
    void Close();

    bool Load(const char *langId, const char *userDic);
    void UnLoad(const char *langId);
    void UnLoad();

    bool Check(const char *text);
    CSpellSuggestV &Suggest(const char *text);

    bool AddWord(const char *text);

    CSpellSuggestV &GetSuggest()
    {
        return mSuggest;
    }
    CSpellLangV    &GetLangs()
    {
        return mLangs;
    }
    CSpellLangV    &GetLangsLoaded()
    {
        return mLangsLoaded;
    }
    const std::vector<const char*> GetLangCodes();

    bool IsUdrLoaded();

    bool IsInited()
    {
        return mInited;
    }
    bool IsLoaded()
    {
        return !mLangsLoaded.empty();
    }
    bool IsLoaded(const char *langId);
};


//  ------------------------------------------------------------------

#endif  //#if defined(GCFG_SPELL_INCLUDED)


//  ------------------------------------------------------------------

#endif  //#ifndef __GESPELL_H__


//  ------------------------------------------------------------------
