Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Namespace McDull.Windows.Forms
    <Description("Provides a user control that allows the user to edit HTML page."), ClassInterface(ClassInterfaceType.AutoDispatch)>
    Public Partial Class HTMLTextBox
        Inherits UserControl

        Public Sub New()
            dataUpdate = 0
            InitializeComponent()
            InitializeControls()
        End Sub

        Public Overrides Property Text As String
            Get
                Return webBrowserBody.DocumentText
            End Get
            Set(ByVal value As String)
                webBrowserBody.DocumentText = value.Replace(vbCrLf, "<br>")
            End Set
        End Property

        Public ReadOnly Property Images As String()
            Get
                Dim imagestmp As List(Of String) = New List(Of String)()

                For Each element As HtmlElement In webBrowserBody.Document.Images
                    Dim image As String = element.GetAttribute("src")

                    If Not imagestmp.Contains(image) Then
                        imagestmp.Add(image)
                    End If
                Next

                Return imagestmp.ToArray()
            End Get
        End Property

        Private Sub InitializeControls()
            BeginUpdate()

            For Each family As FontFamily In FontFamily.Families
                toolStripComboBoxName.Items.Add(family.Name)
            Next

            toolStripComboBoxSize.Items.AddRange(FontSize.All.ToArray())
            webBrowserBody.DocumentText = String.Empty
            AddHandler webBrowserBody.Document.Click, AddressOf webBrowserBody_DocumentClick
            AddHandler webBrowserBody.Document.Focusing, AddressOf webBrowserBody_DocumentFocusing
            webBrowserBody.Document.ExecCommand("EditMode", False, Nothing)
            webBrowserBody.Document.ExecCommand("LiveResize", False, Nothing)
            EndUpdate()
        End Sub

        Private Sub RefreshToolBar()
            BeginUpdate()

            Try
                Dim document = webBrowserBody.Document.DomDocument 'As mshtml.IHTMLDocument2 = CType(webBrowserBody.Document.DomDocument, mshtml.IHTMLDocument2)
                toolStripComboBoxName.Text = document.queryCommandValue("FontName").ToString()
                toolStripComboBoxSize.SelectedItem = FontSize.Find(CInt(document.queryCommandValue("FontSize")))
                toolStripButtonBold.Checked = document.queryCommandState("Bold")
                toolStripButtonItalic.Checked = document.queryCommandState("Italic")
                toolStripButtonUnderline.Checked = document.queryCommandState("Underline")
                toolStripButtonNumbers.Checked = document.queryCommandState("InsertOrderedList")
                toolStripButtonBullets.Checked = document.queryCommandState("InsertUnorderedList")
                toolStripButtonLeft.Checked = document.queryCommandState("JustifyLeft")
                toolStripButtonCenter.Checked = document.queryCommandState("JustifyCenter")
                toolStripButtonRight.Checked = document.queryCommandState("JustifyRight")
                toolStripButtonFull.Checked = document.queryCommandState("JustifyFull")
            Catch e As Exception
                System.Diagnostics.Debug.WriteLine(e)
            Finally
                EndUpdate()
            End Try
        End Sub

        Private dataUpdate As Integer

        Private ReadOnly Property Updating As Boolean
            Get
                Return dataUpdate<> 0
            End Get
        End Property

        Private Sub BeginUpdate()
            dataUpdate += 1
        End Sub

        Private Sub EndUpdate()
            dataUpdate -= 1
        End Sub

        Private Sub toolStripComboBoxName_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("FontName", False, toolStripComboBoxName.Text)
        End Sub

        Private Sub toolStripComboBoxSize_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            Dim size As Integer = If((toolStripComboBoxSize.SelectedItem Is Nothing), 1, (TryCast(toolStripComboBoxSize.SelectedItem, FontSize)).Value)
            webBrowserBody.Document.ExecCommand("FontSize", False, size)
        End Sub

        Private Sub toolStripButtonBold_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("Bold", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonItalic_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("Italic", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonUnderline_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("Underline", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonColor_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            ' Dim fontcolor As Integer = CInt((CType(webBrowserBody.Document.DomDocument, mshtml.IHTMLDocument2)).queryCommandValue("ForeColor"))
            Dim dialog As ColorDialog = New ColorDialog()
                        ''' Cannot convert ExpressionStatementSyntax, System.ArgumentOutOfRangeException: Exception of type 'System.ArgumentOutOfRangeException' was thrown.
''' Parameter name: op
''' Actual value was RightShiftExpression.
'''    at ICSharpCode.CodeConverter.Util.VBUtil.GetExpressionOperatorTokenKind(SyntaxKind op)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitBinaryExpression(BinaryExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitBinaryExpression(BinaryExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitBinaryExpression(BinaryExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitBinaryExpression(BinaryExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.BinaryExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitArgument(ArgumentSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitArgument(ArgumentSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.<VisitArgumentList>b__99_0(ArgumentSyntax a)
'''    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
'''    at Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.SeparatedList[TNode](IEnumerable`1 nodes)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitArgumentList(ArgumentListSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitArgumentList(ArgumentListSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitInvocationExpression(InvocationExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitInvocationExpression(InvocationExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.MakeAssignmentStatement(AssignmentExpressionSyntax node)
'''    at ICSharpCode.CodeConverter.VB.NodesVisitor.VisitAssignmentExpression(AssignmentExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.AssignmentExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingNodesVisitor.DefaultVisit(SyntaxNode node)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitAssignmentExpression(AssignmentExpressionSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.AssignmentExpressionSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at ICSharpCode.CodeConverter.VB.MethodBodyVisitor.ConvertSingleExpression(ExpressionSyntax node)
'''    at ICSharpCode.CodeConverter.VB.MethodBodyVisitor.VisitExpressionStatement(ExpressionStatementSyntax node)
'''    at Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
'''    at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.Visit(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingMethodBodyVisitor.ConvertWithTrivia(SyntaxNode node)
'''    at ICSharpCode.CodeConverter.VB.CommentConvertingMethodBodyVisitor.DefaultVisit(SyntaxNode node)
''' 
''' Input: 
'''             dialog.Color = Color.FromArgb(0xff, fontcolor & 0xff, (fontcolor >> 8) & 0xff, (fontcolor >> 16) & 0xff);

''' 
            Dim result As DialogResult = dialog.ShowDialog()

            If result = DialogResult.OK Then
                Dim color As String = dialog.Color.Name

                If Not dialog.Color.IsNamedColor Then
                    color = "#" & color.Remove(0, 2)
                End If

                webBrowserBody.Document.ExecCommand("ForeColor", False, color)
            End If

            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonNumbers_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("InsertOrderedList", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonBullets_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("InsertUnorderedList", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonOutdent_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("Outdent", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonIndent_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("Indent", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonLeft_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("JustifyLeft", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonCenter_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("JustifyCenter", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonRight_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("JustifyRight", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonFull_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("JustifyFull", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonLine_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("InsertHorizontalRule", False, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonHyperlink_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("CreateLink", True, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub toolStripButtonPicture_Click(ByVal sender As Object, ByVal e As EventArgs)
            If Updating Then
                Return
            End If

            webBrowserBody.Document.ExecCommand("InsertImage", True, Nothing)
            RefreshToolBar()
        End Sub

        Private Sub webBrowserBody_DocumentCompleted(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
        End Sub

        Private Sub webBrowserBody_PreviewKeyDown(ByVal sender As Object, ByVal e As PreviewKeyDownEventArgs)
            If e.IsInputKey Then
                Return
            End If

            RefreshToolBar()
        End Sub

        Private Sub webBrowserBody_DocumentClick(ByVal sender As Object, ByVal e As HtmlElementEventArgs)
            RefreshToolBar()
        End Sub

        Private Sub webBrowserBody_DocumentFocusing(ByVal sender As Object, ByVal e As HtmlElementEventArgs)
            RefreshToolBar()
        End Sub

        Private Class FontSize
            Private Shared allFontSize As List(Of FontSize) = Nothing

            Public Shared ReadOnly Property All As List(Of FontSize)
                Get

                    If allFontSize Is Nothing Then
                        allFontSize = New List(Of FontSize)()
                        allFontSize.Add(New FontSize(8, 1))
                        allFontSize.Add(New FontSize(10, 2))
                        allFontSize.Add(New FontSize(12, 3))
                        allFontSize.Add(New FontSize(14, 4))
                        allFontSize.Add(New FontSize(18, 5))
                        allFontSize.Add(New FontSize(24, 6))
                        allFontSize.Add(New FontSize(36, 7))
                    End If

                    Return allFontSize
                End Get
            End Property

            Public Shared Function Find(ByVal value As Integer) As FontSize
                If value< 1 Then
                    Return All(0)
                End If

                If value > 7 Then
                    Return All(6)
                End If

                Return All(value - 1)
            End Function

            Private Sub New(ByVal display As Integer, ByVal value As Integer)
                displaySize = display
                valueSize = value
            End Sub

            Private valueSize As Integer

            Public ReadOnly Property Value As Integer
                Get
                    Return valueSize
                End Get
            End Property

            Private displaySize As Integer

            Public ReadOnly Property Display As Integer
                Get
                    Return displaySize
                End Get
            End Property

            Public Overrides Function ToString() As String
                Return displaySize.ToString()
            End Function
        End Class

        Private Class ToolStripComboBoxEx
            Inherits ToolStripComboBox

            Public Overrides Function GetPreferredSize(ByVal constrainingSize As Size) As Size
                Dim size As Size = MyBase.GetPreferredSize(constrainingSize)
                size.Width = Math.Max(Width, &H20)
                Return size
            End Function
        End Class
    End Class
End Namespace
