// ZenLib::ZtringListListF - ZtringListList with file load/save
// Copyright (C) 2002-2005 Jerome Martinez, Zen@MediaArea.net
//
// This software is provided 'as-is', without any express or implied
// warranty.  In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// ZtringListList with file load/save
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
#ifdef __BORLANDC__
    #include <sstream> //Needed for wx
#endif
#ifdef _WIN32
    #include <windows.h> //Needed for file access functions
#endif
#include <wx/textfile.h>
#include <wx/strconv.h>
#include <wx/utils.h>
#include <ZenLib/ZtringListListF.h>
//---------------------------------------------------------------------------

namespace ZenLib
{

//***************************************************************************
// Constructors/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
// Constructors
void ZtringListListF::ZtringListListF_Common ()
{
    Backup_Nb_Max=0;
	Backup_Nb=0;
    Sauvegarde=true;
    #ifdef _UNICODE
        Local=false;
    #else
        Local=true;
    #endif
}

ZtringListListF::ZtringListListF ()
:ZtringListList ()
{
	ZtringListListF_Common();
}

ZtringListListF::ZtringListListF (const ZtringListList &Source)
:ZtringListList (Source)
{
	ZtringListListF_Common();
}

ZtringListListF::ZtringListListF (const Ztring &Source)
:ZtringListList (Source)
{
	ZtringListListF_Common();
}

ZtringListListF::ZtringListListF (const Char *Source)
:ZtringListList (Source)
{
	ZtringListListF_Common();
}

#ifdef _UNICODE
ZtringListListF::ZtringListListF (const char* Source)
:ZtringListList (Source)
{
	ZtringListListF_Common();
}
#endif

//***************************************************************************
// File management
//***************************************************************************

//---------------------------------------------------------------------------
// Load
size_t ZtringListListF::Load (const Ztring &NewFileName)
{
    if (NewFileName!=_T(""))
        Nom=NewFileName;

    clear();
    size_t I1=Error;

    if (Nom.find(_T(".csv"))!=Error)
        I1=CSV_Charger();
    if (Nom.find(_T(".cfg"))!=Error)
        I1=CFG_Charger();
    if (I1>0)
    {
        Backup_Nb=0; //mettre ici le code pour trouver le nb de backup
        return Backup_Nb;
    }
    else
        return 0;
}

//---------------------------------------------------------------------------
// Load CSV
size_t ZtringListListF::CSV_Charger ()
{
    //Read file
    char *Buffer=NULL;
    unsigned long BytesCount;
    #ifdef _WIN32 //Awful hack to be able to read files with Unicode in their name
    HANDLE Handle=CreateFile(Nom.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (Handle!=(HANDLE)-1)
    {
        DWORD Length_High;DWORD Length_Low=GetFileSize(Handle, &Length_High);
        Buffer=new char[Length_Low+1];
        ReadFile(Handle, Buffer, Length_Low, &BytesCount, NULL);
        CloseHandle(Handle);
    }
    else
    {
    #endif
        wxFile F;
        if (!F.Open(Nom.c_str()))
        {
            delete[] Buffer;
            return Error;
        }
        Buffer=new char[F.Length()+1];
        BytesCount=F.Read(Buffer, F.Length());
        F.Close();
    #ifdef _WIN32 //Awful hack to be able to read files with Unicode in their name
    }
    #endif
    if (BytesCount==Error)
    {
        delete[] Buffer;
        return Error;
    }
    Buffer[BytesCount]='\0';

    //Convert file in UTF-8 or Local
    Ztring File;
    if (!Local)
    {
        //UTF-8
        File.From_UTF8(Buffer, BytesCount);
        #ifdef _DEBUG
        if (File.size()==0)
        {
            File.From_Local(Buffer, BytesCount);
            /*wxCSConv Russian(wxFONTENCODING_CP1251);
            wxWCharBuffer B=Russian.cMB2WC(Buffer);
            File=B.data();
            wxFile F;*/
            /*if (!F.Open((Nom+_T(".utf8")).c_str(), wxFile::write))
            {
                delete[] Buffer;
                return Error;
            }
            F.Write(File.c_str());
            F.Close();*/
        }
        #endif //_DEBUG
    }
    if (File.size()==0)
        //Local of UTF-8 failed
        File.From_Local(Buffer, BytesCount);

    //Separators
    if (Separator[0]==_T("(Default)"))
        Separator[0]=wxTextFile::GetEOL();
    Ztring SeparatorT=Separator[1];
    Separator[1]=_T(";");

    //Writing
    Write(File);

    //Separators
    Separator[1]=SeparatorT;

    delete[] Buffer;
    return 1;
}

//---------------------------------------------------------------------------
// Chargement CFG
size_t ZtringListListF::CFG_Charger ()
{
    wxTextFile F;
    if (!F.Open(Nom.c_str()))
        return Error;

    Ztring SeparatorT=Separator[1];
    Separator[1]=_T(";");

    Ztring Lu;
    Ztring Propriete, Valeur, Commentaire;

    for (size_t Pos=0; Pos<F.GetLineCount(); Pos++)
    {
        if ((Lu=F.GetLine(Pos).c_str()).size()==0)
        {
            Separator[1]=SeparatorT;
            return Error;
        }
        if (Lu.find(_T("="))>0)
        {
            //Obtention du nom
            Propriete=Lu.SubString(_T(""), _T("="));
            NettoyerEspaces(Propriete);
            //Obtention de la valeur
            Valeur=Lu.SubString(_T("="), _T(";"), 0, Ztring_AddLastItem);
            NettoyerEspaces(Valeur);
        }
        //Obtention du commentaire
        Commentaire=Lu.SubString(_T(";"), _T(""), 0, Ztring_AddLastItem);
        NettoyerEspaces(Commentaire);
        //Ecriture
        push_back((Propriete+_T(";")+Valeur+_T(";")+Commentaire).c_str()); //Visual C++ 6 is old...
    }
    Separator[1]=SeparatorT;
    return 1;
}

//---------------------------------------------------------------------------
// Sauvegarde globale
size_t ZtringListListF::Save (const Ztring &FileName)
{
    //Gestion de l'annulation de la sauvegarde
    if (!Sauvegarde)
        return Backup_Nb;

    if (FileName!=_T(""))
        Nom=FileName;

    //Gestion des backups
    Backup_Nb=0;
    size_t I2;
    if (Backup_Nb_Max>0)
    {
        //TODO : not tested
        for (size_t I1=Backup_Nb_Max-1; I1>0; I1--)
        {
            Ztring Z1=Nom+_T(".sav"); Z1+=Ztring::ToZtring((intu)I1);
            Ztring Z2=Nom+_T(".sav"); Z2+=Ztring::ToZtring((intu)I1+1);
            wxRemoveFile (Z2.c_str());
            I2=wxRenameFile(Z1.c_str(), Z2.c_str());
            if (I2 && !Backup_Nb)
                Backup_Nb=I2;
        }
        Ztring Z1=Nom+_T(".sav0");
		wxRemoveFile(Z1.c_str());
        wxRenameFile(Nom.c_str(), Z1.c_str());
        Backup_Nb++;
    }

    I2=Error;
    if (Nom.find(_T(".csv"))!=Error)
        I2=CSV_Sauvegarder();
    if (Nom.find(_T(".cfg"))!=Error)
        I2=CFG_Sauvegarder();

    if (I2>0)
    {
        return Backup_Nb;
    }
    else
        return 0;
}

//---------------------------------------------------------------------------
// Sauvegarde CSV
size_t ZtringListListF::CSV_Sauvegarder ()
{
    //Sauvegarde
    wxRemoveFile(Nom.c_str());
    wxFile F;
    if (!F.Open(Nom.c_str(), wxFile::write))
        return Error;

    if (Separator[0]==_T("(Default)"))
        Separator[0]=wxTextFile::GetEOL();

    F.Write(Read().c_str());

    return 1;
}

//---------------------------------------------------------------------------
// Sauvegarde CFG
size_t ZtringListListF::CFG_Sauvegarder ()
{
    wxFile F;
    if (!F.Create(Nom.c_str(), true))
        return Error;

    Ztring ToWrite;
    Ztring Propriete, Valeur, Commentaire;

    ;
    for (size_t Pos=0; Pos<size(); Pos++)
    {
        Propriete=Read(Pos, 0);
        Valeur=Read(Pos, 1);
        Commentaire=Read(Pos, 2);
        if (Propriete!=_T(""))
        {
            ToWrite+=Propriete+_T(" = ");
            if (Valeur!=_T(""))
                ToWrite+=Valeur+_T(" ");
        }
        if (Commentaire!=_T(""))
            ToWrite+=_T("; ")+Commentaire;
        ToWrite+=_T("\r\n");
    }
    F.Write(ToWrite.c_str());

    return 1;
}

//---------------------------------------------------------------------------
// Annulation
size_t ZtringListListF::Cancel ()
{
    Ztring Z1=Nom+_T(".sav0"); //Visual C++ 6 patch 
	wxRemoveFile(Nom.c_str());
    wxRenameFile(Z1.c_str(), Nom.c_str());
    for (size_t I1=1; I1<=Backup_Nb; I1++)
	{
		Ztring Z2=Nom+_T(".sav"); Z2+=Ztring::ToZtring((intu)I1); //Visual C++ 6 patch
		Ztring Z3=Nom+_T(".sav"); Z3+=Ztring::ToZtring((intu)I1-1); //Visual C++ 6 patch 
        wxRemoveFile(Z3.c_str());
        wxRenameFile(Z2.c_str(), Z3.c_str());
    }
	Write(_T(""));
    return CSV_Charger();
}

//***************************************************************************
// Divers
//***************************************************************************

//---------------------------------------------------------------------------
// Nettoyage
size_t ZtringListListF::NettoyerEspaces (Ztring &ANettoyer)
{
    size_t Debut=0;
    while (Debut<ANettoyer.size() && ANettoyer[Debut]==_T(' '))
        Debut++;
    size_t Fin=ANettoyer.size()-1;
    while (Fin!=(size_t)-2 && ANettoyer[Fin]==_T(' '))
        Fin--;
    if (Fin>=Debut)
        ANettoyer=ANettoyer.substr(Debut, Fin-Debut+1);
    else
        ANettoyer=_T("");
    return 1;
}

//---------------------------------------------------------------------------
// Backup
void ZtringListListF::Backup_Set (bool NewSave)
{
    Sauvegarde=NewSave;
    Save();
}

void ZtringListListF::Backup_Count_Set (size_t NewCount)
{
    Backup_Nb_Max=NewCount;
}

//---------------------------------------------------------------------------
// Local
void ZtringListListF::Local_Set (bool NewLocal)
{
    Local=NewLocal;
}

} //Namespace

