from core.combat import applyDamage

from siege import game
from siege.component import Component, ComponentDefinition, ComponentFactory
from siege.util import PropertyInt, Timer
from siege.world.realm import WaterCell


class Breath(ComponentDefinition):
    def __init__(self, capacity, area):
        ComponentDefinition.__init__(self)
        self.capacity = capacity
        self.area = area
        self.freeze()

    def getType(self):
        return BreathComponent.TYPE


class BreathComponent(Component):
    '''Component Dependencies: Physics, Stats, Combat'''

    TYPE = "breath"
    CID = 0
    VERSION = 1
    UPDATE_TIME = 500
    BREATH_CONSUMPTION = 5
    BREATH_RESTORE = 10

    def getType(self):
        return BreathComponent.TYPE

    @staticmethod
    def create(entity, componentType, definition):
        if entity.isContentEntity():
            entity.add(BreathComponent(definition, None, None, None))
            breath = None  # Set breath to None here so that the BasicSystem does not manage the component
        else:
            breath = BreathComponent(definition, entity.physics, entity.stats, entity.combat)
            entity.add(breath)
        return breath

    def __init__(self, definition, physics, stats, combat):
        Component.__init__(self)
        self.current = PropertyInt(definition.capacity)
        self.capacity = PropertyInt(definition.capacity)
        self.area = definition.area
        self.physics = physics
        self.stats = stats
        self.combat = combat
        self.updateTimer = Timer(self.UPDATE_TIME)
        self.freeze()

    def update(self, frameTime):
        self.updateTimer.update(frameTime)
        if not self.updateTimer.expired():
            return
        self.updateTimer.reset(self.UPDATE_TIME)
        if self.isSubmerged():
            if self.hasBreath():
                self.dirty()
                self.current.set(max(0, self.current.get() - self.BREATH_CONSUMPTION))
            elif self.combat.isAlive.get() and not self.combat.isInvincible.get():
                damage = self.stats.HP.getMax() / 10
                applyDamage(self.getParent(), damage, origin=None, knockback=None, deathMessage="DeathDrown")
        elif not self.hasFullBreath():
            self.dirty()
            self.current.set(min(self.current.get() + self.BREATH_RESTORE, self.capacity.get()))

    def isSubmerged(self):
        body = self.physics.getWorldBody()
        body.x += self.area.x
        body.y += self.area.y
        body.width = self.area.width
        body.height = self.area.height
        cells = self.getParent().realm.automata.getCells(body)
        if cells:
            for cell in cells:
                if not isinstance(cell, WaterCell) or not cell.isFull():
                    return False
            return True
        return False

    def hasBreath(self):
        return self.current.get() > 0

    def hasFullBreath(self):
        return self.current.get() >= self.capacity.get()

    def restoreBreath(self):
        return self.current.set(self.capacity.get())

    def write(self, stream):
        self.current.write(stream)

    def read(self, stream, version):
        self.current.read(stream)

    @staticmethod
    def register():
        BreathComponent.CID = game.entity.requestCid(BreathComponent.TYPE, Breath)
        game.registerComponent(BreathComponent.TYPE, ComponentFactory.create(BreathComponent.create))
