Imports Windows.Storage.Streams
Imports Windows.UI.Xaml.Media.Imaging
Imports Windows.Storage
Imports Windows.Storage.Pickers
Imports docs = C1.Xaml.RichTextBox.Documents
Imports System.Collections.Generic
Imports RichTextBoxSamples.Tools
Imports C1.Xaml.RichTextBox.Documents
Imports C1.Xaml.RichTextBox
Imports C1.Xaml
Imports Windows.UI.Xaml.Navigation
Imports Windows.UI.Xaml.Input
Imports Windows.UI.Xaml.Controls.Primitives
Imports Windows.UI.Xaml.Controls
Imports Windows.UI.Xaml
Imports Windows.UI.Text
Imports Windows.UI.Popups
Imports System.Reflection
Imports System.Linq
Imports System.IO
Imports System

''' <summary>
''' An empty page that can be used on its own or navigated to within a Frame.
''' </summary>
Partial Public NotInheritable Class AppBarDemo
    Inherits Page
    Private dicFontSize As Dictionary(Of C1Run, Double)
    Private newElement As C1InlineUIContainer

    Public Sub New()
        Me.InitializeComponent()

        InitMorePopup()
        InitAlignPopup()
        dicFontSize = New Dictionary(Of C1Run, Double)()

        btnBold.RichTextBox = rtb
        btnItalic.RichTextBox = rtb
        btnUnderline.RichTextBox = rtb

        Dim asm As Assembly = GetType(DemoRichTextBox).GetTypeInfo().Assembly
        Dim stream As Stream = asm.GetManifestResourceStream("RichTextBoxSamples.simple.htm")
        Dim sr As StreamReader = New StreamReader(stream)
        Dim html As String = sr.ReadToEnd()
        rtb.Html = html

        AddHandler rtb.RightTapped, AddressOf rtb_RightTapped
        AddHandler rtb.SelectionChanged, AddressOf rtb_SelectionChanged
    End Sub

    Sub rtb_SelectionChanged(sender As Object, e As EventArgs)
        dicFontSize.Clear()
        Dim range As C1TextRange = rtb.Selection
        If Not range.Runs.Any() Then
            Return
        End If
        For Each run As C1Run In range.Runs
            dicFontSize.Add(run, run.FontSize)
        Next
    End Sub

    Sub rtb_RightTapped(sender As Object, e As RightTappedRoutedEventArgs)
        BottomAppBar.IsOpen = True
    End Sub

    Private Async Sub rtb_RequestNavigate(sender As Object, e As RequestNavigateEventArgs)
        Dim md As New MessageDialog(String.Concat(Strings.NavigateMessage, e.Hyperlink.NavigateUri), Strings.Navigate)

        md.Commands.Add(New UICommand(Strings.Ok, Function(UICommandInvokedHandler)
                                                      Windows.System.Launcher.LaunchUriAsync(e.Hyperlink.NavigateUri)

                                                  End Function))

        md.Commands.Add(New UICommand(Strings.Cancel, Function(UICommandInvokedHandler)
                                                          rtb.[Select](e.Hyperlink.ContentStart.TextOffset, e.Hyperlink.ContentRange.Text.Length)

                                                      End Function))

        Await md.ShowAsync()
    End Sub
#Region "Clipboard"
    Private Sub btnCopy_Click(sender As Object, e As Windows.UI.Xaml.RoutedEventArgs)
        rtb.ClipboardCopy()
    End Sub

    Private Sub btnCut_Click(sender As Object, e As Windows.UI.Xaml.RoutedEventArgs)
        If rtb.IsReadOnly Then
            rtb.ClipboardCopy()
        Else
            rtb.ClipboardCut()
        End If
    End Sub

    Private Sub btnPaste_Click(sender As Object, e As Windows.UI.Xaml.RoutedEventArgs)
        If Not rtb.IsReadOnly Then
            rtb.ClipboardPaste()
        End If
    End Sub
#End Region

#Region "Undo/Redo"
    Sub btnRedo_Click(sender As Object, e As RoutedEventArgs)
        If rtb.DocumentHistory.CanRedo Then
            rtb.DocumentHistory.Redo()
        End If
        morePopUp.Hide()
    End Sub

    Sub btnUndo_Click(sender As Object, e As RoutedEventArgs)
        If rtb.DocumentHistory.CanUndo Then
            rtb.DocumentHistory.Undo()
        End If
        morePopUp.Hide()
    End Sub
#End Region

#Region "Lists"
    Sub btnBulletedList_Click(sender As Object, e As RoutedEventArgs)
        Using New DocumentHistoryGroup(rtb.DocumentHistory)
            Dim range As C1TextRange = rtb.Selection
            ' check if selection is already a list
            Dim isChecked As Boolean = range.EditRanges.All(Function(r) docs.TextMarkerStyle.Disc.Equals(GetMarkerStyle(r)))
            range.TrimRuns()
            rtb.Selection = range
            For Each r As C1TextRange In range.EditRanges
                If isChecked Then
                    ' undo list
                    range.UndoList()
                Else
                    ' make bullet list
                    range.MakeList(docs.TextMarkerStyle.Disc)
                End If
            Next
        End Using
        morePopUp.Hide()
    End Sub

    Sub btnNumberedList_Click(sender As Object, e As RoutedEventArgs)
        Using New DocumentHistoryGroup(rtb.DocumentHistory)
            Dim range As C1TextRange = rtb.Selection
            ' check if selection is already a list
            Dim isChecked As Boolean = range.EditRanges.All(Function(r) docs.TextMarkerStyle.[Decimal].Equals(GetMarkerStyle(r)))
            range.TrimRuns()
            rtb.Selection = range
            For Each r As C1TextRange In range.EditRanges
                If isChecked Then
                    ' undo list
                    range.UndoList()
                Else
                    ' make number list
                    range.MakeList(docs.TextMarkerStyle.[Decimal])
                End If
            Next
        End Using
        morePopUp.Hide()
    End Sub

    ''' <summary>
    ''' Get the MarkerStyle of the selection.
    ''' </summary>
    ''' <param name="range"></param>
    ''' <returns></returns>
    Function GetMarkerStyle(range As C1TextRange) As System.Nullable(Of docs.TextMarkerStyle)
        Dim lists As List(Of C1List) = range.Lists.ToList()
        Dim marker As System.Nullable(Of docs.TextMarkerStyle) = If(lists.Any(), New System.Nullable(Of docs.TextMarkerStyle)(lists.First().MarkerStyle), Nothing)
        For Each list As C1List In lists
            If marker <> list.MarkerStyle Then
                Return Nothing
            End If
        Next
        Return marker
    End Function
