#include "WorldGenerator.h"
#include "StaticRegistry.h"
#include "Game.h"
#include "PerlinNoise.h"
#include "AddChunkUpdate.h"

using namespace Framework;

WorldGenerator::WorldGenerator( int seed, Game *zGame )
    : Thread(),
    zGame( zGame ),
    noise( new PerlinNoise( seed ) ),
    exit( 0 )
{
    start();
}

WorldGenerator::~WorldGenerator()
{
    noise->release();
}

void WorldGenerator::thread()
{
    while( !exit )
    {
        cs.Enter();
        Area next;
        bool hasNext = 0;
        if( requestQueue.getEintragAnzahl() > 0 )
        {
            next = requestQueue.get( 0 );
            requestQueue.remove( 0 );
            hasNext = 1;
        }
        cs.Leave();
        if( !hasNext )
        {
            sleep( 1 );
            continue;
        }
        Punkt start = zGame->getChunkCenter( next.startX, next.startY );
        Punkt end = zGame->getChunkCenter( next.endX, next.endY );
        int xDir = start.x > end.x ? -1 : ( start.x < end.x ? 1 : 0 );
        int yDir = start.y > end.y ? -1 : ( start.y < end.y ? 1 : 0 );
        for( int x = start.x; x != end.x; x += CHUNK_SIZE * xDir )
        {
            for( int y = start.y; y != end.y; y += CHUNK_SIZE * yDir )
            {
                if( !zGame->doesChunkExist( x, y, next.dimensionId ) )
                {
                    Chunk *generatedChunk = StaticRegistry<DimensionGenerator>::INSTANCE.zElement( next.dimensionId )->generateChunk( noise, zGame, x, y );
                    zGame->requestWorldUpdate( new AddChunkUpdate( generatedChunk ) );
                }
            }
        }
    }
}

void WorldGenerator::requestGeneration( Area request )
{
    cs.Enter();
    requestQueue.add( request );
    cs.Leave();
}

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