/**********************************************************************/
/*                                                                    */
/*      COMP.C                                                        */
/*                                                                    */
/*      Copyright (c) 1995  Microsoft Corporation                     */
/*                                                                    */
/**********************************************************************/

#include "windows.h"
#include "imm.h"
#include "resource.h"
#include "imeapps.h"

#define DEBUG 1

LRESULT HandleStartComposition(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
    COMPOSITIONFORM cpf;
    HIMC hIMC;
 
#ifdef DEBUG
    OutputDebugString("WM_STARTCOMPOSITIONSTRING!!!\r\n");
#endif

    if (fdwProperty & IME_PROP_SPECIAL_UI)
    {
        // Normally, we need to set the composition window
        // position to caret position for a special UI IME
    }
    else if (fdwProperty & IME_PROP_AT_CARET)
    {
        // If an application show composition string by itself, we do not
        // need to set the position of composition window for an at caret
        // IME.

        return 1;
    }
    else
    {
        // Normally, we need to set the composition window
        // position to caret position for a near caret IME
    }

    hIMC = ImmGetContext(hWnd);

    if (!hIMC)
    {
        return 1;
    }

    cpf.dwStyle = CFS_POINT;
    cpf.ptCurrentPos.x = ptImeUIPos.x;
    cpf.ptCurrentPos.y = ptImeUIPos.y;

    ImmSetCompositionWindow(hIMC,&cpf);

    ImmReleaseContext(hWnd,hIMC);

    return 1;
}

LRESULT HandleEndComposition(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
#ifdef DEBUG
    OutputDebugString("WM_ENDCOMPOSITIONSTRING!!!\r\n");
#endif
    dwCompStrLen      = 0;
    dwCompAttrLen     = 0;
    dwCompClsLen      = 0;
    dwCompReadStrLen  = 0;
    dwCompReadAttrLen = 0;
    dwCompReadClsLen  = 0;
    dwResultStrLen      = 0;
    dwResultClsLen      = 0;
    dwResultReadStrLen  = 0;
    dwResultReadClsLen  = 0;
    InvalidateRect(hWnd,NULL,TRUE);

    return 1;
}

void MakePaintString(HWND hWnd, LPSTR lpStr,DWORD dwStrLen,LPDWORD lpCls,DWORD dwClsLen,LPSTR lpPaintStr)
{
    LPSTR lpPaintStart = lpPaintStr;

    lpPaintStr += lstrlen(lpPaintStr);

    if (dwStrLen)
    {
        if (dwClsLen)
        {
            lpCls[127] = 0;

            while (*(lpCls+1) && *lpCls < dwStrLen)
            {
                DWORD dwTextLen = *(lpCls+1) - *lpCls;
                LPSTR lpT = lpStr + *lpCls;

                memcpy(lpPaintStr,lpT,dwTextLen);
                lpPaintStr += dwTextLen;
                *lpPaintStr = ',';
                lpPaintStr++;
                lpCls++;
            }
            *lpPaintStr = '\0';
        }
        else
        {
            lstrcpy(lpPaintStr,lpStr);
            lstrcat(lpPaintStr,",");
        }
    }

}

