/*
 *
 * UNICON - The Console Chinese & I18N
 * Copyright (c) 1999-2002
 *
 * This file is part of UNICON, a console Chinese & I18N
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * See the file COPYING directory of this archive
 * Author: see CREDITS
 */

#include 	<stdio.h>
#include 	<unistd.h>
#include 	<stdlib.h>
#include 	<stdarg.h>
#include	<string.h>
#include        <ctype.h>
#include        <time.h>
#include        <assert.h>
#include        "xl_hzinput.h"
#include        "xl_sysphrase.h"
#include        "xl_phrase.h"

#define         error       printf

void ResetInput (HzInputTable_T *pClient);
static void GetAssociatePhrases (HzInputTable_T *pClient, unsigned char *p);
static void FindMatchKey (HzInputTable_T *pClient);
static void FillAssociateChars(HzInputTable_T *pClient, int index);
static void FillMatchChars (HzInputTable_T *pClient, int j);

extern int FindAssociateKey (HzInputTable_T *pClient, u_char *pStr);
extern void LoadPhrase (HzInputTable_T *pClient, int phrno, char *tt);
extern long GetAssociatePhraseIndex (HzInputTable_T *pClient,
                                     int index, u_long *nPhrase);
extern int AppendPhrase (HzInputTable_T *p, char *szCode, char *szPhrase);
extern hz_input_table* LoadInputMethod(char *filename);
static void FillAllMatchChars (HzInputTable_T *pClient, int j);

/***************************************************************************
 *                           variable defines                              *
 ***************************************************************************/
/* 6 bit a key mask */
unsigned long mask[]=
{
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
   0x3F000000, 0x3FFC0000, 0x3FFFF000, 0x3FFFFFC0, 0x3FFFFFFF, 0x3FFFFFFF,
   0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF
};

/***************************************************************************
 *                              public function                            *
 ***************************************************************************/

static void GetAssociatePhrases (HzInputTable_T *pClient, unsigned char *p)
{
    int len = strlen(p);

    if (pClient->InputCount <= pClient->InputMatch)  /* All Match */
    {
        // index = (int)p[len-2] * 256 + p[len-1];
        ResetInput (pClient);
        if (pClient->UseAssociateMode)
        {
             FindAssociateKey (pClient, (u_char*) &p[len-2]);
             pClient->CurrentPageIndex = pClient->StartKey;
             pClient->MultiPageMode = 0;
             FillAssociateChars (pClient, pClient->StartKey);
             if (pClient->CurSelNum > 0)
             {
                pClient->IsAssociateMode = 1;
             }
        }
    }
    else
    {
        int nCount = pClient->InputCount - pClient->InputMatch,
            nMatch = pClient->InputMatch, i;
        pClient->MultiPageMode = 
        pClient->NextPageIndex = 
        pClient->CurrentPageIndex = 0;      
        pClient->InputCount = pClient->InputMatch = 0;

        for(i = 0; i < nCount; i++)
            pClient->save_InpKey[i] = pClient->InpKey[nMatch+i];

        bzero(pClient->InpKey, sizeof(pClient->InpKey));
        for(i = 1; i <= nCount; i++)  /* feed the additional keys */
        {
            pClient->InpKey[pClient->InputCount] =
                      pClient->save_InpKey[pClient->InputCount++];
            if (pClient->InputCount <= pClient->InputMatch+1)
            {
                FindMatchKey (pClient);
                pClient->MultiPageMode = 0;
                pClient->CurrentPageIndex = pClient->StartKey;
                FillMatchChars (pClient, pClient->StartKey);
            }
        }
        if (pClient->InputMatch == 0)    /* left key has no match, delete */
        {
            ResetInput (pClient);
            return;
        }
    }
}

