#include "M2Datei.h"
#include "Text.h"
#include "Datei.h"
#include "Model2D.h"

using namespace Framework;

// Inhalt der M2Datei Klasse aus M2Datei.h
// Konstruktor
M2Datei::M2Datei()
    : ReferenceCounter()
{
    pfad = new Text();
    modelName = new RCArray< Text >();
    modelPos = new Array< __int64 >();
}

M2Datei::M2Datei( const char *pfad )
    : ReferenceCounter()
{
    this->pfad = new Text( pfad );
    modelName = new RCArray< Text >();
    modelPos = new Array< __int64 >();
}

M2Datei::M2Datei( Text *pfad )
    : ReferenceCounter()
{
    this->pfad = pfad;
    modelName = new RCArray< Text >();
    modelPos = new Array< __int64 >();
}

// Destruktor
M2Datei::~M2Datei()
{
    pfad->release();
    modelName->release();
    modelPos->release();
}

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

void M2Datei::setPfadZ( Text *pfad )
{
    if( this->pfad )
        this->pfad->release();
    this->pfad = pfad;
}

void M2Datei::leseDaten()
{
    Datei d;
    d.setDatei( pfad->getText() );
    d.open( Datei::Style::lesen );
    char anz = 0;
    d.lese( &anz, 1 );
    modelName->leeren();
    modelPos->leeren();
    for( int i = 0; i < anz; i++ )
    {
        char len = 0;
        d.lese( &len, 1 );
        char *txt = new char[ len + 1 ];
        d.lese( txt, len );
        txt[ (int)len ] = 0;
        modelName->set( new Text( txt ), i );
        delete[] txt;
        __int64 pos = 0;
        d.lese( (char *)&pos, 8 );
        modelPos->set( pos, i );
    }
    d.close();
}

bool M2Datei::saveModel( Model2DData *zMdr, Text *name )
{
    bool ret = saveModel( zMdr, name->getText() );
    name->release();
    return ret;
}

bool M2Datei::saveModel( Model2DData *zMdr, const char *name )
{
    int anz = modelName->getEintragAnzahl();
    for( int i = 0; i < anz; i++ )
    {
        if( modelName->z( i )->istGleich( name ) )
        {
            if( !removeModel( name ) )
                return 0;
            break;
        }
    }
    anz = modelName->getEintragAnzahl();
    Datei d;
    d.setDatei( pfad->getText() );
    d.open( Datei::Style::lesen );
    Datei neu;
    neu.setDatei( pfad->getText() );
    neu.zPfad()->append( "0" );
    while( neu.existiert() )
        neu.zPfad()->append( "0" );
    if( !neu.open( Datei::Style::schreiben ) )
    {
        if( d.istOffen() )
            d.close();
        return 0;
    }
    modelName->add( new Text( name ) );
    int offs = textLength( name ) + 9;
    for( int i = 0; i < anz; i++ )
        modelPos->set( modelPos->get( i ) + offs, i );
    if( d.getSize() < 0 )
        modelPos->add( offs + 1 );
    else
        modelPos->add( d.getSize() + offs );
    anz++;
    char tmp = (char)anz;
    neu.schreibe( &tmp, 1 );
    for( int i = 0; i < anz; i++ )
    {
        char len = (char)modelName->z( i )->getLength();
        neu.schreibe( &len, 1 );
        neu.schreibe( modelName->z( i )->getText(), len );
        __int64 pos = modelPos->get( i );
        neu.schreibe( (char *)&pos, 8 );
    }
    if( d.existiert() )
    {
        d.setLPosition( modelPos->get( 0 ) - offs, 0 );
        __int64 dl = d.getSize() - d.getLPosition();
        char bytes[ 2048 ];
        while( dl )
        {
            int l = dl > 2048 ? 2048 : (int)dl;
            d.lese( bytes, l );
            neu.schreibe( bytes, l );
            dl -= l;
        }
    }
    d.close();
    char pAnz = (char)zMdr->polygons->getEintragAnzahl();
    neu.schreibe( &pAnz, 1 );
    for( int p = 0; p < pAnz; p++ )
    {
        char pNameL = (char)zMdr->polygons->get( p ).name->getLength();
        int vAnz = zMdr->polygons->get( p ).vertex->getEintragAnzahl();
        char options = 1;
        for( int i = 0; i < vAnz; i++ )
            options = (char)( options & (char)zMdr->polygons->get( p ).tKordinaten->hat( i ) );
        if( pNameL != 0 )
            options |= 2;
        if( zMdr->polygons->get( p ).transparent )
            options |= 4;
        neu.schreibe( &options, 1 );
        if( ( options | 2 ) == options ) // name
        {
            neu.schreibe( &pNameL, 1 );
            neu.schreibe( zMdr->polygons->get( p ).name->getText(), pNameL );
        }
        neu.schreibe( (char *)&vAnz, 4 );
        for( int i = 0; i < vAnz; i++ )
        {
            float v = zMdr->polygons->get( p ).vertex->get( i ).x;
            neu.schreibe( (char *)&v, 4 );
            v = zMdr->polygons->get( p ).vertex->get( i ).y;
            neu.schreibe( (char *)&v, 4 );
            if( ( options | 1 ) == options ) // textur
            {
                float t = zMdr->polygons->get( p ).tKordinaten->get( i ).x;
                neu.schreibe( (char *)&t, 4 );
                t = zMdr->polygons->get( p ).tKordinaten->get( i ).y;
                neu.schreibe( (char *)&t, 4 );
            }
        }
    }
    d.remove();
    neu.close();
    neu.umbenennen( pfad->getText() );
    leseDaten();
    return 1;
}

