
/*
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <xl_hzinput.h>
#include <xl_sysphrase.h>
#include <xl_mfile.h>

#define INCREM 8196
unsigned int phrase_size = 0;

#define MAX_HASH 64
int head[MAX_HASH];

/* simple hash function */
unsigned int hash_val (const unsigned char *str)
{
	register unsigned int val = 0;
	for (; *str; )
		val += *str++;

	return (val % MAX_HASH);
}

/* Low IO interface for TL */
/*****************************************************************************
 *                   System Phrase File Format
 *  symbol        len                      meaning
 *  Mark          "TL Phrase Mark" 
 *  TotalPhrase   long
 *  index area    long offset, 
 *                u_char len
 *  data  area  
 *
 ****************************************************************************/
static char *PureSystemPhraseMark = "TL Phrase Mark";
// static PureSystemPhrase *pPhrase = NULL;
// static long PureSystemPhraseUseCount = 0;
static TL_SysPhrase_T *pSysPhrase = NULL;
static long PureSystemPhraseUseCount = 0;

TL_SysPhrase_T * LoadSystemPhrase (char *szFileName, int type)
{
    FILE *fp;
    TL_SysPhrase_T *p;
    PureSystemPhrase *pPhrase = NULL;
    long TotalPhrase = 0;
    char buf[256];
    long i, handle, offset, end;

   if (PureSystemPhraseUseCount != 0)
    {
        PureSystemPhraseUseCount ++;
        return pSysPhrase;
    }

   /* Initialize hash table */
    for (i = 0; i < MAX_HASH; ++i)
		head[i] = -1; 

    if ((fp = fopen (szFileName, "rb")) == NULL)
    {
        // printf ("Can't open %s \n", szFileName);
        goto end_process;
    }
    fread (buf, 1, sizeof (PureSystemPhraseMark), fp);
    if (strcmp (buf, PureSystemPhraseMark) == 0)
    {
        printf ("Bad File Mark... in LoadSystemPhrase () \n");
        exit (1);
    }
    fread (&TotalPhrase, sizeof (long), 1, fp);
    pPhrase = malloc (sizeof (PureSystemPhrase) * TotalPhrase);
    if (pPhrase == NULL)
    {
        printf ("No enough memory to run in LoadSystemPhrase () \n");
        fclose (fp);
        exit (1);
    }
    memset (pPhrase, 0, (sizeof (PureSystemPhrase) * TotalPhrase));
	phrase_size = TotalPhrase;

    offset = ftell (fp);
    fseek (fp, 0L, SEEK_END);
    end = ftell (fp);
    handle = openMemFile (fp, offset, end - offset);

    for (i = 0;i < TotalPhrase; i++)
    {
        freq_t *freq;
        count_t *count;
        char *p1;
        SystemPhraseIndex idx;
		unsigned int hval;

        // fseek (fp, sizeof (PureSystemPhraseMark) + sizeof (long) +
        //           i * sizeof (SystemPhraseIndex),
        //           SEEK_SET);
        lseekMemFile (handle, sizeof (PureSystemPhraseMark) + 
                              sizeof (long) + i * sizeof (SystemPhraseIndex));

        // fread (&idx, sizeof (SystemPhraseIndex), 1, fp);
        readMemFile (handle, sizeof (SystemPhraseIndex), (void *) &idx);

        // fseek (fp, idx.offset, SEEK_SET);
        lseekMemFile (handle, idx.offset);

        // fread (buf, 1, idx.len, fp);
        readMemFile (handle, idx.len, buf);

        p1 = buf;
        freq = (freq_t *) p1;
        p1 += sizeof (freq_t);
        count = p1;
        p1 += sizeof (count_t); 
        pPhrase[i].frequency = *freq;
        pPhrase[i].user_select_count = *count;
        pPhrase[i].szPhrase = strdup (p1);
		/* hash */
		hval = hash_val (pPhrase[i].szPhrase);
		pPhrase[i].next = head[hval];
		head[hval] = i;
    } 
    closeMemFile (handle);
    fclose (fp); 
end_process:
    if ((p = malloc (sizeof (TL_SysPhrase_T))) == NULL)
    {
        printf ("No enough memory to run in LoadSystemPhrase () \n");
        exit (1);
    }
    p->TotalPhrase = TotalPhrase; 
    p->pPhrase = pPhrase;
    pSysPhrase = p;
    PureSystemPhraseUseCount ++;
    return p;
}