void ResetInput (HzInputTable_T *pClient)
{
    bzero (pClient->InpKey, sizeof(pClient->InpKey) );
    bzero (pClient->seltab, sizeof(pClient->seltab) );
    bzero (pClient->seltab_phrase, sizeof(pClient->seltab_phrase) );
    pClient->MultiPageMode = 0,
    pClient->NextPageIndex = 0,
    pClient->CurrentPageIndex = 0;
    pClient->CurSelNum = 0,
    pClient->InputCount = 0,
    pClient->InputMatch = 0;
    pClient->IsAssociateMode = 0;   /* lian xiang */
}

/* After add/delete a char, search the matched char/phrase, update the
   pClient->StartKey/pClient->EndKey key,  save the related keys at first, 
   if no match is found, we may restore its original value
*/
static void FindMatchKey (HzInputTable_T *pClient)
{
    // pClient->bIsFinishSorting = 0;
    pClient->save_StartKey = pClient->StartKey;
    pClient->save_EndKey = pClient->EndKey;
    pClient->save_MultiPageMode = pClient->MultiPageMode;
    pClient->save_NextPageIndex = pClient->NextPageIndex;
    pClient->save_CurrentPageIndex = pClient->CurrentPageIndex;

    pClient->val1 = pClient->InpKey[4] | (pClient->InpKey[3]<<6) | 
                (pClient->InpKey[2]<<12) | (pClient->InpKey[1]<<18) | 
                (pClient->InpKey[0]<<24);
    pClient->val2 = pClient->InpKey[9] | (pClient->InpKey[8]<<6) | 
               (pClient->InpKey[7]<<12) | (pClient->InpKey[6]<<18) | 
               (pClient->InpKey[5]<<24);

    if (pClient->InputCount == 1)
        pClient->StartKey = pClient->cur_table->KeyIndex[pClient->InpKey[0]];
    else
        pClient->StartKey = pClient->CharIndex[pClient->InputCount-1];
    pClient->EndKey = pClient->cur_table->KeyIndex[pClient->InpKey[0]+1];
    for (; pClient->StartKey < pClient->EndKey; pClient->StartKey++)
    {
        pClient->key1 = (pClient->cur_table->item[pClient->StartKey].key1 & 
                         mask[pClient->InputCount+5]);
        pClient->key2 = (pClient->cur_table->item[pClient->StartKey].key2 & 
                         mask[pClient->InputCount]);

        if (pClient->key1 > pClient->val1) break;
        if (pClient->key1 < pClient->val1) continue;
        if (pClient->key2 < pClient->val2) continue;
        break;
    }
    pClient->CharIndex[pClient->InputCount] = pClient->StartKey;
    // Add by Arthur Ma, 04-26-2000
    FillAllMatchChars (pClient, pClient->StartKey);
}

/*  Find the matched chars/phrases and fill it into SelTab
    The starting checked index is j 
 
    The Selection Line 1xxx 2xxx,  80-20=60 60/2=30 chinese chars only
    0-9 Selection can contain only 30 chinese chars

    SelectionXMax-SelectionX-20

#define SelectionXMax  78
#define MAX_SEL_LENGTH (SelectionXMax-SelectionX-18)
*/

static int IsSelectDup (HzInputTable_T *pClient, int CurSelNum, char *szPhrase)
{
    int i;
    if (szPhrase[0] == '\0')
        return 1;
    for (i = 0; i < CurSelNum; i++)
       if (strcmp (pClient->seltab[i], szPhrase) == 0)
           return 1;
    return 0;
}

static void FillAssociateChars(HzInputTable_T *pClient, int index)
{
    unsigned char str[25];
    int CurLen = 0;
   
    pClient->CurSelNum = 0; 
    while (pClient->CurSelNum < pClient->cur_table->MaxDupSel && 
           index < pClient->EndKey)
    {
         u_long nPhrase;
         if (GetAssociatePhraseIndex (pClient, index, &nPhrase) == 0)
             continue;
         LoadPhrase (pClient, nPhrase, str); 
         if (IsSelectDup (pClient, pClient->CurSelNum, str) == 0)
         {
             CurLen += (strlen(str) + 2);
             if (CurLen >= pClient->MAX_SEL_LENGTH - 2)
                 break;
             strcpy(pClient->seltab[pClient->CurSelNum],str);
             pClient->seltab_phrase[pClient->CurSelNum] = nPhrase;
             CurLen += (strlen(pClient->seltab[pClient->CurSelNum++]) + 2);
         }
         index++;
    }

    /* check if more than one page */
    if (index < pClient->EndKey && 
        pClient->CurSelNum == pClient->cur_table->MaxDupSel)
    {
      /* has another matched key, so enter pClient->MultiPageMode, 
         has more pages */
        pClient->NextPageIndex = index;
        pClient->MultiPageMode = 1;
    }
    else if (pClient->MultiPageMode)
        pClient->NextPageIndex = pClient->StartKey; /* rotate selection */
    else 
        pClient->MultiPageMode = 0;
}