#End Region

#Region "Font Colors"

    Private Sub btnFontColor_Click(sender As Object, e As RoutedEventArgs)
        Dim fontColorPicker As New FontColorTool()
        fontColorPicker.RichTextBox = rtb
        fontColorPicker.ColorMode = FontColorMode.Foreground
        fontColorPicker.Popup.Placement = FlyoutPlacementMode.Top
        fontColorPicker.Show(TryCast(sender, FrameworkElement))
    End Sub

    Private Sub btnHighlight_Click(sender As Object, e As RoutedEventArgs)
        Dim fontColorPicker As New FontColorTool()
        fontColorPicker.RichTextBox = rtb
        fontColorPicker.ColorMode = FontColorMode.Background
        fontColorPicker.Popup.Placement = FlyoutPlacementMode.Top
        fontColorPicker.Show(TryCast(sender, FrameworkElement))
    End Sub

#End Region

#Region "Insert Objects"

    Private Sub btnInsertTable_Click(sender As Object, e As RoutedEventArgs)
        Dim tableTool As New InsertTableTool()
        tableTool.RichTextBox = rtb
        tableTool.Popup.Placement = FlyoutPlacementMode.Top
        tableTool.Show(TryCast(sender, FrameworkElement))
    End Sub

    Private Sub btnInsertHyperlink_Click(sender As Object, e As RoutedEventArgs)
        Dim hyperlinkTool As New InsertHyperlinkTool()
        hyperlinkTool.RichTextBox = rtb
        hyperlinkTool.Popup.Placement = FlyoutPlacementMode.Top
        hyperlinkTool.Show(TryCast(sender, FrameworkElement))
    End Sub

    Private Sub btnInsertPicture_Click(sender As Object, e As RoutedEventArgs)
        Dim imageTool As New InsertImageTool()
        imageTool.RichTextBox = rtb
        imageTool.Popup.Placement = FlyoutPlacementMode.Top
        imageTool.Show(TryCast(sender, FrameworkElement))
    End Sub

    Private Async Sub btnPicture_Click(sender As Object, e As RoutedEventArgs)
        Dim openPicker As New FileOpenPicker()
        openPicker.ViewMode = PickerViewMode.Thumbnail
        openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary
        openPicker.FileTypeFilter.Add(".jpg")
        openPicker.FileTypeFilter.Add(".jpeg")
        openPicker.FileTypeFilter.Add(".png")
        Dim file As StorageFile = Await openPicker.PickSingleFileAsync()
        If file IsNot Nothing Then
            Dim source As New BitmapImage()
            Dim newElement As New C1InlineUIContainer() With {
                .Content = source,
                .ContentTemplate = ImageAttach.ImageTemplate
            }
            AddHandler source.ImageFailed, AddressOf OnImageFailed


            Dim stream As IRandomAccessStream = Await file.OpenAsync(FileAccessMode.Read)
            source.SetSource(stream)

            Using dataReader As New DataReader(stream)
                stream.Seek(0)
                Dim bytes As Byte() = New Byte(stream.Size) {}
                Await dataReader.LoadAsync(CType(stream.Size, UInteger))
                dataReader.ReadBytes(bytes)
                ImageAttach.SetStream(source, bytes)
            End Using
            Using New DocumentHistoryGroup(rtb.DocumentHistory)
                rtb.Selection.Delete()
                rtb.Selection.Start.InsertInline(newElement)
            End Using
            rtb.Focus(FocusState.Programmatic)
        End If
    End Sub

    Private Sub OnImageFailed(sender As Object, e As ExceptionRoutedEventArgs)
        newElement.Remove()
    End Sub
