from __future__ import division
import random
import wx

class BoundingBox(object):
    
    def __init__(self):
        #values hardcoded to stay the same as a real example
        self.min_pointx = 559
        self.min_pointy = 506
        self.max_pointx = 1359
        self.max_pointy = 1029
        self.width = self.max_pointx - self.min_pointx
        self.height = self.max_pointy - self.min_pointy

class wxWindowsGerberCanvas(object):
    
    def __init__(self):
        self.DrawData = None
        self._BoundingBox = None
        self._transx = 0
        self._transy = 0
        self._panX = self._transx
        self._panY = self._transy
        self.ZoomPositionX = 0
        self.ZoomPositionY = 0
        self._Zoom = 0
        self.scaleX = 1.0
        self.scaleY = 1.0
        self.firstload = False
        self._BoundingBox = BoundingBox()
    
    def StartPanning(self):
        print "StartPanning"
        self._panX = self._transx
        self._panY = self._transy
    
    def Pan(self, deltaX, deltaY):
        print "Pan"
        self._transx = self._panX + (deltaX / self.scaleX)
        self._transy = self._panY + (deltaY / self.scaleY)
        self.ZoomPositionX = (self._BoundingBox.min_pointx * self.scaleX) + (-self._transx * self.scaleX)
        self.ZoomPositionY = (self._BoundingBox.min_pointy * self.scaleY) + (-self._transy * self.scaleY)
        print "ZoomPosition: ", self.ZoomPositionX, self.ZoomPositionY

    def FitToPage(self, width, height):
        print "FitToPage"
        self._Zoom = 0
        self._transx = 0
        self._transy = 0
        x = self._BoundingBox.width
        y = self._BoundingBox.height
        scaleX = x / width
        scaleY = y / height
        scaleX = 1 / scaleX
        scaleY = 1 / scaleY
        print "SetUserScale(%s, %s)"%(min(scaleX, scaleY), min(scaleX, scaleY))
        self.scaleX = min(scaleX, scaleY)
        self.scaleY = min(scaleX, scaleY)
        self.ZoomPositionX = self._BoundingBox.min_pointx * self.scaleX
        self.ZoomPositionY = self._BoundingBox.min_pointy * self.scaleY
        abuffer = wx.EmptyBitmap(self.scaleX * self._BoundingBox.width, self.scaleY * self._BoundingBox.height)
        return abuffer

    def Zoom(self, _in = True):
        print "Zoom"
        amount = 0.1
        if _in:
            self.scaleX += amount
            self.scaleY += amount
        else:
            if (self.scaleX - amount <= amount) or (self.scaleY - amount <= amount):
                return
            self.scaleX -= amount
            self.scaleY -= amount
        new_width = self._BoundingBox.width * self.scaleX
        new_height = self._BoundingBox.height * self.scaleY
        abuffer = wx.EmptyBitmap(new_width, new_height)
        self.ZoomPositionX = self._BoundingBox.min_pointx * self.scaleX
        self.ZoomPositionY = self._BoundingBox.min_pointy * self.scaleY
        
        return abuffer
        
    def Save(self, dc):
        print "Save"
        dc.SetAxisOrientation(True, True)
        dc.SetUserScale(self.scaleX, self.scaleY)
        dc.SetDeviceOrigin(0 - self.ZoomPositionX,
                                    dc.GetSizeTuple()[1] + self.ZoomPositionY
                                   )
        self.draw(dc)


    def MakeNewData(self):
        ## This method makes some random data to draw things with.
        MaxX = self._BoundingBox.max_pointx
        MaxY = self._BoundingBox.max_pointy
        MinX = self._BoundingBox.min_pointx
        MinY = self._BoundingBox.min_pointy
        DrawData = {}
        primitives_count = 1833
        # make some random rectangles
        l = []
        for i in range(primitives_count):
            w = random.randint(1,30)
            h = random.randint(1,30)
            x = random.randint(MinX,int(MaxX-w))
            y = random.randint(MinY,int(MaxY-h))
            l.append( (x,y,w,h) )
        DrawData["Rectangles"] = l
        #make some random lines
        l = []
        for i in range(primitives_count):
            x1 = random.randint(MinX,int(MaxX))
            y1 = random.randint(MinY,int(MaxY))
            x2 = random.randint(MinX,int(MaxX))
            y2 = random.randint(MinY,int(MaxY))
            l.append( (x1,y1,x2,y2) )
        DrawData["Lines"] = l

        # make some random ellipses
        l = []
        for i in range(primitives_count):
            w = random.randint(1,30)
            h = random.randint(1,30)
            x = random.randint(MinX,int(MaxX-w))
            y = random.randint(MinY,int(MaxY-h))
            l.append( (x,y,w,h) )
        DrawData["Ellipses"] = l
