Imports System.ComponentModel
Imports System.Web.UI
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Net
Imports System.IO
Imports System.Drawing.Text
Imports System.Math

<DefaultProperty("Text"), ToolboxData("<{0}:NetGraph runat=server></{0}:NetGraph>")> Public Class NetGraph
    Inherits System.Web.UI.WebControls.WebControl

    Event GraphBinding(ByVal sender As Object, ByVal e As DataValues)
    Event AfterRenderBackground(ByVal sender As Object, ByVal e As JpgRenderEventArgs)
    Event BeforeFlushResponse(ByVal sender As Object, ByVal e As JpgRenderEventArgs)


    Dim _text As String
    Dim _DefaultColors() As Color = New Color() {Color.Blue, Color.Red, Color.Green, Color.Orange, Color.Yellow, _
        Color.Purple, Color.Gray, Color.Brown, Color.Cyan, Color.Gold, Color.Pink, Color.Salmon}


#Region "Public Properties"
    <System.ComponentModel.Description("The color used to create a gradient background"), System.ComponentModel.Category("Appearance")> _
    Public Property GradientColor() As Color
        Get
            Try
                Return CType(viewstate("GradientColor"), Color)
            Catch ex As Exception
                Dim Clr As Color = Color.Empty
                Return Clr
            End Try
        End Get
        Set(ByVal Value As Color)
            viewstate("GradientColor") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Range 0-100, specifies the Opacity of the fill under a line graph"), System.ComponentModel.DefaultValue(50), System.ComponentModel.Category("Appearance")> _
    Public Property FillOpacity() As Integer
        Get
            Try
                Return CInt(viewstate("FillOpacity"))
            Catch ex As Exception
                Return 50
            End Try
        End Get
        Set(ByVal Value As Integer)
            viewstate("FillOpacity") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Range 0-360, specifies the angle of the background gradient"), System.ComponentModel.DefaultValue(0), System.ComponentModel.Category("Appearance")> _
    Public Property GradientAngle() As Integer
        Get
            Try
                Return CInt(viewstate("GradientAngle"))
            Catch ex As Exception
                Return 0
            End Try
        End Get
        Set(ByVal Value As Integer)
            viewstate("GradientAngle") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the line color used for rendering graphs"), System.ComponentModel.DefaultValue(GetType(System.Drawing.Color), "Black"), System.ComponentModel.Category("Appearance")> _
    Public Property LineColor() As Color
        Get
            Try
                Return CType(viewstate("LineColor"), Color)
            Catch ex As Exception
                Return Color.Black
            End Try
        End Get
        Set(ByVal Value As Color)
            viewstate("LineColor") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the fill color for region under a line graph"), System.ComponentModel.DefaultValue(GetType(System.Drawing.Color), "Lime"), System.ComponentModel.Category("Appearance")> _
        Public Property FillColor() As Color
        Get
            Try
                Return CType(viewstate("FillColor"), Color)
            Catch ex As Exception
                Return Color.Lime
            End Try
        End Get
        Set(ByVal Value As Color)
            viewstate("FillColor") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the Jpeg quality for Jpeg graphs."), System.ComponentModel.DefaultValue(GetType(GraphQuality), "Best"), System.ComponentModel.Category("Appearance")> _
        Public Property GraphQuality() As GraphQuality
        Get
            Try
                Return CType(viewstate("GraphQuality"), GraphQuality)
            Catch ex As Exception
                Return GraphQuality.Best
            End Try
        End Get
        Set(ByVal Value As GraphQuality)
            viewstate("GraphQuality") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the color of the grid lines on bar and line graphs"), System.ComponentModel.DefaultValue(GetType(System.Drawing.Color), "Black"), System.ComponentModel.Category("Appearance")> _
        Public Property GridLineColor() As Color
        Get
            Try
                Return CType(viewstate("GridLineColor"), Color)
            Catch ex As Exception
                Return Color.Black
            End Try
        End Get
        Set(ByVal Value As Color)
            viewstate("GridLineColor") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the type of graph"), System.ComponentModel.DefaultValue(GetType(GraphType), "JpgPie"), System.ComponentModel.Category("Appearance")> _
        Public Property GraphType() As GraphType
        Get
            Try
                Return CType(Me.ViewState("GraphType"), GraphType)
            Catch ex As Exception
                Return GraphType.JpgPie
            End Try
        End Get
        Set(ByVal Value As GraphType)
            Me.ViewState("GraphType") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the left margin of the graph"), System.ComponentModel.DefaultValue(0), System.ComponentModel.Category("Layout")> _
    Public Property LeftMargin() As Integer
        Get
            Try
                Return CInt(viewstate("LeftMargin"))
            Catch ex As Exception
                Return 0
            End Try
        End Get
        Set(ByVal Value As Integer)
            viewstate("LeftMargin") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the right margin of the graph"), System.ComponentModel.DefaultValue(0), System.ComponentModel.Category("Layout")> _
    Public Property RightMargin() As Integer
        Get
            Try
                Return CInt(viewstate("RightMargin"))
            Catch ex As Exception
                Return 0
            End Try
        End Get
        Set(ByVal Value As Integer)
            viewstate("RightMargin") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the bottom margin of the graph"), System.ComponentModel.DefaultValue(0), System.ComponentModel.Category("Layout")> _
    Public Property BottomMargin() As Integer
        Get
            Try
                Return CInt(viewstate("BottomMargin"))
            Catch ex As Exception
                Return 0
            End Try
        End Get
        Set(ByVal Value As Integer)
            viewstate("BottomMargin") = Value
        End Set
    End Property

    <System.ComponentModel.Description("Specifies the top margin of the graph"), System.ComponentModel.DefaultValue(0), System.ComponentModel.Category("Layout")> _
    Public Property TopMargin() As Integer
        Get
            Try
                Return CInt(viewstate("TopMargin"))
            Catch ex As Exception
                Return 0
            End Try
        End Get
        Set(ByVal Value As Integer)
            viewstate("TopMargin") = Value
        End Set
    End Property