#End Region

#Region "clear formatting"
    Sub btnClear_Click(sender As Object, e As RoutedEventArgs)
        Using New DocumentHistoryGroup(rtb.DocumentHistory)
            ' clear foreground and background colors
            rtb.Selection.InlineBackground = Nothing
            rtb.Selection.Foreground = rtb.Foreground

            ' clear font
            rtb.Selection.FontWeight = FontWeights.Normal
            rtb.Selection.FontStyle = FontStyle.Normal
            rtb.Selection.TextDecorations = Nothing
            If dicFontSize.Count > 0 Then
                For Each el As Object In dicFontSize.Keys
                    el.FontSize = dicFontSize(el)
                Next
            End If
        End Using
    End Sub
#End Region

#Region "sub/super script"
    Sub btnSubscript_Click(sender As Object, e As RoutedEventArgs)
        ' subscript
        Using New DocumentHistoryGroup(rtb.DocumentHistory)
            Dim range As C1TextRange = rtb.Selection
            range.TrimRuns()
            rtb.Selection = range
            For Each ran As C1TextRange In range.EditRanges
                Dim isSub As Boolean = ran.EditRanges.All(Function(r) (C1VerticalAlignment.[Sub]).Equals(r.InlineAlignment))
                Dim isSuper As Boolean = ran.EditRanges.All(Function(r) (C1VerticalAlignment.Super).Equals(r.InlineAlignment))
                If isSub Then
                    ran.InlineAlignment = C1VerticalAlignment.Baseline
                    GrowFont(4)
                Else
                    ran.InlineAlignment = C1VerticalAlignment.[Sub]
                    If Not isSuper Then
                        ShrinkFont(4)
                    End If
                End If
            Next
        End Using
        morePopUp.Hide()
    End Sub

    Sub btnSuperscript_Click(sender As Object, e As RoutedEventArgs)
        ' superscript
        Using New DocumentHistoryGroup(rtb.DocumentHistory)
            Dim range As C1TextRange = rtb.Selection
            range.TrimRuns()
            rtb.Selection = range
            For Each ran As C1TextRange In range.EditRanges
                Dim isSub As Boolean = ran.EditRanges.All(Function(r) (C1VerticalAlignment.[Sub]).Equals(r.InlineAlignment))
                Dim isSuper As Boolean = ran.EditRanges.All(Function(r) (C1VerticalAlignment.Super).Equals(r.InlineAlignment))
                If isSuper Then
                    ran.InlineAlignment = C1VerticalAlignment.Baseline
                    GrowFont(4)
                Else
                    ran.InlineAlignment = C1VerticalAlignment.Super
                    If Not isSub Then
                        ShrinkFont(4)
                    End If
                End If
            Next
        End Using

        morePopUp.Hide()
    End Sub

    Private Sub GrowFont(size As Integer)
        ' grow font
        rtb.Selection.TrimRuns()
        For Each run As C1Run In rtb.Selection.Runs
            run.FontSize += size
        Next
    End Sub

    Private Sub ShrinkFont(size As Integer)
        ' shrink font
        rtb.Selection.TrimRuns()
        For Each run As C1Run In rtb.Selection.Runs
            run.FontSize -= size
        Next
    End Sub