static HzInputTable_T *pDefaultClient = NULL;
static int qcmp (void *t1, void *t2)
{
    long c1, c2, k1, k2;
    long *a = (long *) t1,
         *b = (long *) t2;
    int n1, n2, m1, m2;
    static char p1[256], p2[256];
    n1 = pDefaultClient->cur_table->item[*a].nPhrase;
    n2 = pDefaultClient->cur_table->item[*b].nPhrase;

    TL_GetPhrase (pDefaultClient->pSysPhrase, n1, p1);
    TL_GetPhrase (pDefaultClient->pSysPhrase, n2, p2);
    
    m1 = strlen (p1); 
    m2 = strlen (p2); 
    if (m1 > m2)
        return 1;
    else if (m1 < m2)
        return -1;

    TL_GetUserSelectPhraseCount (pDefaultClient->pSysPhrase, n1, &k1);
    TL_GetUserSelectPhraseCount (pDefaultClient->pSysPhrase, n2, &k2);
    if (k1 < k2)
        return 1;
    else if (k1 > k2)
        return -1;
    TL_GetPhraseFreq (pDefaultClient->pSysPhrase, n1, &c1);
    TL_GetPhraseFreq (pDefaultClient->pSysPhrase, n2, &c2);
    if (c1 < c2)
       return 1;
    else if (c1 > c2)
       return -1;
    return 0;
}

static void SortAllOutput (HzInputTable_T *pClient)
{
    pDefaultClient = pClient;
    qsort (pClient->OutputPhrase, pClient->TotalOutputPhrase,  
           sizeof(long), qcmp);
}

static void FillAllMatchChars (HzInputTable_T *pClient, int j)
{
    int i = 0;
    while ((pClient->cur_table->item[j].key1 &
                mask[pClient->InputCount+5]) == pClient->val1 &&
           (pClient->cur_table->item[j].key2 &
                mask[pClient->InputCount]) == pClient->val2 &&
            j < pClient->EndKey)
    {
        pClient->OutputPhrase[i++] = j++;
    }
    pClient->TotalOutputPhrase = i;
    SortAllOutput (pClient);
    pClient->EndKey = i;
    pClient->StartKey = 0;
}