#End Region

#Region "Private Properties"
    Private ReadOnly Property MyWidth() As Integer
        Get
            Dim Width As Integer = 435
            If InStr(Me.Width.ToString, "px", CompareMethod.Text) > 0 Then Width = CInt(Replace(Me.Width.ToString, "px", ""))
            Return Width
        End Get
    End Property

    Private ReadOnly Property MyHeight() As Integer
        Get
            Dim Height As Integer = 265
            If InStr(Me.Height.ToString, "px", CompareMethod.Text) > 0 Then Height = CInt(Replace(Me.Height.ToString, "px", ""))
            Return Height
        End Get
    End Property

    Private ReadOnly Property MyFont() As Font
        Get
            Return New Font("Arial", 8, FontStyle.Bold)
        End Get
    End Property

    Private ReadOnly Property TextAngle() As Integer
        Get
            Return -25
        End Get
    End Property
#End Region

#Region "Control Rendering Methods"

    Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
        If Me.GridLineColor.IsEmpty Then Me.GridLineColor = Color.Black
        If Me.LineColor.IsEmpty Then Me.LineColor = Color.Black
        If Me.FillColor.IsEmpty Then Me.FillColor = Color.White
        If Me.ForeColor.IsEmpty Then Me.ForeColor = Color.Black

        Select Case Me.GraphType
            Case GraphType.FlashBar, GraphType.FlashLine, GraphType.FlashPie
                RenderFlash(output)
            Case GraphType.JpgBar, GraphType.JpgLine, GraphType.JpgPie
                RenderJPG(output)
        End Select
    End Sub

    Private Sub RenderJPG(ByVal output As System.Web.UI.HtmlTextWriter)
        Try
            Dim POSTURL As String
            Dim UniqueID As String
            Dim Div As String = "<DIV"
            Try

                POSTURL = Me.Page.Request.Url.ToString
                UniqueID = Me.UniqueID.ToString

                If POSTURL.IndexOf("?") > 0 Then
                    POSTURL &= "&Ctrl=" & UniqueID
                Else
                    POSTURL &= "?Ctrl=" & UniqueID
                End If
                POSTURL &= "&TickCount=" & Environment.TickCount.ToString & "&GraphType=" & Me.GraphType.ToString

            Catch ex As Exception

            End Try
            If Not Me.Style("LEFT") Is Nothing And Not Me.Style("TOP") Is Nothing Then
                Div &= " style=""POSITION: absolute; LEFT: " & Me.Style("LEFT") & "; TOP: " & Me.Style("TOP") & """"
            End If
            Div &= ">"
            Dim Text As String = Div & "<img src=""" & POSTURL & """ width=""" & MyWidth.ToString & "px"" height=""" & MyHeight.ToString & "px"" /></DIV>"
            output.Write(Text)
        Catch ex As Exception
            output.Write(ex.Message)

        End Try
    End Sub

    Private Sub RenderFlash(ByVal output As System.Web.UI.HtmlTextWriter)
        Try
            If Me.GradientColor.IsEmpty Then Me.GradientColor = Me.BackColor

            Dim Height As Integer = 265
            Dim Width As Integer = 435
            If InStr(Me.Width.ToString, "px", CompareMethod.Text) > 0 Then Width = CInt(Replace(Me.Width.ToString, "px", ""))
            If InStr(Me.Height.ToString, "px", CompareMethod.Text) > 0 Then Height = CInt(Replace(Me.Height.ToString, "px", ""))
            Dim BackColor As String = Mid(Hex(Me.BackColor.ToArgb), 3, 100)
            Dim FillColor As String = Mid(Hex(Me.FillColor.ToArgb), 3, 100)
            Dim FontColor As String = Mid(Hex(Me.ForeColor.ToArgb), 3, 100)
            Dim LineColor As String = Mid(Hex(Me.LineColor.ToArgb), 3, 100)
            Dim GradientColor As String = ""
            If Me.GradientColor.IsEmpty = False Then GradientColor = Mid(Hex(Me.GradientColor.ToArgb), 3, 100)

            Dim GridLineColor As String = Mid(Hex(Me.GridLineColor.ToArgb), 3, 100)
            Dim FileName As String
            Select Case Me.GraphType
                Case GraphType.FlashBar
                    FileName = "NetFlashBar.swf"
                Case GraphType.FlashLine
                    FileName = "NetFlashLine.swf"
                Case GraphType.FlashPie
                    FileName = "NetFlashPie.swf"
            End Select
            Dim URL As String
            Try
                If Not Me.Page Is Nothing Then
                    URL = Me.Page.Request.ApplicationPath & "/FlashResources/" & FileName 'Me.ResolveUrl(Me.MovieURL)
                Else
                    URL = "FlashResources/" & FileName
                End If
            Catch
                URL = "FlashResources/" & FileName
            End Try
            Dim POSTURL As String
            Dim UniqueID As String
            Dim Div As String = "<DIV"
            Try
                POSTURL = Me.Page.Request.Path
                UniqueID = Me.UniqueID.ToString
            Catch ex As Exception

            End Try
            If Not Me.Style("LEFT") Is Nothing And Not Me.Style("TOP") Is Nothing Then
                Div &= " style=""POSITION: absolute; LEFT: " & Me.Style("LEFT") & "; TOP: " & Me.Style("TOP") & """"
            End If
            Div &= ">"
            Dim Text As String = Div & "<!--url's used in the movie-->" & vbCrLf _
                & "<!--text used in the movie-->" & vbCrLf _
                & "<!-- saved from url=(0013)about:internet -->" & vbCrLf _
                & "<object classid=""clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"" codebase=""http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0"" width=""" & Width & """ height=""" & Height & """ id=""MyGraph"" align=""middle"">" & vbCrLf _
                & "<param name=""allowScriptAccess"" value=""sameDomain"" />" & vbCrLf _
                & "<param name=""movie"" value=""" & URL & "?GraphType=" & Me.GraphType.ToString & "&FillTransparency=" & Me.FillOpacity.ToString _
                    & "&BgColor=" & BackColor & "&GradientAngle=" & Me.GradientAngle.ToString & "&GradientColor=" & GradientColor _
                    & "&TickCount=" & Environment.TickCount.ToString & "&PostURL=" & POSTURL & "&UniqueID=" & UniqueID _
                    & "&GraphHeight=" & Height.ToString & "&GraphWidth=" & Width.ToString & "&FillColor=" & FillColor _
                    & "&FontColor=" & FontColor & "&LineColor=" & LineColor & "&GridLineColor=" & GridLineColor _
                    & "&RightMargin=" & Me.RightMargin.ToString & "&LeftMargin=" & Me.LeftMargin.ToString & "&TopMargin=" & Me.TopMargin.ToString _
                    & "&BottomMargin=" & Me.BottomMargin.ToString & """ />" & vbCrLf _
                & "<param name=""quality"" value=""high"" />" & vbCrLf _
                & "<param name=""bgcolor"" value=""#" & BackColor & """ />" & vbCrLf _
                & "<param name=""menu"" value=""false"" />" & vbCrLf _
                & "<embed src=""" & URL & """ quality=""high"" bgcolor=""#" & BackColor & """ width=""" & Width.ToString & """ height=""" & Height.ToString & """ name=""MyGraph"" align=""middle"" allowScriptAccess=""sameDomain"" type=""application/x-shockwave-flash"" pluginspage=""http://www.macromedia.com/go/getflashplayer"" />" & vbCrLf _
                & "</object></DIV>"

            output.Write(Text)
        Catch ex As Exception
            output.Write(ex.Message)
        End Try
    End Sub