#End Region

#Region "align"

    Private alignPopUp As New Flyout()
    Private Sub btnAlign_Click(sender As Object, e As RoutedEventArgs)
        alignPopUp.Placement = FlyoutPlacementMode.Top
        alignPopUp.ShowAt(TryCast(sender, FrameworkElement))
    End Sub

    Sub InitAlignPopup()
        Dim menuBorder As New Border()
        menuBorder.Height = 140
        menuBorder.Width = 150
        Dim panel As New StackPanel()
        panel.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center

        ' align left
        Dim btnLeftAlign As New Button()
        btnLeftAlign.Content = Strings.AlignLeft
        btnLeftAlign.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnLeftAlign.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnLeftAlign.Click, AddressOf btnLeftAlign_Click

        ' align center
        Dim btnCenterAlign As New Button()
        btnCenterAlign.Content = Strings.AlignCenter
        btnCenterAlign.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnCenterAlign.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnCenterAlign.Click, AddressOf btnCenterAlign_Click

        ' align right
        Dim btnRightAlign As New Button()
        btnRightAlign.Content = Strings.AlignRight
        btnRightAlign.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnRightAlign.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnRightAlign.Click, AddressOf btnRightAlign_Click

        ' justify
        Dim btnJustify As New Button()
        btnJustify.Content = Strings.Justify
        btnJustify.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnJustify.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnJustify.Click, AddressOf btnJustify_Click

        panel.Children.Add(btnLeftAlign)
        panel.Children.Add(btnCenterAlign)
        panel.Children.Add(btnRightAlign)
        panel.Children.Add(btnJustify)
        menuBorder.Child = panel
        alignPopUp.Content = menuBorder
    End Sub

    Sub btnJustify_Click(sender As Object, e As RoutedEventArgs)
        rtb.Selection.TextAlignment = C1TextAlignment.Justify
        alignPopUp.Hide()
    End Sub

    Sub btnRightAlign_Click(sender As Object, e As RoutedEventArgs)
        rtb.Selection.TextAlignment = C1TextAlignment.Right
        alignPopUp.Hide()
    End Sub

    Sub btnCenterAlign_Click(sender As Object, e As RoutedEventArgs)
        rtb.Selection.TextAlignment = C1TextAlignment.Center
        alignPopUp.Hide()
    End Sub

    Sub btnLeftAlign_Click(sender As Object, e As RoutedEventArgs)
        rtb.Selection.TextAlignment = C1TextAlignment.Left
        alignPopUp.Hide()
    End Sub

#End Region