#
#        # Polygons
#        l = []
#        for i in range(primitives_count):
#            points = []
#            for j in range(random.randint(3,8)):
#                point = (random.randint(1,MaxX),random.randint(1,MaxY))
#                points.append(point)
#            l.append(points)
#        DrawData["Polygons"] = l
        self.DrawData = DrawData
        return DrawData

    def draw(self, dc):
        import datetime
        a = datetime.datetime.now()
        print "draw start"
        if self.DrawData != None:
            dc.BeginDrawing()
            dc.SetBackground( wx.Brush("White") )
            dc.Clear()
    
            for key, data in self.DrawData.items():
                if key == "Rectangles":
                    dc.SetBrush(wx.BLUE_BRUSH)
                    dc.SetPen(wx.Pen('VIOLET', 4))
                    dc.DrawRectangleList(data)
                    #for r in data:
                    #    dc.DrawRectangle(*r)
                elif key == "Ellipses":
                    dc.SetBrush(wx.Brush("GREEN YELLOW"))
                    dc.SetPen(wx.Pen('CADET BLUE', 2))
                    dc.DrawEllipseList(data)
                elif key == "Lines":
                    dc.SetBrush(wx.Brush("GREEN"))
                    dc.SetPen(wx.Pen('RED', 2))
                    dc.DrawLineList(data)
                    #for r in data:
                    #    dc.DrawEllipse(*r)
                elif key == "Polygons":
                    dc.SetBrush(wx.Brush("SALMON"))
                    dc.SetPen(wx.Pen('VIOLET RED', 4))
                    for r in data:
                        dc.DrawPolygon(r)
                dc.EndDrawing()
        b = datetime.datetime.now()
        delta = b - a
        print "draw end", delta.total_seconds()

    def Clear(self, dc):
        print "Clear"
        oldBrush = dc.GetBackground()
        dc.SetBackground(wx.BLACK_BRUSH)
        dc.Clear()
        dc.SetBackground(oldBrush)