bool M2Datei::removeModel( Text *name )
{
    bool ret = removeModel( name->getText() );
    name->release();
    return ret;
}

bool M2Datei::removeModel( const char *name )
{
    int anz = modelName->getEintragAnzahl();
    int p = -1;
    for( int i = 0; i < anz; i++ )
    {
        if( modelName->z( i )->istGleich( name ) )
        {
            p = i;
            break;
        }
    }
    if( p < 0 )
        return 0;
    Datei d;
    d.setDatei( pfad->getText() );
    if( !d.open( Datei::Style::lesen ) )
        return 0;
    Datei neu;
    neu.setDatei( pfad->getText() );
    neu.zPfad()->append( "0" );
    while( neu.existiert() )
        neu.zPfad()->append( "0" );
    if( !neu.open( Datei::Style::schreiben ) )
    {
        if( d.istOffen() )
            d.close();
        return 0;
    }
    char nAnz = (char)( anz - 1 );
    neu.schreibe( &nAnz, 1 );
    int offs = modelName->z( p )->getLength() + 9;
    __int64 startP = 0, endP = 0, start2P = 0;
    for( int i = 0; i < anz; i++ )
    {
        char nLen = (char)modelName->z( i )->getLength();
        char *n = modelName->z( i )->getText();
        __int64 pos = modelPos->get( i );
        if( !startP )
            startP = pos;
        if( i == p + 1 )
            start2P = pos;
        if( i == p )
        {
            if( !endP )
                endP = pos;
            if( i < anz - 1 )
                offs += (int)( modelPos->get( i + 1 ) - pos );
        }
        if( i != p )
        {
            pos -= offs;
            neu.schreibe( &nLen, 1 );
            neu.schreibe( n, nLen );
            neu.schreibe( (char *)&pos, 8 );
        }
    }
    if( d.istOffen() )
    {
        d.setLPosition( startP, 0 );
        __int64 bLen = endP - startP;
        char bytes[ 2048 ];
        while( bLen > 0 )
        {
            int l = 2048 > bLen ? (int)bLen : 2048;
            d.lese( bytes, l );
            neu.schreibe( bytes, l );
            bLen -= l;
        }
        if( start2P )
        {
            d.setLPosition( start2P, 0 );
            bLen = d.getSize() - start2P;
            while( bLen > 0 )
            {
                int l = 2048 > bLen ? (int)bLen : 2048;
                d.lese( bytes, l );
                neu.schreibe( bytes, l );
                bLen -= l;
            }
        }
        d.close();
    }
    d.remove();
    neu.close();
    neu.umbenennen( pfad->getText() );
    leseDaten();
    return 1;
}

// constant
Model2DData *M2Datei::ladeModel( Text *name ) const
{
    Model2DData *ret = ladeModel( name->getText() );
    name->release();
    return ret;
}

Model2DData *M2Datei::ladeModel( const char *name ) const
{
    Datei d;
    d.setDatei( pfad->getText() );
    if( !d.open( Datei::Style::lesen ) )
        return 0;
    int anz = modelName->getEintragAnzahl();
    for( int i = 0; i < anz; i++ )
    {
        if( modelName->z( i )->istGleich( name ) )
        {
            d.setLPosition( modelPos->get( i ), 0 );
            break;
        }
    }
    if( !d.getLPosition() )
    {
        d.close();
        return 0;
    }
    char pAnz = 0;
    d.lese( &pAnz, 1 );
    Array< Polygon2D > *polygons = new Array< Polygon2D >();
    for( int p = 0; p < pAnz; p++ )
    {
        char options = 0;
        d.lese( &options, 1 );
        Polygon2D polygon;
        polygon.schwerpunkt = new Vertex( 0, 0 );
        polygon.transparent = ( options | 4 ) == options;
        polygon.name = new Text();
        if( ( options | 2 ) == options )
        {
            char nameL = 0;
            d.lese( &nameL, 1 );
            char *name = new char[ nameL + 1 ];
            name[ (int)nameL ] = 0;
            d.lese( name, nameL );
            polygon.name->setText( name );
            delete[] name;
        }
        int vAnz = 0;
        d.lese( (char *)&vAnz, 4 );
        if( polygons->hat( p ) )
        {
            if( polygons->get( p ).vertex )
                polygons->get( p ).vertex->release();
            if( polygons->get( p ).tKordinaten )
                polygons->get( p ).tKordinaten->release();
        }
        polygon.vertex = new Array< Vertex >();
        if( ( options | 1 ) == options ) // wenn textur
            polygon.tKordinaten = new Array< Vertex >();
        else
            polygon.tKordinaten = 0;
        for( int v = 0; v < vAnz; v++ )
        {
            Vertex p;
            d.lese( (char *)&p.x, 4 );
            d.lese( (char *)&p.y, 4 );
            *polygon.schwerpunkt += p * (float)( 1.0 / vAnz );
            polygon.vertex->add( p );
            if( ( options | 1 ) == options ) // wenn textur
            {
                Vertex tp;
                d.lese( (char *)&tp.x, 4 );
                d.lese( (char *)&tp.y, 4 );
                polygon.tKordinaten->add( tp );
            }
        }
        polygons->add( polygon );
    }
    d.close();
    Model2DData *ret = new Model2DData();
    ret->erstelleModell( polygons );
    return ret;
}

bool M2Datei::hatModel( const char *name ) const
{
    int anz = modelName->getEintragAnzahl();
    for( int i = 0; i < anz; i++ )
    {
        if( modelName->z( i )->istGleich( name ) )
            return 1;
    }
    return 0;
}

int M2Datei::getModelAnzahl() const
{
    return modelName->getEintragAnzahl();
}

Text *M2Datei::zModelName( int i ) const
{
    return modelName->z( i );
}