static void ResortCharsAfterSelect (HzInputTable_T *pClient, int nSelNum)
{
/*
    long n = pClient->seltab_phrase[SelNum];
    long t = pClient->OutputPhrase[0];
    u_long count;
    if (TL_GetUserSelectPhraseCount (n, &count) == 0 || count < 3)
        return;
    if (TL_GetUserPhraseFreq (n, &count) == 0)
 */
}
/*
static int GetMatchCharsIndex (HzInputTable_T *pClient, int j)
{
    long n;
    for (n = 0; n < pClient->TotalOutputPhrase; n++)  
    {
        if (pClient->OutputPhrase[n] == j)
            return n;
    }
    assert (0);
    return 0;
}
*/
static void FillMatchChars (HzInputTable_T *pClient, int j)
{
    int SelNum = 0, CurLen = 0;
    int n = j;
    do
    {
        if (n >= pClient->TotalOutputPhrase)
            break;
        j = pClient->OutputPhrase[n];
        if (SelNum < pClient->cur_table->MaxDupSel) 
        {
            LoadPhrase (pClient, 
                    pClient->cur_table->item[j].nPhrase, 
                    pClient->seltab[SelNum]);
           if (IsSelectDup (pClient, SelNum, pClient->seltab[SelNum]) == 0)
           {
                CurLen += (strlen(pClient->seltab[SelNum]) + 2);
                if (CurLen >= pClient->MAX_SEL_LENGTH - 2)
                    break;
                // printf ("phase = %s\n", pClient->seltab[SelNum]);
                pClient->seltab_phrase[SelNum] = 
                    pClient->cur_table->item[j].nPhrase;
                SelNum++;
            }
        }
        else
            break;
        n++;
    }
    while (1);
    // printf ("SelNum = %d, n = %d\n", SelNum, n);
    if (SelNum == 0)  /* some match found */
    {
        pClient->StartKey = pClient->save_StartKey;
        pClient->EndKey = pClient->save_EndKey;
        pClient->MultiPageMode = pClient->save_MultiPageMode;
        pClient->NextPageIndex = pClient->save_NextPageIndex;
        pClient->CurrentPageIndex = pClient->save_CurrentPageIndex;
        return;    /* keep the original selection */
    }

    pClient->CurSelNum = SelNum;

    for(SelNum = pClient->CurSelNum; SelNum < 16; SelNum++)
    {
       pClient->seltab[SelNum][0] = '\0';    /* zero out the unused area */
       pClient->seltab_phrase[SelNum] = -1;  /* zero out the unused area */
    }
    pClient->InputMatch = pClient->InputCount;/* until now, have some matches */

    /* check if more than one page */
    if (n < pClient->TotalOutputPhrase)
    {
        pClient->NextPageIndex = n; //j;
        pClient->MultiPageMode = 1;
    }  
    else if (pClient->MultiPageMode)
    {
        pClient->MultiPageMode = 1;
  //      pClient->NextPageIndex = pClient->StartKey; 
    }
    else pClient->MultiPageMode = 0;
}

void Simulate_putstr (char *p, HzInputTable_T *pClient, int SelNum)
{
    int index,len = strlen(p);

    ResortCharsAfterSelect (pClient, SelNum);
    if (pClient->InputCount <= pClient->InputMatch)  /* All Match */
    {
        index = (int)p[len-2] * 256 + p[len-1];
        ResetInput (pClient);
        if (pClient->UseAssociateMode)
        {
             FindAssociateKey (pClient, &p[len-2]);
             pClient->CurrentPageIndex = pClient->StartKey;
             pClient->MultiPageMode = 0;
             FillAssociateChars (pClient, pClient->StartKey);
             if (pClient->CurSelNum > 0)
             {
                pClient->IsAssociateMode = 1;
             }
        }
    }
    else
    {
      int nCount = pClient->InputCount - pClient->InputMatch,
          nMatch = pClient->InputMatch,i;

      pClient->MultiPageMode = 
      pClient->NextPageIndex = 
      pClient->CurrentPageIndex = 0;      
      pClient->InputCount = pClient->InputMatch = 0;

      for(i = 0; i < nCount; i++)
        pClient->save_InpKey[i] = pClient->InpKey[nMatch+i];

      bzero(pClient->InpKey, sizeof(pClient->InpKey));
      for(i = 1; i <= nCount; i++)  /* feed the additional keys */
      {
         pClient->InpKey[pClient->InputCount] =
                               pClient->save_InpKey[pClient->InputCount++];
         if (pClient->InputCount <= pClient->InputMatch+1)
         {
             FindMatchKey (pClient);
             pClient->MultiPageMode = 0;
             pClient->CurrentPageIndex = pClient->StartKey;
             FillMatchChars (pClient, pClient->StartKey);
         }
      }
      if (pClient->InputMatch == 0)    /* left key has no match, delete */
      {
         ResetInput (pClient);
         return;
      }
    }
}

