Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Imports Pilz.Drawing

''' <summary>
''' Contains static methods that are used for the standart PaintingObject Types.
''' </summary>
Public Class DefaultDrawMethodes

    Public Shared Sub DrawText(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject
        Dim b As New SolidBrush(obj.TextColor)
        Dim p As New PointF
        Dim rect As New Rectangle(e.X, e.Y, obj.Width, obj.Height)

        Dim f As StringFormat = StringFormat.GenericDefault
        f.Alignment = obj.HorizontalTextAlignment
        f.LineAlignment = obj.VerticalTextAlignment

        Dim zoomFactor As Single
        If obj.Parent Is Nothing Then
            zoomFactor = 1.0!
        Else
            zoomFactor = obj.Parent.ZoomFactor.Width
        End If

        e.Graphics.DrawString(obj.Text, New Font(obj.TextFont.FontFamily, obj.TextFont.Size * zoomFactor, obj.TextFont.Style), b, rect, f)
    End Sub

    Public Shared Sub DrawPicture(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject
        Dim objImg As Image
        Dim objImgSize As Size
        Dim result As RectangleF
        Dim image As Bitmap
        Dim zoomf As SizeF
        Dim hasNoParent As Boolean = e.PaintingObject.Parent Is Nothing
        Dim syncObj As Object

        If hasNoParent Then
            zoomf = New SizeF(1, 1)
            Static newSyncObj As New Object
            syncObj = newSyncObj
        Else
            zoomf = e.PaintingObject.Parent.ZoomFactor
            syncObj = e.PaintingObject.Parent
        End If

        SyncLock syncObj
            If obj?.Image Is Nothing Then Return
            objImg = obj.Image
            objImgSize = objImg.Size
        End SyncLock

        image = obj.BufferedImage
        result = CalculateImageResolution(obj, objImgSize, zoomf)

        If obj.ImageProperties.Rotate = 90 OrElse obj.ImageProperties.Rotate = 270 Then
            result = CalculateImageResolution(obj, New SizeF(objImgSize.Height, objImgSize.Width), zoomf)
        End If

        If image Is Nothing Then
            Dim needRescaleImageBecauseRot As Boolean = False

            image = DrawToNewImage(objImg, result.Size)

            Select Case obj.ImageProperties.Rotate
                Case 90
                    image.RotateFlip(RotateFlipType.Rotate90FlipNone)
                    needRescaleImageBecauseRot = True
                Case 180
                    image.RotateFlip(RotateFlipType.Rotate180FlipNone)
                Case 270
                    image.RotateFlip(RotateFlipType.Rotate270FlipNone)
                    needRescaleImageBecauseRot = True
            End Select
            If obj.ImageProperties.FlipX Then
                image.RotateFlip(RotateFlipType.RotateNoneFlipX)
            End If
            If obj.ImageProperties.FlipY Then
                image.RotateFlip(RotateFlipType.RotateNoneFlipY)
            End If

            If needRescaleImageBecauseRot Then
                result = CalculateImageResolution(obj, New SizeF(objImgSize.Height, objImgSize.Width), zoomf)
                image = DrawToNewImage(image, result.Size)
            End If

            obj.BufferedImage = image
        End If

        If image IsNot Nothing Then
            SyncLock syncObj
                e.Graphics.DrawImageUnscaled(image, New Rectangle(New Point(obj.Location.X + result.Location.X - e.Offset.X, obj.Location.Y + result.Location.Y - e.Offset.Y), result.Size.ToSize))
            End SyncLock
        End If
    End Sub

    Private Shared Function DrawToNewImage(image As Bitmap, newSize As SizeF) As Bitmap
        Dim bmp As New Bitmap(CInt(If(newSize.Width < 0, newSize.Width * -1, newSize.Width)),
                              CInt(If(newSize.Height < 0, newSize.Height * -1, newSize.Height)))
        Dim gimage As Graphics = Graphics.FromImage(bmp)
        gimage.SmoothingMode = SmoothingMode.HighQuality
        gimage.PixelOffsetMode = PixelOffsetMode.HighQuality
        gimage.PageUnit = GraphicsUnit.Pixel
        gimage.InterpolationMode = InterpolationMode.HighQualityBicubic
        gimage.DrawImage(image, New RectangleF(PointF.Empty, newSize))
        gimage.Dispose()
        Return bmp
    End Function

    Public Shared Sub DrawLine(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject
        Dim p2 As New Pen(obj.OutlineColor, obj.OutlineThicknes) With {
            .DashStyle = obj.OutlineDashStyle
        }

        If obj.LineEndCap IsNot Nothing Then
            Dim args As LineCapConfigurationArgs = obj.LineEndCap.Configure
            p2.StartCap = args.LineCap
            p2.CustomStartCap = args.CustomLineCap
        End If

        If obj.LineStartCap IsNot Nothing Then
            Dim args As LineCapConfigurationArgs = obj.LineStartCap.Configure
            p2.EndCap = args.LineCap
            p2.CustomEndCap = args.CustomLineCap
        End If

        p2.Alignment = PenAlignment.Center
        Dim no As PointF = New PointF(e.X, e.Y)
        e.Graphics.DrawLine(p2, no, no + obj.Size)
    End Sub

    Private Shared Function CalculateImageResolution(obj As PaintingObject, imageSize As SizeF, zoom As SizeF) As RectangleF
        Dim result As New RectangleF
        Dim objrect As New RectangleF(obj.Location, obj.Size)
        Dim size As SizeF = New SizeF(imageSize.Width * zoom.Width, imageSize.Height * zoom.Height)
        Dim clientRectangle As RectangleF = objrect
        Dim val As Single = clientRectangle.Width / size.Width

        clientRectangle = objrect
        Dim num As Single = Math.Min(val, clientRectangle.Height / size.Height)

        result.Width = CInt(Math.Truncate(size.Width * num))
        result.Height = CInt(Math.Truncate(size.Height * num))

        clientRectangle = objrect
        result.X = (clientRectangle.Width - result.Width) \ 2

        clientRectangle = objrect
        result.Y = (clientRectangle.Height - result.Height) \ 2

        Return result
    End Function

    Public Shared Sub DrawTriangle(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject

        Dim p1 As New Point(obj.Size.Width / 2 + e.X, e.Y)
        Dim p2 As New Point(e.X, e.Y + obj.Size.Height)
        Dim p3 As New Point(e.X + obj.Size.Width, e.Y + obj.Size.Height)

        If obj.EnableFill Then
            Dim b As New SolidBrush(obj.FillColor)
            e.Graphics.FillPolygon(b, {p1, p2, p3})
        End If

        If obj.EnableOutline Then
            Dim lw As Single = obj.OutlineThicknes
            Dim p As New Pen(obj.OutlineColor, obj.OutlineThicknes) With {.DashStyle = obj.OutlineDashStyle, .Alignment = PenAlignment.Inset}
            e.Graphics.DrawPolygon(p, {p1, p2, p3})
        End If
    End Sub

    Public Shared Sub DrawRectangle(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject
        Dim hol As Single = obj.OutlineThicknes / 2

        If obj.EnableFill Then
            Dim b As New SolidBrush(obj.FillColor)
            Dim rect As Rectangle = If(obj.EnableOutline,
                New Rectangle(e.X + hol, e.Y + hol, obj.Size.Width - hol * 2, obj.Size.Height - hol * 2),
                New Rectangle(e.X, e.Y, obj.Size.Width, obj.Size.Height))
            e.Graphics.FillRectangle(b, rect)
        End If

        If obj.EnableOutline Then
            Dim p As New Pen(obj.OutlineColor, obj.OutlineThicknes) With {.DashStyle = obj.OutlineDashStyle, .Alignment = PenAlignment.Inset}
            Dim rect As New Rectangle(e.X, e.Y, obj.Size.Width, obj.Size.Height)
            e.Graphics.DrawRectangle(p, rect)
        End If
    End Sub

    Public Shared Sub DrawEllipse(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject

        If obj.EnableFill Then
            Dim b As New SolidBrush(obj.FillColor)
            Dim rect As Rectangle = New Rectangle(e.X, e.Y, obj.Size.Width, obj.Size.Height)
            e.Graphics.FillEllipse(b, rect)
        End If

        If obj.EnableOutline Then
            Dim p As New Pen(obj.OutlineColor, obj.OutlineThicknes) With {.DashStyle = obj.OutlineDashStyle, .Alignment = PenAlignment.Inset}
            Dim rect As New Rectangle(e.X, e.Y, obj.Size.Width, obj.Size.Height)
            e.Graphics.DrawEllipse(p, rect)
        End If
    End Sub

    Public Shared Sub DrawSelection(e As PaintingObjectPaintEventArgs)
        Dim obj As PaintingObject = e.PaintingObject
        Dim lw As Single = 2.5!
        Dim hlw As Single = lw / 2
        Dim hlwphol As Single = hlw '+ hol
        Dim hlwpholm2 As Single = hlwphol * 2

        Dim p As New Pen(Color.CornflowerBlue, lw) With {.DashStyle = obj.SelectionDashStyle, .Alignment = PenAlignment.Outset}
        Dim rect As New Rectangle(e.X - hlwphol, e.Y - hlwphol, obj.Size.Width + hlwpholm2, obj.Size.Height + hlwpholm2)
        e.Graphics.DrawRectangle(p, rect)
    End Sub

    Public Shared Sub DrawGrid(e As PaintEventArgs, pc As PaintingControl, offset As PointF)
        Dim p As New Pen(pc.GridColor, 0.5)

        Dim curX As Integer = pc.GridChunkSize.Width * pc.ZoomFactor.Width - offset.X
        Do While curX < pc.Width
            e.Graphics.DrawLine(p, curX, -offset.Y, curX, pc.Height)
            curX += (pc.GridChunkSize.Width * pc.ZoomFactor.Width)
        Loop

        Dim curY As Integer = pc.GridChunkSize.Height * pc.ZoomFactor.Height - offset.Y
        Do While curY < pc.Height
            e.Graphics.DrawLine(p, -offset.X, curY, pc.Width, curY)
            curY += (pc.GridChunkSize.Height * pc.ZoomFactor.Height)
        Loop
    End Sub

    Public Shared Sub DrawAreaSelection(e As PaintEventArgs, pc As PaintingControl, startMousePos As PointF, lastMousePos As PointF)
        Dim rectToDraw As RectangleF = HelpfulDrawingFunctions.GetRectangle(startMousePos, lastMousePos)
        Dim p As New Pen(pc.AreaSelectionColor)
        p.DashStyle = If(startMousePos.X >= lastMousePos.X, DashStyle.DashDot, DashStyle.Solid)
        p.Width = 3
        e.Graphics.DrawRectangle(p, rectToDraw.X, rectToDraw.Y, rectToDraw.Width, rectToDraw.Height)
    End Sub

End Class
