Imports System
Imports System.Windows.Forms
Imports QWhale.Common
Imports QWhale.Syntax
Imports QWhale.Syntax.Lexer
Imports QWhale.Syntax.Parsers
Imports QWhale.Editor
Imports QWhale.Syntax.CodeCompletion

Public Class Form1 Inherits Form
	Private methods As ArrayList
	Private comments As ArrayList

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		methods = New ArrayList
		comments = New ArrayList
		
	End Sub
	
	Private Sub cbIdentsColor_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cbIdentsColor.SelectedIndexChanged
		syntaxEdit1.Invalidate()
	End Sub

	Private Sub syntaxEdit1_CustomDraw(ByVal sender As Object, ByVal e As QWhale.Editor.CustomDrawEventArgs) Handles syntaxEdit1.CustomDraw
		' drawing all identifier with different color
		If ((e.DrawStage = DrawStage.Before) And (((e.DrawState And DrawState.Text) <> 0) And (e.DrawState And DrawState.Selection) = 0)) Then
			Dim tok As LexToken = CType(e.DrawInfo.Style - 1, LexToken)
			If (tok = LexToken.Identifier) Then
				e.Painter.TextColor = cbIdentsColor.SelectedColor
			End If
		End If
		'fill button gradient
		If ((e.DrawStage = DrawStage.Before) And (DrawState.OutlineImage And e.DrawState) <> 0) Then
			Dim r As Rectangle = e.Rect
			r.X = r.X + 1
			r.Y = r.Y + 1
			r.Width = r.Width - 1
			r.Height = r.Height - 1
			e.Painter.FillGradient(r.X, r.Y, r.Width, r.Height, Color.Blue, Color.White, e.Rect.Location, New Point(r.Right, r.Bottom))
			e.Painter.ExcludeClipRect(e.Rect)
		End If
		'fill method background
		If ((e.DrawStage = DrawStage.Before) And ((e.DrawState = DrawState.Text) Or (e.DrawState = DrawState.BeyondEol))) Then
			If (DrawInMethod(syntaxEdit1.ScreenToText(e.Rect.Left, e.Rect.Top))) Then
				e.Painter.BackColor = cbMethodBkColor.SelectedColor
			End If
		End If
		'drawwing polygon around method
		If ((e.DrawStage = DrawStage.Before) And (e.DrawState = DrawState.Control)) Then
			For Each method As ISyntaxNode In methods
				Dim outRange As IOutlineRange = syntaxEdit1.Outlining.GetOutlineRange(method.Range.StartPoint)
				If (Not outRange Is Nothing) Then
					If (outRange.Visible) Then
						DrawRangeRect(e.Painter, method.Range, Color.Red)
					End If
				End If
			Next method
		End If
		If ((e.DrawState = DrawState.Control) And (e.DrawStage = DrawStage.After)) Then
			' drawing separator between methods
			Dim x1 As Integer = syntaxEdit1.ClientRect.Left + syntaxEdit1.Gutter.Rect.Width
			Dim x2 As Integer = syntaxEdit1.ClientRect.Right
			For i As Integer = 0 To methods.Count - 1
				'Dim index As Integer = CType(methods(i), Integer)
				Dim index As Integer = CType(methods(i), ISyntaxNode).Range.EndPoint.Y + 1
				Dim pos As Point = syntaxEdit1.DisplayToScreen(0, index)
				e.Painter.DrawLine(x1, pos.Y, x2, pos.Y, Color.Green, 1, System.Drawing.Drawing2D.DashStyle.Dot)
			Next i
			' draw rectangle around comments
			Dim start As Point = Point.Empty
			Dim endPos As Point = Point.Empty
			For Each range As IRange In comments
				DrawRangeRect(e.Painter, range, Color.Gray)
			Next range
		End If
	End Sub

	Private Sub ProcessNode(ByVal node As ISyntaxNode)
		If (node.NodeType = NetNodeType.Method) Or (node.NodeType = NetNodeType.Constructor) Then
			methods.Add(node)
		End If
		'        If (node.NodeType = NetNodeType.Method) Or (node.NodeType = NetNodeType.Constructor) Then
		'       methods.Add(node.Range.EndPoint.Y + 1)
		'      End If
		If ((node.NodeType = NetNodeType.Comment) Or (node.NodeType = NetNodeType.XmlComment)) Then
			comments.Add(node.Range)
		End If
		If (node.HasChildren) Then
			For i As Integer = 0 To node.ChildCount - 1
				ProcessNode(node.ChildList(i))
			Next i
		End If
	End Sub

	Private Sub syntaxEdit1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles syntaxEdit1.Resize
		syntaxEdit1.Invalidate()
	End Sub

	Private Sub VbParser1_TextReparsed(ByVal sender As Object, ByVal e As System.EventArgs) Handles VbParser1.TextReparsed
		If (Not methods Is Nothing) And (Not comments Is Nothing) Then
			methods.Clear()
			comments.Clear()
			ProcessNode(VbParser1.SyntaxTree.Root)
			syntaxEdit1.Invalidate()
		End If
	End Sub
	Private Function GetPolygon(ByVal startPt As Point, ByVal endPt As Point, ByVal h As Integer) As Point()
		Dim isRect As Boolean = True
		Dim right As Integer = syntaxEdit1.ClientRect.Right - 1
		Dim left As Integer = syntaxEdit1.Gutter.Rect.Width
		Dim result As Point()
		isRect = startPt.Y = endPt.Y
		If (isRect) Then
			result = New Point(3) {}
		Else
			result = New Point(7) {}
		End If
		For i As Integer = 0 To result.Length - 1
			Select Case (i)
				Case 0
					result(i) = startPt
				Case 1
					If isRect Then
						result(i) = endPt
					Else
						result(i) = New Point(right, startPt.Y)
					End If
				Case 2
					If isRect Then
						result(i) = New Point(endPt.X, endPt.Y + h)
					Else
						result(i) = New Point(right, endPt.Y)
					End If
				Case 3
					If isRect Then
						result(i) = New Point(startPt.X, startPt.Y + h)
					Else
						result(i) = endPt
					End If
				Case 4
					result(i) = New Point(endPt.X, endPt.Y + h)
				Case 5
					result(i) = New Point(left, endPt.Y + h)
				Case 6
					result(i) = New Point(left, startPt.Y + h)
				Case 7
					result(i) = New Point(startPt.X, startPt.Y + h)
			End Select
		Next i
		Return result
	End Function

	Private Sub DrawRangeRect(ByVal painter As IPainter, ByVal range As IRange, ByVal color As Color)
		painter.ForeColor = color
		Dim right As Integer = syntaxEdit1.ClientRect.Right - 1
		Dim Left As Integer = syntaxEdit1.Gutter.Rect.Width + 1
		Dim h As Integer = painter.FontHeight
		Dim startPt As Point = syntaxEdit1.TextToScreen(range.StartPoint.X, range.StartPoint.Y)
		Dim endPt As Point = syntaxEdit1.TextToScreen(range.EndPoint.X, range.EndPoint.Y)
		startPt.X = Math.Max(startPt.X, Left - 1)
		endPt.X = Math.Max(endPt.X, Left - 1)

		If (range.EndPoint.X = Integer.MaxValue) Then
			endPt.X = syntaxEdit1.ClientRect.Right - 1
		End If

		Dim points As Point() = GetPolygon(startPt, endPt, h)
		For i As Integer = 0 To points.Length - 1
			If (i < points.Length - 1) Then
				If ((points(i).X <= points(i + 1).X) And (points(i).Y <= points(i + 1).Y)) Then
					painter.DrawLine(points(i).X, points(i).Y, points(i + 1).X, points(i + 1).Y)
				Else
					painter.DrawLine(points(i + 1).X, points(i + 1).Y, points(i).X, points(i).Y)
				End If
			Else
				painter.DrawLine(points(0).X, points(0).Y, points(i).X, points(i).Y)
			End If
		Next i
		Dim rect As Rectangle
		For j As Integer = 0 To points.Length - 1
			If (j < points.Length - 1) Then
				If ((points(j).X <= points(j + 1).X) And (points(j).Y <= points(j + 1).Y)) Then
					rect = New Rectangle(points(j).X, points(j).Y, Math.Max(1, points(j + 1).X - points(j).X), Math.Max(1, points(j + 1).Y - points(j).Y))
				Else
					rect = New Rectangle(points(j + 1).X, points(j + 1).Y, Math.Max(1, points(j).X - points(j + 1).X), Math.Max(1, points(j).Y - points(j + 1).Y))
				End If
			Else
				rect = New Rectangle(points(0).X, points(0).Y, Math.Max(1, points(j).X - points(0).X), Math.Max(1, points(j).Y - points(0).Y))
			End If
			painter.ExcludeClipRect(rect)
		Next j
	End Sub
	Private Class RangeComparer
		Implements IComparer

		Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
			Dim pt As Point = CType(x, Point)
			Dim sPt As Point = CType(y, IRange).StartPoint
			Dim ePt As Point = CType(y, IRange).EndPoint
			If ((pt.Y < sPt.Y) Or ((pt.Y = sPt.Y) And (pt.X < sPt.X))) Then
				Return -1
			Else
				If ((pt.Y > ePt.Y) Or ((pt.Y = ePt.Y) And (pt.X >= ePt.X))) Then
					Return 1
				Else
					Return 0
				End If
			End If
		End Function
	End Class
	Private comparer As IComparer = New RangeComparer
	Private Function DrawInMethod(ByVal pt As Point) As Boolean
		For Each method As ISyntaxNode In methods
			If (comparer.Compare(pt, method.Range) = 0) Then
				Return True
			End If
		Next
		Return False
	End Function

	Private Sub cbMethodBkColor_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbMethodBkColor.SelectedIndexChanged
		syntaxEdit1.Invalidate()
	End Sub

	Private Sub syntaxEdit1_HorizontalScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles syntaxEdit1.HorizontalScroll
		syntaxEdit1.Invalidate()
	End Sub
End Class