#End Region

#Region "Data Rendering Methods"

    Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
        Try

            If Me.Page.Request.QueryString("Ctrl") = Me.UniqueID Then
                Dim Items As New DataValues
                RaiseEvent GraphBinding(Me, Items)
                Dim CurrentColorIndex As Integer
                For Each Item As DataValue In Items
                    If Item.ItemColor.IsEmpty Then Item.ItemColor = _DefaultColors(CurrentColorIndex)
                    CurrentColorIndex += 1
                    If CurrentColorIndex >= _DefaultColors.Length Then CurrentColorIndex = 0
                Next
                RenderGraphData(Items)
                Me.Page.Response.End()

                Exit Sub
            End If

        Catch ex As Exception
            System.Diagnostics.Debug.WriteLine(ex.Message)

        End Try
    End Sub

    Protected Sub RenderGraphData(ByVal items As DataValues)
        Dim GraphType As GraphType = System.Enum.Parse(Me.GraphType.GetType, Me.Page.Request.QueryString("GraphType"))
        Select Case GraphType
            Case GraphType.FlashBar, GraphType.FlashLine, GraphType.FlashPie
                RenderFlashGraphData(items)
            Case GraphType.JpgBar, GraphType.JpgLine, GraphType.JpgPie
                RenderJPGGraphData(items)
        End Select
    End Sub

    Private Sub RenderJPGGraphData(ByVal items As DataValues)
        Dim bmp As New System.Drawing.Bitmap(Me.MyWidth, Me.MyHeight)
        Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
        Dim BkColor As System.Drawing.Color
        If Me.BackColor.IsEmpty Then
            BkColor = Color.White
        Else
            BkColor = Me.BackColor
        End If
        If Me.GridLineColor.IsEmpty Then Me.GridLineColor = Color.Black
        If Me.ForeColor.IsEmpty Then Me.ForeColor = Color.Blue
        If Me.FillColor.IsEmpty Then Me.FillColor = Color.Transparent

        If Me.GradientColor.IsEmpty Then Me.GradientColor = Me.BackColor

        Dim Brush As New LinearGradientBrush(New Rectangle(-1, -1, bmp.Width + 1, bmp.Height + 1), Me.GradientColor, Me.BackColor, Me.GradientAngle + 180)

        g.FillRectangle(Brush, New RectangleF(-1, -1, bmp.Width + 1, bmp.Height + 1))
        Brush.Dispose()
        Dim Args As New JpgRenderEventArgs(bmp, g, items)

        RaiseEvent AfterRenderBackground(Me, Args)
        bmp = Args.Bitmap

        Select Case GraphType
            Case GraphType.JpgPie
                RenderPie(bmp, g, items)
            Case GraphType.JpgBar
                RenderJpgBar(bmp, g, items)
            Case GraphType.JpgLine
                RenderJpgLine(bmp, g, items)
        End Select

        g.Dispose()
        RaiseEvent BeforeFlushResponse(Me, Args)
        bmp = Args.Bitmap
        SaveImageToResponse(bmp, Me.Page.Response)
    End Sub

    Private Sub RenderFlashGraphData(ByVal items As DataValues)
        Dim XML As String = "<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?><Results>"
        Dim DataValue As DataValue


        For Each DataValue In items
            Dim Clr As String = ""
            'If DataValue.ItemColor.ToArgb <> Color.Transparent.ToArgb Then 
            If DataValue.ItemColor.IsEmpty = False Then Clr = Mid(Hex(DataValue.ItemColor.ToArgb), 3, 100)
            XML &= "<Result><Label>" & DataValue.Label & "</Label>"
            XML &= "<Value>" & DataValue.Value.ToString & "</Value>"
            XML &= "<URL>" & DataValue.URL & "</URL>"
            XML &= "<PopupLabel>" & DataValue.PopupLabel & "</PopupLabel>"
            XML &= "<ItemColor>" & Clr & "</ItemColor>"
            XML &= "</Result>"
        Next
        XML &= "</Results>"

        Me.Page.Response.Clear()
        Me.Page.Response.Write(XML)
        Me.Page.Response.End()
    End Sub

    Private Sub SaveImageToResponse(ByVal bmp As System.Drawing.Bitmap, ByVal response As System.Web.HttpResponse)
        Dim jpegCodecInfo As Imaging.ImageCodecInfo = GetEncoderInfo("image/jpeg")
        Dim QualityEncoder As Imaging.Encoder = Imaging.Encoder.Quality
        Dim Value As Long = 100
        Select Case Me.GraphQuality
            Case GraphQuality.Best
                Value = 100
            Case GraphQuality.High
                Value = 90
            Case GraphQuality.MediumHigh
                Value = 75
            Case GraphQuality.Medium
                Value = 50
            Case GraphQuality.MediumLow
                Value = 30
            Case GraphQuality.Low
                Value = 20
            Case GraphQuality.Lowest
                Value = 10
        End Select
        Dim Ratio As New Imaging.EncoderParameter(QualityEncoder, Value)

        Dim codecParams As Imaging.EncoderParameters = New Imaging.EncoderParameters(1)
        codecParams.Param(0) = Ratio
        response.Clear()
        bmp.Save(response.OutputStream, jpegCodecInfo, codecParams)

        response.ContentType = "image/jpeg"
        response.End()
    End Sub

    Private Function GetEncoderInfo(ByVal mimeType As String) As Imaging.ImageCodecInfo
        Dim j As Integer
        Dim encoders() As Imaging.ImageCodecInfo = Imaging.ImageCodecInfo.GetImageEncoders()
        For j = 0 To encoders.Length - 1
            If encoders(j).MimeType = mimeType Then Return encoders(j)
        Next

        Return Nothing
    End Function