LRESULT HandleComposition(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
    HIMC hIMC;
    BOOL fRedraw = FALSE;

    hIMC = ImmGetContext(hWnd);

    if (lParam & GCS_COMPSTR)
    {
        dwCompStrLen = ImmGetCompositionString(hIMC,GCS_COMPSTR,szCompStr,sizeof(szCompStr));
        szCompStr[dwCompStrLen] = '\0';
        fRedraw = TRUE;
    }
    else
    {
        dwCompStrLen = 0;
        szCompStr[0] = '\0';
    }

    if (lParam & GCS_COMPATTR)
    {
        dwCompAttrLen = ImmGetCompositionString(hIMC,GCS_COMPATTR,bCompAttr,sizeof(bCompAttr));
        fRedraw = TRUE;
    }
    else
    {
        dwCompAttrLen = 0;
        bCompAttr[0] = 0;
    }

    if (lParam & GCS_COMPCLAUSE)
    {
        dwCompClsLen = ImmGetCompositionString(hIMC,GCS_COMPCLAUSE,dwCompCls,sizeof(dwCompCls));
        fRedraw = TRUE;
    }
    else
    {
        dwCompClsLen = 0;
        dwCompCls[0] = 0;
        dwCompCls[1] = 0;
    }


    if (lParam & GCS_COMPREADSTR)
    {
        dwCompReadStrLen = ImmGetCompositionString(hIMC,GCS_COMPREADSTR,szCompReadStr,sizeof(szCompReadStr));
        szCompReadStr[dwCompReadStrLen] = '\0';
        fRedraw = TRUE;
    }
    else
    {
        dwCompReadStrLen = 0;
        szCompReadStr[0] = '\0';
    }

    if (lParam & GCS_COMPREADATTR)
    {
        dwCompReadAttrLen = ImmGetCompositionString(hIMC,GCS_COMPREADATTR,bCompReadAttr,sizeof(bCompReadAttr));
        fRedraw = TRUE;
    }
    else
    {
        dwCompReadAttrLen = 0;
        bCompReadAttr[0] = 0;
    }

    if (lParam & GCS_COMPREADCLAUSE)
    {
        dwCompReadClsLen = ImmGetCompositionString(hIMC,GCS_COMPREADCLAUSE,dwCompReadCls,sizeof(dwCompReadCls));
        fRedraw = TRUE;
    }
    else
    {
        dwCompReadClsLen = 0;
        dwCompReadCls[0] = 0;
        dwCompReadCls[1] = 0;
    }


    if (lParam & GCS_RESULTSTR)
    {
        RECT rc;
        HDC hIC;
        SIZE sz0,sz1;
        HFONT hOldFont;

        if (lParam & GCS_RESULTCLAUSE)
        {
            dwResultClsLen = ImmGetCompositionString(hIMC,GCS_RESULTCLAUSE,dwResultCls,sizeof(dwResultCls));
        }
        else
        {
            dwResultClsLen = 0;
            dwResultCls[0] = 0;
            dwResultCls[1] = 0;
        }

        dwResultStrLen = ImmGetCompositionString(hIMC,GCS_RESULTSTR,szResultStr,sizeof(szResultStr));
        szResultStr[dwResultStrLen] = '\0';


        // szPaintResult may overflow..
        GetClientRect(hWnd,&rc);
        hIC = CreateIC("DISPLAY", NULL, NULL, NULL);
        hOldFont = SelectObject(hIC,hFont);
        GetTextExtentPoint(hIC,szPaintResult,lstrlen(szPaintResult),&sz0);
        GetTextExtentPoint(hIC,szResultStr,lstrlen(szResultStr),&sz1);
        if (sz0.cx + sz1.cx >= rc.right)
        {
            szPaintResult[0] = '\0';
            szPaintResultRead[0] = '\0';
        }
        SelectObject(hIC,hOldFont);
        DeleteDC(hIC);

        MakePaintString(hWnd,szResultStr,dwResultStrLen,dwResultCls,dwResultClsLen,szPaintResult);

        fRedraw = TRUE;
    }
    else
    {
        dwResultStrLen = 0;
        szResultStr[0] = '\0';
        dwResultClsLen = 0;
        dwResultCls[0] = 0;
        dwResultCls[1] = 0;
    }



    if (lParam & GCS_RESULTREADSTR)
    {
        if (lParam & GCS_RESULTREADCLAUSE)
        {
            dwResultReadClsLen = ImmGetCompositionString(hIMC,GCS_RESULTREADCLAUSE,dwResultReadCls,sizeof(dwResultReadCls));
            fRedraw = TRUE;
        }
        else
        {
            dwResultReadClsLen = 0;
            dwResultReadCls[0] = 0;
            dwResultReadCls[1] = 0;
        }
        dwResultReadStrLen = ImmGetCompositionString(hIMC,GCS_RESULTREADSTR,szResultReadStr,sizeof(szResultReadStr));
        szResultReadStr[dwResultReadStrLen] = '\0';
        MakePaintString(hWnd,szResultReadStr,dwResultReadStrLen,dwResultReadCls,dwResultReadClsLen,szPaintResultRead);
        fRedraw = TRUE;
    }
    else
    {
        dwResultReadStrLen = 0;
        szResultReadStr[0] = '\0';
        dwResultReadClsLen = 0;
        dwResultReadCls[0] = 0;
        dwResultReadCls[1] = 0;
    }



    if (fRedraw)
    {
        InvalidateRect(hWnd,NULL,TRUE);
        UpdateWindow(hWnd);
    }
    return 1;
}