int TL_KeyFilter (HzInputTable_T *pClient, u_char key, char *buf, int *len)
{
    int inkey = 0,vv;
    char *is_sel_key = (char*)0;
    // long b = 0;

    inkey = pClient->cur_table->KeyMap[key];
    is_sel_key = strchr( pClient->cur_table->selkey, key);
    if (inkey != 0 || is_sel_key != 0)
        goto do_our_filter;
    switch (key)
    {
        case '\010':  /* BackSpace Ctrl+H */
        case '\177':  /* BackSpace */
           if ( pClient->InputCount > 0 )
           {
               pClient->InpKey[--pClient->InputCount]=0;
               if (pClient->InputCount == 0)
               {
                   ResetInput (pClient);
               }
               else if (pClient->InputCount < pClient->InputMatch)
               {
                   FindMatchKey (pClient);
                   pClient->MultiPageMode = 0;
                   pClient->CurrentPageIndex = pClient->StartKey;
                   FillMatchChars (pClient, pClient->StartKey);
               }
               return 1;
           }
           else 
               return 0;
        case '\033':  /* ESCAPE */
  /*    case 0x09:  */  /* tab key */
            if (pClient->InputCount > 0)
            {
                ResetInput (pClient);
                return 1;
            }
            else 
                return 0;
        case '<':
        case '-':
        case ',':
        case '[':
            if (pClient->InputCount == 0)
                return 0;
            if ( pClient->MultiPageMode )
            {
                if (pClient->CurrentPageIndex > pClient->StartKey)
                {
                    pClient->CurrentPageIndex = pClient->CurrentPageIndex - 
                                             pClient->cur_table->MaxDupSel;
                    if (pClient->CurrentPageIndex < pClient->StartKey)
                        pClient->CurrentPageIndex = pClient->StartKey;
                }
                else 
                    pClient->CurrentPageIndex = pClient->StartKey;
                if (pClient->IsAssociateMode)
                    FillAssociateChars (pClient, pClient->CurrentPageIndex);
                else 
                    FillMatchChars (pClient, pClient->CurrentPageIndex);
                return 1;
            }
            else 
                return 1;
            break;
        case '>':
        case ']':
        case '.':
        case '=':
            if (pClient->InputCount == 0)
                return 0;
            if ( pClient->MultiPageMode )
            {
                pClient->CurrentPageIndex = pClient->NextPageIndex;
                if (pClient->IsAssociateMode)
                    FillAssociateChars (pClient, pClient->CurrentPageIndex);
                else 
                    FillMatchChars (pClient, pClient->CurrentPageIndex);
                return 1;
            }
            else 
                return 1;
        case ' ':
            if ( pClient->CurSelNum == 0 )
                return 0;
            if ( pClient->seltab[0][0] )
            {
                strcpy (buf, pClient->seltab[0]);
                *len = strlen (buf);
                AdjustPhraseOrder (pClient, pClient->seltab_phrase[0]);
                Simulate_putstr (buf, pClient, 0);
                return 2;
            }
            return 0;
        default:
            return 0;
    }
    /* switch */
do_our_filter:
    // inkey   = pClient->cur_table->KeyMap[key];
    // is_sel_key = strchr( pClient->cur_table->selkey, key);
    vv = is_sel_key - pClient->cur_table->selkey;
    /* selkey index, strchr may return NULL */
    /* if a key is simultaneously inkey & is_sel_key, 
       then selkey first? */
    if ( (!inkey && !is_sel_key) ||
         (!inkey && is_sel_key && (pClient->CurSelNum == 0 || 
           pClient->seltab[vv][0] == 0)) )
    {
         pClient->IsAssociateMode = 0;
         ResetInput (pClient);
         return 0;
    }
    if (is_sel_key && pClient->CurSelNum > 0 && pClient->seltab[vv][0])
    {
        strcpy (buf, pClient->seltab[vv]);
        *len = strlen (buf);
        AdjustPhraseOrder (pClient, pClient->seltab_phrase[vv]);
        Simulate_putstr (buf, pClient, vv);
        return 2;
    }

    /* now it must be inkey? */
    pClient->IsAssociateMode = 0;
    if ( inkey >= 1 && pClient->InputCount < MAX_INPUT_LENGTH )
        pClient->InpKey[pClient->InputCount++] = inkey;
    if (pClient->InputCount <= pClient->InputMatch+1)
    {
        FindMatchKey (pClient);
        pClient->CurrentPageIndex = pClient->StartKey;
        pClient->MultiPageMode = 0;
        FillMatchChars(pClient, pClient->StartKey);
        if (pClient->InputCount >= pClient->cur_table->MaxPress &&
            pClient->CurSelNum == 1 &&
            pClient->cur_table->last_full)
        {  // left only one selection
            strcpy (buf, pClient->seltab[0]);
            *len = strlen (buf);
            AdjustPhraseOrder (pClient, pClient->seltab_phrase[0]);
            Simulate_putstr (buf, pClient, 0);
            return 2;
        }
        return 1;
    }
    return 1;
}