#End Region

#Region "Shared JPG Methods"
    Private Function GetBottomMargin(ByVal items As DataValues, ByVal g As Graphics) As Integer
        Dim Margin As Integer = 0

        For Each item As DataValue In items
            Dim SizeF As SizeF = g.MeasureString(item.Label, Me.MyFont)
            Dim angle_radians As Double = Me.TextAngle * PI / 180
            Dim HeightNeeded As Decimal = CDec(Math.Sin(Math.Abs(angle_radians)) * SizeF.Width)
            If HeightNeeded > Margin Then Margin = HeightNeeded
        Next
        Return Margin + 10
    End Function

    Private Function GetLeftMargin(ByVal items As DataValues, ByVal g As Graphics) As Integer
        Dim Margin As Integer = 0

        For Each item As DataValue In items
            Dim SizeF As SizeF = g.MeasureString(Format(item.Value, "Standard"), Me.MyFont)
            If SizeF.Width > Margin Then Margin = SizeF.Width
        Next
        Return Margin + 7
    End Function

    Private Function DrawBottomCaption(ByVal maxValue As Decimal, ByVal g As Graphics, ByVal items As DataValues, ByVal bmp As Bitmap, ByVal rightMargin As Integer, ByVal leftMargin As Integer, ByVal topMargin As Integer, ByVal bottomMargin As Integer, ByVal minValue As Decimal, ByVal offsetX As Integer) As Integer
        Dim F As New System.Drawing.Font("Arial", 8)

        Dim GraphWidth As Integer = bmp.Width - rightMargin - leftMargin
        Dim BarPadding As Integer = 3
        Dim GraphWidthMinusPadding As Integer = GraphWidth - (items.Count * BarPadding)
        If GraphWidthMinusPadding < 0 Then
            GraphWidthMinusPadding = GraphWidth - items.Count
            BarPadding = 1
        End If
        Dim BarWidth As Integer = leftMargin + BarPadding
        Dim ColorIndex As Integer = 0
        Dim Scale As Decimal = (maxValue - minValue) / (bmp.Height - topMargin - bottomMargin)
        Dim X As Decimal = leftMargin + BarWidth + BarPadding


        Dim i As Integer
        If items.Count <> 0 Then

            BarWidth = CInt(GraphWidthMinusPadding / items.Count)
            If Me.GraphType = GraphType.JpgLine And items.Count > 1 Then BarWidth = CInt(GraphWidthMinusPadding / (items.Count - 1))
        End If
        Dim FourBars As Integer = CInt(bmp.Width / 6)

        If BarWidth > FourBars Then BarWidth = FourBars
        i = 0

        For Each Item As DataValue In items
            Dim OpColor As Color = Color.FromArgb(255, 255 - Me.ForeColor.R, 255 - Me.ForeColor.B, 255 - Me.ForeColor.G)

            Dim Description As String = Item.Label
            Dim StringSize As SizeF = g.MeasureString(Description, F)
            Dim bmpNew As New Bitmap(CInt(StringSize.Width) + 10, CInt(StringSize.Width) + 10)
            Dim gi As Graphics = Graphics.FromImage(bmpNew)
            gi.FillRectangle(New SolidBrush(OpColor), New Rectangle(0, 0, bmp.Width, bmp.Height))
            Dim Width As Decimal = DrawAngleText(gi, Description)
            gi.Dispose()
            X = leftMargin + BarPadding + i * BarWidth + i * BarPadding - Width + CInt(BarWidth / 2) + offsetX
            Dim Point As New PointF(X, bmp.Height - bottomMargin)
            bmpNew.MakeTransparent(OpColor)

            g.DrawImage(bmpNew, Point)
            X += BarWidth + BarPadding
            i += 1
        Next
    End Function

    Private Function DrawAngleText(ByVal g As Graphics, ByVal text As String) As Decimal
        'If Me.ForeColor.IsEmpty Then Me.ForeColor = Color.Black

        'Dim fnt As Font = New Font("Arial", 8, FontStyle.Regular)
        Dim SizeF As SizeF = g.MeasureString(text, Me.MyFont)
        'Dim Angle_Degrees As Decimal = 25 * -1
        Dim angle_radians As Double = Me.TextAngle * PI / 180
        Dim Y As Decimal = CDec(Math.Sin(Math.Abs(angle_radians)) * SizeF.Width)
        g.TranslateTransform(0, Y)
        g.RotateTransform(Me.TextAngle)
        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit
        g.DrawString(text, Me.MyFont, New SolidBrush(Me.ForeColor), 0, 0)
        Return CDec(Math.Cos(angle_radians) * SizeF.Width)
    End Function

    Private Sub DrawGridLines(ByVal g As Graphics, ByVal maxValue As Decimal, ByVal bmp As Bitmap, ByVal topMargin As Integer, ByVal bottomMargin As Integer, ByVal leftMargin As Integer, ByVal rightMargin As Integer, ByVal minValue As Integer)
        Dim Padding As Integer = 3
        If Me.GridLineColor.IsEmpty Then Me.GridLineColor = Color.Black

        Dim StructurePen As New Pen(Me.GridLineColor, 3)
        Dim LinePen As New Pen(Me.GridLineColor, 1)
        Dim Scale As Decimal = (maxValue - minValue) / (bmp.Height - topMargin - bottomMargin)
        Dim i As Integer

        g.DrawLine(StructurePen, leftMargin, topMargin, leftMargin, bmp.Height - bottomMargin)
        g.DrawLine(StructurePen, leftMargin, bmp.Height - bottomMargin, bmp.Width - rightMargin, bmp.Height - bottomMargin)
        Dim LineHeight = (bmp.Height - topMargin - bottomMargin) / 10
        Dim Units As Decimal = (maxValue - minValue) / 10

        For i = 0 To 10
            Dim Y As Integer = CInt(LineHeight * i)
            Dim StringFormat As New StringFormat
            Dim StringMeasure As SizeF = g.MeasureString(i.ToString, Me.MyFont)

            StringFormat.Alignment = StringAlignment.Far
            StringFormat.LineAlignment = StringAlignment.Center
            Y = bmp.Height - bottomMargin - Y
            Dim StringRect As New RectangleF(0, Y - 5, leftMargin - 5, StringMeasure.Height)
            g.DrawLine(LinePen, leftMargin - 5, Y, bmp.Width - rightMargin, Y)
            g.DrawString(Format(i * Units + minValue, "Standard"), Me.MyFont, New SolidBrush(Me.ForeColor), StringRect, StringFormat)
        Next
    End Sub