LRESULT HandleChar(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
    RECT rc;
    HDC hIC;
    SIZE sz0,sz1;
    HFONT hOldFont;
    LPSTR lp;
    // is the previous received char is a DBCS lead byte char ?
    static BOOL fIsPrevLeadByte = FALSE;

    GetClientRect(hWnd,&rc);
    hIC = CreateIC("DISPLAY", NULL, NULL, NULL);
    hOldFont = SelectObject(hIC,hFont);
    GetTextExtentPoint(hIC,szPaintResult,lstrlen(szPaintResult),&sz0);
    GetTextExtentPoint(hIC,szResultStr,lstrlen(szResultStr),&sz1);
    if (sz0.cx + sz1.cx >= rc.right)
    {
        szPaintResult[0] = '\0';
        szPaintResultRead[0] = '\0';
    }
    SelectObject(hIC,hOldFont);
    DeleteDC(hIC);

    lp = szPaintResult + lstrlen(szPaintResult);

#ifndef UNICODE
    if (fIsPrevLeadByte) {
        // remove , and append second byte for showing DBCS char
        if (*(lp - 1) == ',') {
            lp--;
        }
    }
#endif

    // append second byte
    *lp++ = (BYTE)wParam;
    *lp++ = ',';
    *lp++ = '\0';

    lp = szPaintResultRead + lstrlen(szPaintResultRead);

#ifndef UNICODE
    if (fIsPrevLeadByte) {
        // remove , and append second byte for showing DBCS char
        if (*(lp - 1) == ',') {
            lp--;
        }

        fIsPrevLeadByte = FALSE;
    } else {
        fIsPrevLeadByte = IsDBCSLeadByte((BYTE)wParam);
    }
#endif

    *lp++ = (BYTE)wParam;
    *lp++ = ',';
    *lp++ = '\0';

    InvalidateRect(hWnd,NULL,TRUE);
    UpdateWindow(hWnd);

    return 1;
}