int UnloadSystePhrase (TL_SysPhrase_T *p)
{
    long i;
    if (PureSystemPhraseUseCount != 1)
    {
        PureSystemPhraseUseCount --;
        return 1;
    }
    p = pSysPhrase;
    for (i = 0;i < p->TotalPhrase; i++)
    {
        free (p->pPhrase[i].szPhrase);
    }
    free (p->pPhrase);
    free (p);
    pSysPhrase = NULL;
    PureSystemPhraseUseCount = 0;
    return 1;
}

/* public interface */
int TL_MatchPhrase (TL_SysPhrase_T *p, 
                    char *szPhraseg, u_long *freq, long *nPhrase)
{
    int i;
	unsigned int hval;
    if (p->pPhrase == NULL)
        return 0;

	hval = hash_val (szPhraseg);
	i = head[hval];

	while (i >= 0) {
        if (strcmp (szPhraseg, p->pPhrase[i].szPhrase) == 0)
        {
             *nPhrase = i;
             *freq = 0; //pPhrase[i].frequency;
             return 1;
        }

		i = p->pPhrase[i].next;
	}
    return 0;

}

int TL_GetPhraseFreq (TL_SysPhrase_T *p, long nPhrase, u_long *freq)
{
    int i = nPhrase;
    assert (nPhrase < p->TotalPhrase);
    *freq = (u_long) p->pPhrase[i].frequency;
    return 1;
}

int TL_GetUserSelectPhraseCount (TL_SysPhrase_T *p, long nPhrase, u_long *count)
{
    int i = nPhrase;
    assert (nPhrase < p->TotalPhrase);
    *count = (u_long) p->pPhrase[i].user_select_count;
    return 1;
}

int TL_AdjustPhraseOrder (TL_SysPhrase_T *p, long nPhrase)
{
    int i = nPhrase;
    assert (nPhrase < p->TotalPhrase);
    if (i > p->TotalPhrase || i < 0)
    {
        printf ("warning::i > TotalPhrase || i < 0\n");
        printf ("i = %d, TotalPhrase = %ld\n", i, p->TotalPhrase);
        return 0;
    }
/*
    if (pPhrase[i].frequency < USER_PHRASE_FREQUENCY_MAX)
        pPhrase[i].frequency ++;
 */
    if (p->pPhrase[i].user_select_count < USER_SELECT_COUNT_MAX)
        p->pPhrase[i].user_select_count++;
/*
    printf ("TL_GetPhrase::%s:%d\n", 
        pPhrase[i].szPhrase,
        pPhrase[i].frequ
 */
    return 1;
}

#include <assert.h>
int TL_GetPhrase (TL_SysPhrase_T *p, u_long nPhrase, char *buf)
{
    assert (nPhrase < p->TotalPhrase);
    strcpy (buf, p->pPhrase[nPhrase].szPhrase);
    return 1;
}

