/*
 *
 * 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>
#define         error       printf

static void UnloadInputMethod (hz_input_table *p);
static void ResetInput (HzInputTable_T *pClient);
static void FindAssociateKey (HzInputTable_T *pClient, int index);
static hz_input_table* LoadInputMethod(char *filename);
static void GetAssociatePhrases (HzInputTable_T *pClient, unsigned char *p);
static void LoadPhrase (HzInputTable_T *pClient, int phrno, char *tt);
static void FindMatchKey (HzInputTable_T *pClient);
static void FillAssociateChars(HzInputTable_T *pClient, int index);
static void FillMatchChars (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 hz_input_table* LoadInputMethod(char *filename)
{
  int  nread;
  FILE *fd;
  char phrase_filename[100],assoc_filename[100];
  hz_input_table *table;
  
  table = malloc (sizeof (hz_input_table));
  if (table == NULL)
    error("Out of memory in LoadInputMethod");

  fd = fopen (filename, "r");
  if (fd == NULL)
  {
    error ("Cannot open input method %s", filename); 
    free (table);
    return NULL;
  }

  nread = fread (table, sizeof (hz_input_table),1,fd);
  if (nread != 1)
  {
    error ("Cannot read file header %s", filename);
    free (table);
	fclose (fd);
    return NULL;
  }

  if (strcmp (MAGIC_NUMBER, table->magic_number))
  {
	printf ("Invalid TAB file\n\n");
	free (table);
	fclose (fd);
	return NULL;
  }

  table -> item = (ITEM *) malloc (sizeof(ITEM ) * table->TotalChar); 
  if ( table->item == NULL ) 
  {
        error("Gosh, cannot malloc enough memory");
		free (table);
		fclose (fd);
        return NULL;
  }

  fread (table->item, sizeof (ITEM) , table->TotalChar,fd);
  fclose (fd);
 
  if (table->PhraseNum > 0)
  {
     strcpy (phrase_filename, filename);
     strcat (phrase_filename, ".phr");
     strcpy (assoc_filename, filename);
     strcat (assoc_filename, ".lx");
     
     table -> PhraseFile = fopen (phrase_filename, "r");
     table -> AssocFile = fopen (assoc_filename, "r");

     if (table -> PhraseFile == NULL || table -> AssocFile == NULL) 
     {
          printf ("Load Phrase/Assoc File error!\n");
		  free (table->item);
          free (table);
          return NULL;
     }
  }
  else
  {
      table->PhraseFile = table->AssocFile = NULL;
  }

  return table;
}

static void GetAssociatePhrases (HzInputTable_T *pClient, unsigned char *p)
{
    int index,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, index);
             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;
        }
    }
}

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

static void FindAssociateKey(HzInputTable_T *pClient, int index)
{
    FILE *fp = pClient->cur_table->AssocFile;
    int ofs[2],offset;
   
    if (index < 0xB0A1) 
    {
       pClient->StartKey = pClient->EndKey = 0;
       return;  /* no match */
    }  
   
    offset = (index / 256 - 0xB0) * 94 + index % 256 - 0xA1; 
    fseek(fp, offset * sizeof(int), SEEK_SET);
    fread(ofs,sizeof(int),2,fp);
    pClient->StartKey = 72 * 94 + 1 + ofs[0];
    pClient->EndKey = 72 * 94 + 1 + ofs[1];
}

/* phrno: Phrase Number, return in tt */
static void LoadPhrase (HzInputTable_T *pClient, int phrno, char *tt )
{
    FILE *fp = pClient->cur_table->PhraseFile;
    int ofs[2], len;

    fseek( fp, ( phrno + 1 ) * 4, SEEK_SET );
    fread( ofs, 4, 2, fp );
    len = ofs[1] - ofs[0];

    if ( len > 128 || len <= 0 ) {
        error( "phrase error %d\n" , len );
        strcpy( tt, "error" );
        return;
    }

    ofs[0] += ( pClient->cur_table->PhraseNum + 1 ) * 4;
    /* Add the index area length */
    fseek( fp, ofs[0], SEEK_SET );
    fread( tt, 1, len, fp );
    tt[len] = 0;
}