LRESULT HandleNotify(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HIMC hIMC;
    BOOL fOpen;
    DWORD dwConvMode,dwSentMode;


    switch (wParam)
    {
        case IMN_OPENSTATUSWINDOW:
        case IMN_CLOSESTATUSWINDOW:
            break;

        case IMN_SETOPENSTATUS:
            SetStatusItems(hWnd);

            hIMC = ImmGetContext(hWnd);
            fOpen = ImmGetOpenStatus(hIMC);
            UpdateShowOpenStatusButton(fOpen);

            ImmReleaseContext(hWnd,hIMC);
            break;

        case IMN_SETCONVERSIONMODE:
            hIMC = ImmGetContext(hWnd);
            fOpen = ImmGetOpenStatus(hIMC);
            ImmGetConversionStatus(hIMC,&dwConvMode,&dwSentMode);
            if (fOpen)
            {
                SetConvModeParts(dwConvMode);
                UpdateModeButton(dwConvMode);
            }
            else
                ClearConvModeParts();
            ImmReleaseContext(hWnd,hIMC);
            break;

        case IMN_OPENCANDIDATE:
            if (!fShowCand || (lParam != 0x01))
            {
                if (fdwProperty & IME_PROP_SPECIAL_UI)
                {
                    // Normally, we only need to set the composition window
                    // position for a special UI IME
                }
                else if (fdwProperty & IME_PROP_AT_CARET)
                {
                    CANDIDATEFORM cdf;
                    HIMC          hIMC;
 
                    hIMC = ImmGetContext(hWnd);

                    cdf.dwIndex = 0;
                    cdf.dwStyle = CFS_CANDIDATEPOS;
                    cdf.ptCurrentPos.x = ptImeUIPos.x;
                    cdf.ptCurrentPos.y = ptImeUIPos.y;
                    ImmSetCandidateWindow(hIMC,&cdf);

                    ImmReleaseContext(hWnd,hIMC);
                }
                else
                {
                    // Normally, we only need to set the composition window
                    // position for a near caret IME
                }

                return (DefWindowProc(hWnd, message, wParam, lParam));
            }

        case IMN_CHANGECANDIDATE:

#ifdef _DEBUG
{
char szDev[80];
DWORD dwSize;
LPCANDIDATELIST lpC;

hIMC = ImmGetContext(hWnd);
if (dwSize = ImmGetCandidateList(hIMC,0x0,NULL,0))
{
    lpC = (LPCANDIDATELIST)GlobalAlloc(GPTR,dwSize);
   
    ImmGetCandidateList(hIMC,0x0,lpC,dwSize);

    OutputDebugString("DumpCandList!!!\r\n");
    wsprintf((LPSTR)szDev,"dwCount %d\r\n",lpC->dwCount);
    OutputDebugString((LPSTR)szDev);
    wsprintf((LPSTR)szDev,"dwSelection %d\r\n",lpC->dwSelection);
    OutputDebugString((LPSTR)szDev);
    wsprintf((LPSTR)szDev,"dwPageStart %d\r\n",lpC->dwPageStart);
    OutputDebugString((LPSTR)szDev);
    wsprintf((LPSTR)szDev,"dwPageSize %d\r\n",lpC->dwPageSize);
    OutputDebugString((LPSTR)szDev);
    GlobalFree((HANDLE)lpC);
}
}
#endif
            if (fShowCand && (lParam == 0x01))
            {
                DWORD dwSize;

                if (!lpCandList)
                    lpCandList = (LPCANDIDATELIST)GlobalAlloc(GPTR,sizeof(CANDIDATELIST));

                hIMC = ImmGetContext(hWnd);
                if (dwSize = ImmGetCandidateList(hIMC,0x0,NULL,0))
                {
                    GlobalFree((HANDLE)lpCandList);
                    lpCandList = (LPCANDIDATELIST)GlobalAlloc(GPTR,dwSize);
                   
                    ImmGetCandidateList(hIMC,0x0,lpCandList,dwSize);

                }
                else
                {
                    memset(lpCandList, 0, sizeof(CANDIDATELIST));
                }

                InvalidateRect(hWndCandList,NULL,TRUE);
                UpdateWindow(hWndCandList);
                    

                ImmReleaseContext(hWnd,hIMC);
            }
            else
            {
                return (DefWindowProc(hWnd, message, wParam, lParam));
            }
            break;

        case IMN_CLOSECANDIDATE:
            if (fShowCand && (lParam == 0x01))
            {
                if (!lpCandList)
                    lpCandList = (LPCANDIDATELIST)GlobalAlloc(GPTR,sizeof(CANDIDATELIST));

                memset(lpCandList, 0, sizeof(CANDIDATELIST));
                InvalidateRect(hWndCandList,NULL,TRUE);
                UpdateWindow(hWndCandList);
            }
            else
            {
                return (DefWindowProc(hWnd, message, wParam, lParam));
            }
            break;


       default:
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }

    return 0;
}
