from olives_gamestate import GameState
from olives_object_type import ObjectType

from .olives_abstractobject import AbstractObject
from olives_object import Object, MessageType
from olives_types import Position2, Position3, LightInfo


class AbstractLight(AbstractObject):
    """
    This is the base class for light objects.

    The "olives" prefix in the file indicates it is not meant to be edited,
    as this will most definitely result in breakage.
    """
    intensity = 0
    cone_width = 0
    is_active = 1
    colour = Position3(0, 0, 0)
    direction = Position3(0, 0, 0)
    light_id = 0
    add_light = False
    move_light = False
    change_status = False

    def __init__(self, object_type_name: str, object_id: int, object_type: ObjectType):
        super().__init__(object_type_name, object_id, object_type)
        light_info = object_type.get_light_info()
        self.intensity = light_info.intensity
        self.type = light_info.type
        self.is_active = light_info.is_active
        self.direction = Position3(light_info.get_direction_x(), light_info.get_direction_y(), light_info.get_direction_z())
        self.colour = Position3(light_info.get_colour_r(), light_info.get_colour_g(), light_info.get_colour_b())
        self.cone_width = light_info.cone_width

    def on_tick(self, obj: Object, elapsed_ticks: int, game_state: GameState, temperature: int):
        """
        Adds, changes and enables/disabldes lights asynchronously as we do not have access
        to the game state in the other callbacks. Light removal is done differently,
        through a message, which can be processed even after the object was destroyed.
        """
        if self.add_light:
            self.light_id = game_state.add_light(self.generate_lightinfo(), obj.get_position())
            self.add_light = False
            # also reset this flag in case the light was moved before it was created,
            # which means it was already created in the right place
            self.move_light = False
            return

        if self.move_light:
            game_state.update_light(self.light_id, self.generate_lightinfo(), obj.get_position())
            self.move_light = False
            return

        if self.change_status:
            game_state.update_light(self.light_id, self.generate_lightinfo(), obj.get_position())
            self.change_status = False
            return

    def on_create(self, obj: Object, pos: Position2):
        self.add_light = True

    def on_move(self, obj: Object, pos: Position2):
        self.move_light = True

    def on_remove(self, obj: Object, pos: Position2):
        # only try to remove a light if one was added already
        if not self.add_light:
            self.add_job_message(obj, MessageType.REMOVE_LIGHT, self.light_id)

    def on_enable(self, obj: Object):
        self.is_active = 1
        self.change_status = True

    def on_disable(self, obj: Object):
        self.is_active = 0
        self.change_status = True

    def generate_lightinfo(self) -> LightInfo:
        """
        Creates a LightInfo instance based on the current settings
        """
        return LightInfo(self.type, self.intensity, self.cone_width, self.is_active, Position3(0.0, 0.0, 0.0), self.direction, self.colour)