' *
' * The project site is at: http://sourceforge.jp/projects/fishbornas/
' *
' * First author tiritomato 2012.
' *
' * Distributed under the FishbornArchiveShelf License (See
' *  file "Licenses/License.txt" contained in a project, or the following link.
' *  http://sourceforge.jp/projects/fishbornas/scm/svn/blobs/head/trunk/Licenses/License.txt)
' *
' * 2012.06.07 Initial Revision (tiritomato)
' *

Imports System.Collections
Partial Public Class Logic
    Partial Class Collections

        Public Class KeyBase(Of T)
            Implements System.IComparable(Of KeyBase(Of T))
            Implements System.IEquatable(Of KeyBase(Of T))
            Public Delegate Function ToBoolean(ByVal src As KeyBase(Of T))
            Private Hash As Integer
            Private _Key As T
            Private Dictionaries As Generic.LinkedList(Of ICollection)
            Public Sub New()
                _Key = Nothing
                Hash = 0
                Dictionaries = Nothing
            End Sub
            Public Sub New(ByVal v As T)
                _Key = v
                If Not v Is Nothing Then
                    Hash = v.GetHashCode
                Else
                    Hash = 0
                End If
                Dictionaries = Nothing
            End Sub
            Public Property Key As T
                Get
                    Key = _Key
                End Get
                Set(ByVal value As T)
                    ' Remove Dictionaries
                    Dim RefArray() As ICollection = Nothing
                    If Not Dictionaries Is Nothing Then
                        ReDim RefArray(Dictionaries.Count - 1)
                        Dictionaries.CopyTo(RefArray, 0)
                        For idx As Integer = 0 To RefArray.Length - 1
                            If Not RefArray(idx) Is Nothing AndAlso RefArray(idx).Remove(_Key) = False Then RefArray(idx) = Nothing
                        Next
                    End If
                    ' Key Refresh
                    _Key = value
                    If value Is Nothing Then
                        Hash = 0
                    Else
                        Hash = value.GetHashCode
                        ' Restore Dictionaries
                        If Not RefArray Is Nothing AndAlso 0 < RefArray.Length Then
                            For idx As Integer = 0 To RefArray.Length - 1
                                If Not RefArray(idx) Is Nothing Then RefArray(idx).Add(Me)
                            Next
                            If Dictionaries.Count <= 0 Then Dictionaries = Nothing
                        End If
                    End If
                End Set
            End Property
            Public Function Excuse(ByVal src As T) As Boolean
                For Each dic As ICollection In Dictionaries
                    If dic.Contains(src) Then Return False
                Next
                Return True
            End Function
            Public ReadOnly Property IsChained(ByVal col As ICollection) As Boolean
                Get
                    If Dictionaries Is Nothing Then Return False
                    Return Not Dictionaries.Find(col) Is Nothing
                End Get
            End Property
            Public NotOverridable Overrides Function Equals(ByVal src As Object) As Boolean
                If src Is Nothing Then Return False
                Dim ref As KeyBase(Of T) = TryCast(src, KeyBase(Of T))
                If ref Is Nothing Then Return False
                Return Equals(ref._Key)
            End Function
            Public Overloads Function Equals(ByVal v As T) As Boolean
                Return Key.Equals(v)
            End Function
            Public Overloads Function Equals(ByVal src As KeyBase(Of T)) As Boolean Implements System.IEquatable(Of KeyBase(Of T)).Equals
                Return Equals(src._Key)
            End Function
            Public Shared Operator =(ByVal x As KeyBase(Of T), ByVal y As KeyBase(Of T)) As Boolean
                If x Is y Then Return True
                If Not x Is Nothing Then Return x.Equals(y)
                Return y.Equals(x)
            End Operator
            Public Shared Operator <>(ByVal x As KeyBase(Of T), ByVal y As KeyBase(Of T)) As Boolean
                Return Not (x = y)
            End Operator
            Public NotOverridable Overrides Function GetHashCode() As Integer
                Return Hash
            End Function
            Public Function CompareTo(ByVal other As KeyBase(Of T)) As Integer Implements System.IComparable(Of KeyBase(Of T)).CompareTo
                If other Is Nothing Then Return 1
                Return Generic.Comparer(Of T).Default.Compare(_Key, other._Key)
            End Function

            Public Interface ICollection
                Function Remove(ByVal Key As T) As Boolean
                Function Add(ByVal src As KeyBase(Of T), Optional ByVal isEnable As KeyBase(Of T).ToBoolean = Nothing) As Boolean
                Function Contains(ByVal Key As T) As Boolean
            End Interface

            Public Class Collection(Of TVal As {New, KeyBase(Of T)})
                Implements IEnumerable
                Implements ICollection

                Private ary As New Generic.SortedDictionary(Of Integer, Generic.List(Of TVal))

                Default Public ReadOnly Property Item(ByVal Key As T) As TVal
                    Get
                        Dim KeyBase As New TVal
                        KeyBase.Key = Key
                        If ary.ContainsKey(KeyBase.Hash) Then
                            Dim idx As Integer = ary(KeyBase.Hash).BinarySearch(KeyBase)
                            If 0 <= idx Then Return ary(KeyBase.Hash)(idx)
                        End If
                        Return Nothing
                    End Get
                End Property

                Public Function Contains(ByVal Key As T) As Boolean Implements ICollection.Contains
                    Dim KeyBase As New TVal
                    KeyBase.Key = Key
                    If ary.ContainsKey(KeyBase.Hash) Then Return 0 <= ary(KeyBase.Hash).BinarySearch(KeyBase)
                    Return False
                End Function

                Public Function Contains(ByVal src As KeyBase(Of T)) As Boolean
                    If Not src Is Nothing AndAlso ary.ContainsKey(src.Hash) Then Return 0 <= ary(src.Hash).BinarySearch(src)
                    Return False
                End Function

                Public Function GetEnumerator() As System.Collections.IEnumerator Implements IEnumerable.GetEnumerator
                    Return ary.GetEnumerator
                End Function

                Public Function Add(ByVal src As KeyBase(Of T), Optional ByVal isEnable As KeyBase(Of T).ToBoolean = Nothing) As Boolean Implements ICollection.Add
                    If (src Is Nothing) Or (Not isEnable Is Nothing AndAlso isEnable(src) = False) Then Return False
                    Dim ref As Generic.List(Of TVal) = Nothing
                    If ary.ContainsKey(src.Hash) Then
                        ref = ary(src.Hash)
                        Dim idx As Integer = ref.BinarySearch(src)
                        If 0 <= idx Then Return False
                        ref.Insert(idx Xor -1, src)
                    Else
                        ref = New Generic.List(Of TVal)(1)
                        ary.Add(src.Hash, ref)
                        ref.Add(src)
                    End If
                    If src.Dictionaries Is Nothing Then src.Dictionaries = New Generic.LinkedList(Of ICollection)
                    If Not src.IsChained(Me) Then src.Dictionaries.AddLast(Me)
                    Return True
                End Function

                Public Function Remove(ByVal Key As T) As Boolean Implements ICollection.Remove
                    Dim KeyBase As New TVal
                    KeyBase.Key = Key
                    If ary.ContainsKey(KeyBase.Hash) Then
                        Dim idx As Integer = ary(KeyBase.Hash).BinarySearch(KeyBase)
                        If 0 <= idx Then
                            Dim src As KeyBase(Of T) = ary(KeyBase.Hash)(idx)
                            ary(KeyBase.Hash).RemoveAt(idx)
                            If ary(KeyBase.Hash).Count <= 0 Then ary.Remove(KeyBase.Hash)
                            If Not src.Dictionaries Is Nothing Then
                                Dim Dictionary As Generic.LinkedListNode(Of ICollection) = src.Dictionaries.Find(Me)
                                If Not Dictionary Is Nothing Then src.Dictionaries.Remove(Dictionary)
                            End If
                            Return True
                        End If
                    End If
                    Return False
                End Function
                Public Sub Clear()
                    ary.Clear()
                End Sub

            End Class ' Collection

        End Class ' KeyBase

    End Class
End Class