long TL_AppendPhrase (TL_SysPhrase_T *p, char *buf)
{
    int i;
	unsigned int hval;

	hval = hash_val (buf);
	i = head[hval];

	while (i >= 0) {
        if (strcmp (p->pPhrase[i].szPhrase, buf) == 0)
        {
            p->pPhrase[i].frequency ++;
            return i;
        }

		i = p->pPhrase[i].next;
	}

    p->TotalPhrase++;
	if (p->TotalPhrase > phrase_size) {
		phrase_size += INCREM;
		if (p->pPhrase == NULL)
		{
			p->pPhrase = (PureSystemPhrase *)
							   malloc (sizeof (PureSystemPhrase) * phrase_size);
		}
		else
		{
			p->pPhrase = (PureSystemPhrase *)
					realloc (p->pPhrase,
							 sizeof (PureSystemPhrase) * phrase_size);
		}

		if (!p->pPhrase)
		{
			printf ("No enough memory!\n");
			exit (1);
		}
	}
    p->pPhrase[p->TotalPhrase-1].szPhrase = strdup (buf);
    p->pPhrase[p->TotalPhrase-1].frequency = DEFAULT_FREQ;
    p->pPhrase[p->TotalPhrase-1].user_select_count 
                          = USER_PHRASE_DEFAULT_COUNT;
	p->pPhrase[p->TotalPhrase-1].next = head[hval];
	head[hval] = p->TotalPhrase-1;

    return p->TotalPhrase - 1;
}

/* Only Called by AddPhrase.c */
long TL_AddPhrase (TL_SysPhrase_T *p, char *buf, u_long freq)
{
    long n = TL_AppendPhrase (p, buf);
    assert (freq < 256);
    p->pPhrase[n].frequency = (freq_t) freq;
    p->pPhrase[n].user_select_count = 0;
    return n;
}

int TL_DeletePhrase (TL_SysPhrase_T *p, char *buf)
{
    return 1;
}

int TL_SaveAllPhrase (TL_SysPhrase_T *p, char *szFileName)
{
    FILE *fp;
    PureSystemPhrase *pPhrase = pPhrase;
    SystemPhraseIndex *idx;
    long t, i;

    if ((fp = fopen (szFileName, "wb")) == NULL)
    {
        printf ("Can't open %s \n", szFileName);
        return 0;
    }
    fwrite (PureSystemPhraseMark, 1, sizeof (PureSystemPhraseMark), fp);
    fwrite (&p->TotalPhrase, sizeof (long), 1, fp);
    idx = (SystemPhraseIndex *) malloc 
                   (p->TotalPhrase * sizeof (SystemPhraseIndex));
    memset (idx, 0, p->TotalPhrase * sizeof (SystemPhraseIndex));
    for (t = 0, i = 0; i < p->TotalPhrase; i++)
    {
        idx[i].offset = sizeof (PureSystemPhraseMark) + sizeof (long) +
                        p->TotalPhrase * sizeof (SystemPhraseIndex) + t;
        idx[i].len = strlen (p->pPhrase[i].szPhrase) + 1 + 
                        sizeof (freq_t) + sizeof (count_t);
        t += idx[i].len;
    }
    for (i = 0;i < p->TotalPhrase; i++)
        fwrite (&idx[i], sizeof (SystemPhraseIndex), 1, fp);
    for (i = 0;i < p->TotalPhrase; i++)
    {
        fwrite (&p->pPhrase[i].frequency, sizeof (freq_t), 1, fp);
        fwrite (&p->pPhrase[i].user_select_count, sizeof (count_t), 1, fp);
        fwrite (p->pPhrase[i].szPhrase, 1, 
                idx[i].len - sizeof (freq_t) - sizeof (count_t), fp);
    }
    fclose (fp);
    return 1;
}

int TL_DumpAllPhrase (TL_SysPhrase_T *p, char *szFileName)
{
    FILE *fp;
    long i;

    if ((fp = fopen (szFileName, "wt")) == NULL)
    {
        printf ("Can't open %s \n", szFileName);
        return 0;
    }
    fprintf (fp, "No     Phrase    Freq  SelectCount\n");
    for (i = 0; i < p->TotalPhrase; i++)
    {
        fprintf (fp, "%ld, %s  %ld  %ld\n", 
             (i+1),   p->pPhrase[i].szPhrase,
             (u_long) p->pPhrase[i].frequency,
             (u_long) p->pPhrase[i].user_select_count);
    }
    fclose (fp);
    return 1;
}