long TL_KeyPressed (HzInputTable_T *pClient, u_char key)
{
    int inkey = 0,vv;
    char *is_sel_key = (char*)0;
    switch ( key )
    {
        case '\177':  /* BackSpace */
            if (pClient->InputCount > 0 ) 
            {
                pClient->InpKey[--pClient->InputCount]=0;
                if (pClient->InputCount == 0)
                {
                    ResetInput (pClient);
                    return 1;
                }
                else if (pClient->InputCount < pClient->InputMatch)
                {
                    FindMatchKey (pClient);
                    pClient->MultiPageMode = 0;
                    pClient->CurrentPageIndex = pClient->StartKey;
                    FillMatchChars (pClient, pClient->StartKey); 
                }
            }
            else 
                return 0;
            break;
        case '\033':  /* ESCAPE */
            ResetInput (pClient);
            break;
        case '[':
            if (pClient->MultiPageMode)
            {
                if (pClient->CurrentPageIndex > pClient->StartKey) 
                    pClient->CurrentPageIndex = 
                                pClient->CurrentPageIndex - 
                                pClient->cur_table->MaxDupSel;
                else 
                    pClient->CurrentPageIndex = pClient->StartKey;
                if (pClient->IsAssociateMode)
                    FillAssociateChars (pClient, pClient->CurrentPageIndex);
                else 
                    FillMatchChars (pClient, pClient->CurrentPageIndex);
            }
            else
                return 0;
            break;
        case ']':
            if (pClient->MultiPageMode)
            {
                 pClient->CurrentPageIndex = pClient->NextPageIndex;
                 if (pClient->IsAssociateMode)
                     FillAssociateChars (pClient, pClient->CurrentPageIndex);
                 else 
                     FillMatchChars(pClient, pClient->CurrentPageIndex);
            }
            else
                return 0;
            break;
       case ' ':
            ResetInput(pClient);
            return 0;
       default:
            inkey = pClient->cur_table->KeyMap[key];
            is_sel_key = strchr( pClient->cur_table->selkey, key);
            vv = is_sel_key - pClient->cur_table->selkey; 
            /* selkey index, strchr may return NULL */
  
            /* if a key is simultaneously inkey & is_sel_key, 
               then selkey first? */
            if ( (!inkey && !is_sel_key) || 
                 (!inkey && is_sel_key && 
                   (pClient->CurSelNum == 0 || 
                    pClient->seltab[vv][0] == 0)) )
            {
                 pClient->IsAssociateMode = 0;
                 ResetInput(pClient);
                 break;
            }
            if (is_sel_key && pClient->CurSelNum > 0 && 
                pClient->seltab[vv][0])
            {
                 // ResetInput(pClient);
                 break;
            }
            /* now it must be inkey? */
            pClient->IsAssociateMode = 0; 
            if (inkey >= 1 && pClient->InputCount < MAX_INPUT_LENGTH)
                pClient->InpKey[pClient->InputCount++] = inkey;
             
            if (pClient->InputCount <= pClient->InputMatch+1) 
            {
                FindMatchKey (pClient);
                pClient->CurrentPageIndex = pClient->StartKey;
                pClient->MultiPageMode = 0;
                FillMatchChars (pClient, pClient->StartKey);
            }
            else 
                return 0;
            break;
    } /* switch */
    return (long) pClient->CurSelNum;
}

