from siege import game
from siege.component import Component, ComponentDefinition
from siege.world.realm import Layer, RealmArea
from siege.util import Rect, RangeInt, Timer, minutes


class Travel(ComponentDefinition):
    def __init__(self):
        ComponentDefinition.__init__(self)
        self.freeze()

    def getType(self):
        return TravelComponent.TYPE


class TravelComponent(Component):
    TYPE = "travel"
    CID = 0
    VERSION = 1
    SPAWN_TIME = RangeInt(minutes(8), minutes(10))
    SPAWN_RANGE = 125
    SPAWN_LIMIT = 8

    def getType(self):
        return TravelComponent.TYPE

    def __init__(self, definition):
        Component.__init__(self)
        self.shardTimer = Timer(self.SPAWN_TIME.getRandom())
        self.freeze()

    def update(self, time):
        self.shardTimer.update(time)
        if self.shardTimer.expired():
            self.shardTimer.reset(self.SPAWN_TIME.getRandom())
            # Try to spawn a shard nearby
            parent = self.getParent()
            position = parent.getPosition()
            area = Rect(position.x - self.SPAWN_RANGE, position.y - self.SPAWN_RANGE, self.SPAWN_RANGE * 2, self.SPAWN_RANGE * 2)
            realm = parent.realm
            entities = realm.layers[Layer.Item].getNearby(area)
            shardPlant = game.content.get('way_shard_plant')
            plantCount = len([entity for entity in entities if entity.content == shardPlant])
            if plantCount < self.SPAWN_LIMIT:
                entities = game.organic.plantMany(shardPlant, realm, RealmArea(area), Layer.Item, 1)
                if not entities:
                    # Failed to create any entities the first time. Try again with a larger area.
                    area = Rect(position.x - self.SPAWN_RANGE * 2, position.y - self.SPAWN_RANGE * 2, self.SPAWN_RANGE * 4, self.SPAWN_RANGE * 4)
                    game.organic.plantMany(shardPlant, realm, RealmArea(area), Layer.Item, 1)

    def pack(self, stream):
        pass

    def unpack(self, stream):
        pass

    def write(self, stream):
        stream.writeUint32(self.shardTimer.remaining())

    def read(self, stream, version):
        self.shardTimer.reset(stream.readUint32())

    @staticmethod
    def register():
        TravelComponent.CID = game.entity.requestCid(TravelComponent.TYPE, Travel)
