'-------------------------------------------------------------------------------
'--                                                                           --
'--  FILE          :  MemberManagerSingleton.vb                               --
'--                                                                           --
'--  Author(s)     :  Yin Xuebin (Three Swordsmen Team)                       --
'--                                                                           --
'--  NameSpace     :  WomenWC.Managers                                        --
'--                                                                           --
'--  Project       :  WomenWC                                                 --
'--                                                                           --
'--  Solution      :  Women Working with COBOL                                --
'--                                                                           --
'--  Creation Date :  2007/04/10                                              --
'-------------------------------------------------------------------------------
'--  Modifications :                                                          --
'--                                                                           --
'--                                                                           --
'--                                                                           --
'-------------------------------------------------------------------------------
'-- Copyright(C) 2007, Three Swordsmen, Beijing China                         --
'--                                                                           --
'-- This software is released under the GNU General Public License            --
'-------------------------------------------------------------------------------

Imports WomenWCCore.Infos.Analyzer
Imports WomenWCCore.EventArgs
Imports WomenWCCore.Document
Imports WomenWCCore.Interfaces.Analyzer
Imports WomenWCCore.Interfaces.Editor
Imports WomenWCCore.Interfaces.View
Imports WomenWC.Forms
Imports WomenWC.Managers.Manager
Imports System.Threading