char *szGetSelItem (HzInputTable_T *pClient, int vv)
{
     if (pClient->CurSelNum > 0 && pClient->seltab[vv][0])
          return pClient->seltab[vv];
     return NULL;
}

/*************************************************************************
 *                        public function                                *
 *************************************************************************/
void TL_InputInit (HzInputTable_T *p)
{
    // p->bIsFinishSorting = 0;
    p->TotalOutputPhrase = 0;
    p->IsHanziInput = 0;	// default is ascii input 
    p->IsFullCharBackup = 0;
    p->IsFullCommaInEnglish = 0; 
    p->IsFullChar = 0;
    p->IsFullCommaInChinese = 0;
    p->IsFullComma = 0;
    p->current_method = 0;
    p->cur_table = NULL;
    p->CurSelNum = 0; 
    p->UseAssociateMode = 0;
    p->IsHanziInputBackup = 0;
    p->IsSysMenu = 0;
    p->IsHelpMenu = 0;
    p->MaxSelectLen = 72;
    p->MAX_SEL_LENGTH = p->MaxSelectLen - 16;
    p->InputCount = 0;
}
/*
static void InputCleanup (hz_input_table *p)
{
    UnloadInputMethod (p);
    // UnloadSysPhrase ();
    // UnloadUserPhrase ();
}

static void UnloadInputMethod (hz_input_table *p)
{
    int i;
    if (p == NULL)
        return;
    free (p->item);
    for (i = 0; i < p->TotalAssociatePhrase; i++)
        if (p->pAssociatePhrase[i].pPhrase != NULL)
            free (p->pAssociatePhrase[i].pPhrase);
   free (p);
}
*/
hz_input_table* TL_LoadMethod (char *szName)
{
    hz_input_table *p;
    p = LoadInputMethod (szName);
    return p;
}

void TL_UnloadMethod (hz_input_table *p)
{
    UnloadInputMethod (p);
}

char * TL_DoSelectItem (HzInputTable_T *p, u_long vv, char *s)
{
    if (vv < p->CurSelNum && p->seltab[vv][0])
    {
        strcpy (s, p->seltab[vv]);
        GetAssociatePhrases (p, s);
        // ResetInput (p);
        return s;
    }
    return NULL;
}

int TL_ConfigureInputArea (HzInputTable_T *p, int MaxSelectLen)
{
    p->MaxSelectLen = MaxSelectLen;
    p->MAX_SEL_LENGTH = p->MaxSelectLen - 8;
    return 1;
}

int TL_GetInputDisplay (HzInputTable_T * p, char *buf)
{
    int i, len = 9;
    char c;
    char *q = buf;

    if (p->InputCount == 0)
        return 0; 
    for( i = 0; i <= len ; i++)
    {
        if (i < p->InputCount)
            c = p->cur_table->KeyName[p->InpKey[i]];
        else c= ' ';
        if (i == p->InputMatch &&
            p->InputCount > p->InputMatch && i != 0)
                *q++ = '-';
        *q++ = c;
    }
    *q = '\0';
    return 1;
}

int TL_GetSelectDisplay (HzInputTable_T * p, char *buf)
{
    int i, len;  
    char buf1[256];
    
    buf[0] = '\0';
    if (p->CurSelNum == 0)
         return 0;
    /* not first page */
    if (p->MultiPageMode && p->CurrentPageIndex != p->StartKey)
        strcat (buf, "< ");
    for (i = 0; i < p->CurSelNum; i++)
    {
        if (i != 9)
            sprintf (buf1, "%d%s ", i + 1, p->seltab[i]);
        else
            sprintf (buf1, "0%s ", p->seltab[i]);
        len = strlen(buf1);
        strcat (buf, buf1);
    }
    /* not last page */
    if (p->MultiPageMode && p->NextPageIndex != p->StartKey)
        strcat (buf, "> ");
    return i;
}