#End Region

#Region "JPG Pie Methods"
    Private Sub RenderPie(ByVal bmp As Bitmap, ByVal g As Graphics, ByVal items As DataValues)
        Dim Total As Decimal = 0
        Dim LegendSpaceNeeded As Integer = 0
        Dim LineWidth As Integer = 2

        For Each item As DataValue In items
            Dim SizeF As SizeF = g.MeasureString(item.Label, Me.MyFont)
            If SizeF.Width > LegendSpaceNeeded Then LegendSpaceNeeded = CInt(SizeF.Width)
            Total += item.Value
        Next
        LegendSpaceNeeded += 20

        Dim StartAngle As Decimal = 0

        Dim Radius As Integer
        If (Me.MyHeight - Me.TopMargin - Me.BottomMargin) > (Me.MyWidth - LegendSpaceNeeded - Me.LeftMargin + Me.RightMargin) Then Radius = (Me.MyWidth - LegendSpaceNeeded - Me.RightMargin - Me.LeftMargin) Else Radius = Me.MyHeight - Me.TopMargin - Me.BottomMargin
        Radius -= LineWidth * 2
        Dim rectSquare As Rectangle = New Rectangle(1 + Me.LeftMargin, 1 + Me.TopMargin, Radius, Radius)

        DrawLegend(bmp, g, items, Radius)

        items.Reverse()

        For Each Item As DataValue In items
            Dim bmpTmp As New System.Drawing.Bitmap(bmp.Width, bmp.Height)
            Dim g2 As Graphics = Graphics.FromImage(bmpTmp)

            Dim graphPath As Drawing2D.GraphicsPath
            Dim brushSquare As Drawing2D.PathGradientBrush
            graphPath = New Drawing2D.GraphicsPath
            graphPath.AddEllipse(rectSquare)

            brushSquare = New Drawing2D.PathGradientBrush(graphPath)
            brushSquare.CenterColor = Color.White
            brushSquare.SurroundColors = New Color() {item.ItemColor}
            Dim b As New Blend
            b.Factors = New Single() {1, 0, 0}
            b.Positions = New Single() {0, 0.15F, 1.0F}
            brushSquare.Blend = b
            g2.FillPath(brushSquare, graphPath)
            Dim SweepAngle = item.Value / Total * 360
            g2.FillPie(New SolidBrush(Color.White), rectSquare, StartAngle + SweepAngle, 360 - SweepAngle)
            Dim LineColor As Color = Me.LineColor

            g2.DrawPie(New Pen(LineColor, LineWidth), rectSquare, StartAngle, SweepAngle)

            StartAngle += SweepAngle
            bmpTmp.MakeTransparent(Color.White)
            g.DrawImage(bmpTmp, New Point(0, 0))
            bmpTmp.Dispose()
            g2.Dispose()
        Next
    End Sub

    Private Function DrawLegend(ByVal bmp As Bitmap, ByVal g As Graphics, ByVal items As DataValues, ByVal radius As Integer) As Integer
        Dim Y As Integer = 10
        For Each Item As DataValue In items
            Dim StringSize As SizeF = g.MeasureString(Item.Label, Me.MyFont)
            Dim rectSquare As Rectangle
            Dim graphPath As Drawing2D.GraphicsPath
            Dim brushSquare As Drawing2D.PathGradientBrush

            graphPath = New Drawing2D.GraphicsPath

            rectSquare = New Rectangle(radius + 3 + Me.LeftMargin, Y + 3 + Me.TopMargin, 15, 15)
            graphPath.AddRectangle(rectSquare)
            brushSquare = New Drawing2D.PathGradientBrush(graphPath)
            brushSquare.CenterColor = Color.White
            brushSquare.SurroundColors = New Color() {Item.ItemColor}
            g.FillPath(brushSquare, graphPath)
            Dim Clr As Color
            If Me.ForeColor.IsEmpty Then Clr = Color.Black Else Clr = Me.ForeColor
            g.DrawString(Item.Label, Me.MyFont, New SolidBrush(Clr), radius + 18 + Me.LeftMargin, Y + Me.TopMargin)
            Y += 18
        Next
    End Function
