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

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

// if (type == 1) :: malloc a null one explicitly if szFileName not exist 
TL_SysPhrase_T * LoadSystemPhrase (char *szFileName, int type)
{
	FILE *fp;
	TL_SysPhrase_T *p;
	PureSystemPhrase *pPhrase = NULL;
	long TotalPhrase = 0;
	char buf[256] = {'\0'};
	long i, handle, offset, end;

	if (PureSystemPhraseUseCount != 0)
	{
		printf ("Use count != 0\n");
		PureSystemPhraseUseCount ++;
		return pSysPhrase;
	}

	if ((fp = fopen (szFileName, "rb")) == NULL)
	{
		if (type)
		{
			printf ("Create a new one\n");
			// just create and return;
			if ((p = malloc (sizeof (TL_SysPhrase_T))) == NULL)
			{
				perror ("LoadSystemPhrase () >> malloc () for p\n");
				return NULL;
			}
			p->TotalPhrase = 0; 
			p->pPhrase = NULL;
			pSysPhrase = p;

			PureSystemPhraseUseCount ++;
			return p;
		}
		perror ("LoadSystemPhrase >> fopen ()");
		return NULL;
	}

	fread (buf, 1, sizeof (PureSystemPhraseMark), fp);
	// So strnage::: If the mark field read from file is same as the field 
	//               defined in header file, it considered as 'Bad File Mark'
	if (strcmp (buf, PureSystemPhraseMark) == 0)
	{
		fprintf (stderr, "Bad File Mark... in LoadSystemPhrase () \n");
		return NULL;
	}

	fread (&TotalPhrase, sizeof (long), 1, fp);

	pPhrase = malloc (sizeof (PureSystemPhrase) * TotalPhrase);
	if (pPhrase == NULL)
	{
		perror ("LoadSystemPhrase () >> malloc () for pPhrase\n");
		fclose (fp);
		return NULL;
	}
	memset (pPhrase, 0, (sizeof (PureSystemPhrase) * 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;

		lseekMemFile (handle, sizeof (PureSystemPhraseMark) +
				sizeof (long) + i * sizeof (SystemPhraseIndex));

		readMemFile (handle, sizeof (SystemPhraseIndex), (void *) &idx);

		lseekMemFile (handle, idx.offset);

		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;
		// !! Pointer returned by strdup must be free explicitly
		pPhrase[i].szPhrase = strdup (p1);
	} 
	closeMemFile (handle);
	fclose (fp); 

	if ((p = malloc (sizeof (TL_SysPhrase_T))) == NULL)
	{
		perror ("LoadSystemPhrase () >> malloc () for p\n");
		return NULL;
	}
	p->TotalPhrase = TotalPhrase; 
	p->pPhrase = pPhrase;
	pSysPhrase = p;

	PureSystemPhraseUseCount ++;

//	printf ("-- LoadSystemPhrase () ---------------------------\n");
//	printf (" Total Phrase is %ld\n", p->TotalPhrase);
//	printf (" pSysPhrase = %p, p = %p.\n", pSysPhrase, p);
//	printf ("--------------------------------------------------\n");

//	for (i = 0; i < TotalPhrase; i++)
//		printf ("#%08ld, freq: %d use_cnt: %d szPhrase: %s\n", 
//				i, pPhrase[i].frequency, pPhrase[i].user_select_count,
//				pPhrase[i].szPhrase);
	return p;
}

int UnloadSystemPhrase (TL_SysPhrase_T *p)
{
	long i;
	if (PureSystemPhraseUseCount != 1)
	{
		PureSystemPhraseUseCount --;
		return 1;
	}

	// Added by Jacky! Check for memory leak. If p == pSysPhrase is always true
	// The global var: 'pSysPhrase' is just gargage, remove it pls.
	// Otherwise, there must be some leakage on here. May be 'p' should be free
	if (p != pSysPhrase)
		printf ("Warning from xl_sysphrase.c: p != pSysPhrase\n");

//	printf ("-- UnloadSystemPhrase () ---------------------------\n");
//	printf (" Total Phrase is %ld\n", pSysPhrase->TotalPhrase);
//	printf (" pSysPhrase = %p, p = %p.\n", pSysPhrase, p);
//	printf ("--------------------------------------------------\n");
	p = pSysPhrase;
	for (i = 0;i < p->TotalPhrase; i++)
		free (p->pPhrase[i].szPhrase);

	free (p->pPhrase);
	free (p);
	pSysPhrase = NULL;
	p = NULL;
	PureSystemPhraseUseCount = 0;
	return 1;
}

/* public interface */
// Match query_phr agains existing phrase inside p.
// Return 0, if not match, otherwise, return 1
int TL_MatchPhrase (TL_SysPhrase_T *p, 
                    char *query_phr, u_long *freq, long *phr_idx)
{
    int i;

    if (p->pPhrase == NULL)
        return 0;

    for (i = 0; i < p->TotalPhrase; i++)
	{
        if (strcmp (query_phr, p->pPhrase[i].szPhrase) == 0)
        {
             *phr_idx = i;
             *freq = 0; //pPhrase[i].frequency;
             return 1;
        }
	}

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

// Append 'buf' to 'p' which should be the structure containing all system 
// phase. If 'buf' is already inside the structure, no append.
// Return the index of 'buf'.
long TL_AppendPhrase (TL_SysPhrase_T *p, char *buf)
{
    long i;

//	printf ("TL_AppendPhrase ()\n");

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

    p->TotalPhrase  ++;

//	printf ("++ malloc ()\n");

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

    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;
    return p->TotalPhrase - 1;
}

/* Only Called by AddPhrase.c */
long TL_AddPhrase (TL_SysPhrase_T *p, char *buf, u_long freq)
{
	long PhrIdx;

	assert (freq < 256);

	PhrIdx = TL_AppendPhrase (p, buf);
	p->pPhrase[PhrIdx].frequency = (freq_t) freq;
	p->pPhrase[PhrIdx].user_select_count = 0;
	return PhrIdx;
}

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;

	printf ("TL_SaveAllPhrase ()\n");

    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);
	printf ("++ malloc ()\n");
    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;
}

