#include "Dimension.h"
#include "Constants.h"
#include "Datei.h"
#include "Game.h"

using namespace Framework;


Dimension::Dimension( int id )
    : dimensionId( id ),
    chunks( new Trie<Chunk>() ),
    entities( new RCArray<Entity>() )
{}

Dimension::~Dimension()
{
    entities->release();
    chunks->release();
}

void Dimension::updateVisibility()
{
    bool changed = true;
    while( changed )
    {
        changed = false;
        for( auto chunk = chunks->getIterator(); chunk; chunk++ )
            changed |= chunk->updateVisibility();
    }
}

void Dimension::getAddrOf( Punkt cPos, char *addr ) const
{
    *(int *)addr = cPos.x;
    *( (int *)addr + 1 ) = cPos.y;
    addr[ 8 ] = 0;
}

void Dimension::getAddrOfWorld( Punkt wPos, char *addr ) const
{
    wPos /= CHUNK_SIZE;
    getAddrOf( wPos, addr );
}

Chunk *Dimension::zChunk( Punkt wPos ) const
{
    char addr[ 9 ];
    getAddrOfWorld( wPos, addr );
    return chunks->z( addr );
}

Block *Dimension::zBlock( Vec3<int> location )
{
    Chunk *c = zChunk( Punkt( location.x, location.y ) );
    if( c )
        return c->zBlockAt( Vec3<int>( location.x % CHUNK_SIZE, location.y % CHUNK_SIZE, location.z ) );
    return 0;
}

void Dimension::addEntity( Entity *entity )
{
    entities->add( entity );
}

void Dimension::addChunk( Chunk *chunk )
{
    char addr[ 9 ];
    getAddrOf( chunk->getCenter(), addr );
    if( !chunks->z( addr ) )
    {
        chunks->set( addr, chunk );
        getAddrOf( chunk->getCenter() + Punkt( CHUNK_SIZE, 0 ), addr );
        Chunk *zChunk = chunks->z( addr );
        if( zChunk )
        {
            zChunk->setNeighbor( WEST, chunk );
            chunk->setNeighbor( EAST, chunk );
        }
        getAddrOf( chunk->getCenter() + Punkt( -CHUNK_SIZE, 0 ), addr );
        zChunk = chunks->z( addr );
        if( zChunk )
        {
            zChunk->setNeighbor( EAST, chunk );
            chunk->setNeighbor( WEST, chunk );
        }
        getAddrOf( chunk->getCenter() + Punkt( 0, CHUNK_SIZE ), addr );
        zChunk = chunks->z( addr );
        if( zChunk )
        {
            zChunk->setNeighbor( NORTH, chunk );
            chunk->setNeighbor( SOUTH, chunk );
        }
        getAddrOf( chunk->getCenter() + Punkt( 0, -CHUNK_SIZE ), addr );
        zChunk = chunks->z( addr );
        if( zChunk )
        {
            zChunk->setNeighbor( SOUTH, chunk );
            chunk->setNeighbor( NORTH, chunk );
        }
    }
    else
        chunk->release();
}

int Dimension::getDimensionId() const
{
    return dimensionId;
}

bool Dimension::hasChunck( int x, int y ) const
{
    return zChunk( Punkt( x, y ) );
}