/*
 *
 * UNICON - The Console Chinese & I18N
 * Copyright (c) 1999-2000
 *
 * 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
 */

/* 
      Phrase Manager
 */

/* 
                System Phrase Format 

      ID                      length              explain
      "TL_PhraseManager"      sizeof(ID)
      type                    long
      Total Phrase            long
      Phrase Index            long + u_short
          long offset
          u_short len
      Phrase                  char + szPhrase
          u_short count,
          char *szPhrase;
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <TLS_MemBlock.hpp>

#define  TL_PHRASEFILE_MARK   "TL_PhraseManager" 
#define  DEFAULT_COUNT        32
#define  DEFAULT_INC          32

struct ServerPhraseItem
{
    u_short count;   
    char *szPhrase;
};

void PhraseCountInc (char *szPhrase)
{
    if (szPhrase == NULL)
        return;
    ServerPhraseItem *p = (ServerPhraseItem *) (szPhrase - sizeof (u_short));
    if (p->count < USHRT_MAX)
        p->count ++;
    printf ("%s::%d\n", szPhrase, p->count);
}   

void PhraseCountDec (char *szPhrase)
{
    if (szPhrase == NULL)
        return;
    ServerPhraseItem *p = (ServerPhraseItem *) (szPhrase - sizeof (u_short));
    if (p->count != 0)
        p->count --;
    printf ("%s::%d\n", szPhrase, p->count);
}

class TLS_CPhraseManager
{
private:
    char *szFileName;
    CMemBlock *pMemBlock;
    ServerPhraseItem *pServerPhraseItem;
    long TotalPhrase;
    long MaxTotalPhrase;
    long type;
private:
    char *szSearchPhrase (char *szPhrase);
    bool LoadPhraseFile (char *szFileName);
public:
    TLS_CPhraseManager (char *szFileName = NULL, long type = 0);
    ~TLS_CPhraseManager ();
    bool SavePhraseFile (char *szFileName);

    /* Public Interface for Phrase Operation */
    char *szGetMatchPhrase (char *szPhrase);

    /* Phrase Operations */
    char *szAddPhrase (char *szPhrase);
    bool DelPhrase (char *szPhrase);
    bool ModifyPhrase (char *szPhrase, u_short newcount);
};

TLS_CPhraseManager::TLS_CPhraseManager (char *szFileName0, long type)
{
    szFileName = NULL;
    MaxTotalPhrase = TotalPhrase = 0;
    pMemBlock = new CMemBlock ();
    pServerPhraseItem = NULL;
    if (szFileName0 != NULL)
    {
        szFileName = strdup (szFileName0);
        LoadPhraseFile (szFileName);
        MaxTotalPhrase = TotalPhrase;
    }
}

TLS_CPhraseManager::~TLS_CPhraseManager ()
{
    if (szFileName != NULL)
    {
        SavePhraseFile (szFileName);
        free (szFileName);
    }
    if (pServerPhraseItem != NULL)
        delete pServerPhraseItem;
    delete pMemBlock;
}

bool TLS_CPhraseManager::LoadPhraseFile (char *szFileName)
{
    u_short len;
    char buf[512];
    FILE *fp;
    printf ("loading %s\n", szFileName);
    if ((fp = fopen (szFileName, "rb")) == NULL)
    {
         printf ("Can't open %s \n", szFileName);
         exit (-1);
    } 

    /* Verify the head mark */
    int n = fread (buf, 1, sizeof (TL_PHRASEFILE_MARK), fp);
    if (n != sizeof (TL_PHRASEFILE_MARK) ||
        memcmp (buf, TL_PHRASEFILE_MARK, n) != 0)
        return false;

    fread (&type, sizeof (long), 1, fp);
    fread (&TotalPhrase, sizeof (long), 1, fp);
    pServerPhraseItem = (ServerPhraseItem *) malloc 
                             (sizeof (ServerPhraseItem) * TotalPhrase);
    if (pServerPhraseItem == NULL)
    {
        printf ("no enough memory to run ......\n");
        exit (-1);
    }
    for (long i = 0; i < TotalPhrase; i++)
    {
         fread (&pServerPhraseItem[i].count, sizeof (u_short), 1, fp);
         fread (&len, sizeof (u_short), 1, fp);
         fread (buf, 1, len, fp);
         pServerPhraseItem[i].szPhrase = 
                         pMemBlock->MemDup (buf, strlen(buf) + 1);
#ifdef __PHRASE_MANAGER_DEBUG__
         printf ("len = %d, %s \n", len, buf);
#endif
    }
    return true;
}

