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

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#include <SysConfig.hpp>

/* CSysConfigGroup Implementation */

CSysConfigGroup::CSysConfigGroup (const char *szGroupName0)
{
   szGroupName = NULL;
   if (szGroupName0 != NULL)
       szGroupName = strdup (szGroupName0);
   pOurCap = NULL;
   nTotalCap = 0; 
}

CSysConfigGroup::~CSysConfigGroup ()
{
   if (pOurCap == NULL)
       return;
   for (int i = 0; i < nTotalCap; i++) 
   {
       free (pOurCap[i].szName);
       free (pOurCap[i].szValue);
   }
   free (pOurCap);
}

char *CSysConfigGroup::szGetGroupName ()
{
    return szGroupName;
}

bool CSysConfigGroup::SetGroupName (const char *szGroupName0)
{
    if (szGroupName != NULL)
        free (szGroupName);
    szGroupName = strdup (szGroupName0);
    return true;
}

SysConfigCap *CSysConfigGroup::pFindItem (const char *szItemName)
{
   if (pOurCap == NULL)
       return NULL;
   for (int i = 0; i < nTotalCap; i++) 
       if (strcmp (pOurCap[i].szName, szItemName) == 0)
           return &pOurCap[i];
   return NULL;
}

bool CSysConfigGroup::bChangeItem (const char *szItemName, const char *szNewValue)
{
    SysConfigCap *p;
    if ((p = pFindItem (szItemName)) == NULL)
         return bAddItem (szItemName, szNewValue);
    free (p->szValue);
    p->szValue = strdup (szNewValue);
    return true;
}

bool CSysConfigGroup::bAddItem (const char *szItemName, const char *szValue)
{
   if (pOurCap == NULL)
   {
       pOurCap = (SysConfigCap *) malloc (sizeof (SysConfigCap));
       nTotalCap = 1; 
   }
   else
   {
       nTotalCap ++;
       pOurCap = (SysConfigCap *) realloc 
                     (pOurCap, nTotalCap * sizeof (SysConfigCap));
   }
   pOurCap[nTotalCap - 1].szName = strdup (szItemName);
   pOurCap[nTotalCap - 1].szValue = strdup (szValue);
   return true;
}

char *CSysConfigGroup::szGetItemValue (const char *szItemName)
{
    SysConfigCap *p = pFindItem (szItemName);
    if (p == NULL)
        return NULL;
    return p->szValue;
}

ifstream & operator >> (ifstream &a, CSysConfigGroup &b)
{
   char *p, szTemp[128];
   char szItemName[128], szValue[128];
   int i;
   char *buf;
   /* read the name */
   do
   {
       a.gets (&buf);
   }
   while (buf != NULL && buf[0] == '\0');

   if (buf == NULL)
       return a;

   for (p = buf; *p != '['; p++)
       ;
   for (p++, i = 0; *p != ']' && *p; p++, i++)
       szTemp[i] = *p;
   szTemp[i] = '\0';
   b.SetGroupName (szTemp);

   do
   {
       a.gets (&buf);

       if (buf == NULL)
           break;

       if (buf[0] == '\0')
           break; 
       for (i = 0, p = buf; *p != '='; p++, i++)
            szItemName[i] = *p;
       szItemName[i] = '\0';

       for (i = 0, p++; *p != '\0'; p++, i++)
            szValue[i] = *p;
       szValue[i] = '\0';
       b.bAddItem (szItemName, szValue);
   }
   while (! a.eof () && buf[0] != '\0');
   return a;
}

ofstream & operator << (ofstream &a, CSysConfigGroup &b)
{
    
    a << "[" << b.szGroupName << "]" << "\n";
    for (int i = 0; i < b.nTotalCap; i++) 
        a << b.pOurCap[i].szName << "=" << b.pOurCap[i].szValue << "\n";
    a << "\n";
    return a;
}

/* SysConfig Implementation */
CSysConfig::CSysConfig (const char *szFileName0)
{
    ppOurGroup = NULL;
    nTotalGroup = 0;
    if (szFileName0 != NULL)
    {
        szFileName = strdup (szFileName0);
        ifstream mystream (szFileName);

        CSysConfigGroup *pTmpGroup;
        do
        {
            pTmpGroup = new CSysConfigGroup ();
            mystream >> *pTmpGroup;
            if (pTmpGroup->nTotalCap == 0) 
            {
                delete pTmpGroup;
                continue;
            }
            AddGroup (pTmpGroup);
        }
        while (! mystream.eof ());
    }
    else
        szFileName = NULL;    
    modified = 0;
}

CSysConfig::~CSysConfig ()
{
    if (szFileName != NULL)
        free (szFileName);
    if (modified)
        bSave (szFileName);
    for (int i = 0; i < nTotalGroup; i++)
        delete ppOurGroup[i];
}

bool CSysConfig::bSave (const char *szFileName)
{
    ofstream mystream (szFileName);
    for (int i = 0; i < nTotalGroup; i++)
        mystream << *ppOurGroup[i];
    modified = 0;
    return true;
}

CSysConfigGroup *CSysConfig::AddGroup (CSysConfigGroup *p)
{
     if (ppOurGroup == NULL)
     {
         nTotalGroup = 1;
         ppOurGroup = (CSysConfigGroup **) malloc
                      (nTotalGroup * sizeof (CSysConfigGroup *));
     }    
     else
     {
         nTotalGroup ++;
         ppOurGroup = (CSysConfigGroup **) realloc
                 (ppOurGroup, nTotalGroup * sizeof (CSysConfigGroup *));
     }
     ppOurGroup[nTotalGroup - 1] = p;
     return p;
}

CSysConfigGroup *CSysConfig::pFindGroup (const char *szGroup)
{
    CSysConfigGroup *p = NULL;
    for (int i = 0; i < nTotalGroup; i++)
    {
        if (strcmp (ppOurGroup[i]->szGetGroupName(), szGroup) == 0)
        {
             p = ppOurGroup[i];
             break;
        }
    }
    return p;
}

bool CSysConfig::bWriteCapItem (const char *szGroup, 
                       const char *capName, const char *value)
{
    CSysConfigGroup *p = pFindGroup (szGroup);

    if (p == NULL)
        p = pCreateNewGroup (szGroup);

    p->bAddItem (capName, value);
    modified = 1;
    return true;
}

char *CSysConfig::szReadCapItem (const char *szGroup, const char *szCapName)
{
    CSysConfigGroup *p = pFindGroup (szGroup);
    if (p == NULL)
        return NULL;
    return p->szGetItemValue (szCapName);
}

CSysConfigGroup *CSysConfig::pCreateNewGroup (const char *szGroup)
{
    CSysConfigGroup *p = new CSysConfigGroup (szGroup);
    return AddGroup (p);
}

#ifdef __SYSCONFIG_DEBUG__
#include <iostream.h>
int main (int argc, char **argv)
{
    CSysConfig MyConfig ("test.ini");
    cout << MyConfig.szReadCapItem ("test", "me") << "\n";
    MyConfig.bWriteCapItem ("test", "mywife", "jinqing");
    MyConfig.bWriteCapItem ("john", "job", "programmer");
    MyConfig.bSave ("temp.ini");
}
#endif