#End Region

#Region "JPG Line Methods"
    Private Sub RenderJpgLine(ByVal bmp As Bitmap, ByVal g As Graphics, ByVal items As DataValues)
        Dim MaxValue As Decimal = 0
        Dim TopMargin As Integer = Me.TopMargin
        Dim BottomMargin As Integer = Me.BottomMargin
        Dim BarPadding As Integer = 0
        Dim LeftMargin As Integer = 70
        LeftMargin = GetLeftMargin(items, g) + Me.LeftMargin
        Dim RightMargin As Integer = Me.RightMargin + 10
        Dim X As Decimal = LeftMargin
        Dim MinValue As Decimal = 9999999999
        Dim Pen As New Pen(Me.LineColor, 2)

        BottomMargin = GetBottomMargin(items, g) + Me.BottomMargin

        Dim BarWidth As Decimal = (bmp.Width - RightMargin - LeftMargin - (items.Count * BarPadding)) / (items.Count - 1)

        For Each Item As DataValue In items
            If Item.Value > MaxValue Then
                MaxValue = Item.Value

                System.Diagnostics.Debug.Write("Debug")
            End If
            If item.Value < MinValue Then
                MinValue = item.Value
            End If
        Next
        Dim Scale As Decimal = (MaxValue - MinValue) / (bmp.Height - TopMargin - BottomMargin)
        DrawGridLines(g, MaxValue, bmp, TopMargin, BottomMargin, LeftMargin, RightMargin, MinValue)
        Dim LastPoint As New Point(-1, -1)
        Dim GraphPath As New GraphicsPath
        Dim Y As Integer = 0
        Dim FirstPoint As Point
        For Each Item As DataValue In items
            Dim PointHeight As Integer = item.Value / Scale - MinValue / Scale
            Y = bmp.Height - BottomMargin - PointHeight

            g.DrawLine(Pen, X, TopMargin, X, bmp.Height - BottomMargin)
            If LastPoint.X > -1 Then
                Dim CurrentPoint As New Point(X, Y)
                g.DrawLine(Pen, LastPoint, CurrentPoint)
                GraphPath.AddLine(LastPoint, CurrentPoint)
            Else
                FirstPoint = New Point(X, Y)
            End If
            LastPoint = New Point(X, Y)
            g.FillEllipse(New SolidBrush(Me.LineColor), New Rectangle(X - 3, Y - 3, 7, 7))
            X = X + BarWidth
        Next
        GraphPath.AddLine(New Point(X, Y), New Point(X, bmp.Height - BottomMargin))
        GraphPath.AddLine(New Point(X, bmp.Height - BottomMargin), New Point(LeftMargin, bmp.Height - BottomMargin))
        GraphPath.AddLine(New Point(LeftMargin, bmp.Height - BottomMargin), FirstPoint)
        Dim OpacityFactor As Integer = CInt(Me.FillOpacity * 255 / 100)
        Dim FillColor As Color = Color.FromArgb(OpacityFactor, Me.FillColor.R, Me.FillColor.G, Me.FillColor.B)
        g.FillPath(New SolidBrush(FillColor), GraphPath)

        DrawBottomCaption(MaxValue, g, items, bmp, RightMargin, LeftMargin, TopMargin, BottomMargin, MinValue, -1 * (BarWidth / 2))

    End Sub