Namespace Managers
    Public Class MemberManagerSingleton

        Private _functionInfoTable As Dictionary(Of String, List(Of FunctionInfo))
        Private _variableInfoTable As Dictionary(Of String, List(Of VariableInfo))
        Private _includeInfoTable As Dictionary(Of String, List(Of IncludeInfo))
        Private _needUpdateMemberViewList As List(Of INeedUpdateMember)

        Private Shared _memberManager As MemberManagerSingleton

        Private Sub New()
            _functionInfoTable = New Dictionary(Of String, List(Of FunctionInfo))
            _variableInfoTable = New Dictionary(Of String, List(Of VariableInfo))
            _includeInfoTable = New Dictionary(Of String, List(Of IncludeInfo))
            _needUpdateMemberViewList = New List(Of INeedUpdateMember)
        End Sub

        Public Shared ReadOnly Property MemberManager() As MemberManagerSingleton
            Get
                If _memberManager Is Nothing Then
                    _memberManager = New MemberManagerSingleton
                End If
                Return _memberManager
            End Get
        End Property

        Public Sub Initialize(ByVal ParamArray needUpdateMemberViews() As INeedUpdateMember)
            For Each needUpdateMemberView As INeedUpdateMember In needUpdateMemberViews
                _needUpdateMemberViewList.Add(needUpdateMemberView)
            Next
        End Sub

        Public Sub InitializeMemberInfosFromProjectInfo(ByVal projectInfo As ProjectInfo)
            Dim document As Document
            Dim womenWCAnalyzer As IWomenWCAnalyzer
            Dim womenWCSyntax As IWomenWCSyntax

            For Each programinfo As ProgramInfo In projectInfo.ProgramInfos
                document = DocumentManager.Documents(programinfo.ProgramFileName)
                womenWCAnalyzer = AnalyzerManager.Analyzers(programinfo.ProgramType)
                If womenWCAnalyzer IsNot Nothing Then
                    womenWCSyntax = womenWCAnalyzer.WomenWCSyntax
                Else
                    womenWCSyntax = Nothing
                End If
                If document IsNot Nothing Then
                    SetMembers(document, womenWCSyntax)                    
                End If
            Next

        End Sub

        Public Sub SetMembers(ByVal document As Document, ByVal womenWCSyntax As IWomenWCSyntax)
            Dim functionInfoList As List(Of FunctionInfo)
            Dim variableInfoList As List(Of VariableInfo)
            Dim includeInfoList As List(Of IncludeInfo)


            functionInfoList = New List(Of FunctionInfo)
            variableInfoList = New List(Of VariableInfo)
            includeInfoList = New List(Of IncludeInfo)

            If womenWCSyntax IsNot Nothing Then
                womenWCSyntax.GetMembers(document, functionInfoList, variableInfoList, includeInfoList)
                _functionInfoTable.Remove(document.DocumentFileName)
                _functionInfoTable.Add(document.DocumentFileName, functionInfoList)
                _variableInfoTable.Remove(document.DocumentFileName)
                _variableInfoTable.Add(document.DocumentFileName, variableInfoList)
                _includeInfoTable.Remove(document.DocumentFileName)
                _includeInfoTable.Add(document.DocumentFileName, includeInfoList)
            Else
            End If

        End Sub

        Public Sub DeleteMembers(ByVal DocumentName As String)
            _functionInfoTable.Remove(DocumentName)
            _variableInfoTable.Remove(DocumentName)
            _includeInfoTable.Remove(DocumentName)
        End Sub

        Public Sub SetFunctionInfos(ByVal document As Document, ByVal womenWCSyntax As IWomenWCSyntax)
            Dim functionInfoList As List(Of FunctionInfo)
            If womenWCSyntax IsNot Nothing Then
                _functionInfoTable.Remove(document.DocumentFileName)
                functionInfoList = womenWCSyntax.GetFunctions(document)
                _functionInfoTable.Add(document.DocumentFileName, functionInfoList)
            Else
            End If
        End Sub

        Public Sub SetVariableInfos(ByVal document As Document, ByVal womenWCSyntax As IWomenWCSyntax)
            Dim variableInfoList As List(Of VariableInfo)
            If womenWCSyntax IsNot Nothing Then
                _variableInfoTable.Remove(document.DocumentFileName)
                variableInfoList = womenWCSyntax.GetVariables(document)
                _variableInfoTable.Add(document.DocumentFileName, variableInfoList)
            Else
            End If
        End Sub

        Public Sub SetIncludeInfos(ByVal document As Document, ByVal womenWCSyntax As IWomenWCSyntax)
            Dim includeInfoList As List(Of IncludeInfo)
            If womenWCSyntax IsNot Nothing Then
                _includeInfoTable.Remove(document.DocumentFileName)
                includeInfoList = womenWCSyntax.GetIncludes(document)
                _includeInfoTable.Add(document.DocumentFileName, includeInfoList)
            Else
            End If
        End Sub

        Public Sub RemoveAllMember()
            Me._functionInfoTable.Clear()
            Me._includeInfoTable.Clear()
            Me._variableInfoTable.Clear()
        End Sub

        Public Sub AddDocumentForm(ByVal documentForm As DocumentForm)
            AddHandler documentForm.WomenWCEditor.MouseStopAtWord, AddressOf OnEditorMouseStopAtWord
            AddHandler documentForm.WomenWCEditor.NeedUpdateMember, AddressOf OnEditorNeedUpdateMember
            AddHandler documentForm.Load, AddressOf OnDocumentFormLoad
        End Sub

        Public Sub RemoveDocumentForm(ByVal documentForm As DocumentForm)
            RemoveHandler documentForm.WomenWCEditor.MouseStopAtWord, AddressOf OnEditorMouseStopAtWord
            RemoveHandler documentForm.WomenWCEditor.NeedUpdateMember, AddressOf OnEditorNeedUpdateMember
            RemoveHandler documentForm.Load, AddressOf OnDocumentFormLoad
        End Sub

        Public Function GetFunctionInfoList(ByVal documentFileName As String) As List(Of FunctionInfo)
            Dim result As List(Of FunctionInfo)
            If _functionInfoTable.ContainsKey(documentFileName) Then
                result = _functionInfoTable(documentFileName)
            Else
                result = New List(Of FunctionInfo)
                result.Clear()
            End If
            Return result
        End Function

        Public Function GetFunctionInfo(ByVal documentFileName As String, ByVal functionName As String, Optional ByVal withInclude As Boolean = False, Optional ByVal includeInfo As IncludeInfo = Nothing) As FunctionInfo
            Dim result As FunctionInfo
            Dim functionInfoList As List(Of FunctionInfo)
            Dim prefixing As String
            Dim suffixing As String

            result = Nothing
            functionInfoList = GetFunctionInfoList(documentFileName)
            If includeInfo IsNot Nothing Then
                prefixing = includeInfo.IncludePrefixing
                suffixing = includeInfo.IncludeSuffixing
            Else
                prefixing = String.Empty
                suffixing = String.Empty
            End If

            For Each functionInfo As FunctionInfo In functionInfoList
                If functionName = prefixing & functionInfo.FunctionName & suffixing Then
                    result = functionInfo
                    Exit For
                End If
            Next

            If result Is Nothing AndAlso withInclude AndAlso _includeInfoTable.ContainsKey(documentFileName) Then
                For Each subIncludeInfo As IncludeInfo In _includeInfoTable(documentFileName)
                    If functionName.StartsWith(subIncludeInfo.IncludePrefixing) AndAlso _
                       functionName.EndsWith(subIncludeInfo.IncludeSuffixing) Then
                        result = GetFunctionInfo(GetFileNameFromIncludeName(subIncludeInfo.IncludeName), functionName, True, subIncludeInfo)
                        If result IsNot Nothing Then
                            Exit For
                        Else
                        End If
                    End If
                Next
            End If

            Return result
        End Function

        Public Function GetVariableInfoList(ByVal documentFileName As String) As List(Of VariableInfo)
            Dim result As List(Of VariableInfo)
            If _variableInfoTable.ContainsKey(documentFileName) Then
                result = _variableInfoTable(documentFileName)
            Else
                result = New List(Of VariableInfo)
                result.Clear()
            End If
            Return result
        End Function

        Public Function GetVariableInfo(ByVal documentFileName As String, ByVal variableName As String, Optional ByVal withInclude As Boolean = False, Optional ByVal includeInfo As IncludeInfo = Nothing) As VariableInfo
            Dim result As VariableInfo
            Dim variableInfoList As List(Of VariableInfo)
            Dim prefixing As String
            Dim suffixing As String

            result = Nothing
            variableInfoList = GetVariableInfoList(documentFileName)
            If includeInfo IsNot Nothing Then
                prefixing = includeInfo.IncludePrefixing
                suffixing = includeInfo.IncludeSuffixing
            Else
                prefixing = String.Empty
                suffixing = String.Empty
            End If

            For Each variableInfo As VariableInfo In variableInfoList
                If variableName = prefixing & variableInfo.VariableName & suffixing Then
                    result = variableInfo
                    Exit For
                End If
            Next

            If result Is Nothing AndAlso withInclude AndAlso _includeInfoTable.ContainsKey(documentFileName) Then
                For Each subIncludeInfo As IncludeInfo In _includeInfoTable(documentFileName)
                    If variableName.StartsWith(subIncludeInfo.IncludePrefixing) AndAlso _
                       variableName.EndsWith(subIncludeInfo.IncludeSuffixing) Then
                        result = GetVariableInfo(GetFileNameFromIncludeName(subIncludeInfo.IncludeName), variableName, True, subIncludeInfo)
                        If result IsNot Nothing Then
                            Exit For
                        Else
                        End If
                    End If
                Next
            End If

            Return result
        End Function

        Public Function GetIncludeInfoList(ByVal documentFileName As String) As List(Of IncludeInfo)
            Dim result As List(Of IncludeInfo)
            If _includeInfoTable.ContainsKey(documentFileName) Then
                result = _includeInfoTable(documentFileName)
            Else
                result = New List(Of IncludeInfo)
                result.Clear()
            End If
            Return result
        End Function

        Public Function GetFunctionNameList(ByVal documentFileName As String, Optional ByVal withInclude As Boolean = False, Optional ByVal includeInfo As IncludeInfo = Nothing) As List(Of String)
            Dim result As List(Of String)
            Dim prefixing As String
            Dim suffixing As String


            result = New List(Of String)
            If includeInfo IsNot Nothing Then
                prefixing = includeInfo.IncludePrefixing
                suffixing = includeInfo.IncludeSuffixing
            Else
                prefixing = String.Empty
                suffixing = String.Empty
            End If

            If _functionInfoTable.ContainsKey(documentFileName) Then
                For Each functionInfo As FunctionInfo In _functionInfoTable(documentFileName)
                    result.Add(prefixing & functionInfo.FunctionName & suffixing)
                Next
            Else
            End If

            If withInclude AndAlso _includeInfoTable.ContainsKey(documentFileName) Then
                For Each subIncludeInfo As IncludeInfo In _includeInfoTable(documentFileName)
                    result.AddRange(GetFunctionNameList(GetFileNameFromIncludeName(subIncludeInfo.IncludeName), True, subIncludeInfo))
                Next
            Else
            End If
            Return result
        End Function

        Public Function GetVariableNameList(ByVal documentFileName As String, Optional ByVal withInclude As Boolean = False, Optional ByVal includeInfo As IncludeInfo = Nothing) As List(Of String)
            Dim result As List(Of String)

            Dim prefixing As String
            Dim suffixing As String


            result = New List(Of String)
            If includeInfo IsNot Nothing Then
                prefixing = includeInfo.IncludePrefixing
                suffixing = includeInfo.IncludeSuffixing
            Else
                prefixing = String.Empty
                suffixing = String.Empty
            End If

            If _variableInfoTable.ContainsKey(documentFileName) Then
                For Each variableInfo As VariableInfo In _variableInfoTable(documentFileName)
                    result.Add(prefixing & variableInfo.VariableName & suffixing)
                Next
            Else
            End If

            If withInclude AndAlso _includeInfoTable.ContainsKey(documentFileName) Then
                For Each subIncludeInfo As IncludeInfo In _includeInfoTable(documentFileName)
                    result.AddRange(GetVariableNameList(GetFileNameFromIncludeName(subIncludeInfo.IncludeName), True, subIncludeInfo))
                Next
            Else
            End If
            Return result
        End Function

        Private Sub OnEditorMouseStopAtWord(ByVal sender As Object, ByVal e As MouseStopAtWordEventArgs)
            Dim womenWCEditor As IWomenWCEditor
            Dim functionInfo As FunctionInfo
            Dim variableInfo As VariableInfo
            Dim commentTipPosition As Point

            If TypeOf sender Is IWomenWCEditor Then
                womenWCEditor = DirectCast(sender, IWomenWCEditor)
                commentTipPosition = e.Position
                commentTipPosition.Offset(16, -16)

                If e.Word.WordType = WomenWCCore.Enums.WordTypeEnum.NormalWord Then
                    functionInfo = GetFunctionInfo(womenWCEditor.Document.DocumentFileName, e.Word.WordString, True)
                    If functionInfo IsNot Nothing Then
                        womenWCEditor.ShowCommentTip(functionInfo.FunctionDeclare, commentTipPosition, -1)
                        Return
                    End If
                    variableInfo = GetVariableInfo(womenWCEditor.Document.DocumentFileName, e.Word.WordString, True)
                    If variableInfo IsNot Nothing Then
                        womenWCEditor.ShowCommentTip(variableInfo.VariableDeclare, commentTipPosition, -1)
                        Return
                    End If
                    womenWCEditor.HideCommentTip()
                Else
                    womenWCEditor.HideCommentTip()
                End If
            Else
            End If
        End Sub

        Private Sub OnDocumentFormLoad(ByVal sender As Object, ByVal e As System.EventArgs)
            Dim documentForm As DocumentForm

            If TypeOf sender Is DocumentForm Then
                documentForm = DirectCast(sender, DocumentForm)
                SetEditorCodeCompletionForm(documentForm.WomenWCEditor)
            End If
        End Sub

        Private Sub OnEditorNeedUpdateMember(ByVal sender As Object, ByVal e As NeedUpdateMemberEventArgs)
            If TypeOf sender Is IWomenWCEditor Then
                UpdateMember(DirectCast(sender, IWomenWCEditor))
            Else
            End If
        End Sub

        Private Sub UpdateMember(ByVal womenWCEditor As IWomenWCEditor)
            Dim womenWCSyntax As IWomenWCSyntax
            Dim updateEditorThread As Thread

            If ProjectManager.ProjectInfo IsNot Nothing AndAlso _
               ProjectManager.ProjectInfo.ProgramInfos(womenWCEditor.Document.DocumentFileName) IsNot Nothing Then

                If womenWCEditor.WomenWCAnalyzer IsNot Nothing AndAlso _
                   womenWCEditor.WomenWCAnalyzer.WomenWCSyntax IsNot Nothing Then
                    womenWCSyntax = womenWCEditor.WomenWCAnalyzer.WomenWCSyntax
                Else
                    womenWCSyntax = Nothing
                End If
                SetMembers(womenWCEditor.Document, womenWCSyntax)

                updateEditorThread = New Thread(AddressOf SetEditorCodeCompletionForm)
                updateEditorThread.Start(womenWCEditor)

                UpdateViews(ProjectManager.ProjectInfo.ProgramInfos(womenWCEditor.Document.DocumentFileName))
            Else
            End If

        End Sub

        Private Sub SetEditorCodeCompletionForm(ByVal threadObject As Object)
            Dim womenWCEditor As IWomenWCEditor
            Dim keyWords As List(Of String)
            Dim functionList As List(Of String)
            Dim variableList As List(Of String)

            If TypeOf threadObject Is IWomenWCEditor Then
                womenWCEditor = DirectCast(threadObject, IWomenWCEditor)
                If womenWCEditor.WomenWCAnalyzer IsNot Nothing AndAlso _
                   womenWCEditor.WomenWCAnalyzer.WomenWCLex IsNot Nothing Then
                    keyWords = womenWCEditor.WomenWCAnalyzer.WomenWCLex.KeyWords
                Else
                    keyWords = Nothing
                End If

                functionList = GetFunctionNameList(womenWCEditor.Document.DocumentFileName, True)
                variableList = GetVariableNameList(womenWCEditor.Document.DocumentFileName, True)

                womenWCEditor.InitializeCodeListView(WomenWCCore.Enums.CodeCompletionListTypeEnum.All, _
                                                     keyWords, functionList, variableList)
            Else
            End If
        End Sub

        Private Sub UpdateViews(ByVal programInfo As ProgramInfo)
            For Each needUpdateMemberView As INeedUpdateMember In _needUpdateMemberViewList
                needUpdateMemberView.UpdateMember(programInfo)
            Next
        End Sub

        Private Function GetFileNameFromIncludeName(ByVal includeName As String) As String
            Dim result As String
            result = String.Empty
            For Each programInfo As ProgramInfo In ProjectManager.ProjectInfo.ProgramInfos
                If IO.Path.HasExtension(includeName) Then
                    If IO.Path.GetFileName(programInfo.ProgramFileName) = includeName Then
                        result = programInfo.ProgramFileName
                        Exit For
                    Else
                    End If
                Else
                    If IO.Path.GetFileNameWithoutExtension(programInfo.ProgramFileName) = includeName Then
                        result = programInfo.ProgramFileName
                        Exit For
                    Else
                    End If
                End If
            Next
            Return result
        End Function

    End Class
End Namespace