class TestCanvas(wx.Panel):

    def __init__(self,parent,
                 ID=-1,
                 pos = wx.DefaultPosition,
                 size = wx.DefaultSize
                ):
        wx.Panel.__init__(self,parent,ID, pos, size)
        self.Bind(wx.EVT_SIZE, self.onSize)
        self.Bind(wx.EVT_PAINT, self.onPaint)
        self.Bind(wx.EVT_MOTION, self.onMouseMotion)
        self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
        self.Bind(wx.EVT_LEFT_DOWN, self.onMouseLeftDown)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseLeaveWindow)
        self.Bind(wx.EVT_ENTER_WINDOW, self.onMouseEnterWindow)
        self.lastLeftMouseDownX = 0
        self.lastLeftMouseDownY = 0
        self.MouseInCanvas = False
        
        self.aGerberCanvas = None
        Size  = self.GetClientSize()
        self.Buffer = wx.EmptyBitmap(Size.width, Size.height)
        #self.Buffer = None

        self.Zoom = 1
        self.deltaX = 0
        self.deltaY = 0
        self.panX = 0
        self.panY = 0
        self.BlitX = 0
        self.BlitY = 0
    
    def Setup(self):
        self.lastLeftMouseDownX = 0
        self.lastLeftMouseDownY = 0
        self.MouseInCanvas = False
        
        self.aGerberCanvas = None
        Size  = self.GetClientSize()
        self.Buffer = wx.EmptyBitmap(Size.width, Size.height)
        #self.Buffer = None

        self.Zoom = 1
        self.deltaX = 0
        self.deltaY = 0
        self.panX = 0
        self.panY = 0
        self.BlitX = 0
        self.BlitY = 0
        
        
    def UpdateDrawing(self):
        print "UpdateDrawing"
        dc = wx.MemoryDC()
        dc.SelectObject(self.Buffer)
        if self.aGerberCanvas != None:
            self.aGerberCanvas.Clear(dc)
            self.aGerberCanvas.Save(dc)
        del dc 
        self.Refresh()
        
 

    def onSize(self,event):
        print "onSize"

    def onMouseLeftDown(self, event):
        print "onMouseLeftDown"
        self.lastLeftMouseDownX = event.GetX()
        self.lastLeftMouseDownY = event.GetY() 
        self.aGerberCanvas.StartPanning()
        self.panX = self.deltaX
        self.panY = self.deltaY
      
    def onMouseLeaveWindow(self, event):
        self.MouseInCanvas = False
        
    def onMouseEnterWindow(self, event):
        self.MouseInCanvas = True 
            
    def onMouseMotion(self, event):
        print "onMouseMotion x: %s y: %s" %(event.GetX(), event.GetY())
        if event.Dragging() and event.LeftIsDown() and self.MouseInCanvas:
            currentX = event.GetX()
            currentY =  event.GetY()
            deltaX = currentX - self.lastLeftMouseDownX
            deltaY = currentY - self.lastLeftMouseDownY
            
            self.deltaX = self.panX + (deltaX / self.aGerberCanvas.scaleX)
            self.deltaY = self.panY + (deltaY / self.aGerberCanvas.scaleY)
            self.BlitX = self.deltaX * self.aGerberCanvas.scaleX
            self.BlitY = self.deltaY * self.aGerberCanvas.scaleX
            self.Refresh()

    def onMouseWheel(self, event):
        print "onMouseWheel"
        oldx = event.GetX() / self.aGerberCanvas.scaleX
        oldy = event.GetY() / self.aGerberCanvas.scaleY
        if event.GetWheelRotation() < 0:
            aBuffer = self.aGerberCanvas.Zoom(False)
        else:
            aBuffer = self.aGerberCanvas.Zoom(True)
        if aBuffer:
            self.Buffer = aBuffer
        newx = event.GetX() / self.aGerberCanvas.scaleX
        newy = event.GetY() / self.aGerberCanvas.scaleY
        self.deltaX = (newx - oldx  + self.deltaX)
        self.deltaY = (newy - oldy  + self.deltaY)
        self.BlitX = self.deltaX * self.aGerberCanvas.scaleX
        self.BlitY = self.deltaY * self.aGerberCanvas.scaleY
        print "deltaX: %s deltaY: %s"%(self.deltaX, self.deltaY)
        self.UpdateDrawing()
        self.Refresh()


    def onPaint(self,event):
        print"onPaint"
        source = wx.MemoryDC()
        source.SelectObject(self.Buffer)

        dc = wx.PaintDC(self)

        print "onPaint deltaX: %s deltaY %s"%(self.deltaX, self.deltaY)
        dc.Blit(self.BlitX, self.BlitY, source.GetSizeTuple()[0], source.GetSizeTuple()[1], source, 0, 0)




class TestFrame(wx.Frame):

    def __init__(self,
                 parent=None,
                 ID=-1,
                 title="Pan Test",
                 pos=wx.DefaultPosition,
                 size=wx.DefaultSize,
                 style=wx.DEFAULT_FRAME_STYLE):
        wx.Frame.__init__(self,parent,ID,title,pos,size,style)
        self.canvas = TestCanvas(self, pos = (0,0), size = wx.Size(400,280))
        self.button = wx.Button(self, wx.ID_ANY, "Make TestData and Draw")
        print "TestFrame Size:", self.canvas.GetClientSizeTuple()
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
        self.sizer.Add(self.button)
        self.sizer.Add(self.canvas, proportion = 1, flag = wx.ALL | wx.EXPAND)
        self.sizer.SetSizeHints(self)
        
        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.button.Bind(wx.EVT_BUTTON, self.onClick)

    def onClose(self,event):
        self.Show(False)
        self.Destroy()

    def onClick(self, event):
        print "onClick"
        self.canvas.Setup()
        self.canvas.aGerberCanvas = wxWindowsGerberCanvas()
        self.canvas.aGerberCanvas.MakeNewData()
        self.canvas.Buffer = self.canvas.aGerberCanvas.FitToPage(self.canvas.GetClientSizeTuple()[0], self.canvas.GetClientSizeTuple()[1])
        self.canvas.UpdateDrawing()



def main():
    app = wx.PySimpleApp()
    frame = TestFrame()
    frame.Show(True)
    app.MainLoop()

if __name__ == '__main__':
    main()