#include <Punkt.h>
#include <Text.h>

#include "WorldLoader.h"
#include "Game.h"
#include "AddChunkUpdate.h"

using namespace Framework;

WorldLoader::WorldLoader()
    : Thread(),
    exit( 0 )
{
    Datei d;
    d.setDatei( Game::INSTANCE->getWorldDirectory() + "/dim" );
    RCArray<Text>* names = d.getDateiListe();
    if( names )
    {
        for( Text* name : *names )
        {
            Datei entities;
            entities.setDatei( Game::INSTANCE->getWorldDirectory() + "/dim/" + Text( name->getText() ) + "/entities" );
            if( entities.open( Datei::Style::lesen ) )
            {
                Dimension* dim = new Dimension( *name );
                while( !entities.istEnde() )
                {
                    int type = 0;
                    entities.lese( (char*)&type, 4 );
                    dim->addEntity( StaticRegistry<EntityType>::INSTANCE.zElement( type )->loadEntity( &entities ) );
                }
                Game::INSTANCE->addDimension( dim );
            }
        }
        names->release();
    }
    start();
}

WorldLoader::~WorldLoader()
{}

void WorldLoader::thread()
{
    while( !exit )
    {
        cs.lock();
        Area next;
        bool hasNext = 0;
        if( requestQueue.getEintragAnzahl() > 0 )
        {
            next = requestQueue.get( 0 );
            requestQueue.remove( 0 );
            hasNext = 1;
        }
        cs.unlock();
        if( !hasNext )
        {
            Sleep( 1000 );
            continue;
        }
        Punkt start = Game::INSTANCE->getChunkCenter( next.startX, next.startY );
        Punkt end = Game::INSTANCE->getChunkCenter( next.endX, next.endY );
        int xDir = start.x > end.x ? -1 : 1;
        int yDir = start.y > end.y ? -1 : 1;
        for( int x = start.x; xDir < 0 ? x >= end.x : x <= end.x; x += CHUNK_SIZE * xDir )
        {
            for( int y = start.y; yDir < 0 ? y >= end.y : y <= end.y; y += CHUNK_SIZE * yDir )
            {
                if( !Game::INSTANCE->isChunkLoaded( x, y, next.dimensionId ) )
                {
                    Datei* file = new Datei();
                    Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + next.dimensionId + "/";
                    filePath.appendHex( x );
                    filePath += "_";
                    filePath.appendHex( y );
                    filePath += ".chunk";
                    file->setDatei( filePath );
                    if( file->open( Datei::Style::lesen ) )
                    {
                        Chunk* chunk = new Chunk( Framework::Punkt( x, y ), next.dimensionId, file );
                        Game::INSTANCE->requestWorldUpdate( new AddChunkUpdate( chunk ) );
                    }
                    file->close();
                    file->release();
                }
            }
        }
    }
}

void WorldLoader::requestLoading( Area request )
{
    cs.lock();
    requestQueue.add( request );
    cs.unlock();
}

void WorldLoader::exitAndWait()
{
    exit = 1;
    warteAufThread( 10000 );
    ende();
}

bool WorldLoader::existsChunk( int x, int y, int dimension ) const
{
    Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + dimension + "/";
    filePath.appendHex( x );
    filePath += "_";
    filePath.appendHex( y );
    filePath += ".chunk";
    return DateiExistiert( filePath );
}