Imports System.Reflection
Imports System.ComponentModel
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Drawing.Design
Imports System.Runtime.InteropServices
Imports System.IO

Imports Stax.DynamicObject
Imports Stax.Win32
Imports Stax.ComponentModel

Namespace UI
    Public Class OpenFileDialogEditor
        Inherits UITypeEditor

        Public Overloads Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object
            Dim f As New OpenFileDialog

            If f.ShowDialog = DialogResult.OK Then
                Return f.FileName
            Else
                Return value
            End If
        End Function

        Public Overloads Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle
            Return UITypeEditorEditStyle.Modal
        End Function
    End Class

    Public Class StringEditor
        Inherits UITypeEditor

        Public Sub New()
        End Sub

        Public Overloads Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object
            Dim f As New StringEditorForm
            f.tb.Text = DirectCast(value, String)

            If f.ShowDialog() = DialogResult.OK Then
                Return StringHelp.FixBreak(f.tb.Text)
            Else
                Return value
            End If
        End Function

        Public Overloads Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return UITypeEditorEditStyle.Modal
        End Function
    End Class

    Public Class ListBag(Of T)
        Public Sub New(ByVal text As String, ByVal value As T)
            Me.Text = text
            Me.Value = value
        End Sub

        Private TextValue As String

        Public Property Text() As String
            Get
                Return TextValue
            End Get
            Set(ByVal Value As String)
                TextValue = Value
            End Set
        End Property

        Private ValueValue As T

        Public Property Value() As T
            Get
                Return ValueValue
            End Get
            Set(ByVal Value As T)
                ValueValue = Value
            End Set
        End Property

        Public Shared Sub SelectItem(ByVal cb As ComboBox, ByVal value As T)
            Dim selectItem As Object = Nothing

            For Each i As ListBag(Of T) In cb.Items
                If i.Value.Equals(value) Then
                    selectItem = i
                End If
            Next

            If Not selectItem Is Nothing Then
                cb.SelectedItem = selectItem
            End If
        End Sub

        Public Shared Function GetValue(ByVal cb As ComboBox) As T
            Return DirectCast(DirectCast(cb.SelectedItem, ListBag(Of T)).Value, T)
        End Function

        Public Shared Sub PopulateList(ByVal cb As ComboBox)
            For Each i As T In System.Enum.GetValues(GetType(T))
                cb.Items.Add(New ListBag(Of T)(NameAttribute.GetEnumName(Of T)(i), i))
            Next
        End Sub

        Public Overrides Function ToString() As String
            Return Text
        End Function
    End Class

    <ProvideProperty("Pattern", GetType(Control))> _
    Public Class ValidationProvider
        Inherits Component
        Implements IExtenderProvider

        Private Patterns As New Dictionary(Of Control, String)
        Private Defaults As New Dictionary(Of Control, String)

        Public Function CanExtend(ByVal obj As Object) As Boolean Implements IExtenderProvider.CanExtend
            Return TypeOf obj Is Control
        End Function

        <DefaultValue("")> _
           Public Function GetPattern(ByVal c As Control) As String
            If Patterns.ContainsKey(c) Then
                Return Patterns(c)
            End If

            Return ""
        End Function

        Public Sub SetPattern(ByVal c As Control, ByVal value As String)
            If Not Patterns.ContainsKey(c) Then
                AddHandler c.Validating, AddressOf Validating
                AddHandler c.Enter, AddressOf Enter
            End If

            Patterns(c) = value
        End Sub

        Public Sub Validating(ByVal sender As Object, ByVal e As CancelEventArgs)
            Dim c As Control = CType(sender, Control)

            If Not Regex.IsMatch(c.Text, Patterns(c)) Then
                Msg.Show("""" + c.Text + """ is no valid input.", "Invalid Input", _
                    MsgIcon.Warning, MessageBoxButtons.OK)

                c.Text = Defaults(c)
            End If
        End Sub

        Public Sub Enter(ByVal sender As Object, ByVal e As EventArgs)
            Dim c As Control = CType(sender, Control)
            Defaults(c) = c.Text
        End Sub
    End Class

    Public Delegate Sub MessageDispatchCallback(ByRef m As Message, ByRef cancel As Boolean)

    Public Class MessageFiler
        Implements IMessageFilter

        Private Cancel As Boolean
        Private Callback As MessageDispatchCallback

        Public Sub New(ByVal callback As MessageDispatchCallback)
            Me.Callback = callback
        End Sub

        Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
            Cancel = False
            Callback(m, Cancel)

            If Cancel Then
                Return True
            End If
        End Function
    End Class

    Public Class FileDialogFilter
        Public Shared Function GetAllFiles() As String
            Return "All Files|*.*"
        End Function

        Public Shared Function GetLine(ByVal text As String, ByVal ParamArray extensions As String()) As String
            Return text + " (" + String.Join(", ", extensions) + ")|" + "*." + _
                String.Join(";*.", extensions)
        End Function
    End Class

    <Serializable()> _
    Public Class WindowPositions
        Private Sizes As New Dictionary(Of String, Size)
        Private Positions As New Dictionary(Of String, Point)
        Private WindowStates As New Dictionary(Of String, FormWindowState)

        Public Enum Mode
            Position = 1
            WindowState = 2
            Size = 4
            ClientSize = 8
        End Enum

        Public Sub Save(ByVal f As Form, ByVal m As Mode)
            If (m And Mode.Position) = Mode.Position Then
                SavePosition(f)
            End If

            If (m And Mode.Size) = Mode.Size Then
                SaveSize(f)
            End If

            If (m And Mode.ClientSize) = Mode.ClientSize Then
                SaveClientSize(f)
            End If

            If (m And Mode.WindowState) = Mode.WindowState Then
                SaveWindowState(f)
            End If
        End Sub

        Private Sub SavePosition(ByVal f As Form)
            If f.WindowState = FormWindowState.Normal Then
                Positions(GetKey(f)) = f.Location
            End If
        End Sub

        Private Sub SaveSize(ByVal f As Form)
            If f.WindowState = FormWindowState.Normal Then
                Sizes(GetKey(f)) = f.Size
            End If
        End Sub

        Private Sub SaveClientSize(ByVal f As Form)
            If f.WindowState = FormWindowState.Normal Then
                Sizes(GetKey(f)) = f.ClientSize
            End If
        End Sub

        Private Sub SaveWindowState(ByVal f As Form)
            WindowStates(GetKey(f)) = f.WindowState
        End Sub

        Private Sub RestorePosition(ByVal f As Form)
            If Positions.ContainsKey(GetKey(f)) Then
                f.Location = Positions(GetKey(f))
            Else
                f.Left = 150
                f.Top = 100
            End If
        End Sub

        Private Sub RestoreSize(ByVal f As Form)
            If Sizes.ContainsKey(GetKey(f)) Then
                f.Size = Sizes(GetKey(f))
            End If
        End Sub

        Private Sub RestoreClientSize(ByVal f As Form)
            If Sizes.ContainsKey(GetKey(f)) Then
                f.ClientSize = Sizes(GetKey(f))
            End If
        End Sub

        Private Sub RestoreWindowState(ByVal f As Form)
            If WindowStates.ContainsKey(GetKey(f)) Then
                f.WindowState = WindowStates(GetKey(f))
            End If
        End Sub

        Public Sub Restore(ByVal f As Form, ByVal m As Mode)
            If (m And Mode.Position) = Mode.Position Then
                RestorePosition(f)
            End If

            If (m And Mode.Size) = Mode.Size Then
                RestoreSize(f)
            End If

            If (m And Mode.ClientSize) = Mode.ClientSize Then
                RestoreClientSize(f)
            End If

            If (m And Mode.WindowState) = Mode.WindowState Then
                RestoreWindowState(f)
            End If
        End Sub

        Private Function GetKey(ByVal f As Form) As String
            Return f.Name + f.GetType().FullName
        End Function
    End Class
End Namespace