/* 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->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;
}

/*  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 void FillAssociateChars(HzInputTable_T *pClient, int index)
{
    unsigned char str[25];
    int PhraseNo, CurLen = 0;
   
    pClient->CurSelNum = 0; 
    while (pClient->CurSelNum < pClient->cur_table->MaxDupSel && 
           index < pClient->EndKey && CurLen < pClient->MAX_SEL_LENGTH)
    {
         fseek( pClient->cur_table->AssocFile, index << 2, SEEK_SET );
         fread( &PhraseNo, sizeof(int), 1, pClient->cur_table->AssocFile );
         LoadPhrase(pClient,  PhraseNo, str );
         strcpy(pClient->seltab[pClient->CurSelNum],str+2);
         CurLen += strlen(pClient->seltab[pClient->CurSelNum++]);
         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 void FillMatchChars (HzInputTable_T *pClient, int j)
{
    int SelNum = 0, CurLen = 0;
    //bzero( pClient->seltab, sizeof( pClient->seltab ) );

    while ((pClient->cur_table->item[j].key1 & 
                mask[pClient->InputCount+5]) 
            == pClient->val1 &&
           (pClient->cur_table->item[j].key2 & 
                mask[pClient->InputCount]) 
            == pClient->val2 &&
            SelNum < pClient->cur_table->MaxDupSel && 
            j < pClient->EndKey && 
            CurLen < pClient->MAX_SEL_LENGTH)
    {
          if (pClient->cur_table->item[j].ch < 0xA1A1)
              LoadPhrase (pClient, pClient->cur_table->item[j].ch, 
                          pClient->seltab[SelNum]);
          else
          {
              memcpy (&pClient->seltab[SelNum], 
                      &(pClient->cur_table->item[j].ch), 2);
              pClient->seltab[SelNum][2] = '\0';
          }
          CurLen += strlen(pClient->seltab[SelNum++]);
          j++;
    }
    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->InputMatch = pClient->InputCount; /* until now we have some matches */

    /* check if more than one page */
    if (j < pClient->EndKey && 
        (pClient->cur_table->item[j].key1 & 
         mask[pClient->InputCount+5]) == pClient->val1 &&
        (pClient->cur_table->item[j].key2 & 
         mask[pClient->InputCount] ) == pClient->val2 &&
        pClient->CurSelNum == pClient->cur_table->MaxDupSel)
    {
        /* has another matched key, so enter pClient->MultiPageMode, 
           has more pages */
        pClient->NextPageIndex = j;
        pClient->MultiPageMode = 1;
    }  
    else if (pClient->MultiPageMode)
    {
        pClient->NextPageIndex = pClient->StartKey; /* rotate selection */
    }
    else pClient->MultiPageMode = 0;
}

void Simulate_putstr (char *p, HzInputTable_T *pClient)
{
    int index,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, index);
             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 CCE_KeyFilter (HzInputTable_T *pClient, u_char key, char *buf, int *len)
{
    int inkey = 0,vv;
    char *is_sel_key = (char*)0;
    // long b = 0;
    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;
            break;
        case '\033':  /* ESCAPE */
  /*    case 0x09:  */  /* tab key */
            if (pClient->InputCount > 0)
                ResetInput (pClient);
            else 
                return 0;
            break;
        case '<':
        case '-':
        case ',':
        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);
                return 1;
            }
            else 
                return 1;
            break;
        case '>':
        case ']':
        case '.':
        case '=':
            if ( pClient->MultiPageMode )
            {
                pClient->CurrentPageIndex = pClient->NextPageIndex;
                if (pClient->IsAssociateMode)
                    FillAssociateChars (pClient, pClient->CurrentPageIndex);
                else 
                    FillMatchChars (pClient, pClient->CurrentPageIndex);
                return 1;
            }
            else 
                return 1;
            break;
        case ' ':
            if ( pClient->CurSelNum == 0 )
                return 0;
            if ( pClient->seltab[0][0] )
            {
                strcpy (buf, pClient->seltab[0]);
                *len = strlen (buf);
                Simulate_putstr (buf, pClient);
                return 2;
            }
            break;
        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);
                 return 0;
            }
            if (is_sel_key && pClient->CurSelNum > 0 && pClient->seltab[vv][0])
            {
                strcpy (buf, pClient->seltab[vv]);
                *len = strlen (buf);
                Simulate_putstr (buf, pClient);
                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);
                    Simulate_putstr (buf, pClient);
                    return 2;
                }
                // printf ("key::%c::0x%x\n", key, key);
                return 1;
            }
            return 1;
     } /* switch */
     return 0;
}

long CCE_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 CCE_InputInit (HzInputTable_T *p)
{
    memset (p, 0, sizeof (HzInputTable_T));
    p->MaxSelectLen = 72;
    p->MAX_SEL_LENGTH = p->MaxSelectLen - 8;
}

static void InputCleanup (hz_input_table *p)
{
    UnloadInputMethod (p);
    // UnloadSysPhrase ();
    // UnloadUserPhrase ();
}

static void UnloadInputMethod (hz_input_table *p)
{
    if (p == NULL)
        return;
   if (p->PhraseFile)
       fclose (p->PhraseFile);
   if (p->AssocFile)
       fclose (p->AssocFile);
   free (p->item);
   free (p);
}

hz_input_table* CCE_LoadMethod (char *szName)
{
    hz_input_table *p;
    p = LoadInputMethod (szName);
    if (p == NULL)
        return NULL;
    return p;
}

void CCE_UnloadMethod (hz_input_table *p)
{
    InputCleanup (p);
}

char * CCE_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 CCE_ConfigureInputArea (HzInputTable_T *p, int MaxSelectLen)
{
    p->MaxSelectLen = MaxSelectLen;
    p->MAX_SEL_LENGTH = p->MaxSelectLen - 8;
    return 1;
}

int CCE_GetInputDisplay (HzInputTable_T * p, char *buf)
{
    int i, len = p->InputCount;
    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 CCE_GetSelectDisplay (HzInputTable_T * p, char *buf)
{
    int i, pos = 0, 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 (!p->seltab[i][0])
        {
            if (i == 0)
                continue;
            else
                break;
        }
        if (i != 9)
            sprintf (buf1, "%d%s ", i + 1, p->seltab[i]);
        else
            sprintf (buf1, "0%s ", p->seltab[i]);
        len = strlen(buf1);
        if (pos+len+1 >= p->MaxSelectLen) 
            break;
        strcat (buf, buf1);
        pos += len + 1;
    }
    /* not last page */
    if (p->MultiPageMode && p->NextPageIndex != p->StartKey)
        strcat (buf, "> ");
    return i;
}