#End Region

#Region "JPG Bar Methods"
    Private Sub RenderJpgBar(ByVal bmp As Bitmap, ByVal g As Graphics, ByVal items As DataValues)
        Dim MaxValue As Decimal = 0
        Dim TopMargin As Integer = 10 + Me.TopMargin
        Dim BottomMargin As Integer = 30
        Dim BarPadding As Integer = 3
        Dim LeftMargin As Integer = 60
        LeftMargin = GetLeftMargin(items, g) + Me.LeftMargin
        Dim RightMargin As Integer = Me.RightMargin + 10
        Dim X As Decimal
        BottomMargin = GetBottomMargin(items, g) + Me.BottomMargin

        Dim BarWidth As Decimal = (bmp.Width - RightMargin - LeftMargin - (items.Count * BarPadding)) / items.Count

        For Each Item As DataValue In items
            If item.Value > MaxValue Then
                MaxValue = item.Value
                System.Diagnostics.Debug.Write("Debug")
            End If
        Next
        Dim Scale As Decimal = MaxValue / (bmp.Height - TopMargin - BottomMargin)
        DrawGridLines(g, MaxValue, bmp, TopMargin, BottomMargin, LeftMargin, RightMargin, 0)

        For Each Item As DataValue In items
            Dim Height As Decimal = (item.Value / Scale)
            Dim Y As Decimal = bmp.Height - BottomMargin - Height

            Dim rectSquare As Rectangle
            Dim graphPath As Drawing2D.GraphicsPath
            Dim brushSquare As Drawing2D.PathGradientBrush
            graphPath = New Drawing2D.GraphicsPath
            If Height < 1 Then Height = 1
            rectSquare = New Rectangle(CInt(LeftMargin + X + BarPadding), CInt(Y), CInt(BarWidth), CInt(Height))
            graphPath.AddRectangle(rectSquare)
            brushSquare = New Drawing2D.PathGradientBrush(graphPath)
            brushSquare.CenterColor = Color.White
            brushSquare.SurroundColors = New Color() {item.ItemColor}
            g.FillPath(brushSquare, graphPath)

            Dim FillRectangle As New RectangleF(LeftMargin + X + BarPadding, Y, BarWidth, Height)

            'g.FillRectangle(New SolidBrush(ItemColors(ColorIndex)), FillRectangle)
            X += BarWidth + BarPadding

            'If Not m_BarItems Is Nothing Then m_BarItems.Add(New Rectangle(CInt(FillRectangle.X), CInt(FillRectangle.Y), CInt(FillRectangle.Width), CInt(FillRectangle.Height)), i)
        Next
        DrawBottomCaption(MaxValue, g, items, bmp, RightMargin, LeftMargin, TopMargin, BottomMargin, 0, 0)

    End Sub
