// ZenLib::ZtringListList - std::vector<std::vector<std::(w)string>> is better
// 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.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// More methods for std::vector<std::vector<std::(w)string>>
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// 2005-03-25, Zen@MediaArea.net
// New design
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
#ifdef __BORLANDC__
    #include <sstream> //Needed for wx
#endif
#include <wx/strconv.h>
#include <algorithm>
#include <ZenLib/ZtringListList.h>
using std::vector; //Visual C++ 6 patch
//---------------------------------------------------------------------------


namespace ZenLib
{

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

//---------------------------------------------------------------------------
// Constructors
ZtringListList::ZtringListList()
{
    Separator[0]=_T("\r\n");
    Separator[1]=_T(";");
    Quote=_T("\"");
}

ZtringListList::ZtringListList(const ZtringListList &Source)
{
    Separator[0]=Source.Separator[0];
    Separator[1]=Source.Separator[1];
    Quote=Source.Quote;
    reserve(Source.size());
    Write(Source.Read());
}

ZtringListList::ZtringListList(const Ztring &Source)
{
    Separator[0]=_T("\r\n");
    Separator[1]=_T(";");
    Quote=_T("\"");
    Write(Source.c_str());
}

ZtringListList::ZtringListList(const Char *Source)
{
    Separator[0]=_T("\r\n");
    Separator[1]=_T(";");
    Quote=_T("\"");
    Write(Source);
}

#ifdef _UNICODE
ZtringListList::ZtringListList (const char* S)
{
    Separator[0]=_T("\r\n");
    Separator[1]=_T(";");
    Quote=_T("\"");
    Write(wxConvUTF8.cMB2WC(S).data());
}
#endif

//***************************************************************************
// Operators
//***************************************************************************

//---------------------------------------------------------------------------
//Operator ==
bool ZtringListList::operator == (const ZtringListList &Source) const
{
    return (Read()==Source.Read());
}

//---------------------------------------------------------------------------
//Operator !=
bool ZtringListList::operator != (const ZtringListList &Source) const
{
    return (!(Read()==Source.Read()));
}

//---------------------------------------------------------------------------
// Operator +=
ZtringListList &ZtringListList::operator += (const ZtringListList &Source)
{
    reserve(size()+Source.size());
    for (size_t Pos=0; Pos<Source.size(); Pos++)
        push_back(Source[Pos]);

    return *this;
}

//---------------------------------------------------------------------------
// Operator =
ZtringListList &ZtringListList::operator = (const ZtringListList &Source)
{
    clear();

    Ztring C0=Separator[0];
    Ztring C1=Separator[1];
    Ztring Q=Quote;

    Separator[0]=Source.Separator[0];
    Separator[1]=Source.Separator[1];
    Quote=Source.Quote;
    reserve(Source.size());
    Write(Source.Read());

    Separator[0]=C0;
    Separator[1]=C1;
    Quote=Q;
    
    return *this;
}

//---------------------------------------------------------------------------
// Operatorr ()
ZtringList &ZtringListList::operator () (size_t Pos0)
{
    //Integrity
    if (Pos0>=size())
        Write(_T(""), Pos0);

    return operator [] (Pos0);
}

Ztring &ZtringListList::operator () (size_t Pos0, size_t Pos1)
{
    //Integrity 0
    if (Pos0>=size())
        Write(_T(""), Pos0);

    //Integrity 1
    if (Pos1>=operator [] (Pos0).size())
        operator [] (Pos0).Write(_T(""), Pos1);

    return operator [] (Pos0).operator () (Pos1);
}

Ztring &ZtringListList::operator () (const Ztring &Pos0, size_t Pos0_1, size_t Pos1)
{
    size_t Pos=Find(Pos0, Pos0_1);

    //Integrity 0
    if (Pos==Error)
    {
        Write (Pos0, size(), Pos0_1);
        Pos=size()-1;
    }

    return operator() (Pos, Pos1);
}

//***************************************************************************
// In/Out
//***************************************************************************

//---------------------------------------------------------------------------
// Read
Ztring ZtringListList::Read () const
{
    if (size()==0)
        return _T("");

    Ztring ToReturn;
    for (size_type Pos0=0; Pos0<size(); Pos0++)
        ToReturn+=Read(Pos0)+Separator[0];

    //delete all useless separators at the end
    while (ToReturn.find(Separator[0].c_str(), ToReturn.size()-Separator[0].size())!=std::string::npos)
        ToReturn.resize(ToReturn.size()-Separator[0].size());

    return ToReturn;
}

Ztring ZtringListList::Read (size_t Pos0) const
{
    //Integrity 0
    if (Pos0>=size())
        return _T("");

    return operator [] (Pos0).Read();
}

Ztring ZtringListList::Read (size_t Pos0, size_t Pos1) const
{
    //Integrity 0
    if (Pos0>=size())
        return _T("");

    return operator [] (Pos0).Read(Pos1);
}

Ztring ZtringListList::Read (const Ztring &Pos0, Ztring Default, size_t Pos0_1, size_t Pos1) const //Lecture d'un champs en position 0 avec une option par defaut
{
    size_t Pos=Find(Pos0, Pos0_1);
    if (Pos==Error)
        return Default;

    return Read(Pos, Pos1);
}

Ztring ZtringListList::Read1 (size_t Pos1) const
{
    Ztring ToReturn;
    for (size_t Pos=0; Pos<size(); Pos++)
        ToReturn+=operator [] (Pos).Read(Pos1)+Separator[0];

    ToReturn.resize(ToReturn.size()-Separator[0].size());
    return ToReturn;
}

//---------------------------------------------------------------------------
// Write
void ZtringListList::Write(const Ztring &ToWrite)
{
    clear();
    if (!&ToWrite || !ToWrite.size())
        return;

    size_t Pos0=0;
    size_t PosC=0;
    bool Fini=false;
    Ztring C1;
    ZtringList ZL1;
    ZL1.Separator_Set(0, Separator[1]);
    ZL1.Quote_Set(Quote);

    do
    {
        C1=ToWrite.SubString(_T(""), Separator[0], PosC, Ztring_AddLastItem);
        ZL1.Write(C1);
        Write(ZL1, Pos0);
        Pos0++;
        PosC+=C1.size()+Separator[0].size();
        if (PosC>=ToWrite.size())
            Fini=true;
    }
    while (!Fini);
}

void ZtringListList::Write(const ZtringList &ToWrite, size_t Pos)
{
    //Integrity
    if (Pos==Error)
        return;

    //ecriture
    if (Pos>=size())
    {
        //Reservation de ressources
        if (!capacity())
            reserve(1);
        while (Pos>=capacity())
            reserve(capacity()*2);

        while (Pos>size())
            push_back (_T(""));
        push_back(ToWrite);
    }
    else
        operator [] (Pos)=ToWrite;
}

void ZtringListList::Write(const Ztring &ToWrite, size_t Pos0, size_t Pos1)
{
    if (Pos0>=size())
        Write(_T(""), Pos0);

    operator [] (Pos0).Write(ToWrite, Pos1);
}

void ZtringListList::push_back (const ZtringList &ToAdd)
{
    vector<ZtringList>::push_back(ToAdd); //Visual C++ 6 patch, should be std::vector
    operator () (size()-1).Separator_Set(0, Separator[1]);
    operator () (size()-1).Quote_Set(Quote);
}

void ZtringListList::push_back (const Ztring &ToAdd)
{
    ZtringList ZL1;
    ZL1.Separator_Set(0, Separator[1]);
    ZL1.Quote_Set(Quote);
    ZL1.Write(ToAdd);
    push_back(ZL1);
}

//---------------------------------------------------------------------------
// Insert
void ZtringListList::Insert1 (const Ztring &ToInsert, size_t Pos1)
{
    for (size_t Pos0=0; Pos0<size(); Pos0++)
        operator [] (Pos0).Insert(ToInsert, Pos1);
}

//---------------------------------------------------------------------------
// Delete
void ZtringListList::Delete (const Ztring &ToFind, size_t Pos1, const Ztring &Comparator, ztring_t Options)
{
    size_t Pos0=0;
    while ((Pos0=Find(ToFind, Pos1, Pos0, Comparator, Options))!=Error)
        operator [] (Pos0).Delete(Pos1);
}

void ZtringListList::Delete1 (size_t Pos1)
{
    for (size_t Pos0=0; Pos0<size(); Pos0++)
        operator [] (Pos0).Delete(Pos1);
}

//***************************************************************************
// Edition
//***************************************************************************

//---------------------------------------------------------------------------
// Swap
void ZtringListList::Swap (size_t Pos0_A, size_t Pos0_B)
{
    //Integrity
    size_t Pos_Max;
	if (Pos0_A<Pos0_B)
		Pos_Max=Pos0_B;
	else
		Pos_Max=Pos0_A;
    if (Pos_Max>=size())
        Write(_T(""), Pos_Max);

    operator [] (Pos0_A).swap(operator [] (Pos0_B));
}

void ZtringListList::Swap1 (size_t Pos1_A, size_t Pos1_B)
{
    for (size_t Pos0=0; Pos0<size(); Pos0++)
        operator () (Pos0, Pos1_A).swap(operator () (Pos0, Pos1_B));
}

//---------------------------------------------------------------------------
// Sort
void ZtringListList::Sort(size_t Pos1, ztring_t Options)
{
    std::stable_sort(begin(), end());
    return;
}

//---------------------------------------------------------------------------
// Find
size_t ZtringListList::Find (const Ztring &ToFind, size_t Pos1, size_t Pos0, const Ztring &Comparator, ztring_t Options) const
{
    while (Pos0<size() && &at(Pos0)
       && (    Pos1>=at(Pos0).size()
            || !&at(Pos0).at(Pos1)
            || &at(Pos0).at(Pos1) && !(at(Pos0).at(Pos1).Compare(ToFind, Comparator, Options))))
        Pos0++;
    if (Pos0>=size() || !&at(Pos0))
        return Error;
    return Pos0;
}

Ztring ZtringListList::FindValue (const Ztring &ToFind, size_t Pos1Value, size_t Pos1, size_t Pos0Begin, const Ztring &Comparator, ztring_t Options) const
{
    size_t Pos0=Find(ToFind, Pos1, Pos0Begin, Comparator);
    if (Pos0==Error)
        return _T("");

    return Read(Pos0, Pos1Value);
}

ZtringListList ZtringListList::SubSheet (const Ztring &ToFind, size_t Pos1, size_t Pos0, const Ztring &Comparator, ztring_t Options) const
{
    ZtringListList ToReturn;
    ToReturn.Separator[0]=Separator[0];
    ToReturn.Separator[1]=Separator[1];
    ToReturn.Quote=Quote;

    Pos0--;
    do
    {
        Pos0=Find(ToFind, Pos1, Pos0+1, Comparator);
        ToReturn.push_back(Read(Pos0));
    }
    while (Pos0!=Error);

    return ToReturn;
}
//***************************************************************************
// Configuration
//***************************************************************************

//---------------------------------------------------------------------------
// Separator
void ZtringListList::Separator_Set (size_t Level, const Ztring &NewSeparator)
{
    if (Level>1)
        return;

    Separator[Level]=NewSeparator;
    if (Level==1)
        for (size_type Pos0=0; Pos0<size(); Pos0++)
            operator () (Pos0).Separator_Set(0, Separator[1]);
}

//---------------------------------------------------------------------------
// Quote
void ZtringListList::Quote_Set (const Ztring &NewQuote)
{
    Quote=NewQuote;
    for (size_type Pos0=0; Pos0<size(); Pos0++)
        operator () (Pos0).Quote_Set(Quote);
}

} //namespace








