/**********************************************************************

Filename    :   GFxKoreanIME.cpp
Content     :   Core implementation of Korean IME
Created     :   Feb 27, 2008
Authors     :   A. Mohan, A. Bolgar

Copyright   :   (c) 2001-2008 Scaleform Corp. All Rights Reserved.

Notes       :   

Licensees may use this file in accordance with the valid Scaleform
Commercial License Agreement provided with the software.

This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING 
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.

**********************************************************************/
#ifndef UNICODE
#define UNICODE //necessary for IME functions
#endif //UNICODE

#include "GTypes.h"

#if defined(GFC_OS_WIN32) && !defined(GFC_NO_BUILTIN_KOREAN_IME) && !defined(GFC_NO_IME_SUPPORT)
#include "GFxPlayerImpl.h"
#include "GFxText.h"
#include "GFxIMEImm32Dll.h"

UInt GFxMovieRoot::HandleKoreanIME(const GFxIMEEvent& imeEvent)
{
    // check if Imm32.dll is available.
    if (!Imm32Dll.IsAvailable())
    {
        UInt32 errorCode;
        if ((errorCode = Imm32Dll.GetErrorCode()) != 0)
        {
            GFxLog* plog = GetLog();
            plog->LogError("Error: IMM32.DLL is not available, error code = 0x%X\n", errorCode);
            Imm32Dll.ResetErrorCode(); 
        }
        return GFxMovieRoot::HE_NotHandled; // no Imm32 is available, aborting....
    }

    const GFxIMEWin32Event& winEvt = static_cast<const GFxIMEWin32Event&>(imeEvent);
    if (winEvt.IMEEvtType != GFxIMEEvent::IME_PreProcessKeyboard)
    {
        HWND hWND = (HWND)winEvt.hWND;
        union {
            HKL     hkl;
            size_t  langId;
        } un;
        un.hkl = GetKeyboardLayout(0); 
        if ((un.langId & 0xFFFF) == MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN)) //korean
        {
            //printf("!!! %X\n", un.langId);
            switch(winEvt.Message)
            {
            case WM_IME_STARTCOMPOSITION:
                {
                    GPtr<GFxASCharacter> pfocusedCh = GetFocusedCharacter();
                    if (pfocusedCh && pfocusedCh->GetObjectType() == GASObjectInterface::Object_TextField)
                    {
                        GPtr<GASTextField> ptextFld = static_cast<GASTextField*>(pfocusedCh.GetPtr());
                        if (ptextFld->IsIMEEnabled())
                        {
                            // first of all, if we have an active selection - remove it
                            ptextFld->ReplaceText(L"", ptextFld->GetBeginIndex(), 
                                ptextFld->GetEndIndex());

                            ptextFld->CreateCompositionString();
                            ptextFld->SetCompositionStringHighlighting(true);
                        }
                    }
                    return GFxMovieRoot::HE_NoDefaultAction;
                }

            case WM_IME_COMPOSITION:
                {
                    GPtr<GFxASCharacter> pfocusedCh = GetFocusedCharacter();
                    if (pfocusedCh && pfocusedCh->GetObjectType() == GASObjectInterface::Object_TextField)
                    {
                        GPtr<GASTextField> ptextFld = static_cast<GASTextField*>(pfocusedCh.GetPtr());
                        if (ptextFld->IsIMEEnabled())
                        {
                            UPInt keyCode = winEvt.WParam, info = winEvt.LParam;
                            //int options = winEvt.Options;
                            if (info & GCS_RESULTSTR) 
                            {
                                HIMC hIMC = Imm32Dll.ImmGetContext(hWND);
                                // Get the size of the result string.
                                DWORD dwSize = Imm32Dll.ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);
                                wchar_t lpstr[20]; // very unlikely, Korean composition string is longer than 20 chars 
                                                   // (or even, longer than 2 chars). Anyway we have an ASSERT to 
                                                   // catch any weird situations.
                                GASSERT(sizeof(lpstr) >= (dwSize+sizeof(wchar_t)));

                                // Get the result string that is generated by IME into lpstr.
                                LONG res = Imm32Dll.ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);
                                if (res != IMM_ERROR_NODATA && res != IMM_ERROR_GENERAL)
                                {
                                    lpstr[dwSize/2] = 0; //dwSize is in bytes
                                    ptextFld->SetWideCursor(false);
                                }

                                Imm32Dll.ImmReleaseContext(hWND, hIMC);
                                ptextFld->CommitCompositionString(lpstr);
                                ptextFld->SetCompositionStringHighlighting(true);
                            }
                            if ((info & CS_INSERTCHAR) && (info & CS_NOMOVECARET) )
                            {
                                // This is for Korean- a character can change shape depending upon what is typed next, 
                                // so don't advance caret position. Move Caret when the character is finalized.
                                // The "replace" flag is used to indicate whether we should replace the current character 
                                // or not-In case of korean, when the user begins to type, the character should be 
                                // inserted at the current location, but subsequent modifications to the same character 
                                // should replace the existing character.
                                wchar_t lpstr[2];
                                lpstr[0] = (wchar_t)keyCode; lpstr[1] = 0;
 
                                ptextFld->SetWideCursor(true);

                                UPInt pos = ptextFld->GetCaretIndex();
                                ptextFld->SetCompositionStringPosition(pos);
                                ptextFld->SetCompositionStringText(lpstr, 1);
                                ptextFld->SetCursorInCompositionString(0);
                            }
                        }
                    }
                    return GFxMovieRoot::HE_NoDefaultAction;
                }

            case WM_IME_ENDCOMPOSITION:
                {
                    GPtr<GFxASCharacter> pfocusedCh = GetFocusedCharacter();
                    if (pfocusedCh && pfocusedCh->GetObjectType() == GASObjectInterface::Object_TextField)
                    {
                        GPtr<GASTextField> ptextFld = static_cast<GASTextField*>(pfocusedCh.GetPtr());
                        if (ptextFld->IsIMEEnabled())
                        {
                            ptextFld->SetWideCursor(false);
                            ptextFld->ClearCompositionString();
                        }
                    }
                    return GFxMovieRoot::HE_NoDefaultAction;
                }
            case WM_IME_CHAR:
                // This message should not be passed down to DefWinProc otherwise it will
                // generate WM_CHAR messages which will cause text duplication.
                return GFxMovieRoot::HE_NoDefaultAction;
            }
        }
    }
    return GFxMovieRoot::HE_NotHandled;
}
#endif // GFC_NO_BUILTIN_KOREAN_IME
