/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU Lesser
 * General Public License Version 2.1 only ("LGPL") or the Common Development and
 * Distribution License ("CDDL")(collectively, the "License"). You may not use this
 * file except in compliance with the License. You can obtain a copy of the CDDL at
 * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
 * specific language governing permissions and limitations under the License. When
 * distributing the software, include this License Header Notice in each file and
 * include the full text of the License in the License file as well as the
 * following notice:
 * 
 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
 * (CDDL)
 * For Covered Software in this distribution, this License shall be governed by the
 * laws of the State of California (excluding conflict-of-law provisions).
 * Any litigation relating to this License shall be subject to the jurisdiction of
 * the Federal Courts of the Northern District of California and the state courts
 * of the State of California, with venue lying in Santa Clara County, California.
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or only
 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
 * include this software in this distribution under the [CDDL or LGPL Version 2.1]
 * license." If you don't indicate a single choice of license, a recipient has the
 * option to distribute your version of this file under either the CDDL or the LGPL
 * Version 2.1, or to extend the choice of license to its licensees as provided
 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
 * Version 2 license, then the option applies only if the new code is made subject
 * to such option by the copyright holder. 
 */

#ifndef _IMI_OPTIONS_H
#define _IMI_OPTIONS_H

#include "utils.h"
#include "portability.h"
#include "imi_view.h"
#include "imi_view_classic.h"
#include "imi_funcobjs.h"
#include "imi_data.h"
#include "imi_option_event.h"
#include "userdict.h"
#include "ic_history.h"
#include "pinyin/shuangpin_seg.h"
#include "pinyin/hunpin_seg.h"

#ifndef SUNPINYIN_USERDATA_DIR_PREFIX
#define SUNPINYIN_USERDATA_DIR_PREFIX ".sunpinyin"
#endif

struct CSimplifiedChinesePolicy : public IConfigurable
{
    CSimplifiedChinesePolicy ();
    
    bool loadResources ();

    CIMIContext* createContext ();
    void destroyContext (CIMIContext *context);
    
    void setPunctMapping (string_pairs punc_map)
        {m_getFullPunctOp.initPunctMap (punc_map);}

    string_pairs getDefaultPunctMapping () const;
    
    void enableFullSymbol (bool v=true) {m_bEnableFullSymbol = v;}
    void enableFullPunct  (bool v=true) {m_bEnableFullPunct = v;}

    void setDataDir (const std::string& data_dir)
        {m_data_dir = data_dir;}

    void setUserDataDir (const std::string& user_data_dir)
        {m_user_data_dir = user_data_dir;}

    virtual bool onConfigChanged (const COptionEvent& event);
    
    template<class> friend class SingletonHolder;
    
protected:
    ~CSimplifiedChinesePolicy () {}

    bool createDirectory (char *path);
    bool saveUserHistory ();
    
    CIMIData             m_coreData;
    CBigramHistory       m_historyCache;
    bool                 m_bLoaded;
    bool                 m_bTried;
    unsigned             m_csLevel;
    bool                 m_bEnableFullSymbol;
    CGetFullSymbolOp     m_getFullSymbolOp;
    bool                 m_bEnableFullPunct;
    CGetFullPunctOp      m_getFullPunctOp;
    std::string          m_data_dir;
    std::string          m_user_data_dir;
public:
    CUserDict            m_userDict;
};

typedef SingletonHolder<CSimplifiedChinesePolicy> ASimplifiedChinesePolicy;

struct CQuanpinSchemePolicy : IConfigurable
{
public:
    
    IPySegmentor* createPySegmentor () 
    {
        CQuanpinSegmentor *pseg = new CQuanpinSegmentor ();
        pseg->setGetFuzzySyllablesOp (&m_getFuzzySyllablesOp);
        pseg->setGetCorrectionPairOp (&m_getCorrectionPairOp);
        pseg->setGetFuzzySegmentsOp  (&m_getFuzzySegmentsOp);
        return pseg;
    }

    void setFuzzyForwarding (bool enable_fuzzies=true, bool enable_simpler_initials=true)
    {
        m_getFuzzySyllablesOp.setEnableFuzzies (enable_fuzzies);
        m_getFuzzySyllablesOp.setEnableSimplerInitials (enable_simpler_initials);
    }

    void clearFuzzyPinyinPairs ()
        {m_getFuzzySyllablesOp.clearFuzzyMap();}

    void setFuzzyPinyinPairs (const string_pairs& pairs, bool duplex = true)
        {m_getFuzzySyllablesOp.initFuzzyMap (pairs, duplex);}

    void setAutoCorrecting (bool v=true)
        {m_getCorrectionPairOp.setEnable (v);}

