# Copyright (c) 2007 SIEGE Development Team
# All rights reserved.
#
# This file is part of libSIEGE.
#
# This software is copyrighted work licensed under the terms of the
# 2-clause BSD license. Please consult the file "license.txt" for
# details.
#
# If you did not recieve the file with this program, please email
# Tim Chas <darkuranium@gmail.com>.

from siege.common cimport *
cimport entity
from siege.graphics.sprite cimport Sprite
from siege.graphics.mask cimport Mask
from siege.physics.body cimport Body

cdef SGbool _cbInside(SGEntity* entity, float x, float y):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'cbInside') and obj.cbInside is not None:
        return obj.cbInside(x, y)
    return 0

cdef void _lcMouseEnter(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseEnter') and obj.lcMouseEnter is not None:
        obj.lcMouseEnter()
cdef void _lcMouseExit(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseExit') and obj.lcMouseExit is not None:
        obj.lcMouseExit()

cdef void _lcMouseButton(SGEntity* entity, SGuint button):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButton') and obj.lcMouseButton is not None:
        obj.lcMouseButton(button)
cdef void _lcMouseButtonPress(SGEntity* entity, SGuint button):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonPress') and obj.lcMouseButtonPress is not None:
        obj.lcMouseButtonPress(button)
cdef void _lcMouseButtonRelease(SGEntity* entity, SGuint button):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonRelease') and obj.lcMouseButtonRelease is not None:
        obj.lcMouseButtonRelease(button)

cdef void _lcMouseButtonLeft(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonLeft') and obj.lcMouseButtonLeft is not None:
        obj.lcMouseButtonLeft()
cdef void _lcMouseButtonLeftPress(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonLeftPress') and obj.lcMouseButtonLeftPress is not None:
        obj.lcMouseButtonLeftPress()
cdef void _lcMouseButtonLeftRelease(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonLeftRelease') and obj.lcMouseButtonLeftRelease is not None:
        obj.lcMouseButtonLeftRelease()

cdef void _lcMouseButtonRight(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonRight') and obj.lcMouseButtonRight is not None:
        obj.lcMouseButtonRight()
cdef void _lcMouseButtonRightPress(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonRightPress') and obj.lcMouseButtonRightPress is not None:
        obj.lcMouseButtonRightPress()
cdef void _lcMouseButtonRightRelease(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonRightRelease') and obj.lcMouseButtonRightRelease is not None:
        obj.lcMouseButtonRightRelease()

cdef void _lcMouseButtonMiddle(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonMiddle') and obj.lcMouseButtonMiddle is not None:
        obj.lcMouseButtonMiddle()
cdef void _lcMouseButtonMiddlePress(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonMiddlePress') and obj.lcMouseButtonMiddlePress is not None:
        obj.lcMouseButtonMiddlePress()
cdef void _lcMouseButtonMiddleRelease(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseButtonMiddleRelease') and obj.lcMouseButtonMiddleRelease is not None:
        obj.lcMouseButtonMiddleRelease()

cdef void _lcMouseMove(SGEntity* entity, SGint x, SGint y):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseMove') and obj.lcMouseMove is not None:
        obj.lcMouseMove(x, y)
cdef void _lcMouseWheel(SGEntity* entity, SGint wheel):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'lcMouseWheel') and obj.lcMouseWheel is not None:
        obj.lcMouseWheel(wheel)

cdef void _evInit(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evInit') and obj.evInit is not None:
        obj.evInit()
cdef void _evDeinit(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evDeinit') and obj.evDeinit is not None:
        obj.evDeinit()

cdef void _evStart(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evStart') and obj.evStart is not None:
        obj.evStart()
cdef void _evExit(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evExit') and obj.evExit is not None:
        obj.evExit()
cdef void _evTick(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evTick') and obj.evTick is not None:
        obj.evTick()
cdef void _evTickBegin(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evTickBegin') and obj.evTickBegin is not None:
        obj.evTickBegin()
cdef void _evTickEnd(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evTickEnd') and obj.evTickEnd is not None:
        obj.evTickEnd()
cdef void _evDraw(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evDraw') and obj.evDraw is not None:
        obj.evDraw()

cdef void _evWindowOpen(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evWindowOpen') and obj.evWindowOpen is not None:
        obj.evWindowOpen()
cdef void _evWindowClose(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evWindowClose') and obj.evWindowClose is not None:
        obj.evWindowClose()
cdef void _evWindowResize(SGEntity* entity, SGuint width, SGuint height):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evWindowResize') and obj.evWindowResize is not None:
        obj.evWindowResize(width, height)

cdef void _evMouseButton(SGEntity* entity, SGuint button):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButton') and obj.evMouseButton is not None:
        obj.evMouseButton(button)
cdef void _evMouseButtonPress(SGEntity* entity, SGuint button):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonPress') and obj.evMouseButtonPress is not None:
        obj.evMouseButtonPress(button)
cdef void _evMouseButtonRelease(SGEntity* entity, SGuint button):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonRelease') and obj.evMouseButtonRelease is not None:
        obj.evMouseButtonRelease(button)

cdef void _evMouseButtonLeft(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonLeft') and obj.evMouseButtonLeft is not None:
        obj.evMouseButtonLeft()
cdef void _evMouseButtonLeftPress(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonLeftPress') and obj.evMouseButtonLeftPress is not None:
        obj.evMouseButtonLeftPress()
cdef void _evMouseButtonLeftRelease(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonLeftRelease') and obj.evMouseButtonLeftRelease is not None:
        obj.evMouseButtonLeftRelease()

cdef void _evMouseButtonRight(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonRight') and obj.evMouseButtonRight is not None:
        obj.evMouseButtonRight()
cdef void _evMouseButtonRightPress(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonRightPress') and obj.evMouseButtonRightPress is not None:
        obj.evMouseButtonRightPress()
cdef void _evMouseButtonRightRelease(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonRightRelease') and obj.evMouseButtonRightRelease is not None:
        obj.evMouseButtonRightRelease()

cdef void _evMouseButtonMiddle(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonMiddle') and obj.evMouseButtonMiddle is not None:
        obj.evMouseButtonMiddle()
cdef void _evMouseButtonMiddlePress(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonMiddlePress') and obj.evMouseButtonMiddlePress is not None:
        obj.evMouseButtonMiddlePress()
cdef void _evMouseButtonMiddleRelease(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseButtonMiddleRelease') and obj.evMouseButtonMiddleRelease is not None:
        obj.evMouseButtonMiddleRelease()

cdef void _evMouseMove(SGEntity* entity, SGint x, SGint y):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseMove') and obj.evMouseMove is not None:
        obj.evMouseMove(x, y)
cdef void _evMouseWheel(SGEntity* entity, SGint wheel):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evMouseWheel') and obj.evMouseWheel is not None:
        obj.evMouseWheel(wheel)

cdef void _evKeyboardKey(SGEntity* entity, SGuint key):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evKeyboardKey') and obj.evKeyboardKey is not None:
        obj.evKeyboardKey(key)
cdef void _evKeyboardKeyPress(SGEntity* entity, SGuint key):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evKeyboardKeyPress') and obj.evKeyboardKeyPress is not None:
        obj.evKeyboardKeyPress(key)
cdef void _evKeyboardKeyRelease(SGEntity* entity, SGuint key):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evKeyboardKeyRelease') and obj.evKeyboardKeyRelease is not None:
        obj.evKeyboardKeyRelease(key)
cdef void _evKeyboardKeyRepeat(SGEntity* entity, SGuint key):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evKeyboardKeyRepeat') and obj.evKeyboardKeyRepeat is not None:
        obj.evKeyboardKeyRepeat(key)

cdef void _evKeyboardCharPress(SGEntity* entity, SGdchar chr):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evKeyboardCharPress') and obj.evKeyboardCharPress is not None:
        obj.evKeyboardCharPress(chr)
cdef void _evKeyboardCharRepeat(SGEntity* entity, SGdchar chr):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evKeyboardCharRepeat') and obj.evKeyboardCharRepeat is not None:
        obj.evKeyboardCharRepeat(chr)

# TODO: JOYSTICK
# TODO: COLLISION

cdef void _evLevelStart(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evLevelStart') and obj.evLevelStart is not None:
        obj.evLevelStart()
cdef void _evLevelEnd(SGEntity* entity):
    cdef object obj = <object>entity.data
    if hasattr(obj, 'evLevelEnd') and obj.evLevelEnd is not None:
        obj.evLevelEnd()

cdef class Entity:
    cdef SGEntity* handle
    cdef object pydata
    cdef Sprite pysprite
    cdef Mask pymask
    cdef Body pypbody
    
    def __init__(self, priority = 0.0):
        # not an error -- we WANT self.handle to be NULL, to avoid double-init's
        assert self.handle is NULL

        self.handle = sgEntityCreate(priority)
        if self.handle is NULL:
            raise MemoryError()
        self.handle.data = <void*>self
        self.handle.cbInside = _cbInside
        self.handle.lcMouseEnter = _lcMouseEnter
        self.handle.lcMouseExit = _lcMouseExit

        self.handle.lcMouseButton = _lcMouseButton
        self.handle.lcMouseButtonPress = _lcMouseButtonPress
        self.handle.lcMouseButtonRelease = _lcMouseButtonRelease
        
        self.handle.lcMouseButtonLeft = _lcMouseButtonLeft
        self.handle.lcMouseButtonLeftPress = _lcMouseButtonLeftPress
        self.handle.lcMouseButtonLeftRelease = _lcMouseButtonLeftRelease
        
        self.handle.lcMouseButtonRight = _lcMouseButtonRight
        self.handle.lcMouseButtonRightPress = _lcMouseButtonRightPress
        self.handle.lcMouseButtonRightRelease = _lcMouseButtonRightRelease
        
        self.handle.lcMouseButtonMiddle = _lcMouseButtonMiddle
        self.handle.lcMouseButtonMiddlePress = _lcMouseButtonMiddlePress
        self.handle.lcMouseButtonMiddleRelease = _lcMouseButtonMiddleRelease
        
        self.handle.lcMouseMove = _lcMouseMove
        self.handle.lcMouseWheel = _lcMouseWheel
        
        self.handle.evInit = _evInit
        self.handle.evDeinit = _evDeinit
        
        self.handle.evStart = _evStart
        self.handle.evExit = _evExit
        self.handle.evTick = _evTick
        self.handle.evTickBegin = _evTickBegin
        self.handle.evTickEnd = _evTickEnd
        self.handle.evDraw = _evDraw
        
        self.handle.evWindowOpen = _evWindowOpen
        self.handle.evWindowClose = _evWindowClose
        self.handle.evWindowResize = _evWindowResize
        
        self.handle.evMouseButton = _evMouseButton
        self.handle.evMouseButtonPress = _evMouseButtonPress
        self.handle.evMouseButtonRelease = _evMouseButtonRelease
        
        self.handle.evMouseButtonLeft = _evMouseButtonLeft
        self.handle.evMouseButtonLeftPress = _evMouseButtonLeftPress
        self.handle.evMouseButtonLeftRelease = _evMouseButtonLeftRelease
        
        self.handle.evMouseButtonRight = _evMouseButtonRight
        self.handle.evMouseButtonRightPress = _evMouseButtonRightPress
        self.handle.evMouseButtonRightRelease = _evMouseButtonRightRelease
        
        self.handle.evMouseButtonMiddle = _evMouseButtonMiddle
        self.handle.evMouseButtonMiddlePress = _evMouseButtonMiddlePress
        self.handle.evMouseButtonMiddleRelease = _evMouseButtonMiddleRelease
        
        self.handle.evMouseMove = _evMouseMove
        self.handle.evMouseWheel = _evMouseWheel
        
        self.handle.evKeyboardKey = _evKeyboardKey
        self.handle.evKeyboardKeyPress = _evKeyboardKeyPress
        self.handle.evKeyboardKeyRelease = _evKeyboardKeyRelease
        self.handle.evKeyboardKeyRepeat = _evKeyboardKeyRepeat
        
        self.handle.evKeyboardCharPress = _evKeyboardCharPress
        self.handle.evKeyboardCharRepeat = _evKeyboardCharRepeat
        
        #self.handle.evJoystickButton = _evJoystickButton
        #self.handle.evJoystickButtonPress = _evJoystickButtonPress
        #self.handle.evJoystickButtonRelease = _evJoystickButtonRelease
        
        #self.handle.evJoystickMove = _evJoystickMove
        
        # networking goes here

        #self.handle.evCollision = _evCollision
        #self.handle.evCollisionOne = _evCollisionOne
        #self.handle.evCollisionTwo = _evCollisionTwo
        
        #self.handle.evCollisionBegin = _evCollisionBegin
        #self.handle.evCollisionOneBegin = _evCollisionOneBegin
        #self.handle.evCollisionTwoBegin = _evCollisionTwoBegin
        
        #self.handle.evCollisionEnd = _evCollisionEnd
        #self.handle.evCollisionOneEnd = _evCollisionOneEnd
        #self.handle.evCollisionTwoEnd = _evCollisionTwoEnd
        
        #self.handle.evCollisionResult = _evCollisionResult
        #self.handle.evCollisionOneResult = _evCollisionOneResult
        #self.handle.evCollisionTwoResult = _evCollisionTwoResult
        
        self.handle.evLevelStart = _evLevelStart
        self.handle.evLevelEnd = _evLevelEnd
    
    def __dealloc__(self):
        if self.handle is not NULL:
            self.destroy()
    
    cpdef destroy(self):
        assert self.handle is not NULL

        sgEntityDestroy(self.handle)
        self.handle = NULL
    
    property sprite:
        def __set__(self, Sprite sprite):
            assert self.handle is not NULL
            
            self.pysprite = sprite
            if sprite is not None:
                sgEntitySetSprite(self.handle, sprite.handle)
            else:
                sgEntitySetSprite(self.handle, NULL)
        def __get__(self):
            assert self.handle is not NULL
            
            return self.pysprite
        def __del__(self):
            self.sprite = None
    
    property mask:
        def __set__(self, Mask mask):
            assert self.handle is not NULL
            
            self.pymask = mask
            if mask is not None:
                sgEntitySetMask(self.handle, mask.handle)
            else:
                sgEntitySetMask(self.handle, NULL)
        def __get__(self):
            assert self.handle is not NULL
            
            return self.pymask
        def __del__(self):
            self.mask = None
    
    property physicsBody:
        def __set__(self, Body pbody):
            assert self.handle is not NULL
            
            self.pypbody = pbody
            if pbody is not None:
                sgEntitySetPhysicsBody(self.handle, pbody.handle)
            else:
                sgEntitySetPhysicsBody(self.handle, NULL)
        def __get__(self):
            assert self.handle is not NULL
            
            return self.pypbody
        def __del__(self):
            self.physicsBody = None
    
    #property audioSource:
    #def __set__(self, src)
    #def __get__(self):
    #    return self.asource
    #def __del__(self):
    
    property pos:
        def __set__(self, p):
            assert self.handle is not NULL
            
            sgEntitySetPos(self.handle, p[0], p[1])
        def __get__(self):
            assert self.handle is not NULL
            
            cdef float x, y
            sgEntityGetPos(self.handle, &x, &y)
            return (x, y)
    property x:
        def __set__(self, x):
            assert self.handle is not NULL
            
            sgEntitySetPosX(self.handle, x)
        def __get__(self):
            assert self.handle is not NULL
            
            return sgEntityGetPosX(self.handle)
    property y:
        def __set__(self, y):
            assert self.handle is not NULL
            
            sgEntitySetPosY(self.handle, y)
        def __get__(self):
            assert self.handle is not NULL
            
            return sgEntityGetPosY(self.handle)
    
    property depth:
        def __set__(self, depth):
            assert self.handle is not NULL
            
            sgEntitySetDepth(self.handle, depth)
        def __get__(self):
            assert self.handle is not NULL
            
            return sgEntityGetDepth(self.handle)
    
    property angleRads:
        def __set__(self, rads):
            assert self.handle is not NULL
            
            sgEntitySetAngleRads(self.handle, rads)
        def __get__(self):
            assert self.handle is not NULL
            
            return sgEntityGetAngleRads(self.handle)
    
    property angleDegs:
        def __set__(self, degs):
            assert self.handle is not NULL
            
            sgEntitySetAngleDegs(self.handle, degs)
        def __get__(self):
            assert self.handle is not NULL
            
            return sgEntityGetAngleDegs(self.handle)
    
    def draw(self):
        assert self.handle is not NULL
        
        sgEntityDraw(self.handle)
    
    def evDraw(self):
        if self.handle.visible:
            self.draw()
