Imports Stax
Imports Stax.UI
Imports Stax.AppFramework

Public Class AviSynthListView
    Inherits ListView

    Private BlockItemCheck As Boolean
    Private Menu As New ContextMenuStrip

    Public Sub New()
        Menu.ShowImageMargin = False
        ContextMenuStrip = Menu
        AllowDrop = True
        Anchor = AnchorStyles.Top Or AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right
        CheckBoxes = True

        Dim ch1 As New ColumnHeader
        Dim ch2 As New ColumnHeader
        ch1.Width = 70
        ch2.Width = 124

        Columns.AddRange(New ColumnHeader() {ch1, ch2})
        FullRowSelect = True
        HeaderStyle = ColumnHeaderStyle.None
        HideSelection = False
        Location = New Point(8, 16)
        MultiSelect = False
        Size = New Size(216, 126)
        TabIndex = 0
        UseCompatibleStateImageBehavior = False
        View = Windows.Forms.View.Details
    End Sub

    Private GetProfileMethodValue As FunctionDelegate(Of AviSynthDocument)

    Public Property GetProfileMethod() As FunctionDelegate(Of AviSynthDocument)
        Get
            Return GetProfileMethodValue
        End Get
        Set(ByVal Value As FunctionDelegate(Of AviSynthDocument))
            GetProfileMethodValue = Value
        End Set
    End Property

    Public Sub Load()
        BlockItemCheck = True
        Items.Clear()

        For Each i As AviSynthFilter In GetProfileMethod.Invoke.Filters
            Dim item As New ListViewItem
            item.Text = i.Category
            item.Tag = i
            item.Checked = i.Active
            item.SubItems.Add(i.Name)
            Items.Add(item)
        Next

        BlockItemCheck = False
    End Sub

    Public Sub UpdateAviSynthMenu()
        Menu.Items.Clear()

        If SelectedItems.Count > 0 Then
            Dim selectedFilter As AviSynthFilter = DirectCast(SelectedItems(0).Tag, AviSynthFilter)

            For Each i As AviSynthCategory In s.AviSynthCategories
                If i.Name = selectedFilter.Category Then
                    For Each iFilter As AviSynthFilter In i.Filters
                        Menu.Items.Add(New ParamToolStripMenuItem(Of AviSynthFilter)(iFilter.Name, AddressOf AviSynthChangeClick, iFilter.GetCopy))
                    Next
                End If
            Next

            If Menu.Items.Count > 0 Then Menu.Items.Add(New ToolStripSeparator)

            Menu.Items.Add(New SubToolStripMenuItem("Replace...", AddressOf AviSynthPresetsReplaceClick))
            Menu.Items.Add(New SubToolStripMenuItem("Insert...", AddressOf AviSynthPresetsInsertClick))
        End If

        Menu.Items.Add(New SubToolStripMenuItem("Add...", AddressOf AviSynthPresetsAddClick))

        If SelectedItems.Count > 0 Then
            Menu.Items.Add(New ToolStripSeparator)

            Menu.Items.Add(New SubToolStripMenuItem("Edit...", AddressOf AviSynthEditClick))
            Menu.Items.Add(New SubToolStripMenuItem("Remove", AddressOf AviSynthRemoveClick))
        End If

        Menu.Items.Add(New SubToolStripMenuItem("Profiles...", AddressOf g.MainForm.OpenAviSynthFilterProfilesDialog))
    End Sub

    Private Sub lvAviSynth_ItemCheck(ByVal sender As Object, ByVal e As ItemCheckEventArgs) Handles Me.ItemCheck
        Dim filter As AviSynthFilter = CType(Items(e.Index).Tag, AviSynthFilter)
        filter.Active = e.NewValue = CheckState.Checked
    End Sub

    Private Sub AviSynthEditClick()
        Dim index As Integer = SelectedItems(0).Index
        Dim filter As AviSynthFilter = DirectCast(SelectedItems(0).Tag, AviSynthFilter)

        Dim f As New SettingTreeViewForm("Filter Configuration", "The Filter Configuration dialog allows to edit the configuration of the selected AviSynth filter.")
        f.SettingTreeView.AddSetting(New TextBoxTreeNodeSetting("Name", "General", New BindingSettingBag(Of String)(filter, "Name"), Nothing))

        Dim categories As New List(Of String)

        For Each i As AviSynthCategory In s.AviSynthCategories
            categories.Add(i.Name)
        Next

        f.SettingTreeView.AddSetting(New ComboboxTreeNodeSetting(Of String)("Category", "General", New BindingSettingBag(Of String)(filter, "Category"), Nothing, categories.ToArray))
        f.SettingTreeView.AddSetting(New CheckBoxTreeNodeSetting("Active", "General", New BindingSettingBag(Of Boolean)(filter, "Active"), Nothing))
        f.SettingTreeView.AddSetting(New ScriptEditorTreeNodeSetting("Script", "General", New BindingSettingBag(Of String)(filter, "Script"), Nothing))

        f.SettingTreeView.Nodes(0).ExpandAll()

        If f.ShowDialog = DialogResult.OK Then
            Load()
            Items(index).Selected = True
        End If

        f.Dispose()
    End Sub

    Private Sub AviSynthChangeClick(ByVal f As AviSynthFilter)
        Dim index As Integer = SelectedItems(0).Index
        GetProfileMethod.Invoke.Filters(index) = f
        Load()
        Items(index).Selected = True
    End Sub

    Private Sub AviSynthRemoveClick()
        If Msg.Show("Please confirm to remove the selected filter.", "Remove", _
            MsgIcon.Question, MessageBoxButtons.OKCancel) = DialogResult.OK Then

            Dim index As Integer = SelectedItems(0).Index
            GetProfileMethod.Invoke.Filters.RemoveAt(SelectedItems(0).Index)
            Load()
        End If
    End Sub

    Private Sub AviSynthPresetsReplaceClick()
        Dim f As New FilterSelectionForm
        f.Text = "Replace Filter"
        f.ShowDialog()

        If Not f.Filter Is Nothing Then
            Dim newFilter As AviSynthFilter = f.Filter.GetCopy
            Dim index As Integer = SelectedItems(0).Index
            GetProfileMethod.Invoke.Filters(index) = newFilter
            Load()
            Items(index).Selected = True
        End If

        f.Dispose()
    End Sub

    Private Sub AviSynthPresetsInsertClick()
        Dim f As New FilterSelectionForm
        f.Text = "Insert Filter"
        f.ShowDialog()

        If Not f.Filter Is Nothing Then
            Dim newFilter As AviSynthFilter = f.Filter.GetCopy
            Dim index As Integer = SelectedItems(0).Index
            GetProfileMethod.Invoke.Filters.Insert(index, newFilter)
            Load()
            Items(index).Selected = True
        End If

        f.Dispose()
    End Sub

    Private Sub AviSynthPresetsAddClick()
        Dim f As New FilterSelectionForm
        f.Text = "Add Filter"
        f.ShowDialog()

        If Not f.Filter Is Nothing Then
            Dim newFilter As AviSynthFilter = f.Filter.GetCopy
            GetProfileMethod.Invoke.Filters.Add(newFilter)
            Load()
            Items(Items.Count - 1).Selected = True
        End If

        f.Dispose()
    End Sub

    Private Sub lvAviSynth_DragEnter(ByVal sender As Object, ByVal e As DragEventArgs) Handles Me.DragEnter
        e.Effect = DragDropEffects.Move
    End Sub

    Private Sub lvAviSynth_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) Handles Me.DragOver
        Dim mousePos As Point = PointToClient(Control.MousePosition)
        Dim mousePosItem As ListViewItem = GetItemAt(mousePos.X, mousePos.Y)

        If Not mousePosItem Is Nothing AndAlso _
            SelectedItems.Count > 0 AndAlso _
            Not mousePosItem Is SelectedItems(0) Then

            Dim index As Integer = mousePosItem.Index
            Dim selectedItem As ListViewItem = SelectedItems(0)
            BeginUpdate()
            selectedItem.Remove()
            Items.Insert(index, selectedItem)

            For Each i As ListViewItem In Items
                If i.Focused = True Then
                    i.Focused = False
                End If
            Next

            EndUpdate()
        End If
    End Sub

    Private Sub lvAviSynth_ItemDrag(ByVal sender As Object, ByVal e As ItemDragEventArgs) Handles Me.ItemDrag
        DoDragDrop(e.Item, DragDropEffects.Move)
    End Sub

    Private Sub lvAviSynth_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles Me.DragDrop
        UpdateAviSynthDocument()
    End Sub

    Private Sub lvAviSynth_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Right Then
            UpdateAviSynthMenu()
            Menu.Show(Me, PointToClient(Control.MousePosition))
        End If
    End Sub

    Public Sub UpdateAviSynthDocument()
        GetProfileMethod.Invoke.Filters.Clear()

        For Each i As ListViewItem In Items
            GetProfileMethod.Invoke.Filters.Add(CType(i.Tag, AviSynthFilter))
        Next
    End Sub
End Class