# encoding: utf-8
 
import weakref
 
from flappy import _core
from flappy._core import _DisplayObject
from flappy.events import EventDispatcher, Event, EventPhase
from flappy.geom import Transform, ColorTransform, Matrix, Rectangle, Point
from flappy.display import Graphics, BitmapData
 
 
class DisplayObject(_DisplayObject, EventDispatcher):
 
    def __init__(self, name=None):
        self._native_init()
        EventDispatcher.__init__(self, None)
 
        self._parent = None
        if name is None:
            self.name = self.__class__.__name__ + ' #' + str(self.id)
        else:
            self.name = name
        self._graphics = None
        self._scroll_rect = None
 
    def _native_init(self):
        _DisplayObject.__init__(self)
 
    def _dispatch_event(self, e):
        if e.target == None:
            e.target = self
        e.currentTarget = self
        return EventDispatcher.dispatchEvent(self, e)
 
    def _broadcast(self, e):
        self._dispatch_event(e)
 
    def dispatchEvent(self, e):
        ret = self._dispatch_event(e)
        if e.isCancelled:
            return True
        if e.bubbles and self.parent:
            self.parent.dispatchEvent(e)
        return ret
 
    def getBounds(self, coordinate_space):
        return self._getBounds(coordinate_space, True)        
 
    def getRect(self, coordinate_space):
        return self._getBounds(coordinate_space, False)
 
    def globalToLocal(self, point):
        return _DisplayObject.globalToLocal(self, point)
 
    def localToGlobal(self, point):
        return _DisplayObject.localToGlobal(self, point)
 
    def hitTestObject(self, obj):
        if not (obj and obj.parent and self.parent):
            return False
 
        cur_mat = self.transform.concatenatedMatrix
        target_mat = obj.transform.concatenatedMatrix
 
        xpoint = Point(1.0, 0.0)
        ypoint = Point(0.0, 1.0)
 
        obj_width = self.width * cur_mat.deltaTransformPoint(xpoint).length
        obj_height = self.height * cur_mat.deltaTransformPoint(ypoint).length
        tgt_width = obj.width * target_mat.deltaTransformPoint(xpoint).length
        tgt_height = obj.height * target_mat.deltaTransformPoint(ypoint).length
 
        cur_rect = Rectangle(cur_mat.tx, cur_mat.ty, obj_width, obj_height)
        target_rect = Rectangle(target_mat.tx, target_mat.ty, 
                                            tgt_width, tgt_height)
 
        return cur_rect.intersects(target_rect)
 
    def hitTestPoint(self, x, y, shape_flag=False):
        return self._hitTestPoint(x, y, shape_flag, True)
 
    def _find_by_id(self, obj_id):
        if self.id == obj_id:
            return self
        return None
 
    def _get_interactive_object_stack(self, stack):
        from flappy.display import InteractiveObject
 
        if isinstance(self, InteractiveObject):
            stack.append(self)
        if self.parent:
            self.parent._get_interactive_object_stack(stack)
 
    def _fire_event(self, e):
        stack = []
 
        if self.parent:
            self.parent._get_interactive_object_stack(stack)
 
        ln = len(stack)
    #capturing     
        if ln:
            e.eventPhase = EventPhase.CAPTURING_PHASE
            stack.reverse()
 
            for obj in stack:
                e.currentTarget = obj
                obj._dispatch_event(e)
 
                if e.isCancelled:
                    return
    #target
        e.eventPhase = EventPhase.AT_TARGET
        e.currentTarget = self
        self._dispatch_event(e)
 
        if e.isCancelled:
            return
 
    #bubbling
        if e.bubbles:
            e.eventPhase = EventPhase.BUBBLING_PHASE
            stack.reverse()
 
            for obj in stack:
                e.currentTarget = obj
                obj._dispatch_event(e)
 
                if e.isCancelled:
                    return
 
    def _on_added(self, obj, is_on_stage):
        if obj == self:
            evt = Event(Event.ADDED, True, False)
            evt.target = obj
            self.dispatchEvent(evt)
 
        if is_on_stage:
            evt = Event(Event.ADDED_TO_STAGE, False, False)
            evt.target = obj
            self.dispatchEvent(evt)    
 
    def _on_removed(self, obj, was_on_stage):
        if obj == self:
            evt = Event(Event.REMOVED, True, False)
            evt.target = obj
            self.dispatchEvent(evt)
 
        if was_on_stage:
            evt = Event(Event.REMOVED_FROM_STAGE, False, False)
            evt.target = obj
            self.dispatchEvent(evt)
 
    def _set_parent(self, parent):
        if self.parent == parent:
            return parent
 
        if self.parent is not None:
            self.parent._remove_child_from_array(self)
 
        if self.parent is None and parent is not None:
            self._parent = weakref.ref(parent)
            self._on_added(self, parent.stage is not None)
        elif self.parent and not parent:
            self._parent = None
            self._on_removed(self, self.stage is not None)
        else:
            self._parent = weakref.ref(parent) if parent != None else None
 
        return parent
 
    def _get_objects_under_point(self, p, result):
        if self._hitTestPoint(p.x, p.y, True, False):
            result.append(self)
 
    def rotateAroundPoint(self, x, y, deg):
        m = self.transform.matrix
        pt = Point(x, y)
        pt = m.transformPoint(pt)
        m.translate(-pt.x, -pt.y)
        m.rotate(deg)
        m.translate(pt.x, pt.y)
        self.transform.matrix = m
 
    def drawToBitmapData(self, bitmap_data, matrix=Matrix(),
                            color_transform=ColorTransform(), 
                                blend_mode=0, clip_rect=None):
        _DisplayObject._draw_to_surface(self, bitmap_data, matrix, 
                                    color_transform, blend_mode, clip_rect)
 