#Region "More"
    Private morePopUp As New Flyout()
    Private Sub btnMore_Click(sender As Object, e As RoutedEventArgs)
        morePopUp.Placement = FlyoutPlacementMode.Top
        morePopUp.ShowAt(TryCast(sender, FrameworkElement))
    End Sub

    Sub InitMorePopup()
        Dim menuBorder As New Border()
        menuBorder.Height = 320
        menuBorder.Width = 170
        Dim panel As New StackPanel()
        panel.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center

        ' bulleted list
        Dim btnBulletedList As New Button()
        btnBulletedList.Content = Strings.BulletedList
        btnBulletedList.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnBulletedList.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnBulletedList.Click, AddressOf btnBulletedList_Click

        ' numbered list
        Dim btnNumberedList As New Button()
        btnNumberedList.Content = Strings.NumberedList
        btnNumberedList.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnNumberedList.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnNumberedList.Click, AddressOf btnNumberedList_Click

        ' undo
        Dim btnUndo As New Button()
        btnUndo.Content = Strings.Undo
        btnUndo.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnUndo.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnUndo.Click, AddressOf btnUndo_Click

        ' undo
        Dim btnRedo As New Button()
        btnRedo.Content = Strings.Redo
        btnRedo.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnRedo.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnRedo.Click, AddressOf btnRedo_Click

        ' clear formatting
        Dim btnClear As New Button()
        btnClear.Content = Strings.ClearFormat
        btnClear.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnClear.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnClear.Click, AddressOf btnClear_Click

        ' superscript
        Dim btnSuperscript As New Button()
        btnSuperscript.Content = Strings.Superscript
        btnSuperscript.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnSuperscript.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnSuperscript.Click, AddressOf btnSuperscript_Click

        ' subscript
        Dim btnSubscript As New Button()
        btnSubscript.Content = Strings.Subscript
        btnSubscript.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnSubscript.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnSubscript.Click, AddressOf btnSubscript_Click

        ' strikethrough
        Dim btnStrikethrough As New Button()
        btnStrikethrough.Content = Strings.Strikethrough
        btnStrikethrough.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnStrikethrough.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnStrikethrough.Click, AddressOf btnStrikethrough_Click

        ' increase font
        Dim btnIncreaseFontSize As New C1IncreaseFontSizeTool()
        btnIncreaseFontSize.RichTextBox = rtb
        btnIncreaseFontSize.Content = Strings.IncreaseFont
        btnIncreaseFontSize.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnIncreaseFontSize.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnIncreaseFontSize.Click, AddressOf btnIncreaseFontSize_Click

        ' decrease font
        Dim btnDecreaseFontSize As New C1DecreaseFontSizeTool()
        btnDecreaseFontSize.RichTextBox = rtb
        btnDecreaseFontSize.Content = Strings.DecreaseFont
        btnDecreaseFontSize.Style = TryCast(Application.Current.Resources("MenuTextButtonStyle"), Style)
        btnDecreaseFontSize.Margin = New Thickness(20, 5, 20, 5)
        AddHandler btnDecreaseFontSize.Click, AddressOf btnDecreaseFontSize_Click

        panel.Children.Add(btnBulletedList)
        panel.Children.Add(btnNumberedList)
        panel.Children.Add(btnSubscript)
        panel.Children.Add(btnSuperscript)
        panel.Children.Add(btnStrikethrough)
        panel.Children.Add(btnIncreaseFontSize)
        panel.Children.Add(btnDecreaseFontSize)
        panel.Children.Add(btnUndo)
        panel.Children.Add(btnRedo)
        panel.Children.Add(btnClear)
        menuBorder.Child = panel
        morePopUp.Content = menuBorder

    End Sub

    Sub btnDecreaseFontSize_Click(sender As Object, e As RoutedEventArgs)
        morePopUp.Hide()
    End Sub

    Sub btnIncreaseFontSize_Click(sender As Object, e As RoutedEventArgs)
        morePopUp.Hide()
    End Sub

    Sub btnStrikethrough_Click(sender As Object, e As RoutedEventArgs)
        ' strikethrough
        Dim isMenuStrikeChecked As Boolean = rtb.Selection.Runs.Any() AndAlso rtb.Selection.Runs.All(Function(r As C1Run) r.TextDecorations IsNot Nothing AndAlso r.TextDecorations.Contains(C1TextDecorations.Strikethrough(0)))

        Dim value As C1TextDecorationCollection = If(isMenuStrikeChecked, Nothing, C1TextDecorations.Strikethrough)

        Using New DocumentHistoryGroup(rtb.DocumentHistory)
            Dim range As C1TextRange = rtb.Selection
            range.TrimRuns()
            rtb.Selection = range
            For Each r As Object In range.EditRanges
                For Each run As C1Run In range.Runs
                    Dim collection As New C1TextDecorationCollection()
                    If value Is Nothing Then
                        For Each decoration As C1TextDecoration In run.TextDecorations
                            collection.Add(decoration)
                        Next

                        collection.Remove(C1TextDecorations.Strikethrough(0))
                        If collection.Count = 0 Then
                            collection = Nothing
                        End If
                    ElseIf run.TextDecorations Is Nothing Then
                        collection.Add(value(0))
                    ElseIf Not run.TextDecorations.Contains(value(0)) Then
                        For Each decoration As C1TextDecoration In run.TextDecorations
                            collection.Add(decoration)
                        Next
                        collection.Add(value(0))
                    Else
                        Continue For
                    End If
                    run.TextDecorations = Nothing

                    run.TextDecorations = collection
                Next
            Next
        End Using
        morePopUp.Hide()
    End Sub

#End Region
    ''' <summary>
    ''' Invoked when this page is about to be displayed in a Frame.
    ''' </summary>
    ''' <param name="e">Event data that describes how this page was reached.  The Parameter
    ''' property is typically used to configure the page.</param>
    Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
    End Sub
End Class