import random

from siege.log import Log
from siege.world.realm import Layer
from siege.worldgen import Terraform
from siege.util import Rect, TileRect, SegmentRect, Random, Sizes

from core.terraform.way_crystals import placeCrystal
from core.map_painter import saveWorldImage


def LayFoundation(game, world, realm, data):
    """ First lay down the base tiles - the foundation. """
    game.spawner.enabled = False
    data['TreasureSystem'].register(world)
    world.time.hours.set(7)

    # Set the tile ids that we'll be using
    dirtId = game.content.get('dirt').id
    stoneId = game.content.get('stone').id

    # Determine the starting heights in segments
    if 'dirtStartY' not in data:
        dirtStartY = int(realm.size.segmentHeight * Random.get(0.32, 0.37)) - 1
        data['dirtStartY'] = dirtStartY
    else:
        dirtStartY = data['dirtStartY']

    if 'stoneStartY' not in data:
        stoneStartY = int(realm.size.segmentHeight * Random.get(0.60, 0.65))
        data['stoneStartY'] = stoneStartY
    else:
        stoneStartY = data['stoneStartY']

    # From the starting point just flood fill the tiles below
    def fillArea(area, groundId, wallId):
        Terraform.createSegments(realm.layers[Layer.Ground], area, groundId)
        Terraform.createSegments(realm.layers[Layer.Wall], area, wallId)

    fillArea(SegmentRect(0, 0, realm.size.segmentWidth, dirtStartY), 0, 0)

    # KLUGE FOR TESTING
    if stoneStartY:
        fillArea(SegmentRect(0, dirtStartY, realm.size.segmentWidth, stoneStartY - dirtStartY), dirtId, dirtId)
        fillArea(SegmentRect(0, stoneStartY, realm.size.segmentWidth, realm.size.segmentHeight - stoneStartY), stoneId, stoneId)
    else:
        fillArea(SegmentRect(0, dirtStartY, realm.size.segmentWidth, realm.size.segmentHeight - dirtStartY), dirtId, dirtId)

    # Convert from segments to tiles
    realm.groundLevel = (dirtStartY + 1) * Sizes.SEGMENT_TILE
    Log.debug("Ground level: {0}".format(realm.groundLevel))
    data['surfaceLevel'] = dirtStartY * Sizes.SEGMENT_TILE
    realm.surfaceLevel = data['surfaceLevel']
    Log.debug("Surface level: {0}".format(data['surfaceLevel']))
    data['undergroundArea'] = TileRect(0, realm.groundLevel, realm.size.tileWidth, realm.size.tileHeight - realm.groundLevel)


def GrowGrass(game, world, realm, data):
    game.grass = data['GrassSystem']()
    for region in realm.loader.getLoadedRegions():
        game.grass.handleRegionLoad(region, realm.loader.getSegments(region), 0)
    for x in xrange(data['GrassSystem'].UPDATE_COUNT * 6):
        game.grass.update(data['GrassSystem'].UPDATE_TIME)


def SimulateWater(game, world, realm, data):
    data['waterSimulation'] = 0
    return [_simulateWater]


def _simulateWater(game, world, realm, data):
    for _ in xrange(5):
        realm.automata.simulate()
    data['waterSimulation'] += 5
    if not realm.automata.isSettled() and data['waterSimulation'] < 1000 and realm.automata.getActiveCount() > 500:
        return [_simulateWater]
    else:
        Log.info("Simulated water {} times with {} active cells remaining.".format(data['waterSimulation'], realm.automata.getActiveCount()))


def PopulateStartArea(game, world, realm, data):
    """ Make sure the starting location isn't too challenging.
    realm.startArea will be re-used later by other worldgen code to prevent
    extra phenomena (spawners, crystals, etc.) from being placed in this
    carefully-curated section of the realm.
    """
    # Place one way crystal
    area = _determineStartArea(data['biomes'])
    crystal = placeCrystal(game, realm, area, onSurface=True)
    Log.debug("Placed in start area: {0!r} at {1!r}".format(crystal, crystal.getPosition()))
    crystalArea = crystal.render.getRect()
    realm.startArea = Rect(crystalArea.x - 8, crystalArea.y + crystalArea.height, 16, 1)


def _determineStartArea(biomes):
    allPlains = [biome for biome in biomes if biome.biome.name == "Plains"]
    startBiome = random.choice(allPlains)
    # Set the start area and make sure there is enough room on the top
    startArea = TileRect(startBiome.area.x, startBiome.area.y, startBiome.area.width, startBiome.area.height)
    startArea.x += startBiome.area.width / 4
    startArea.width = startBiome.area.width / 2
    y = max(0, startArea.y - 5)
    startArea.height += startArea.y - y
    startArea.y = y
    return Rect(startArea)


def Cleanup(game, world, realm, data):
    game.timer.clear()
    Log.info("Saving world image.")
    realm.layers[Layer.Wall].fullDirty()
    realm.layers[Layer.Ground].fullDirty()


def SaveWorldImage(game, world, realm, data):
    saveWorldImage(game, world, realm, realm.biomeTracker.undergroundThreshold, data['biomes'])