#id
    @property
    def id(self):
        return self.getID()
 
#name
    @property
    def name(self):
        return self.getName()
 
    @name.setter
    def name(self, value):
        self.setName(value)
 
#alpha
    @property 
    def alpha(self):
        return self.getAlpha()
 
    @alpha.setter
    def alpha(self, value):
        self.setAlpha(value)
 
#x
    @property 
    def x(self):
        return self.getX()
 
    @x.setter
    def x(self, value):
        self.setX(value)
 
#y
    @property 
    def y(self):
        return self.getY()
 
    @y.setter
    def y(self, value):
        self.setY(value)
 
#globalX-Y
    @property
    def globalX(self):
        if self.parent:
            return self.x + self.parent.globalX
        return 0.0
 
    @property
    def globalY(self):
        if self.parent:
            return self.y + self.parent.globalY
        return 0.0
 
#width
    @property 
    def width(self):
        return self.getWidth()
 
    @width.setter
    def width(self, value):
        self.setWidth(value)
 
#height
    @property 
    def height(self):
        return self.getHeight()
 
    @height.setter
    def height(self, value):
        self.setHeight(value)
 
#scale
    @property
    def scaleX(self):
        return self.getScaleX()
 
    @scaleX.setter
    def scaleX(self, value):
        self.setScaleX(float(value))    
 
    @property
    def scaleY(self):
        return self.getScaleY()
 
    @scaleY.setter
    def scaleY(self, value):
        self.setScaleY(float(value))
 
#visible
    @property 
    def visible(self):
        return self.getVisible()
 
    @visible.setter
    def visible(self, value):
        self.setVisible(value)
 
#transform
    @property 
    def transform(self):
        return Transform(self)
 
    @transform.setter
    def transform(self, trans):
        self._setMatrix(trans.matrix)
        self._setColorTransform(trans.colorTransform)
        return trans
 
#stage
    @property
    def stage(self):
        if self.parent is not None:
            return self.parent.stage
        return None    
 
    @property
    def root(self):
        return self.stage
 
#graphics
    @property
    def graphics(self):
        if not self._graphics:
            self._graphics = self.getGraphics()
        return self._graphics
 
    def getGraphics(self):
        return Graphics(self)
 
#parent
    @property
    def parent(self):
        if isinstance(self._parent, weakref.ref):
            return self._parent()
        else:
            return self._parent
 
#opaqueBackground
    @property
    def opaqueBackground(self):
        return self.getOpaqueBackground()
 
    @opaqueBackground.setter
    def opaqueBackground(self, value):
        self.setOpaqueBackground(value)
 
#scrollRect
    @property
    def scrollRect(self):
        return self._scroll_rect;
 
    @scrollRect.setter
    def scrollRect(self, value):
        self._scroll_rect = value
        self.setScrollRect(value)
 
    @property
    def cacheAsBitmap(self):
        return self.getCacheAsBitmap()
 
    @cacheAsBitmap.setter
    def cacheAsBitmap(self, value):
        self.setCacheAsBitmap(value)
 
    @property
    def rotation(self):
        return self.getRotation()
 
    @rotation.setter
    def rotation(self, value):
        self.setRotation(value)