#End Region

End Class


#Region "Helper Classes and Enums"
Public Class JpgRenderEventArgs
    Dim _bmp As Bitmap
    Dim _g As Graphics
    Dim _Items As DataValues

    Public Sub New()

    End Sub

    Public Sub New(ByVal bitmap As Bitmap, ByVal graphics As Graphics, ByVal items As DataValues)
        _bmp = bitmap
        _g = graphics
        _Items = items

    End Sub

    Public Property Bitmap() As Bitmap
        Get
            Return _bmp
        End Get
        Set(ByVal Value As Bitmap)
            _bmp = Value
        End Set
    End Property

    Public ReadOnly Property Grahics() As Graphics
        Get
            Return _g
        End Get
    End Property

    Public ReadOnly Property Items() As DataValues
        Get
            Return _Items
        End Get
    End Property
End Class

Public Class DataValues
    Inherits CollectionBase

    Default Public ReadOnly Property Item(ByVal index As Integer) As DataValue
        Get
            Return CType(Me.InnerList(index), DataValue)
        End Get
    End Property

    Public Function Add(ByVal dataValue As DataValue) As DataValue
        Me.InnerList.Add(dataValue)
        Return dataValue
    End Function

    Public Function Add(ByVal label As String, ByVal value As Decimal, ByVal uRL As String, ByVal popUpLabel As String) As DataValue
        Dim DataValue As New DataValue(label, value, uRL, popUpLabel)
        Return Me.Add(DataValue)
    End Function

    Public Function Add(ByVal label As String, ByVal value As Decimal, ByVal uRL As String, ByVal popUpLabel As String, ByVal itemColor As Color) As DataValue
        Dim DataValue As New DataValue(label, value, uRL, popUpLabel)
        DataValue.ItemColor = itemColor
        Return Me.Add(DataValue)
    End Function

    Public Sub Reverse()
        Me.InnerList.Reverse()
    End Sub
End Class

Public Enum GraphType
    FlashLine
    FlashBar
    FlashPie
    JpgLine
    JpgBar
    JpgPie
End Enum

Public Class DataValue
    Dim _Label As String
    Dim _Value As Decimal
    Dim _URL As String
    Dim _PopupLabel As String
    Dim _ItemColor As Color = Color.Empty

    Public Sub New()


    End Sub

    Public Sub New(ByVal label As String, ByVal value As Decimal, ByVal uRL As String, ByVal popupLabel As String)
        _Label = label
        _Value = value
        _URL = uRL
        _PopupLabel = popupLabel
    End Sub

    Public Property ItemColor() As Color
        Get
            Return _ItemColor
        End Get
        Set(ByVal Value As Color)
            _ItemColor = Value
        End Set
    End Property

    Public Property Label() As String
        Get
            Return _Label
        End Get
        Set(ByVal Value As String)
            _Label = Value
        End Set
    End Property

    Public Property Value() As Decimal
        Get
            Return _Value
        End Get
        Set(ByVal Value As Decimal)
            _Value = Value
        End Set
    End Property

    Public Property URL() As String
        Get
            Return _URL
        End Get
        Set(ByVal Value As String)
            _URL = Value
        End Set
    End Property

    Public Property PopupLabel() As String
        Get
            Return _PopupLabel
        End Get
        Set(ByVal Value As String)
            _PopupLabel = Value
        End Set
    End Property
End Class

Public Enum GraphQuality
    Best
    High
    MediumHigh
    Medium
    MediumLow
    Low
    Lowest
End Enum

#End Region