bool TLS_CPhraseManager::SavePhraseFile (char *szFileName)
{
    FILE *fp;
    printf ("saving %s\n", szFileName);
    if ((fp = fopen (szFileName, "wb")) == NULL)
    {
         printf ("Can't open %s \n", szFileName);
         exit (-1);
    }

    /* Verify the head mark */
    long n = fwrite (TL_PHRASEFILE_MARK, 1, sizeof (TL_PHRASEFILE_MARK), fp);

    fwrite (&type, sizeof (long), 1, fp);

    long actual_total = 0, oldoffset = ftell (fp);

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

    for (long i = 0; i < TotalPhrase; i++)
    {
         u_short len;
         char buf[512];
         if (pServerPhraseItem[i].szPhrase[0] == '\0')
             continue;
         fwrite (&pServerPhraseItem[i].count, sizeof (u_short), 1, fp);
         len = strlen (pServerPhraseItem[i].szPhrase) + 1;
         fwrite (&len, sizeof (u_short), 1, fp);
         fwrite (pServerPhraseItem[i].szPhrase, 1, len, fp);
#ifdef __PHRASE_MANAGER_DEBUG__
         printf ("len = %d, %s \n", len, pServerPhraseItem[i].szPhrase);
#endif
         actual_total ++;
    }
    fseek (fp, oldoffset, SEEK_SET);
    fwrite (&actual_total, sizeof (long), 1, fp);
    return true;
}

char *TLS_CPhraseManager::szSearchPhrase (char *szPhrase)
{
    for (long i = 0; i < TotalPhrase; i++)
        if (strcmp (pServerPhraseItem[i].szPhrase, szPhrase) == 0)
             return pServerPhraseItem[i].szPhrase;
        return NULL;
}
 
char *TLS_CPhraseManager::szAddPhrase (char *szPhrase)
{
    char *s = szSearchPhrase (szPhrase);
    if (s != NULL)
        return s;
    if (pServerPhraseItem == NULL || TotalPhrase >= MaxTotalPhrase)
    {
        MaxTotalPhrase += DEFAULT_INC;
        pServerPhraseItem = (ServerPhraseItem *) realloc (
                         (void *) pServerPhraseItem, 
                         MaxTotalPhrase * sizeof (ServerPhraseItem));
        if (pServerPhraseItem == NULL)
        {
            printf ("No enough memory to run ......\n");
            exit (0);
        }
    }
    long i = TotalPhrase++;
    pServerPhraseItem[i].count = DEFAULT_COUNT;
    pServerPhraseItem[i].szPhrase = 
                 pMemBlock->MemDup (szPhrase, strlen (szPhrase) + 1);
    return pServerPhraseItem[i].szPhrase;
}

/* Public Interface for Phrase Operation */
char *TLS_CPhraseManager::szGetMatchPhrase (char *szPhrase)
{
    char *s = szSearchPhrase (szPhrase);
    if (s != NULL)
        return s;
    return szAddPhrase (szPhrase);
}

bool TLS_CPhraseManager::DelPhrase (char *szPhrase)
{
    char *s = szSearchPhrase (szPhrase);
    if (s == NULL)
        return false;
    ServerPhraseItem *p = (ServerPhraseItem *) (s - sizeof (u_short));
    memset (p, 0, sizeof (szPhrase) + sizeof (u_short));
    return true;
}

bool TLS_CPhraseManager::ModifyPhrase (char *szPhrase, u_short newcount)
{
    char *s = szSearchPhrase (szPhrase);
    if (s == NULL)
        return false;
    ServerPhraseItem *p = (ServerPhraseItem *) (s - sizeof (u_short));
    p->count = newcount;
    return true;
}

#ifdef __PHRASE_MANAGER_DEBUG__
int main (int argc, char **argv)
{
    TLS_CPhraseManager *me;
    if (argc < 3)
    {
         printf ("%s <file> <phrase>\n", argv[0]);
         exit (0);
    }
    const char *optstr = "c:a:f:d:m:";
    char opt_char;
    extern char *optarg;
    char *szFileName;
    while ((opt_char = getopt (argc, argv, optstr)) != -1)
    { 
        switch (opt_char)
        {
             case 'c':
             {
                 me = new TLS_CPhraseManager ();
                 szFileName = optarg;
                 me->SavePhraseFile (szFileName);
                 exit (0);
             }      
             case 'f':
                 szFileName = optarg;
                 me = new TLS_CPhraseManager (szFileName);
                 break;
             case 'a':
                 me->szAddPhrase (optarg);
                 break;
             case 'd':
                 me->DelPhrase (optarg);
                 break;
             case 'm':
                 PhraseCountInc (optarg);
                 break;
        }
    }
    delete me;
}
#endif

