#include "KSGTDatei.h"
#include "Text.h"
#include "Datei.h"

using namespace Framework;

// Inhalt der KSGTDatei Klasse aus KSGTDatei.h
// Konstruktor
KSGTDatei::KSGTDatei()
    : ReferenceCounter(),
    pfad( new Text() ),
    data( new RCArray< RCArray< Text > >() )
{}

KSGTDatei::KSGTDatei( const char *pfad )
    : ReferenceCounter(),
    pfad( new Text() ),
    data( new RCArray< RCArray< Text > >() )
{
    setPfad( pfad );
}

KSGTDatei::KSGTDatei( Text *pfad )
    : ReferenceCounter(),
    pfad( new Text() ),
    data( new RCArray< RCArray< Text > >() )
{
    setPfad( pfad );
}

// Destruktor
KSGTDatei::~KSGTDatei()
{
    pfad->release();
    data->release();
}

// nicht constant
void KSGTDatei::setPfad( const char *pfad )
{
    this->pfad->setText( pfad );
}

void KSGTDatei::setPfad( Text *pfad )
{
    this->pfad->setText( pfad );
}

bool KSGTDatei::laden()
{
    std::ifstream inf;
    inf.open( pfad->getText(), std::ios::binary );
    if( !inf.good() || !inf.is_open() )
        return 0;
    data->leeren();
    inf.seekg( 0, std::ios::end );
    __int64 gr = inf.tellg();
    __int64 pos = 0;
    int zeilenPos = 0;
    int feldPos = 0;
    while( pos < gr )
    {
        inf.seekg( pos, std::ios::beg );
        char c = 1;
        int len = 0;
        do
        {
            inf.read( &c, 1 );
            ++len;
        } while( c != 0 && c != '\n' && pos + len < gr );
        if( pos + len == gr )
            ++len;
        inf.seekg( pos, std::ios::beg );
        char *v = new char[ len ];
        v[ len - 1 ] = 0;
        if( len > 1 )
            inf.read( v, len - 1 );
        pos += len;
        if( zeilenPos > data->getLastIndex() )
            data->add( new RCArray< Text > );
        auto line = data->z( zeilenPos );
        if( feldPos > line->getLastIndex() )
            line->add( new Text(v) );
        else
            line->z( feldPos )->setText( v );
        delete[] v;
        if( c == 0 )
            ++feldPos;
        else if( c == '\n' )
        {
            ++zeilenPos;
            feldPos = 0;
        }
        else
            break;
    }
    inf.close();
    return 1;
}

bool KSGTDatei::addZeile( int feldAnzahl, RCArray< Text > *zWert )
{
    auto line = new RCArray< Text >();
    data->add( line );
    for( Text *t : *zWert )
        line->add( (Text*)t ? new Text( t->getText() ) : 0 );
    return 1;
}

bool KSGTDatei::setZeile( int zeile, int feldAnzahl, RCArray< Text > *zWert )
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
        return 0;
    auto line = new RCArray< Text >();
    data->set( line, zeile );
    for( Text* t : *zWert )
        line->add( t ? new Text( t->getText() ) : 0 );
    return 1;
}

bool KSGTDatei::removeZeile( int zeile )
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
        return 0;
    data->remove( zeile );
    return 1;
}

bool KSGTDatei::addFeld( int zeile, int pos, Text *wert )
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
    {
        wert->release();
        return 0;
    }
    int fA = getFeldAnzahl( zeile );
    if( pos > fA )
    {
        wert->release();
        return 0;
    }
    data->z( zeile )->add( new Text( wert->getText() ), pos );
    wert->release();
    return 1;
}

bool KSGTDatei::addFeld( int zeile, int pos, const char *wert )
{
    return addFeld( zeile, pos, new Text( wert ) );
}

bool KSGTDatei::addFeld( int zeile, Text *wert )
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
    {
        wert->release();
        return 0;
    }
    data->z( zeile )->add( new Text( wert->getText() ) );
    wert->release();
    return 1;
}

bool KSGTDatei::addFeld( int zeile, const char *wert )
{
    return addFeld( zeile, new Text( wert ) );
}

bool KSGTDatei::setFeld( int zeile, int feld, Text *wert )
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
    {
        wert->release();
        return 0;
    }
    int fA = getFeldAnzahl( zeile );
    if( feld >= fA )
    {
        wert->release();
        return 0;
    }
    data->z( zeile )->set( new Text( wert->getText() ), feld );
    wert->release();
    return 1;
}

bool KSGTDatei::setFeld( int zeile, int feld, const char *wert )
{
    return setFeld( zeile, feld, new Text( wert ) );
}

bool KSGTDatei::removeFeld( int zeile, int feld )
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
        return 0;
    int fA = getFeldAnzahl( zeile );
    if( feld >= fA )
        return 0;
    data->z( zeile )->remove( feld );
    return 1;
}

bool KSGTDatei::speichern()
{
    if( !pfad->getLength() )
        return 0;
    if( !DateiExistiert( pfad->getText() ) )
        DateiPfadErstellen( pfad->getText() );
    std::ofstream of( pfad->getText(), std::ios::binary );
    if( !of.good() || !of.is_open() )
        return 0;
    int i = 0;
    for( auto line = data->begin(); line; line++, i++ )
    {
        if( i )
            of.write( "\n", 1 );
        int f = 0;
        for( auto field = line->begin(); field; field++, f++ )
        {
            if( f )
                of.write( "\0", 1 );
            if( (Text*)field )
                of.write( field->getText(), field->getLength() );
        }
    }
    of.close();
    return 1;
}

// constant
int KSGTDatei::getZeilenAnzahl() const
{
    return data->getEintragAnzahl();
}

int KSGTDatei::getFeldAnzahl( int zeile ) const
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
        return 0;
    return data->z( zeile )->getEintragAnzahl();
}

Text *KSGTDatei::getFeld( int zeile, int feld ) const
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
        return 0;
    int fA = getFeldAnzahl( zeile );
    if( feld >= fA )
        return 0;
    return data->z( zeile )->get( feld );
}

Text *KSGTDatei::zFeld( int zeile, int feld ) const
{
    int zA = getZeilenAnzahl();
    if( zeile >= zA )
        return 0;
    int fA = getFeldAnzahl( zeile );
    if( feld >= fA )
        return 0;
    return data->z( zeile )->z( feld );
}