from orpg.mapper.base import *
import wx

FACE_NONE = 0
FACE_NORTH = 1
FACE_NORTHEAST = 2
FACE_EAST = 3
FACE_SOUTHEAST = 4
FACE_SOUTH = 5
FACE_SOUTHWEST = 6
FACE_WEST = 7
FACE_NORTHWEST = 8
SNAPTO_ALIGN_CENTER = 0
SNAPTO_ALIGN_TL = 1

class WhiteboardMini:
    def __init__(self, id,path, image, pos=cmpPoint(0,0), heading=FACE_NONE, face=FACE_NONE, label="", locked=False, hide=False, snap_to_align=SNAPTO_ALIGN_CENTER, zorder=0, width=0, height=0, log=None):
        self.log = log
        self.heading = heading
        self.face = face
        self.label = label
        self.path = path
        self.pos = pos
        self.selected = False
        self.locked = locked
        self.snap_to_align = snap_to_align
        self.hide = hide
        self.id = id
        self.zorder = zorder
        self.left = 0
        if not width:
            self.width = 0
        else:
            self.width = width
        if not height:
            self.height = 0
        else:
            self.height = height
        self.right = image.GetWidth()
        self.top = 0
        self.bottom = image.GetHeight()
        self.isUpdated = False
        self.gray = False

        self.set_image(image)

    @classmethod
    def create_from_dom(cls, xml_dom):
        pos = cmpPoint(int(c.getAttribute('posx')),int(c.getAttribute('posy')))
        path = urllib.unquote(c.getAttribute('path'))
        label = c.getAttribute('label')
        height = width = heading = face = snap_to_align = zorder = 0
        locked = hide = False

        if c.hasAttribute('height'):
            height = int(c.getAttribute('height'))
        if c.hasAttribute('width'):
            width = int(c.getAttribute('width'))
        if c.getAttribute('locked') == 'True' or c.getAttribute('locked') == '1':
            locked = True
        if c.getAttribute('hide') == 'True' or c.getAttribute('hide') == '1':
            hide = True
        if c.getAttribute('heading'):
            heading = int(c.getAttribute('heading'))
        if c.hasAttribute('face'):
            face = int(c.getAttribute('face'))
        if c.hasAttribute('align'):
            snap_to_align = int(c.getAttribute('align'))
        if c.getAttribute('zorder'):
            zorder = int(c.getAttribute('zorder'))

        mini = WhiteboardMini(id, path, ImageHandler.load(path, "miniature", id),
                              pos, heading, face, label, locked, hide,
                              snap_to_align, zorder, width, height, self.log)

        return mini

    def set_image(self, image):
        self.image = image
        self.image.ConvertAlphaToMask()
        self.generate_bmps();

    def generate_bmps(self):
        if self.width:
            image = self.image.Copy()
            image.Rescale(int(self.width), int(self.height))
        else:
            image = self.image
        self.bmp = image.ConvertToBitmap()
        self.bmp_gray = image.ConvertToGreyscale().ConvertToBitmap()

    def set_min_props(self, heading=FACE_NONE, face=FACE_NONE, label="", locked=False, hide=False, width=0, height=0):
        self.heading = heading
        self.face = face
        self.label = label
        if locked:
            self.locked = True
        else:
            self.locked = False
        if hide:
            self.hide = True
        else:
            self.hide = False
        self.width = int(width)
        self.height = int(height)
        self.isUpdated = True
        self.generate_bmps()

    def move(self, delta):
        self.pos.x += delta.x
        self.pos.y += delta.y
        self.is_updated = True

    def hit_test(self, pt, dc):
        self.log.log("Enter BmpMiniature->hit_test(self, pt)", ORPG_DEBUG)
        rect = self.get_rect()
        result = None
        result = rect.InsideXY(pt.x, pt.y)
        self.log.log("Exit BmpMiniature->hit_test(self, pt)", ORPG_DEBUG)
        return result

    def highlight(self, highlight = True):
        self.selected = highlight

    def get_rect(self):
        self.log.log("Enter BmpMiniature->get_rect(self)", ORPG_DEBUG)
        ret = wx.Rect(self.pos.x, self.pos.y, self.image.GetWidth(), self.image.GetHeight())
        self.log.log("Exit BmpMiniature->get_rect(self)", ORPG_DEBUG)
        return ret

    def draw(self, mini_layer, dc, op=wx.COPY):
        # check if hidden and GM: we outline the mini in grey (little bit smaller than the actual size)
        # and write the label in the center of the mini
        if self.hide and mini_layer.canvas.frame.session.my_role() == mini_layer.canvas.frame.session.ROLE_GM:
            self.log.log("Enter BmpMiniature->draw->Draw Hidden", ORPG_DEBUG)
            self.left = 0
            self.right = self.bmp.GetWidth()
            self.top = 0
            self.bottom = self.bmp.GetHeight()
            # grey outline
            graypen = wx.Pen("gray", 1, wx.DOT)
            dc.SetPen(graypen)
            dc.SetBrush(wx.TRANSPARENT_BRUSH)
            if self.bmp.GetWidth() <= 20:
                xoffset = 1
            else:
                xoffset = 5
            if self.bmp.GetHeight() <= 20:
                yoffset = 1
            else:
                yoffset = 5
            dc.DrawRectangle(self.pos.x + xoffset, self.pos.y + yoffset, self.bmp.GetWidth() - (xoffset * 2), self.bmp.GetHeight() - (yoffset * 2))
            dc.SetBrush(wx.NullBrush)
            dc.SetPen(wx.NullPen)

            ## draw label in the center of the mini
            if mini_layer.show_labels:
                label = self.label
                if len(label):
                    dc.SetTextForeground(wx.RED)
                    (textWidth,textHeight) = dc.GetTextExtent(label)
                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
                    y = self.pos.y + (self.bmp.GetHeight() / 2)
                    dc.SetPen(wx.GREY_PEN)
                    dc.SetBrush(wx.LIGHT_GREY_BRUSH)
                    dc.DrawRectangle(x, y, textWidth+2, textHeight+2)
                    if (textWidth+2 > self.right):
                        self.right += int((textWidth+2-self.right)/2)+1
                        self.left -= int((textWidth+2-self.right)/2)+1
                    self.bottom = y+textHeight+2-self.pos.y
                    dc.SetPen(wx.NullPen)
                    dc.SetBrush(wx.NullBrush)
                    dc.DrawText(label, x+1, y+1)

            #selected outline
            if self.selected:
                dc.SetPen(wx.RED_PEN)
                dc.SetBrush(wx.TRANSPARENT_BRUSH)
                dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
                dc.SetBrush(wx.NullBrush)
                dc.SetPen(wx.NullPen)
            self.log.log("Exit BmpMiniature->draw->Draw Hidden", ORPG_DEBUG)
            return True

        elif not self.hide:
            self.log.log("Enter BmpMiniature->draw->Not Hidden", ORPG_DEBUG)
            # set the width and height of the image
            if self.gray:
                bmp = self.bmp_gray
            else:
                bmp = self.bmp
            dc.DrawBitmap(bmp, self.pos.x, self.pos.y, True)
            self.left = 0
            self.right = self.bmp.GetWidth()
            self.top = 0
            self.bottom = self.bmp.GetHeight()

            # Draw the facing marker if needed
            if self.face != 0:
                x_mid = self.pos.x + (self.bmp.GetWidth()/2)
                x_right = self.pos.x + self.bmp.GetWidth()
                y_mid = self.pos.y + (self.bmp.GetHeight()/2)
                y_bottom = self.pos.y + self.bmp.GetHeight()

                dc.SetPen(wx.WHITE_PEN)
                dc.SetBrush(wx.RED_BRUSH)
                triangle = []

                # Figure out which direction to draw the marker!!
                if self.face == FACE_WEST:
                    triangle.append(cmpPoint(self.pos.x,self.pos.y))
                    triangle.append(cmpPoint(self.pos.x - 5, y_mid))
                    triangle.append(cmpPoint(self.pos.x, y_bottom))
                elif self.face ==  FACE_EAST:
                    triangle.append(cmpPoint(x_right, self.pos.y))
                    triangle.append(cmpPoint(x_right + 5, y_mid))
                    triangle.append(cmpPoint(x_right, y_bottom))
                elif self.face ==  FACE_SOUTH:
                    triangle.append(cmpPoint(self.pos.x, y_bottom))
                    triangle.append(cmpPoint(x_mid, y_bottom + 5))
                    triangle.append(cmpPoint(x_right, y_bottom))
                elif self.face ==  FACE_NORTH:
                    triangle.append(cmpPoint(self.pos.x, self.pos.y))
                    triangle.append(cmpPoint(x_mid, self.pos.y - 5))
                    triangle.append(cmpPoint(x_right, self.pos.y))
                elif self.face == FACE_NORTHEAST:
                    triangle.append(cmpPoint(x_mid, self.pos.y))
                    triangle.append(cmpPoint(x_right + 5, self.pos.y - 5))
                    triangle.append(cmpPoint(x_right, y_mid))
                    triangle.append(cmpPoint(x_right, self.pos.y))
                elif self.face == FACE_SOUTHEAST:
                    triangle.append(cmpPoint(x_right, y_mid))
                    triangle.append(cmpPoint(x_right + 5, y_bottom + 5))
                    triangle.append(cmpPoint(x_mid, y_bottom))
                    triangle.append(cmpPoint(x_right, y_bottom))
                elif self.face == FACE_SOUTHWEST:
                    triangle.append(cmpPoint(x_mid, y_bottom))
                    triangle.append(cmpPoint(self.pos.x - 5, y_bottom + 5))
                    triangle.append(cmpPoint(self.pos.x, y_mid))
                    triangle.append(cmpPoint(self.pos.x, y_bottom))
                elif self.face == FACE_NORTHWEST:
                    triangle.append(cmpPoint(self.pos.x, y_mid))
                    triangle.append(cmpPoint(self.pos.x - 5, self.pos.y - 5))
                    triangle.append(cmpPoint(x_mid, self.pos.y))
                    triangle.append(cmpPoint(self.pos.x, self.pos.y))
                dc.DrawPolygon(triangle)
                dc.SetBrush(wx.NullBrush)
                dc.SetPen(wx.NullPen)

            # Draw the heading if needed
            if self.heading:
                x_adjust = 0
                y_adjust = 4
                x_half = self.bmp.GetWidth()/2
                y_half = self.bmp.GetHeight()/2
                x_quarter = self.bmp.GetWidth()/4
                y_quarter = self.bmp.GetHeight()/4
                x_3quarter = x_quarter*3
                y_3quarter = y_quarter*3
                x_full = self.bmp.GetWidth()
                y_full = self.bmp.GetHeight()
                x_center = self.pos.x + x_half
                y_center = self.pos.y + y_half

                # Remember, the pen/brush must be a different color than the
                # facing marker!!!!  We'll use black/cyan for starters.
                # Also notice that we will draw the heading on top of the
                # larger facing marker.
                dc.SetPen(wx.BLACK_PEN)
                dc.SetBrush(wx.CYAN_BRUSH)
                triangle = []

                # Figure out which direction to draw the marker!!
                if self.heading == FACE_NORTH:
                    triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
                    triangle.append(cmpPoint(x_center, y_center - y_3quarter ))
                    triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
                elif self.heading ==  FACE_SOUTH:
                    triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
                    triangle.append(cmpPoint(x_center, y_center + y_3quarter ))
                    triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
                elif self.heading == FACE_NORTHEAST:
                    triangle.append(cmpPoint(x_center + x_quarter, y_center - y_half ))
                    triangle.append(cmpPoint(x_center + x_3quarter, y_center - y_3quarter ))
                    triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
                elif self.heading == FACE_EAST:
                    triangle.append(cmpPoint(x_center + x_half, y_center - y_quarter ))
                    triangle.append(cmpPoint(x_center + x_3quarter, y_center ))
                    triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
                elif self.heading == FACE_SOUTHEAST:
                    triangle.append(cmpPoint(x_center + x_half, y_center + y_quarter ))
                    triangle.append(cmpPoint(x_center + x_3quarter, y_center + y_3quarter ))
                    triangle.append(cmpPoint(x_center + x_quarter, y_center + y_half ))
                elif self.heading == FACE_SOUTHWEST:
                    triangle.append(cmpPoint(x_center - x_quarter, y_center + y_half ))
                    triangle.append(cmpPoint(x_center - x_3quarter, y_center + y_3quarter ))
                    triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
                elif self.heading == FACE_WEST:
                    triangle.append(cmpPoint(x_center - x_half, y_center + y_quarter ))
                    triangle.append(cmpPoint(x_center - x_3quarter, y_center ))
                    triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
                elif self.heading == FACE_NORTHWEST:
                    triangle.append(cmpPoint(x_center - x_half, y_center - y_quarter ))
                    triangle.append(cmpPoint(x_center - x_3quarter, y_center - y_3quarter ))
                    triangle.append(cmpPoint(x_center - x_quarter, y_center - y_half ))
                dc.DrawPolygon(triangle)
                dc.SetBrush(wx.NullBrush)
                dc.SetPen(wx.NullPen)
            #selected outline
            if self.selected:
                dc.SetPen(wx.RED_PEN)
                dc.SetBrush(wx.TRANSPARENT_BRUSH)
                dc.DrawRectangle(self.pos.x, self.pos.y, self.bmp.GetWidth(), self.bmp.GetHeight())
                dc.SetBrush(wx.NullBrush)
                dc.SetPen(wx.NullPen)
            # draw label
            if mini_layer.show_labels:
                label = self.label
                if len(label):
                    dc.SetTextForeground(wx.RED)
                    (textWidth,textHeight) = dc.GetTextExtent(label)
                    x = self.pos.x +((self.bmp.GetWidth() - textWidth) /2) - 1
                    y = self.pos.y + self.bmp.GetHeight() + 6
                    dc.SetPen(wx.WHITE_PEN)
                    dc.SetBrush(wx.WHITE_BRUSH)
                    dc.DrawRectangle(x,y,textWidth+2,textHeight+2)
                    if (textWidth+2 > self.right):
                        self.right += int((textWidth+2-self.right)/2)+1
                        self.left -= int((textWidth+2-self.right)/2)+1
                        self.bottom = y+textHeight+2-self.pos.y
                        dc.SetPen(wx.NullPen)
                        dc.SetBrush(wx.NullBrush)
                        dc.DrawText(label,x+1,y+1)
            self.top-=5
            self.bottom+=5
            self.left-=5
            self.right+=5
        return True

    def toxml(self, action="update"):
        self.log.log("Enter BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
        if action == "del":
            xml_str = "<miniature action='del' id='" + self.id + "'/>"
            self.log.log(xml_str, ORPG_DEBUG)
            self.log.log("Exit BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
            return xml_str
        xml_str = "<miniature"
        xml_str += " action='" + action + "'"
        xml_str += " label='" + self.label + "'"
        xml_str+= " id='" + self.id + "'"
        if self.pos != None:
            xml_str += " posx='" + str(self.pos.x) + "'"
            xml_str += " posy='" + str(self.pos.y) + "'"
        if self.heading != None:
            xml_str += " heading='" + str(self.heading) + "'"
        if self.face != None:
            xml_str += " face='" + str(self.face) + "'"
        if self.path != None:
            xml_str += " path='" + urllib.quote(self.path).replace('%3A', ':') + "'"
        if self.locked:
            xml_str += "  locked='1'"
        else:
            xml_str += "  locked='0'"
        if self.hide:
            xml_str += " hide='1'"
        else:
            xml_str += " hide='0'"
        if self.snap_to_align != None:
            xml_str += " align='" + str(self.snap_to_align) + "'"
        if self.id != None:
            xml_str += " zorder='" + str(self.zorder) + "'"
        if self.width != None:
            xml_str += " width='" + str(self.width) + "'"
        if self.height != None:
            xml_str += " height='" + str(self.height) + "'"
        xml_str += " />"
        self.log.log(xml_str, ORPG_DEBUG)
        self.log.log("Exit BmpMiniature->toxml(self, " + action + ")", ORPG_DEBUG)
        if (action == "update" and self.isUpdated) or action == "new":
            self.isUpdated = False
            return xml_str
        else:
            return ''

    def takedom(self, xml_dom):
        self.log.log("Enter BmpMiniature->takedom(self, xml_dom)", ORPG_DEBUG)
        self.id = xml_dom.getAttribute("id")
        self.log.log("self.id=" + str(self.id), ORPG_DEBUG)
        if xml_dom.hasAttribute("posx"):
            self.pos.x = int(xml_dom.getAttribute("posx"))
            self.log.log("self.pos.x=" + str(self.pos.x), ORPG_DEBUG)
        if xml_dom.hasAttribute("posy"):
            self.pos.y = int(xml_dom.getAttribute("posy"))
            self.log.log("self.pos.y=" + str(self.pos.y), ORPG_DEBUG)
        if xml_dom.hasAttribute("heading"):
            self.heading = int(xml_dom.getAttribute("heading"))
            self.log.log("self.heading=" + str(self.heading), ORPG_DEBUG)
        if xml_dom.hasAttribute("face"):
            self.face = int(xml_dom.getAttribute("face"))
            self.log.log("self.face=" + str(self.face), ORPG_DEBUG)
        if xml_dom.hasAttribute("path"):
            self.path = urllib.unquote(xml_dom.getAttribute("path"))
            self.set_image(ImageHandler.load(self.path, "miniature", self.id))
            self.log.log("self.path=" + self.path, ORPG_DEBUG)
        if xml_dom.hasAttribute("locked"):
            if xml_dom.getAttribute("locked") == '1' or xml_dom.getAttribute("locked") == 'True':
                self.locked = True
            else:
                self.locked = False
            self.log.log("self.locked=" + str(self.locked), ORPG_DEBUG)
        if xml_dom.hasAttribute("hide"):
            if xml_dom.getAttribute("hide") == '1' or xml_dom.getAttribute("hide") == 'True':
                self.hide = True
            else:
                self.hide = False
            self.log.log("self.hide=" + str(self.hide), ORPG_DEBUG)
        if xml_dom.hasAttribute("label"):
            self.label = xml_dom.getAttribute("label")
            self.log.log("self.label=" + self.label, ORPG_DEBUG)
        if xml_dom.hasAttribute("zorder"):
            self.zorder = int(xml_dom.getAttribute("zorder"))
            self.log.log("self.zorder=" + str(self.zorder), ORPG_DEBUG)
        if xml_dom.hasAttribute("align"):
            if xml_dom.getAttribute("align") == '1' or xml_dom.getAttribute("align") == 'True':
                self.snap_to_align = 1
            else:
                self.snap_to_align = 0
            self.log.log("self.snap_to_align=" + str(self.snap_to_align), ORPG_DEBUG)
        if xml_dom.hasAttribute("width"):
            self.width = int(xml_dom.getAttribute("width"))
            self.log.log("self.width=" + str(self.width), ORPG_DEBUG)
        if xml_dom.hasAttribute("height"):
            self.height = int(xml_dom.getAttribute("height"))
            self.log.log("self.height=" + str(self.height), ORPG_DEBUG)
        self.log.log("Exit BmpMiniature->takedom(self, xml_dom)", ORPG_DEBUG)