    void setAutoCorrectionPairs (const string_pairs& pairs) 
        {m_getCorrectionPairOp.setCorrectionPairs (pairs);}

    void setFuzzySegmentation (bool v=true)
        {m_getFuzzySegmentsOp.setEnable (v);}

    void setInnerFuzzySegmentation (bool v=true)
        {m_getFuzzySegmentsOp.setInnerFuzzyEnable (v);}

    virtual bool onConfigChanged(const COptionEvent& event);
    
    template<class> friend class SingletonHolder;
    
protected:
    ~CQuanpinSchemePolicy () {}

    CGetFuzzySyllablesOp<CPinyinData>   m_getFuzzySyllablesOp;
    CGetCorrectionPairOp                m_getCorrectionPairOp;
    CGetFuzzySegmentsOp                 m_getFuzzySegmentsOp;
};

typedef SingletonHolder<CQuanpinSchemePolicy> AQuanpinSchemePolicy;

struct CShuangpinSchemePolicy : public IConfigurable
{
public:
    CShuangpinSchemePolicy();
    
    IPySegmentor* createPySegmentor () 
    {
        CShuangpinSegmentor *pseg = new CShuangpinSegmentor (m_shuangpinType);
        pseg->setGetFuzzySyllablesOp (&m_getFuzzySyllablesOp);
        return pseg;
    }

    void setShuangpinType (EShuangpinType t) {m_shuangpinType = t;}

    void setFuzzyForwarding (bool enable_fuzzies=true, bool enable_simpler_initials=true)
    {
        m_getFuzzySyllablesOp.setEnableFuzzies (enable_fuzzies);
        m_getFuzzySyllablesOp.setEnableSimplerInitials (enable_simpler_initials);
    }

    void clearFuzzyPinyinPairs ()
        {m_getFuzzySyllablesOp.clearFuzzyMap();}

    void setFuzzyPinyinPairs (const string_pairs& pairs, bool duplex = true)
        {m_getFuzzySyllablesOp.initFuzzyMap (pairs, duplex);}

    virtual bool onConfigChanged(const COptionEvent& event);
    
    template<class> friend class SingletonHolder;
protected:
    ~CShuangpinSchemePolicy () {}

    EShuangpinType                      m_shuangpinType;
    CGetFuzzySyllablesOp<CPinyinData>   m_getFuzzySyllablesOp;
};

typedef SingletonHolder<CShuangpinSchemePolicy> AShuangpinSchemePolicy;

struct  CHunpinSchemePolicy: public IConfigurable
{
public:
    CHunpinSchemePolicy();
    
    IPySegmentor* createPySegmentor () 
    {
        CHunpinSegmentor *pseg = new CHunpinSegmentor (m_shuangpinType);
        pseg->setGetFuzzySyllablesOp (&m_getFuzzySyllablesOp);
        return pseg;
    }
	
    void setShuangpinType (EShuangpinType t) {m_shuangpinType = t;}
	
    void setFuzzyForwarding (bool enable_fuzzies=true, bool enable_simpler_initials=true)
    {
        m_getFuzzySyllablesOp.setEnableFuzzies (enable_fuzzies);
        m_getFuzzySyllablesOp.setEnableSimplerInitials (enable_simpler_initials);
    }
	
    void clearFuzzyPinyinPairs ()
	{m_getFuzzySyllablesOp.clearFuzzyMap();}
	
    void setFuzzyPinyinPairs (const string_pairs& pairs, bool duplex = true)
	{m_getFuzzySyllablesOp.initFuzzyMap (pairs, duplex);}
	
    virtual bool onConfigChanged(const COptionEvent& event);
    
    template<class> friend class SingletonHolder;
protected:
    ~CHunpinSchemePolicy () {}
	
    EShuangpinType                      m_shuangpinType;
    CGetFuzzySyllablesOp<CPinyinData>   m_getFuzzySyllablesOp;
};

typedef SingletonHolder<CHunpinSchemePolicy> AHunpinSchemePolicy;

struct CClassicStylePolicy : public IConfigurable
{
    CIMIView* createView () {return new CIMIClassicView ();}

    template<class> friend class SingletonHolder;
protected:
    ~CClassicStylePolicy () {}
};

typedef SingletonHolder<CClassicStylePolicy> AClassicStylePolicy;

struct ISunpinyinProfile
{
    virtual CIMIView* createProfile () = 0;
    virtual void destroyProfile (CIMIView *) = 0;
    virtual ~ISunpinyinProfile () {};
};

template <class LanguagePolicy, class PinyinSchemePolicy, class InputStylePolicy>
class CSunpinyinProfile : public ISunpinyinProfile
{
public:
    CSunpinyinProfile () : m_langPolicy(LanguagePolicy::instance()), 
                           m_pySchemePolicy(PinyinSchemePolicy::instance()),
                           m_inputStylePolicy(InputStylePolicy::instance()) 
    {}

    /* profile by itself is a profile, so we are creating a session here? */
    virtual CIMIView* createProfile ()
    {
        if (!m_langPolicy.loadResources ())
            return NULL;

        IPySegmentor* pseg = m_pySchemePolicy.createPySegmentor ();
        if (pseg == NULL)
            return NULL;
        
        CIMIContext *pic = m_langPolicy.createContext ();
        CIMIView* pview = m_inputStylePolicy.createView ();
        pview->attachIC (pic);
        pview->setPySegmentor (pseg);
        
        return pview;
    }

    virtual void destroyProfile(CIMIView* pview)
    {
        if (pview) {
            LanguagePolicy::instance().destroyContext(pview->getIC());
            delete pview->getPySegmentor();
            delete pview;
        }
    }
private:
    typename LanguagePolicy::Type&      m_langPolicy;
    typename PinyinSchemePolicy::Type&  m_pySchemePolicy;
    typename InputStylePolicy::Type&    m_inputStylePolicy;
};

class CSunpinyinSessionFactory : private CNonCopyable
{
public:
    typedef enum {
        QUANPIN,
        SHUANGPIN,
        YUEPIN,
        ZHUYIN,
		HUNPIN,
    } EPyScheme;
    
    typedef enum {
        MSPY_STYLE,
        CLASSIC_STYLE,
    } EInputStyle;

    typedef enum {
        SIMPLIFIED_CHINESE,
        TRADITIONAL_CHINESE,
    } ELanguage;

public:
    static CSunpinyinSessionFactory& getFactory ()
    {
        static CSunpinyinSessionFactory inst;
        return inst;
    }

    void setLanguage (ELanguage lang) {m_lang = lang;}
    void setInputStyle (EInputStyle inputStyle) {m_inputStyle = inputStyle;}
    void setPinyinScheme (EPyScheme pyScheme) {m_pyScheme = pyScheme;}
    void setCandiWindowSize (unsigned size) {m_candiWindowSize = size;}

    CIMIView* createSession ()
    {
        unsigned key = _policiesToKey (m_lang, m_pyScheme, m_inputStyle);
        ISunpinyinProfile *profile = _getProfile(key);
        if (!profile)
            return NULL;
        
        CIMIView *pview = profile->createProfile ();
        if (!pview)
            return NULL;
        
        pview->setHotkeyProfile (&m_hotkeyProfile);
        pview->setCandiWindowSize (m_candiWindowSize);
        return pview;
    }

    void destroySession (CIMIView* pview)
    {
        unsigned key = _policiesToKey (m_lang, m_pyScheme, m_inputStyle);
        ISunpinyinProfile *profile = _getProfile(key);
        if (!profile)
            return;
        profile->destroyProfile(pview);
    }

private:
    CSunpinyinSessionFactory ()
        : m_pyScheme (QUANPIN), m_inputStyle(CLASSIC_STYLE), m_lang(SIMPLIFIED_CHINESE),
          m_candiWindowSize(10)
    {
        m_profiles [_policiesToKey (SIMPLIFIED_CHINESE, QUANPIN, CLASSIC_STYLE)] = 
                new CSunpinyinProfile <ASimplifiedChinesePolicy, AQuanpinSchemePolicy, AClassicStylePolicy> ();

        m_profiles [_policiesToKey (SIMPLIFIED_CHINESE, SHUANGPIN, CLASSIC_STYLE)] = 
                new CSunpinyinProfile <ASimplifiedChinesePolicy, AShuangpinSchemePolicy, AClassicStylePolicy> ();
    }

    ~CSunpinyinSessionFactory ()
    {
        std::map <unsigned, ISunpinyinProfile*>::iterator it  = m_profiles.begin ();
        std::map <unsigned, ISunpinyinProfile*>::iterator ite = m_profiles.end ();
        
        for (; it != ite; ++it)
            delete it->second;
    }

    ISunpinyinProfile* _getProfile(unsigned key)
    {
        std::map <unsigned, ISunpinyinProfile*>::iterator it = m_profiles.find (key);
        if (it != m_profiles.end()) {
            return it->second;
        } else {
            return NULL;
        }
    }

    unsigned _policiesToKey (ELanguage lang, EPyScheme pyScheme, EInputStyle inputStyle)
        {return (lang<<16) + (pyScheme<<8) + inputStyle;}
    
    std::map <unsigned, ISunpinyinProfile*> m_profiles;

    EPyScheme           m_pyScheme;
    EInputStyle         m_inputStyle;
    ELanguage           m_lang;
    unsigned            m_candiWindowSize;
    CHotkeyProfile      m_hotkeyProfile;
};

#endif
