Model : Check xFile exist in dictionnary

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System
USING System.Collections.Generic
USING System.Linq
USING System.Text
USING System.Threading.Tasks
USING EnvDTE
USING LanguageService.CodeAnalysis
USING LanguageService.CodeAnalysis.XSharp
USING System.Collections.Concurrent
USING Microsoft.VisualStudio
USING Microsoft.VisualStudio.Shell.Interop
USING System.Diagnostics

BEGIN NAMESPACE XSharpModel
    [DebuggerDisplay("{Name,nq}")];
    CLASS XProject
        // Fields
        PRIVATE _AssemblyReferences						AS List<AssemblyInfo>
        PRIVATE _parseOptions := NULL					AS XSharpParseOptions
        PRIVATE _projectNode							AS IXSharpProject
        PRIVATE _projectOutputDLLs						AS ConcurrentDictionary<STRING, STRING>
        PRIVATE _ReferencedProjects						AS List<XProject>
        PRIVATE _StrangerProjects						AS List<EnvDTE.Project>
        PRIVATE _typeController							AS SystemTypeController
        PRIVATE _unprocessedAssemblyReferences			AS ConcurrentDictionary<STRING, STRING>
        PRIVATE _unprocessedProjectReferences			AS List<STRING>
        PRIVATE _unprocessedStrangerProjectReferences	AS List<STRING>
        PRIVATE _mergedTypes							AS ConcurrentDictionary<STRING, XType>
        PUBLIC  FileWalkComplete						AS XProject.OnFileWalkComplete
        PRIVATE _OtherFilesDict							AS ConcurrentDictionary<STRING, XFile>
        PRIVATE _SourceFilesDict						AS ConcurrentDictionary<STRING, XFile>
        PRIVATE _TypeDict								AS ConcurrentDictionary<STRING, List<STRING>>
        PRIVATE _ExternalTypeCache						AS ConcurrentDictionary<STRING, System.Type>

        CONSTRUCTOR(project AS IXSharpProject)
            SUPER()
            SELF:_AssemblyReferences := List<AssemblyInfo>{}
            SELF:_unprocessedAssemblyReferences := ConcurrentDictionary<STRING, STRING>{StringComparer.OrdinalIgnoreCase}
            SELF:_unprocessedProjectReferences := List<STRING>{}
            SELF:_unprocessedStrangerProjectReferences := List<STRING>{}
            SELF:_projectOutputDLLs := ConcurrentDictionary<STRING, STRING>{StringComparer.OrdinalIgnoreCase}
            SELF:_mergedTypes   := ConcurrentDictionary<STRING, XType>{StringComparer.OrdinalIgnoreCase}
            SELF:_ReferencedProjects := List<XProject>{}
            SELF:_StrangerProjects := List<Project>{}
            SELF:_projectNode := project
            SELF:_SourceFilesDict := ConcurrentDictionary<STRING, XFile>{StringComparer.OrdinalIgnoreCase}
            SELF:_OtherFilesDict := ConcurrentDictionary<STRING, XFile>{StringComparer.OrdinalIgnoreCase}
            SELF:_typeController := SystemTypeController{}
            SELF:_TypeDict := ConcurrentDictionary<STRING, List<STRING> > {StringComparer.OrdinalIgnoreCase}
            SELF:_ExternalTypeCache := ConcurrentDictionary<STRING, System.Type > {StringComparer.OrdinalIgnoreCase}
            SELF:Loaded := TRUE

        PRIVATE METHOD _clearTypeCache() AS VOID
            SELF:_ExternalTypeCache:Clear()
            RETURN
            #region AssemblyReferences

            METHOD AddAssemblyReference(path AS STRING) AS VOID
                SELF:WriteOutputMessage("AddAssemblyReference (string) "+path)
                SELF:_clearTypeCache()
                IF ! _unprocessedAssemblyReferences:ContainsKey(path)
                    _unprocessedAssemblyReferences.TryAdd(path,path)
                ENDIF

            METHOD AddAssemblyReference(reference AS VSLangProj.Reference) AS VOID
                LOCAL assemblyInfo AS AssemblyInfo
                SELF:WriteOutputMessage("AddAssemblyReference (VSLangProj.Reference) "+reference:Path)
                SELF:_clearTypeCache()
                IF ! AssemblyInfo.DisableAssemblyReferences
                    IF ! String.IsNullorEmpty(reference:Path)
                        AddAssemblyReference(reference:Path)
                    ELSE
                        assemblyInfo := SystemTypeController.LoadAssembly(reference)
                        SELF:_AssemblyReferences:Add(assemblyInfo)
                        assemblyInfo:AddProject(SELF)
                    ENDIF
                ENDIF

            METHOD ClearAssemblyReferences() AS VOID
                SELF:WriteOutputMessage("ClearAssemblyReferences() ")
                SELF:_clearTypeCache()
                FOREACH asm AS AssemblyInfo IN SELF:_AssemblyReferences
                    asm:RemoveProject(SELF)
                NEXT
                SELF:_AssemblyReferences:Clear()

            METHOD RemoveAssemblyReference(fileName AS STRING) AS VOID
                SELF:WriteOutputMessage("RemoveAssemblyReference() "+fileName)
                SELF:_clearTypeCache()
                LOCAL cOld AS STRING
                IF _unprocessedAssemblyReferences:ContainsKey(fileName)
                    _unprocessedAssemblyReferences:TryRemove(fileName, OUT cOld)
                ENDIF
                FOREACH info AS AssemblyInfo IN SELF:_AssemblyReferences
                    IF String.Equals(info:FileName, fileName, System.StringComparison.OrdinalIgnoreCase)
                        SELF:_AssemblyReferences:Remove(info)
                        EXIT
                    ENDIF
                NEXT

            PRIVATE METHOD ResolveUnprocessedAssemblyReferences() AS VOID
                LOCAL loaded AS List<STRING>
                //
                IF SELF:_unprocessedAssemblyReferences:Count > 0 .and. ! AssemblyInfo.DisableAssemblyReferences
                    SELF:WriteOutputMessage("ResolveUnprocessedAssemblyReferences()")
                    loaded := List<STRING>{}
                    FOREACH path AS STRING IN SELF:_unprocessedAssemblyReferences:Keys
                        LOCAL assemblyInfo AS AssemblyInfo
                        IF System.IO.File.Exists(path)
                            assemblyInfo := SystemTypeController.LoadAssembly(path)
                            SELF:_AssemblyReferences:Add(assemblyInfo)
                            assemblyInfo:AddProject(SELF)
                            loaded:Add(path)
                        ENDIF
                    NEXT
                    FOREACH path AS STRING IN Loaded
                        IF SELF:_unprocessedAssemblyReferences:ContainsKey(path)
                            LOCAL cOld AS STRING
                            SELF:_unprocessedAssemblyReferences:TryRemove(path, OUT cOld)
                        ENDIF
                    NEXT
                    SELF:_clearTypeCache()
                ENDIF
                RETURN

            METHOD ResolveReferences() AS VOID
                IF SELF:hasUnprocessedReferences
                    SELF:WriteOutputMessage("<<-- ResolveReferences()")
                    SELF:ProjectNode:SetStatusBarText(String.Format("Loading referenced types for project {0}", SELF:Name))
                    SELF:ProjectNode:SetStatusBarAnimation(TRUE, 0)

                    TRY
                        SELF:ResolveUnprocessedAssemblyReferences()
                        SELF:ResolveUnprocessedProjectReferences()
                        SELF:ResolveUnprocessedStrangerReferences()
                        FOREACH DLL AS STRING IN SELF:_projectOutputDLLs:Values
                            IF SystemTypeController.FindAssemblyByLocation(DLL) == NULL
                                SELF:WriteOutputMessage("ResolveReferences: No need to load types for Foreign assembly. Assembly is already loaded: "+DLL)
                                SELF:AddAssemblyReference(DLL)
                            ENDIF
                        NEXT
                        // repeat the assemblyreferences because we can have _projectOutputDLLs added to the list
                        SELF:ResolveUnprocessedAssemblyReferences()
                    END TRY
                    SELF:ProjectNode:SetStatusBarAnimation(FALSE, 0)
                    SELF:ProjectNode:SetStatusBarText("")
                    SELF:WriteOutputMessage(">>-- ResolveReferences()")
                ENDIF
                RETURN

            METHOD UpdateAssemblyReference(fileName AS STRING) AS VOID
                IF ! AssemblyInfo.DisableAssemblyReferences
                    SystemTypeController.LoadAssembly(fileName):AddProject(SELF)
                ENDIF

                #endregion

            #region ProjectReferences

            METHOD AddProjectReference(url AS STRING) AS LOGIC
                SELF:WriteOutputMessage("Add XSharp ProjectReference "+url)
                IF ! SELF:_unprocessedProjectReferences:Contains(url)
                    SELF:_unprocessedProjectReferences:Add(url)
                    RETURN TRUE
                ENDIF
                RETURN FALSE

            METHOD AddProjectOutput(sProjectURL AS STRING, sOutputDLL AS STRING) AS VOID
                SELF:WriteOutputMessage("AddProjectOutput "+sProjectURL+"("+sOutputDLL+")")
                IF SELF:_projectOutputDLLs:ContainsKey(sProjectURL)
                    SELF:_projectOutputDLLs:Item[sProjectURL] := sOutputDLL
                ELSE
                    SELF:_projectOutputDLLs:TryAdd(sProjectURL, sOutputDLL)
                ENDIF
                SELF:_clearTypeCache()

            METHOD RemoveProjectOutput(sProjectURL AS STRING) AS VOID
                WriteOutputMessage("RemoveProjectOutput() "+sProjectURL)
                IF SELF:_projectOutputDLLs:ContainsKey(sProjectURL)
                    SELF:RemoveProjectReferenceDLL(SELF:_projectOutputDLLs:Item[sProjectURL])
                    LOCAL cOld AS STRING
                    SELF:_projectOutputDLLs:TryRemove(sProjectURL, OUT cOld)
                ENDIF
                SELF:_clearTypeCache()

            METHOD RemoveProjectReference(url AS STRING) AS LOGIC
                LOCAL prj AS XProject
                LOCAL outputname AS STRING
                WriteOutputMessage("RemoveProjectReference() "+url)
                SELF:_clearTypeCache()
                IF SELF:_unprocessedProjectReferences:Contains(url)
                    SELF:_unprocessedProjectReferences:Remove(url)
                    RETURN TRUE
                ENDIF
                // Does this url belongs to a project in the Solution ?
                prj := XSolution.FindProject(url)
                IF (SELF:_ReferencedProjects:Contains(prj))
                    //
                    outputname := prj:ProjectNode:OutputFile
                    SELF:_ReferencedProjects:Remove(prj)
                    RETURN TRUE
                ENDIF
                SELF:RemoveProjectOutput(url)
                RETURN FALSE

            METHOD RemoveProjectReferenceDLL(DLL AS STRING) AS VOID
                WriteOutputMessage("RemoveProjectReferenceDLL() "+DLL)
                SELF:_clearTypeCache()
                SELF:RemoveAssemblyReference(DLL)

            PRIVATE METHOD ResolveUnprocessedProjectReferences() AS VOID
                LOCAL existing AS List<STRING>
                LOCAL p AS XProject
                LOCAL outputFile AS STRING
                IF SELF:_unprocessedProjectReferences:Count > 0  .and. ! AssemblyInfo.DisableXSharpProjectReferences
                    WriteOutputMessage("ResolveUnprocessedProjectReferences()")
                    existing := List<STRING>{}
                    FOREACH sProject AS STRING IN SELF:_unprocessedProjectReferences
                        p := XSolution.FindProject(sProject)
                        IF p != NULL
                            existing:Add(sProject)
                            SELF:_ReferencedProjects:Add(p)
                            outputFile := p:ProjectNode:OutputFile
                            SELF:AddProjectOutput(sProject, outputFile)
                        ENDIF
                    NEXT
                    FOREACH sProject AS STRING IN existing
                        SELF:_unprocessedProjectReferences:Remove(sProject)
                    NEXT
                    SELF:_clearTypeCache()
                ENDIF

                #endregion

            #region References TO other project systems
        METHOD AddStrangerProjectReference(url AS STRING) AS LOGIC
            WriteOutputMessage("Add Foreign ProjectReference"+url)
            IF ! SELF:_unprocessedStrangerProjectReferences:Contains(url)
                SELF:_unprocessedStrangerProjectReferences:Add(url)
                RETURN TRUE
            ENDIF
            RETURN FALSE

        PRIVATE METHOD saveGetProperty(props AS EnvDte.Properties, name AS STRING) AS EnvDte.Property
            LOCAL p AS EnvDte.Property
            TRY
                p := props:Item(name)
            CATCH
                p := NULL
            END TRY
            RETURN p

        PRIVATE METHOD GetStrangerOutputDLL(sProject AS STRING, p AS Project) AS STRING
            VAR outputFile := ""
            TRY
                LOCAL propTypepropName := NULL AS EnvDte.Property
                VAR propType := saveGetProperty(p:Properties, "OutputType")
                VAR propName := saveGetProperty(p:Properties, "AssemblyName")
                VAR propPath := saveGetProperty(p:ConfigurationManager:ActiveConfiguration:Properties, "OutputPath")
                IF propName != NULL .and. propPath != NULL .and. propType != NULL
                    VAR path    := (STRING) propPath:Value
                    VAR type    := (INT) propType:Value
                    outputFile	:= (STRING) propName:Value
                    IF type == 2 // __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_LIBRARY
                        outputFile	+= ".dll"
                    ELSE
                        outputFile	+= ".exe"
                    ENDIF
                    outputFile	:= System.IO.Path.Combine(path, outputFile)
                    IF ! System.IO.Path.IsPathRooted(outputFile)
                        outputFile := System.IO.Path.Combine(System.IO.Path.GetDirectoryName(sProject), outputFile)
                        // remove ../ and other garbage from the path
                        outputFile := System.IO.Path.GetFullPath(outputFile)
                    ENDIF
                ENDIF
            CATCH exception AS Exception
                XSolution.WriteException(exception)
            END TRY
            RETURN outputFile

        METHOD RemoveStrangerProjectReference(url AS STRING) AS LOGIC
            LOCAL prj AS Project
            WriteOutputMessage("RemoveStrangerProjectReference() "+url)
            SELF:_clearTypeCache()
            IF SELF:_unprocessedStrangerProjectReferences:Contains(url)
                SELF:_unprocessedStrangerProjectReferences:Remove(url)
                RETURN TRUE
            ENDIF
            SELF:RemoveProjectOutput(url)
            prj := SELF:ProjectNode:FindProject(url)
            IF prj != NULL .AND. SELF:_StrangerProjects:Contains(prj)
                SELF:_StrangerProjects:Remove(prj)
                RETURN TRUE
            ENDIF
            RETURN FALSE

        PRIVATE METHOD RefreshStrangerProjectDLLOutputFiles() AS VOID
            // Check if any DLL has changed
            IF SELF:_StrangerProjects:Count > 0 .and. ! AssemblyInfo.DisableForeignProjectReferences
                WriteOutputMessage("--> RefreshStrangerProjectDLLOutputFiles() "+SELF:_StrangerProjects:Count())
                FOREACH p AS EnvDte.Project IN SELF:_StrangerProjects
                    VAR sProjectURL := p:FullName
                    VAR mustAdd     := FALSE
                    VAR outputFile  := SELF:GetStrangerOutputDLL(sProjectURL, p)
                    IF SELF:_projectOutputDLLs:ContainsKey(sProjectURL)
                        // when the output file name of the referenced project has changed
                        // then remove the old name
                        IF outputFile:ToLower() != SELF:_projectOutputDLLs:Item[sProjectURL]:ToLower()
                            WriteOutputMessage(i"DLL has been renamed to {outputFile} so remove the old DLL {SELF:_projectOutputDLLs:Item[sProjectURL]}")
                            LOCAL cOld AS STRING
                            SELF:_projectOutputDLLs:TryRemove(sProjectURL, OUT cOld)
                            mustAdd := TRUE
                        ENDIF
                    ELSE
                        mustAdd := TRUE
                    ENDIF
                    IF mustAdd
                        SELF:_unprocessedStrangerProjectReferences:Add(sProjectURL)
                    ENDIF
                NEXT
                WriteOutputMessage("<-- RefreshStrangerProjectDLLOutputFiles()")
            ENDIF

        PRIVATE METHOD ResolveUnprocessedStrangerReferences() AS VOID
            LOCAL existing AS List<STRING>
            LOCAL p AS Project
            LOCAL outputFile AS STRING
            IF SELF:_unprocessedStrangerProjectReferences:Count > 0 .and. ! AssemblyInfo.DisableForeignProjectReferences
                WriteOutputMessage("ResolveUnprocessedStrangerReferences()" +_unprocessedStrangerProjectReferences:Count)
                existing := List<STRING>{}
                FOREACH sProject AS STRING IN SELF:_unprocessedStrangerProjectReferences
                    p := SELF:ProjectNode:FindProject(sProject)
                    IF (p != NULL)
                        SELF:_StrangerProjects:Add(p)
                        outputFile := SELF:GetStrangerOutputDLL(sProject, p)
                        IF !String.IsNullOrEmpty(outputFile)
                            existing:Add(sProject)
                            SELF:AddProjectOutput(sProject, outputFile)
                        ENDIF
                    ENDIF
                NEXT
                FOREACH sProject AS STRING IN existing
                    SELF:_unprocessedStrangerProjectReferences:Remove(sProject)
                NEXT
                SELF:_clearTypeCache()
            ENDIF

            #endregion

        #region 'Normal' Files

        METHOD AddFile(filePath AS STRING) AS LOGIC
            RETURN SELF:AddFile(XFile{filePath})

        METHOD AddFile(xFile AS XFile) AS LOGIC
            LOCAL xamlCodeBehindFile AS STRING
            IF xFile != NULL
                xFile:Project := SELF
                LOCAL oldFile AS XFile
                IF xFile:IsSource
                    IF SELF:_SourceFilesDict:ContainsKey(xFile:FullPath)
                        SELF:_SourceFilesDict:TryRemove(xFile:FullPath, OUT oldFile)
                    ENDIF
                    RETURN SELF:_SourceFilesDict:TryAdd(xFile:FullPath, xFile)
                ENDIF
                IF xFile:IsXaml
                    xamlCodeBehindFile := xFile:XamlCodeBehindFile
                    IF SELF:_SourceFilesDict:ContainsKey(xamlCodeBehindFile)
                        SELF:_SourceFilesDict:TryRemove(xamlCodeBehindFile, OUT  oldFile)
                    ENDIF
                    SELF:_SourceFilesDict:TryAdd(xamlCodeBehindFile, xFile)
                    IF SELF:_OtherFilesDict:ContainsKey(xFile:FullPath)
                        SELF:_OtherFilesDict:TryRemove(xFile:FullPath, OUT oldFile)
                    ENDIF
                    RETURN SELF:_OtherFilesDict:TryAdd(xFile:FullPath, xFile)
                ENDIF
                IF SELF:_OtherFilesDict:ContainsKey(xFile:FullPath)
                    SELF:_OtherFilesDict:TryRemove(xFile:FullPath, OUT oldFile)
                ENDIF
                RETURN SELF:_OtherFilesDict:TryAdd(xFile:FullPath, xFile)
            ENDIF
            RETURN FALSE

        METHOD FindFullPath(fullPath AS STRING) AS XFile
            IF SELF:_SourceFilesDict:ContainsKey(fullPath)
                RETURN SELF:_SourceFilesDict:Item[fullPath]
            ENDIF
            IF SELF:_OtherFilesDict:ContainsKey(fullPath)
                RETURN SELF:_OtherFilesDict:Item[fullPath]
            ENDIF
            RETURN NULL

        METHOD RemoveFile(url AS STRING) AS VOID
            LOCAL file AS XFile
            IF SELF:_OtherFilesDict:ContainsKey(url)
                SELF:_OtherFilesDict:TryRemove(url, OUT file)
                IF file != NULL .and. file:IsXaml
                    url := file:XamlCodeBehindFile
                ENDIF
            ENDIF
            IF SELF:_SourceFilesDict:ContainsKey(url)
                SELF:_SourceFilesDict:TryRemove(url, OUT file)
                IF file != NULL
                    FOREACH VAR type IN file:TypeList:Values
                        SELF:RemoveType(type)
                    NEXT
                ENDIF
            ENDIF

            #endregion

        #region Lookup Types and Functions
        METHOD FindFunction(name AS STRING) AS XTypeMember
            WriteOutputMessage("FindFunction() "+name)
            IF _TypeDict:ContainsKey(XType.GlobalName)
                VAR fileNames := _TypeDict[XType.GlobalName]:ToArray()
                FOREACH sfile AS STRING IN filenames
                    LOCAL file AS XFile
                    // It seems sometimes the Key has changed; may be after a reparse ?
                    // To just TRY to get the file
                    IF _SourceFilesDict:TryGetValue( sFile, REF file )
                        VAR members := file:GlobalType:Members
                        IF members != NULL
                            FOREACH oMember AS XTypeMember IN members
                                IF (oMember:Kind == Kind.Procedure .or. oMember:Kind == Kind.Function ) .and. string.Compare(oMember:Name, name, TRUE) == 0
                                    WriteOutputMessage("FindFunction()  found: "+oMember:FullName)
                                    RETURN oMember
                                ENDIF
                            NEXT
                        ENDIF
                    ENDIF
                NEXT
            ENDIF
            RETURN NULL

        METHOD FindSystemType(name AS STRING, usings AS IList<STRING>) AS Type
            WriteOutputMessage("FindSystemType() "+name)
            IF ! AssemblyInfo.DisableForeignProjectReferences
                SELF:RefreshStrangerProjectDLLOutputFiles()
            ENDIF
            SELF:ResolveReferences()
            IF _ExternalTypeCache:ContainsKey(name)
                WriteOutputMessage("FindSystemType() "+name+" found in cache")
                RETURN _ExternalTypeCache[name]
            ENDIF
            FOREACH VAR u IN usings
                VAR fullname := u+"."+name
                IF _ExternalTypeCache:ContainsKey(fullname)
                    WriteOutputMessage("FindSystemType() "+fullname+" found in cache")
                    RETURN _ExternalTypeCache[fullname]
                ENDIF
            NEXT
            VAR type := SELF:_typeController:FindType(name, usings, SELF:_AssemblyReferences)
            IF type != NULL
                WriteOutputMessage("FindSystemType() "+name+" found "+type:FullName)
                IF !_ExternalTypeCache:ContainsKey(type:FullName)
                    _ExternalTypeCache:TryAdd(type:FullName, type)
                ENDIF
            ENDIF
            RETURN type

        METHOD GetAssemblyNamespaces() AS IList<STRING>
            RETURN SELF:_typeController:GetNamespaces(SELF:_AssemblyReferences)

        METHOD Lookup(typeName AS STRING, caseInvariant AS LOGIC) AS XType
            LOCAL xType AS XType
            LOCAL xTemp AS XType
            WriteOutputMessage("Lookup() "+typeName)
            xType := SELF:LookupMergedType(typeName)
            IF xType != NULL
                WriteOutputMessage("Lookup()  found: "+xType:FullName)
                RETURN xType
            ENDIF
            xTemp := NULL
            IF _typeDict:ContainsKey(typeName)
                VAR files := _typeDict[typeName]:ToArray()
                FOREACH sfile AS STRING IN files
                    LOCAL file AS XFile
                    // It seems sometimes the Key has changed; may be after a reparse ?
                    // To just TRY to get the file
                    IF _SourceFilesDict:TryGetValue( sFile, REF file )
                        IF file:TypeList:TryGetValue(typeName, OUT xTemp ) .and. xTemp  != NULL
                            IF (! caseInvariant .AND. ((xTemp:FullName != typeName) .AND. xTemp:Name != typeName))
                                xTemp := NULL
                            ENDIF
                        ENDIF
                        IF xTemp != NULL
                            IF ! xTemp:IsPartial
                                WriteOutputMessage("Lookup()  found: "+xTemp:FullName)
                                RETURN xTemp
                            ENDIF
                            IF xType != NULL
                                xType := xType:Merge(xTemp)
                            ELSE
                                xType := XType{xTemp}
                            ENDIF
                        ENDIF
                    ENDIF
                NEXT
            ENDIF
            IF xType != NULL
                SELF:AddMergedType(xType)
                WriteOutputMessage("Lookup()  found: "+xType:FullName)
            ENDIF
            IF xType == NULL
                xType := SELF:LookupReferenced(typeName, caseInvariant)
            ENDIF
            RETURN xType

        METHOD LookupReferenced(typeName AS STRING, caseInvariant AS LOGIC) AS XType
            LOCAL xType AS XType
            xType := NULL
            IF ! AssemblyInfo.DisableXSharpProjectReferences
                WriteOutputMessage("LookupReferenced() "+typeName)
                FOREACH project AS XProject IN SELF:ReferencedProjects
                    xType := project:Lookup(typeName, caseInvariant)
                    IF xType != NULL
                        WriteOutputMessage(String.Format("LookupReferenced() found in {0}: {1} ", project:Name, xType:FullName))
                        RETURN xType
                    ENDIF
                NEXT
            ENDIF
            RETURN xType

            #endregion

        METHOD UnLoad() AS VOID
            SELF:Loaded := FALSE
            WriteOutputMessage("UnLoad() ")
            FOREACH asm AS AssemblyInfo IN SELF:_AssemblyReferences
                asm:RemoveProject(SELF)
            NEXT
            SELF:_AssemblyReferences:Clear()

        METHOD Walk() AS VOID
            WriteOutputMessage("Walk() ")
            ModelWalker.GetWalker():AddProject(SELF)

        METHOD WalkFile(file AS XFile) AS VOID
            ModelWalker.GetWalker():FileWalk(file)

        PUBLIC DELEGATE OnFileWalkComplete(xFile AS XFile) AS VOID

        #region Properties
        PROPERTY AssemblyReferences AS List<AssemblyInfo>
            GET
                RETURN SELF:_AssemblyReferences
            END GET
        END PROPERTY

        PRIVATE PROPERTY hasUnprocessedReferences AS LOGIC
            GET
                RETURN SELF:_unprocessedAssemblyReferences:Count + ;
                SELF:_unprocessedProjectReferences:Count + ;
                SELF:_unprocessedStrangerProjectReferences:Count > 0
            END GET
        END PROPERTY

        PROPERTY Loaded AS LOGIC AUTO

        PROPERTY Name AS STRING
            GET
                RETURN System.IO.Path.GetFileNameWithoutExtension(SELF:ProjectNode:Url)
            END GET
        END PROPERTY

        PROPERTY Namespaces AS IList<XType>
            GET
                VAR types := List<XType>{}
                VAR fileArray := SELF:SourceFiles:ToArray()
                FOREACH file AS XFile IN fileArray
                    IF file:TypeList != NULL
                        VAR values := file:TypeList:Values
                        FOREACH elmt AS XType IN values
                            IF elmt:Kind == Kind.Namespace
                                IF types:Find( { x => x:Name:ToLowerInvariant() == elmt:Name:ToLowerInvariant() } ) == NULL
                                    types:Add(elmt)
                                ENDIF
                            ENDIF
                        NEXT
                    ENDIF
                NEXT
                RETURN types
            END GET
        END PROPERTY

        PROPERTY OtherFiles AS List<XFile> GET SELF:_OtherFilesDict:Values:ToList()

        PROPERTY ParseOptions AS XSharpParseOptions
            GET
                IF SELF:_parseOptions == NULL
                    IF SELF:ProjectNode == NULL
                        SELF:_parseOptions := XSharpParseOptions.Default
                    ELSE
                        SELF:_parseOptions := SELF:ProjectNode:ParseOptions
                    ENDIF
                ENDIF
                RETURN SELF:_parseOptions
            END GET
        END PROPERTY

        PROPERTY ProjectNode AS IXSharpProject GET SELF:_projectNode SET SELF:_projectNode := VALUE

        PROPERTY ReferencedProjects AS ILIst<XProject>
            GET
                SELF:ResolveUnprocessedProjectReferences()
                RETURN SELF:_ReferencedProjects.ToArray()
            END GET
        END PROPERTY

        PROPERTY SourceFiles AS List<XFile> GET SELF:_SourceFilesDict:Values:ToList()

        PROPERTY StrangerProjects AS IList<Project>
            GET
                SELF:ResolveUnprocessedStrangerReferences()
                RETURN SELF:_StrangerProjects:ToArray()
            END GET
        END PROPERTY
        #endregion

        #region Types
        INTERNAL METHOD AddType(xType AS XType) AS VOID
            // only add global types that have members
            IF ! XType.IsGlobalType(xType) .or. xType:Members:Count > 0
                VAR typeName := xType:FullName
                VAR fileName := xType:File:FullPath
                BEGIN LOCK _TypeDict
                    IF !SELF:_TypeDict:ContainsKey(typeName)
                        SELF:_typeDict[typeName] := List<STRING>{}
                    ENDIF
                    SELF:_TypeDict[typeName]:Add(fileName)
                END LOCK
            ENDIF
            RETURN

        INTERNAL METHOD RemoveType(xType AS XType) AS VOID
            VAR typeName := xType:FullName
            VAR fileName := xType:File:FullPath
            BEGIN LOCK _TypeDict
                IF SELF:_TypeDict:ContainsKey(typeName)
                    IF SELF:_typeDict[typeName]:Contains(fileName)
                        SELF:_TypeDict[typeName]:Remove(filename)
                    ENDIF
                    IF SELF:_TypeDict[typeName]:Count == 0
                        LOCAL cOld AS List<STRING>
                        SELF:_typeDict:TryRemove(typeName, OUT cOld)
                    ENDIF
                ENDIF
            END LOCK
            RETURN

            #endregion
        #region Merged Types
        INTERNAL METHOD AddMergedType(xType AS XType) AS VOID
            IF xType:Name != XElement.GlobalName
                VAR name := xType:FullName
                IF SELF:_mergedTypes:ContainsKey(name)
                    LOCAL oOld AS XType
                    SELF:_mergedTypes:TryRemove(name, OUT oOld)
                ENDIF
                SELF:_mergedTypes:TryAdd(name, xType)
            ENDIF
            RETURN

        INTERNAL METHOD RemoveMergedType(fullName AS STRING) AS VOID
            IF fullName != XElement.GlobalName
                IF SELF:_mergedTypes:ContainsKey(fullName)
                    LOCAL oOld AS XType
                    SELF:_mergedTypes:TryRemove(fullName, oOld)
                ENDIF
            ENDIF
            RETURN

        INTERNAL METHOD LookupMergedType(fullName AS STRING) AS XType
            IF _mergedTypes:ContainsKey(fullname)
                WriteOutputMessage("LookupMergedType() found "+fullName)
                RETURN _mergedTypes[fullName]
            ENDIF
            RETURN NULL
            #endregion

        PRIVATE METHOD WriteOutputMessage(message AS STRING) AS VOID
            XSOlution.WriteOutputMessage("XModel.Project "+SELF:Name+" "+message)
    END CLASS

END NAMESPACE

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System
USING System.Collections.Generic
USING System.Linq
USING System.Text
USING System.Threading.Tasks
USING EnvDTE
USING LanguageService.CodeAnalysis
USING LanguageService.CodeAnalysis.XSharp
USING System.Collections.Concurrent
USING Microsoft.VisualStudio
USING Microsoft.VisualStudio.Shell.Interop
USING System.Diagnostics

BEGIN NAMESPACE XSharpModel
	[DebuggerDisplay("{Name,nq}")];
	CLASS XProject
		// Fields
		PRIVATE _AssemblyReferences						AS List<AssemblyInfo>
		PRIVATE _parseOptions := NULL					AS XSharpParseOptions
		PRIVATE _projectNode							AS IXSharpProject
		PRIVATE _projectOutputDLLs						AS ConcurrentDictionary<STRING, STRING>
		PRIVATE _ReferencedProjects						AS List<XProject>
		PRIVATE _StrangerProjects						AS List<EnvDTE.Project>
		PRIVATE _typeController							AS SystemTypeController
		PRIVATE _unprocessedAssemblyReferences			AS ConcurrentDictionary<STRING, STRING>
		PRIVATE _unprocessedProjectReferences			AS List<STRING>
		PRIVATE _unprocessedStrangerProjectReferences	AS List<STRING>
		PRIVATE _mergedTypes							AS ConcurrentDictionary<STRING, XType>
		PUBLIC  FileWalkComplete						AS XProject.OnFileWalkComplete
		PRIVATE _OtherFilesDict							AS ConcurrentDictionary<STRING, XFile>
		PRIVATE _SourceFilesDict						AS ConcurrentDictionary<STRING, XFile>
		PRIVATE _TypeDict								AS ConcurrentDictionary<STRING, List<STRING>>
		PRIVATE _ExternalTypeCache						AS ConcurrentDictionary<STRING, System.Type>

		CONSTRUCTOR(project AS IXSharpProject)
			SUPER()
			SELF:_AssemblyReferences := List<AssemblyInfo>{}
			SELF:_unprocessedAssemblyReferences := ConcurrentDictionary<STRING, STRING>{StringComparer.OrdinalIgnoreCase}
			SELF:_unprocessedProjectReferences := List<STRING>{}
			SELF:_unprocessedStrangerProjectReferences := List<STRING>{}
			SELF:_projectOutputDLLs := ConcurrentDictionary<STRING, STRING>{StringComparer.OrdinalIgnoreCase}
			SELF:_mergedTypes   := ConcurrentDictionary<STRING, XType>{StringComparer.OrdinalIgnoreCase}
			SELF:_ReferencedProjects := List<XProject>{}
			SELF:_StrangerProjects := List<Project>{}
			SELF:_projectNode := project
			SELF:_SourceFilesDict := ConcurrentDictionary<STRING, XFile>{StringComparer.OrdinalIgnoreCase}
			SELF:_OtherFilesDict := ConcurrentDictionary<STRING, XFile>{StringComparer.OrdinalIgnoreCase}
			SELF:_typeController := SystemTypeController{}
			SELF:_TypeDict := ConcurrentDictionary<STRING, List<STRING> > {StringComparer.OrdinalIgnoreCase}
			SELF:_ExternalTypeCache := ConcurrentDictionary<STRING, System.Type > {StringComparer.OrdinalIgnoreCase}
			SELF:Loaded := TRUE

		PRIVATE METHOD _clearTypeCache() AS VOID
			SELF:_ExternalTypeCache:Clear()
			RETURN
		#region AssemblyReferences

		METHOD AddAssemblyReference(path AS STRING) AS VOID
			SELF:WriteOutputMessage("AddAssemblyReference (string) "+path)
			SELF:_clearTypeCache()
			IF ! _unprocessedAssemblyReferences:ContainsKey(path)
				_unprocessedAssemblyReferences.TryAdd(path,path)
			ENDIF

		METHOD AddAssemblyReference(reference AS VSLangProj.Reference) AS VOID
			LOCAL assemblyInfo AS AssemblyInfo
			SELF:WriteOutputMessage("AddAssemblyReference (VSLangProj.Reference) "+reference:Path)
			SELF:_clearTypeCache()
			IF ! AssemblyInfo.DisableAssemblyReferences
				IF ! String.IsNullorEmpty(reference:Path)
					AddAssemblyReference(reference:Path)
				ELSE
					assemblyInfo := SystemTypeController.LoadAssembly(reference)
					SELF:_AssemblyReferences:Add(assemblyInfo)
					assemblyInfo:AddProject(SELF)
				ENDIF
			ENDIF

		METHOD ClearAssemblyReferences() AS VOID
			SELF:WriteOutputMessage("ClearAssemblyReferences() ")
			SELF:_clearTypeCache()
			FOREACH asm AS AssemblyInfo IN SELF:_AssemblyReferences
				asm:RemoveProject(SELF)
			NEXT
			SELF:_AssemblyReferences:Clear()

		METHOD RemoveAssemblyReference(fileName AS STRING) AS VOID
			SELF:WriteOutputMessage("RemoveAssemblyReference() "+fileName)
			SELF:_clearTypeCache()
			LOCAL cOld AS STRING
			IF _unprocessedAssemblyReferences:ContainsKey(fileName)
				_unprocessedAssemblyReferences:TryRemove(fileName, OUT cOld)
			ENDIF
			FOREACH info AS AssemblyInfo IN SELF:_AssemblyReferences
				IF String.Equals(info:FileName, fileName, System.StringComparison.OrdinalIgnoreCase)
					SELF:_AssemblyReferences:Remove(info)
					EXIT
				ENDIF
			NEXT

		PRIVATE METHOD ResolveUnprocessedAssemblyReferences() AS VOID
			LOCAL loaded AS List<STRING>
			//
			IF SELF:_unprocessedAssemblyReferences:Count > 0 .and. ! AssemblyInfo.DisableAssemblyReferences
				SELF:WriteOutputMessage("ResolveUnprocessedAssemblyReferences()")
				loaded := List<STRING>{}
				FOREACH path AS STRING IN SELF:_unprocessedAssemblyReferences:Keys
					LOCAL assemblyInfo AS AssemblyInfo
					IF System.IO.File.Exists(path)
						assemblyInfo := SystemTypeController.LoadAssembly(path)
						SELF:_AssemblyReferences:Add(assemblyInfo)
						assemblyInfo:AddProject(SELF)
						loaded:Add(path)
					ENDIF
				NEXT
				FOREACH path AS STRING IN Loaded
					IF SELF:_unprocessedAssemblyReferences:ContainsKey(path)
						LOCAL cOld AS STRING
						SELF:_unprocessedAssemblyReferences:TryRemove(path, OUT cOld)
					ENDIF
				NEXT
				SELF:_clearTypeCache()
			ENDIF
			RETURN

		METHOD ResolveReferences() AS VOID
			IF SELF:hasUnprocessedReferences
				SELF:WriteOutputMessage("<<-- ResolveReferences()")
				SELF:ProjectNode:SetStatusBarText(String.Format("Loading referenced types for project {0}", SELF:Name))
				SELF:ProjectNode:SetStatusBarAnimation(TRUE, 0)

				TRY
					SELF:ResolveUnprocessedAssemblyReferences()
					SELF:ResolveUnprocessedProjectReferences()
					SELF:ResolveUnprocessedStrangerReferences()
					FOREACH DLL AS STRING IN SELF:_projectOutputDLLs:Values
						IF SystemTypeController.FindAssemblyByLocation(DLL) == NULL
							SELF:WriteOutputMessage("ResolveReferences: No need to load types for Foreign assembly. Assembly is already loaded: "+DLL)
							SELF:AddAssemblyReference(DLL)
						ENDIF
					NEXT
					// repeat the assemblyreferences because we can have _projectOutputDLLs added to the list
					SELF:ResolveUnprocessedAssemblyReferences()
				END TRY
				SELF:ProjectNode:SetStatusBarAnimation(FALSE, 0)
				SELF:ProjectNode:SetStatusBarText("")
				SELF:WriteOutputMessage(">>-- ResolveReferences()")
			ENDIF
			RETURN

		METHOD UpdateAssemblyReference(fileName AS STRING) AS VOID
			IF ! AssemblyInfo.DisableAssemblyReferences
				SystemTypeController.LoadAssembly(fileName):AddProject(SELF)
			ENDIF

		#endregion

		#region ProjectReferences

		METHOD AddProjectReference(url AS STRING) AS LOGIC
			SELF:WriteOutputMessage("Add XSharp ProjectReference "+url)
			IF ! SELF:_unprocessedProjectReferences:Contains(url)
				SELF:_unprocessedProjectReferences:Add(url)
				RETURN TRUE
			ENDIF
			RETURN FALSE

		METHOD AddProjectOutput(sProjectURL AS STRING, sOutputDLL AS STRING) AS VOID
			SELF:WriteOutputMessage("AddProjectOutput "+sProjectURL+"("+sOutputDLL+")")
			IF SELF:_projectOutputDLLs:ContainsKey(sProjectURL)
				SELF:_projectOutputDLLs:Item[sProjectURL] := sOutputDLL
			ELSE
				SELF:_projectOutputDLLs:TryAdd(sProjectURL, sOutputDLL)
			ENDIF
			SELF:_clearTypeCache()

		METHOD RemoveProjectOutput(sProjectURL AS STRING) AS VOID
			WriteOutputMessage("RemoveProjectOutput() "+sProjectURL)
			IF SELF:_projectOutputDLLs:ContainsKey(sProjectURL)
				SELF:RemoveProjectReferenceDLL(SELF:_projectOutputDLLs:Item[sProjectURL])
				LOCAL cOld AS STRING
				SELF:_projectOutputDLLs:TryRemove(sProjectURL, OUT cOld)
			ENDIF
			SELF:_clearTypeCache()

		METHOD RemoveProjectReference(url AS STRING) AS LOGIC
			LOCAL prj AS XProject
			LOCAL outputname AS STRING
			WriteOutputMessage("RemoveProjectReference() "+url)
			SELF:_clearTypeCache()
			IF SELF:_unprocessedProjectReferences:Contains(url)
				SELF:_unprocessedProjectReferences:Remove(url)
				RETURN TRUE
			ENDIF
			// Does this url belongs to a project in the Solution ?
			prj := XSolution.FindProject(url)
			IF (SELF:_ReferencedProjects:Contains(prj))
				//
				outputname := prj:ProjectNode:OutputFile
				SELF:_ReferencedProjects:Remove(prj)
				RETURN TRUE
			ENDIF
			SELF:RemoveProjectOutput(url)
			RETURN FALSE

		METHOD RemoveProjectReferenceDLL(DLL AS STRING) AS VOID
			WriteOutputMessage("RemoveProjectReferenceDLL() "+DLL)
			SELF:_clearTypeCache()
			SELF:RemoveAssemblyReference(DLL)

		PRIVATE METHOD ResolveUnprocessedProjectReferences() AS VOID
			LOCAL existing AS List<STRING>
			LOCAL p AS XProject
			LOCAL outputFile AS STRING
			IF SELF:_unprocessedProjectReferences:Count > 0  .and. ! AssemblyInfo.DisableXSharpProjectReferences
				WriteOutputMessage("ResolveUnprocessedProjectReferences()")
				existing := List<STRING>{}
				FOREACH sProject AS STRING IN SELF:_unprocessedProjectReferences
					p := XSolution.FindProject(sProject)
					IF p != NULL
						existing:Add(sProject)
						SELF:_ReferencedProjects:Add(p)
						outputFile := p:ProjectNode:OutputFile
						SELF:AddProjectOutput(sProject, outputFile)
					ENDIF
				NEXT
				FOREACH sProject AS STRING IN existing
					SELF:_unprocessedProjectReferences:Remove(sProject)
				NEXT
				SELF:_clearTypeCache()
			ENDIF

		#endregion

		#region References TO other project systems
		METHOD AddStrangerProjectReference(url AS STRING) AS LOGIC
			WriteOutputMessage("Add Foreign ProjectReference"+url)
			IF ! SELF:_unprocessedStrangerProjectReferences:Contains(url)
				SELF:_unprocessedStrangerProjectReferences:Add(url)
				RETURN TRUE
			ENDIF
			RETURN FALSE

		PRIVATE METHOD saveGetProperty(props AS EnvDte.Properties, name AS STRING) AS EnvDte.Property
			LOCAL p AS EnvDte.Property
			TRY
				p := props:Item(name)
			CATCH
				p := NULL
			END TRY
			RETURN p

		PRIVATE METHOD GetStrangerOutputDLL(sProject AS STRING, p AS Project) AS STRING
			VAR outputFile := ""
			TRY
				LOCAL propTypepropName := NULL AS EnvDte.Property
				VAR propType := saveGetProperty(p:Properties, "OutputType")
				VAR propName := saveGetProperty(p:Properties, "AssemblyName")
				VAR propPath := saveGetProperty(p:ConfigurationManager:ActiveConfiguration:Properties, "OutputPath")
				IF propName != NULL .and. propPath != NULL .and. propType != null
					VAR path    := (STRING) propPath:Value
					VAR type    := (INT) propType:Value
					outputFile	:= (STRING) propName:Value
					IF type == 2 // __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_LIBRARY
						outputFile	+= ".dll"
					ELSE
						outputFile	+= ".exe"
					ENDIF
					outputFile	:= System.IO.Path.Combine(path, outputFile)
					IF ! System.IO.Path.IsPathRooted(outputFile)
						outputFile := System.IO.Path.Combine(System.IO.Path.GetDirectoryName(sProject), outputFile)
						// remove ../ and other garbage from the path
						outputFile := System.IO.Path.GetFullPath(outputFile)
					ENDIF
				ENDIF
			CATCH exception AS Exception
				XSolution.WriteException(exception)
			END TRY
			RETURN outputFile

		METHOD RemoveStrangerProjectReference(url AS STRING) AS LOGIC
			LOCAL prj AS Project
			WriteOutputMessage("RemoveStrangerProjectReference() "+url)
			SELF:_clearTypeCache()
			IF SELF:_unprocessedStrangerProjectReferences:Contains(url)
				SELF:_unprocessedStrangerProjectReferences:Remove(url)
				RETURN TRUE
			ENDIF
			SELF:RemoveProjectOutput(url)
			prj := SELF:ProjectNode:FindProject(url)
			IF prj != NULL .AND. SELF:_StrangerProjects:Contains(prj)
				SELF:_StrangerProjects:Remove(prj)
				RETURN TRUE
			ENDIF
			RETURN FALSE

		PRIVATE METHOD RefreshStrangerProjectDLLOutputFiles() AS VOID
			// Check if any DLL has changed
			IF SELF:_StrangerProjects:Count > 0 .and. ! AssemblyInfo.DisableForeignProjectReferences
				WriteOutputMessage("--> RefreshStrangerProjectDLLOutputFiles() "+SELF:_StrangerProjects:Count())
				FOREACH p AS EnvDte.Project IN SELF:_StrangerProjects
					VAR sProjectURL := p:FullName
					VAR mustAdd     := FALSE
					VAR outputFile  := SELF:GetStrangerOutputDLL(sProjectURL, p)
					IF SELF:_projectOutputDLLs:ContainsKey(sProjectURL)
						// when the output file name of the referenced project has changed
						// then remove the old name
						IF outputFile:ToLower() != SELF:_projectOutputDLLs:Item[sProjectURL]:ToLower()
							WriteOutputMessage(i"DLL has been renamed to {outputFile} so remove the old DLL {SELF:_projectOutputDLLs:Item[sProjectURL]}")
							LOCAL cOld AS STRING
							SELF:_projectOutputDLLs:TryRemove(sProjectURL, OUT cOld)
							mustAdd := TRUE
						ENDIF
					ELSE
						mustAdd := TRUE
					ENDIF
					IF mustAdd
						SELF:_unprocessedStrangerProjectReferences:Add(sProjectURL)
					ENDIF
				NEXT
				WriteOutputMessage("<-- RefreshStrangerProjectDLLOutputFiles()")
			ENDIF

		PRIVATE METHOD ResolveUnprocessedStrangerReferences() AS VOID
			LOCAL existing AS List<STRING>
			LOCAL p AS Project
			LOCAL outputFile AS STRING
			IF SELF:_unprocessedStrangerProjectReferences:Count > 0 .and. ! AssemblyInfo.DisableForeignProjectReferences
				WriteOutputMessage("ResolveUnprocessedStrangerReferences()" +_unprocessedStrangerProjectReferences:Count)
				existing := List<STRING>{}
				FOREACH sProject AS STRING IN SELF:_unprocessedStrangerProjectReferences
					p := SELF:ProjectNode:FindProject(sProject)
					IF (p != NULL)
						SELF:_StrangerProjects:Add(p)
						outputFile := SELF:GetStrangerOutputDLL(sProject, p)
						IF !String.IsNullOrEmpty(outputFile)
							existing:Add(sProject)
							SELF:AddProjectOutput(sProject, outputFile)
						ENDIF
					ENDIF
				NEXT
				FOREACH sProject AS STRING IN existing
					SELF:_unprocessedStrangerProjectReferences:Remove(sProject)
				NEXT
				SELF:_clearTypeCache()
			ENDIF

			#endregion

		#region 'Normal' Files

		METHOD AddFile(filePath AS STRING) AS LOGIC
			RETURN SELF:AddFile(XFile{filePath})

		METHOD AddFile(xFile AS XFile) AS LOGIC
			LOCAL xamlCodeBehindFile AS STRING
			IF xFile != NULL
				xFile:Project := SELF
				LOCAL oldFile AS XFile
				IF xFile:IsSource
					IF SELF:_SourceFilesDict:ContainsKey(xFile:FullPath)
						SELF:_SourceFilesDict:TryRemove(xFile:FullPath, OUT oldFile)
					ENDIF
					RETURN SELF:_SourceFilesDict:TryAdd(xFile:FullPath, xFile)
				ENDIF
				IF xFile:IsXaml
					xamlCodeBehindFile := xFile:XamlCodeBehindFile
					IF SELF:_SourceFilesDict:ContainsKey(xamlCodeBehindFile)
						SELF:_SourceFilesDict:TryRemove(xamlCodeBehindFile, OUT  oldFile)
					ENDIF
					SELF:_SourceFilesDict:TryAdd(xamlCodeBehindFile, xFile)
					IF SELF:_OtherFilesDict:ContainsKey(xFile:FullPath)
						SELF:_OtherFilesDict:TryRemove(xFile:FullPath, OUT oldFile)
					ENDIF
					RETURN SELF:_OtherFilesDict:TryAdd(xFile:FullPath, xFile)
				ENDIF
				IF SELF:_OtherFilesDict:ContainsKey(xFile:FullPath)
					SELF:_OtherFilesDict:TryRemove(xFile:FullPath, OUT oldFile)
				ENDIF
				RETURN SELF:_OtherFilesDict:TryAdd(xFile:FullPath, xFile)
			ENDIF
			RETURN FALSE

		METHOD FindFullPath(fullPath AS STRING) AS XFile
			IF SELF:_SourceFilesDict:ContainsKey(fullPath)
				RETURN SELF:_SourceFilesDict:Item[fullPath]
			ENDIF
			IF SELF:_OtherFilesDict:ContainsKey(fullPath)
				RETURN SELF:_OtherFilesDict:Item[fullPath]
			ENDIF
			RETURN NULL

		METHOD RemoveFile(url AS STRING) AS VOID
			LOCAL file AS XFile
			IF SELF:_OtherFilesDict:ContainsKey(url)
				SELF:_OtherFilesDict:TryRemove(url, OUT file)
				IF file != NULL .and. file:IsXaml
					url := file:XamlCodeBehindFile
				ENDIF
			ENDIF
			IF SELF:_SourceFilesDict:ContainsKey(url)
				SELF:_SourceFilesDict:TryRemove(url, OUT file)
				IF file != NULL
					FOREACH VAR type IN file:TypeList:Values
						SELF:RemoveType(type)
					NEXT
				ENDIF
			ENDIF

			#endregion

		#region Lookup Types and Functions
		METHOD FindFunction(name AS STRING) AS XTypeMember
			WriteOutputMessage("FindFunction() "+name)
			IF _TypeDict:ContainsKey(XType.GlobalName)
				VAR fileNames := _TypeDict[XType.GlobalName]:ToArray()
				FOREACH sfile AS STRING IN filenames
					VAR xFile := _SourceFilesDict[sFile]
					VAR members := xFile:GlobalType:Members
					IF members != NULL
						FOREACH oMember AS XTypeMember IN members
							IF (oMember:Kind == Kind.Procedure .or. oMember:Kind == Kind.Function ) .and. string.Compare(oMember:Name, name, TRUE) == 0
								WriteOutputMessage("FindFunction()  found: "+oMember:FullName)
								RETURN oMember
							ENDIF
						NEXT
					ENDIF
				NEXT
			ENDIF
			RETURN NULL

		METHOD FindSystemType(name AS STRING, usings AS IList<STRING>) AS Type
			WriteOutputMessage("FindSystemType() "+name)
			IF ! AssemblyInfo.DisableForeignProjectReferences
				SELF:RefreshStrangerProjectDLLOutputFiles()
			ENDIF
			SELF:ResolveReferences()
			IF _ExternalTypeCache:ContainsKey(name)
				WriteOutputMessage("FindSystemType() "+name+" found in cache")
				RETURN _ExternalTypeCache[name]
			ENDIF
			FOREACH VAR u IN usings
				VAR fullname := u+"."+name
				IF _ExternalTypeCache:ContainsKey(fullname)
					WriteOutputMessage("FindSystemType() "+fullname+" found in cache")
					RETURN _ExternalTypeCache[fullname]
				ENDIF
			NEXT
			VAR type := SELF:_typeController:FindType(name, usings, SELF:_AssemblyReferences)
			IF type != NULL
				WriteOutputMessage("FindSystemType() "+name+" found "+type:FullName)
				IF !_ExternalTypeCache:ContainsKey(type:FullName)
					_ExternalTypeCache:TryAdd(type:FullName, type)
				ENDIF
			ENDIF
			RETURN type

		METHOD GetAssemblyNamespaces() AS IList<STRING>
			RETURN SELF:_typeController:GetNamespaces(SELF:_AssemblyReferences)

		METHOD Lookup(typeName AS STRING, caseInvariant AS LOGIC) AS XType
			LOCAL xType AS XType
			LOCAL xTemp AS XType
			WriteOutputMessage("Lookup() "+typeName)
			xType := SELF:LookupMergedType(typeName)
			IF xType != NULL
				WriteOutputMessage("Lookup()  found: "+xType:FullName)
				RETURN xType
			ENDIF
			xTemp := NULL
			IF _typeDict:ContainsKey(typeName)
				VAR files := _typeDict[typeName]:ToArray()
				FOREACH sfile AS STRING IN files
					VAR file := _SourceFilesDict[sFile]
					IF file:TypeList:TryGetValue(typeName, OUT xTemp ) .and. xTemp  != NULL
						IF (! caseInvariant .AND. ((xTemp:FullName != typeName) .AND. xTemp:Name != typeName))
							xTemp := NULL
						ENDIF
					ENDIF
					IF xTemp != NULL
						IF ! xTemp:IsPartial
							WriteOutputMessage("Lookup()  found: "+xTemp:FullName)
							RETURN xTemp
						ENDIF
						IF xType != NULL
							xType := xType:Merge(xTemp)
						ELSE
							xType := XType{xTemp}
						ENDIF
					ENDIF
				NEXT
			ENDIF
			IF xType != NULL
				SELF:AddMergedType(xType)
				WriteOutputMessage("Lookup()  found: "+xType:FullName)
			ENDIF
			IF xType == NULL
				xType := SELF:LookupReferenced(typeName, caseInvariant)
			ENDIF
			RETURN xType

		METHOD LookupReferenced(typeName AS STRING, caseInvariant AS LOGIC) AS XType
			LOCAL xType AS XType
			xType := NULL
			IF ! AssemblyInfo.DisableXSharpProjectReferences
				WriteOutputMessage("LookupReferenced() "+typeName)
				FOREACH project AS XProject IN SELF:ReferencedProjects
					xType := project:Lookup(typeName, caseInvariant)
					IF xType != NULL
						WriteOutputMessage(String.Format("LookupReferenced() found in {0}: {1} ", project:Name, xType:FullName))
						RETURN xType
					ENDIF
				NEXT
			ENDIF
			RETURN xType

			#endregion

		METHOD UnLoad() AS VOID
			SELF:Loaded := FALSE
			WriteOutputMessage("UnLoad() ")
			FOREACH asm AS AssemblyInfo IN SELF:_AssemblyReferences
				asm:RemoveProject(SELF)
			NEXT
			SELF:_AssemblyReferences:Clear()

		METHOD Walk() AS VOID
			WriteOutputMessage("Walk() ")
			ModelWalker.GetWalker():AddProject(SELF)

		METHOD WalkFile(file AS XFile) AS VOID
			ModelWalker.GetWalker():FileWalk(file)

		PUBLIC DELEGATE OnFileWalkComplete(xFile AS XFile) AS VOID

		#region Properties
		PROPERTY AssemblyReferences AS List<AssemblyInfo>
			GET
				RETURN SELF:_AssemblyReferences
			END GET
		END PROPERTY

		PRIVATE PROPERTY hasUnprocessedReferences AS LOGIC
			GET
				RETURN SELF:_unprocessedAssemblyReferences:Count + ;
				SELF:_unprocessedProjectReferences:Count + ;
				SELF:_unprocessedStrangerProjectReferences:Count > 0
			END GET
		END PROPERTY

		PROPERTY Loaded AS LOGIC AUTO

		PROPERTY Name AS STRING
			GET
				RETURN System.IO.Path.GetFileNameWithoutExtension(SELF:ProjectNode:Url)
			END GET
		END PROPERTY

		PROPERTY Namespaces AS IList<XType>
			GET
				VAR types := List<XType>{}
				VAR fileArray := SELF:SourceFiles:ToArray()
				FOREACH file AS XFile IN fileArray
					IF file:TypeList != NULL
						VAR values := file:TypeList:Values
						FOREACH elmt AS XType IN values
							IF elmt:Kind == Kind.Namespace
								IF types:Find( { x => x:Name:ToLowerInvariant() == elmt:Name:ToLowerInvariant() } ) == NULL
									types:Add(elmt)
								ENDIF
							ENDIF
						NEXT
					ENDIF
				NEXT
				RETURN types
			END GET
		END PROPERTY

		PROPERTY OtherFiles AS List<XFile> GET SELF:_OtherFilesDict:Values:ToList()

		PROPERTY ParseOptions AS XSharpParseOptions
			GET
				IF SELF:_parseOptions == NULL
					IF SELF:ProjectNode == NULL
						SELF:_parseOptions := XSharpParseOptions.Default
					ELSE
						SELF:_parseOptions := SELF:ProjectNode:ParseOptions
					ENDIF
				ENDIF
				RETURN SELF:_parseOptions
			END GET
		END PROPERTY

		PROPERTY ProjectNode AS IXSharpProject GET SELF:_projectNode SET SELF:_projectNode := VALUE

		PROPERTY ReferencedProjects AS ILIst<XProject>
			GET
				SELF:ResolveUnprocessedProjectReferences()
				RETURN SELF:_ReferencedProjects.ToArray()
			END GET
		END PROPERTY

		PROPERTY SourceFiles AS List<XFile> GET SELF:_SourceFilesDict:Values:ToList()

		PROPERTY StrangerProjects AS IList<Project>
			GET
				SELF:ResolveUnprocessedStrangerReferences()
				RETURN SELF:_StrangerProjects:ToArray()
			END GET
		END PROPERTY
		#endregion

		#region Types
		INTERNAL METHOD AddType(xType AS XType) AS VOID
			// only add global types that have members
			IF ! XType.IsGlobalType(xType) .or. xType:Members:Count > 0
				VAR typeName := xType:FullName
				VAR fileName := xType:File:FullPath
				BEGIN LOCK _TypeDict
					IF !SELF:_TypeDict:ContainsKey(typeName)
						SELF:_typeDict[typeName] := List<STRING>{}
					ENDIF
					SELF:_TypeDict[typeName]:Add(fileName)
				END LOCK
			ENDIF
			RETURN

		INTERNAL METHOD RemoveType(xType AS XType) AS VOID
			VAR typeName := xType:FullName
			VAR fileName := xType:File:FullPath
			BEGIN LOCK _TypeDict
				IF SELF:_TypeDict:ContainsKey(typeName)
					IF SELF:_typeDict[typeName]:Contains(fileName)
						SELF:_TypeDict[typeName]:Remove(filename)
					ENDIF
					IF SELF:_TypeDict[typeName]:Count == 0
						LOCAL cOld AS List<STRING>
						SELF:_typeDict:TryRemove(typeName, OUT cOld)
					ENDIF
				ENDIF
			END LOCK
			RETURN

			#endregion
		#region Merged Types
		INTERNAL METHOD AddMergedType(xType AS XType) AS VOID
			IF xType:Name != XElement.GlobalName
				VAR name := xType:FullName
				IF SELF:_mergedTypes:ContainsKey(name)
					LOCAL oOld AS XType
					SELF:_mergedTypes:TryRemove(name, OUT oOld)
				ENDIF
				SELF:_mergedTypes:TryAdd(name, xType)
			ENDIF
			RETURN

		INTERNAL METHOD RemoveMergedType(fullName AS STRING) AS VOID
			IF fullName != XElement.GlobalName
				IF SELF:_mergedTypes:ContainsKey(fullName)
					LOCAL oOld AS XType
					SELF:_mergedTypes:TryRemove(fullName, oOld)
				ENDIF
			ENDIF
			RETURN

		INTERNAL METHOD LookupMergedType(fullName AS STRING) AS XType
			IF _mergedTypes:ContainsKey(fullname)
				WriteOutputMessage("LookupMergedType() found "+fullName)
				RETURN _mergedTypes[fullName]
			ENDIF
			RETURN NULL
			#endregion

		PRIVATE METHOD WriteOutputMessage(message AS STRING) AS VOID
			XSOlution.WriteOutputMessage("XModel.Project "+SELF:Name+" "+message)
	END CLASS

END NAMESPACE


clean up more

clean up more

import "../src/LangPrelude.prg" (maybeM)

data Thrist :: (l ~> l ~> *) ~> l ~> l ~> * where
  Nil :: Thrist k a a
  Cons :: k a b -> Thrist k b c -> Thrist k a c
 deriving List(t)

data Multiplicity :: *2 where
  Mono :: Multiplicity
  Poly :: Multiplicity

data Lev :: Multiplicity ~> *1 where
  ValueLevel :: Lev Mono
  LevelUp :: Lev m ~> Lev m
  PolyLevel :: Lev Poly -- level n .
 deriving syntax (lev) Nat(ValueLevel, LevelUp)

data HiddenLev :: *1 where
  HideLev :: Lev m ~> HiddenLev

data Level :: Lev n ~> * where
  ValueLevel :: Level ValueLevel
  LevelUp :: Level l -> Level (LevelUp l)
  PolyLevel :: Level PolyLevel
 deriving syntax (l) Nat(ValueLevel, LevelUp)

data Signature = Sig

data Iceberg :: * ~> * ~> * where
  Constructor :: Label t -> Level l -> Signature -> Iceberg () ()

data Icename :: Tag ~> Tag ~> * where -- entities with certain name
  NamedConstructor :: Label t -> Level l -> Signature -> Icename t t

data Icelevel :: Lev n ~> Lev n ~> * where -- entities with certain level
  LevelConstructor :: LevelSubsumes l' l => Label t -> Level l -> Signature -> Icelevel l' l'

builtIn :: Thrist Iceberg () ()
builtIn = [ Constructor `Z 0l Sig, Constructor `S 0l Sig, Constructor natPrime 0l Sig
          , Constructor `Z 1l Sig, Constructor `S 1l Sig, Constructor `Nat 2l Sig
          , Constructor starN (LevelUp (LevelUp PolyLevel)) Sig
          , Constructor constraintN (LevelUp (LevelUp PolyLevel)) Sig]t
  where HideLabel natPrime = newLabel "Nat'"
        HideLabel starN = newLabel "*n"
        HideLabel constraintN = newLabel "#n"

projectName :: Label l -> Thrist Iceberg () () -> Thrist Icename l l
projectName _ []t = []t
projectName l [Constructor l' lev sig; rest]t = case sameLabel l l' of
                                                L Eq -> [NamedConstructor l' lev sig; projectName l rest]t
                                                _ -> projectName l rest

-- should be LevelFits
prop LevelSubsumes :: Lev n ~> Lev n' ~> * where
  BothValue :: LevelSubsumes ValueLevel ValueLevel
  BothPoly :: LevelSubsumes PolyLevel PolyLevel
  BothUp :: LevelSubsumes k k' -> LevelSubsumes (LevelUp k) (LevelUp k')
  UpValuePoly :: LevelSubsumes (LevelUp ValueLevel) PolyLevel

-- should be 'fits'
subsumes :: Level l -> Level l' -> Maybe (LevelSubsumes l l')
subsumes ValueLevel ValueLevel = Just BothValue
subsumes PolyLevel PolyLevel = Just BothPoly
subsumes (LevelUp l) (LevelUp l') = do ev <- subsumes l l'
                                       return $ BothUp ev
                                     where monad maybeM
subsumes (LevelUp ValueLevel) PolyLevel = Just UpValuePoly
subsumes _ _ = Nothing

projectLevel :: Level l -> Thrist Iceberg () () -> Thrist Icelevel l l
projectLevel _ []t = []t
projectLevel l [Constructor t l' sig; rest]t = case subsumes l l' of
                                               Just BothValue -> [LevelConstructor t l' sig; projectLevel l rest]t
                                               Just BothPoly -> [LevelConstructor t l' sig; projectLevel l rest]t
                                               Just (BothUp below) -> [LevelConstructor t l' sig; projectLevel l rest]t
                                               Just UpValuePoly -> [LevelConstructor t l' sig; projectLevel l rest]t
                                               _ -> projectLevel l rest

import "../src/LangPrelude.prg" (maybeM)

data Thrist :: (l ~> l ~> *) ~> l ~> l ~> * where
  Nil :: Thrist k a a
  Cons :: k a b -> Thrist k b c -> Thrist k a c
 deriving List(t)

data Multiplicity :: *2 where
  Mono :: Multiplicity
  Poly :: Multiplicity

data Lev :: Multiplicity ~> *1 where
  ValueLevel :: Lev Mono
  LevelUp :: Lev m ~> Lev m
  PolyLevel :: Lev Poly -- level n .
 deriving syntax (lev) Nat(ValueLevel, LevelUp)

data HiddenLev :: *1 where
  HideLev :: Lev m ~> HiddenLev

data Level :: Lev n ~> * where
  ValueLevel :: Level ValueLevel
  LevelUp :: Level l -> Level (LevelUp l)
  PolyLevel :: Level PolyLevel
 deriving syntax (l) Nat(ValueLevel, LevelUp)

data Signature = Sig

data Iceberg :: * ~> * ~> * where
  Constructor :: Label t -> Level l -> Signature -> Iceberg () ()

data Icename :: Tag ~> Tag ~> * where -- entities with certain name
  NamedConstructor :: Label t -> Level l -> Signature -> Icename t t

--data Icelevel :: HiddenLev ~> HiddenLev ~> * where -- entities with certain level
--  LevelConstructor :: Label t -> Level l -> Signature -> Icelevel (HideLev l) (HideLev l)

data Icelevel' :: Lev n ~> Lev n ~> * where -- entities with certain level
  LevelConstructor' :: LevelSubsumes l' l => Label t -> Level l -> Signature -> Icelevel' l' l'

builtIn :: Thrist Iceberg () ()
builtIn = [ Constructor `Z 0l Sig, Constructor `S 0l Sig, Constructor natPrime 0l Sig
          , Constructor `Z 1l Sig, Constructor `S 1l Sig, Constructor `Nat 2l Sig
          , Constructor starN (LevelUp PolyLevel) Sig
          , Constructor constraintN (LevelUp PolyLevel) Sig]t
  where HideLabel natPrime = newLabel "Nat'"
        HideLabel starN = newLabel "*n"
        HideLabel constraintN = newLabel "#n"

projectName :: Label l -> Thrist Iceberg () () -> Thrist Icename l l
projectName _ []t = []t
projectName l [Constructor l' lev sig; rest]t = case sameLabel l l' of
                                                L Eq -> [NamedConstructor l' lev sig; projectName l rest]t
                                                _ -> projectName l rest

-- should be LevelFits
prop LevelSubsumes :: Lev n ~> Lev n' ~> * where
  BothValue :: LevelSubsumes ValueLevel ValueLevel
  BothPoly :: LevelSubsumes PolyLevel PolyLevel
  BothUp :: LevelSubsumes k k' -> LevelSubsumes (LevelUp k) (LevelUp k')
  UpValuePoly :: LevelSubsumes (LevelUp ValueLevel) PolyLevel
  --Commutes :: LevelSubsumes k k' => LevelSubsumes k' k -- NOT!

-- should be 'fits'
subsumes :: Level l -> Level l' -> Maybe (LevelSubsumes l l')
subsumes ValueLevel ValueLevel = Just BothValue
subsumes PolyLevel PolyLevel = Just BothPoly
subsumes (LevelUp l) (LevelUp l') = do ev <- subsumes l l'
                                       return $ BothUp ev
                                     where monad maybeM
subsumes (LevelUp ValueLevel) PolyLevel = Just UpValuePoly
subsumes _ _ = Nothing

projectLevel' :: Level l -> Thrist Iceberg () () -> Thrist Icelevel' l l
projectLevel' _ []t = []t
projectLevel' l [Constructor t l' sig; rest]t = case subsumes l l' of
                                               Just BothValue -> [LevelConstructor' t l' sig; projectLevel' l rest]t
                                               Just BothPoly -> [LevelConstructor' t l' sig; projectLevel' l rest]t
                                               Just (BothUp below) -> [LevelConstructor' t l' sig; projectLevel' l rest]t
                                               Just UpValuePoly -> [LevelConstructor' t l' sig; projectLevel' l rest]t
                                               _ -> projectLevel' l rest


generalize Pointers a bit more (possibly one day there can be many Fingers in it)

-- Modeling Opetopes
-- here is Eric's editor: http://sma.epfl.ch/~finster/opetope/opetope.html
--
-- Note: Kock et al. use a similar scheme, where
--          - dots    <-->   lines
--          - spheres <-->   dots
--          - lines disappear
--          -                spheres appear

-- Note: In Eric's new work (at IAS) there are no
--       dots any more, instead he uses 'outout cards', so
--          - (output) cards   <-->  lines
--          - space between stacked cards <--> output cards
--          - lines disappear
--          -                (regular) cards appear

--import "../tests/NatList.prg"
import "../tests/Nat.prg"

-- list kind
--kind List = Ni | Co

-- define the Tree kind, a rose tree
-- note: Ni may only appear in Fork second position (TODO: use GADT!)

kind Tree = Unit | Ni | Fork Tree Tree deriving syntax (tr) List(Ni, Fork) Unit(Unit)

-- make it singleton

data Tree' :: Tree ~> * where
  In :: Tree' ()tr
  Fork :: Tree' head -> Tree' tail -> Tree' [head; tail]tr
  Done :: Tree' []tr

-- define a proposition for subtrees
-- to be checked: TakeHead must ensure that all the node is consumed

prop Subtree :: Tree ~> Tree ~> * where
  UnitSub :: Subtree ()tr tr
  BothNil :: Subtree []tr []tr
  TakeHead :: Subtree head head' -> Subtree tail tail' -> Subtree [head; tail]tr [head'; tail']tr

-- now we can stack cards (these are zooms in Kock et al. parlance)

data Stack :: Tree ~> Tree ~> * where
  Empty :: Corolla tr => Tree' tr -> Stack tr ()tr
  SubDone :: Stack ()tr []tr
  Subdivision :: Stack ()tr sub -> Stack tr rest -> Stack tr [sub; rest]tr
  Encompass :: Subtree consumed tr => Stack consumed prod -> Stack tr prod
  -- the following three grab a node (and possibly its offsprings) and incorporate it into a single card
  -- [perhaps, note: there may be other cards stacked on this one]
  NodeDone :: Stack []tr [()tr]tr
  Pick :: {- EntireNode => -} Stack head prodhead -> Stack tail prodtail -> Stack [head; tail]tr [prodhead; prodtail]tr
  Exclude :: {- EntireNode => -} Stack tail prod -> Stack [()tr; tail]tr prod
  -- we need a way to sequence cards
  -- MultiCard :: ??? Disjoint a b 0 => Subtree a -> Subtree b -> Stack tr a [proda, prodb]tr

  On :: (Subtree tr' tr, Pointers 1t at out) => Stack tr' out' -> Stack tr out -> Tree' at -> Stack tr {substitute out' at out}

-- it remains to define corollas

prop Corolla :: Tree ~> * where
  None' :: Corolla []tr
  One' :: Corolla tail -> Corolla [()tr; tail]tr

--  o   --->  |
--  |         |

lolliCell :: Stack []tr ()tr
lolliCell = Empty Done

--  |         |
--  o   --->  |
--  |         |

dolliCell :: Stack [()tr]tr ()tr
dolliCell = Empty $ Fork In Done

--              |
--  [o]   --->  o
--   |          |

lolliFrame :: Stack []tr [()tr]tr
lolliFrame = Encompass NodeDone

--   |          |
--  [o]   --->  o
--   |          |

dolliFrame :: Stack [()tr]tr [()tr]tr
dolliFrame = Encompass (Exclude NodeDone)

--   |          |
--   |          o
-- [[o]]  --->  |
--   |          o
--   |          |

stacked :: Stack [()tr]tr [[()tr]tr]tr
stacked = (dolliFrame `On` dolliFrame) (In `Fork` Done)

--    |           o   |
-- | [o] |  --->   \ /
-- | [|] |          o
--    |             |

--cyclops :: Stack [()tr]tr [[]tr, ()tr]tr
--cyclops = Subdivision SubDone (Exclude NodeDone)

-- Stacking, Valence, Affine subtree, Substitute at an affine position

-- Counting Units in a tree

valence :: Tree ~> Nat
{valence []tr} = 0t
{valence [head; tail]tr} = {plus {valence head} {valence tail}}
{valence ()tr} = 1t

-- a pointer is a valence-1 subtree of a tree
-- it is used to mark a unit in a tree where substitution will occur
--
prop Pointers :: Nat ~> Tree ~> Tree ~> * where
  Finger :: Pointers 1t ()tr ()tr
  Finished :: Pointers 0t []tr []tr
  ThisWay :: Pointers 1t head' head -> Pointers n tail' tail -> Pointers (1+n)t [head'; tail']tr [head; tail]tr
  ElseWhere :: Pointers n tail' tail -> Pointers n [[]tr; tail']tr [head; tail]tr

-- substitute WHAT    WHERE   IN
substitute :: Tree ~> Tree ~> Tree ~> Tree
{substitute what ()tr ()tr} = what
{substitute what []tr []tr} = []tr
{substitute what [head'; tail']tr [head; tail]tr} = [{substitute what head' head}; {substitute what tail' tail}]tr

-- Modeling Opetopes
-- here is Eric's editor: http://sma.epfl.ch/~finster/opetope/opetope.html
--
-- Note: Kock et al. use a similar scheme, where
--          - dots    <-->   lines
--          - spheres <-->   dots
--          - lines disappear
--          -                spheres appear

-- Note: In Eric's new work (at IAS) there are no
--       dots any more, instead he uses 'outout cards', so
--          - (output) cards   <-->  lines
--          - space between stacked cards <--> output cards
--          - lines disappear
--          -                (regular) cards appear

--import "../tests/NatList.prg"
import "../tests/Nat.prg"

-- list kind
--kind List = Ni | Co

-- define the Tree kind, a rose tree
-- note: Ni may only appear in Fork second position (TODO: use GADT!)

kind Tree = Unit | Ni | Fork Tree Tree deriving syntax (tr) List(Ni, Fork) Unit(Unit)

-- make it singleton

data Tree' :: Tree ~> * where
  In :: Tree' ()tr
  Fork :: Tree' head -> Tree' tail -> Tree' [head; tail]tr
  Done :: Tree' []tr

-- define a proposition for subtrees
-- to be checked: TakeHead must ensure that all the node is consumed

prop Subtree :: Tree ~> Tree ~> * where
  UnitSub :: Subtree ()tr tr
  BothNil :: Subtree []tr []tr
  TakeHead :: Subtree head head' -> Subtree tail tail' -> Subtree [head; tail]tr [head'; tail']tr

-- now we can stack cards (these are zooms in Kock et al. parlance)

data Stack :: Tree ~> Tree ~> * where
  Empty :: Corolla tr => Tree' tr -> Stack tr ()tr
  SubDone :: Stack ()tr []tr
  Subdivision :: Stack ()tr sub -> Stack tr rest -> Stack tr [sub; rest]tr
  Encompass :: Subtree consumed tr => Stack consumed prod -> Stack tr prod
  -- the following three grab a node (and possibly its offsprings) and incorporate it into a single card
  -- [perhaps, note: there may be other cards stacked on this one]
  NodeDone :: Stack []tr [()tr]tr
  Pick :: {- EntireNode => -} Stack head prodhead -> Stack tail prodtail -> Stack [head; tail]tr [prodhead; prodtail]tr
  Exclude :: {- EntireNode => -} Stack tail prod -> Stack [()tr; tail]tr prod
  -- we need a way to sequence cards
  -- MultiCard :: ??? Disjoint a b 0 => Subtree a -> Subtree b -> Stack tr a [proda, prodb]tr

  On :: (Subtree tr' tr, Pointers 1t at out) => Stack tr' out' -> Stack tr out -> Tree' at -> Stack tr {substitute out' at out}

-- it remains to define corollas

prop Corolla :: Tree ~> * where
  None' :: Corolla []tr
  One' :: Corolla tail -> Corolla [()tr; tail]tr

--  o   --->  |
--  |         |

lolliCell :: Stack []tr ()tr
lolliCell = Empty Done

--  |         |
--  o   --->  |
--  |         |

dolliCell :: Stack [()tr]tr ()tr
dolliCell = Empty $ Fork In Done

--              |
--  [o]   --->  o
--   |          |

lolliFrame :: Stack []tr [()tr]tr
lolliFrame = Encompass NodeDone

--   |          |
--  [o]   --->  o
--   |          |

dolliFrame :: Stack [()tr]tr [()tr]tr
dolliFrame = Encompass (Exclude NodeDone)

--   |          |
--   |          o
-- [[o]]  --->  |
--   |          o
--   |          |

stacked :: Stack [()tr]tr [[()tr]tr]tr
stacked = (dolliFrame `On` dolliFrame) (In `Fork` Done)

--    |           o   |
-- | [o] |  --->   \ /
-- | [|] |          o
--    |             |

--cyclops :: Stack [()tr]tr [[]tr, ()tr]tr
--cyclops = Subdivision SubDone (Exclude NodeDone)

-- Stacking, Valence, Affine subtree, Substitute at an affine position

-- Counting Units in a tree

valence :: Tree ~> Nat
{valence []tr} = 0t
{valence [head; tail]tr} = {plus {valence head} {valence tail}}
{valence ()tr} = 1t

-- a pointer is a valence-1 subtree of a tree
-- it is used to mark a unit in a tree where substitution will occur
--
prop Pointers :: Nat ~> Tree ~> Tree ~> * where
  Finger :: Pointers 1t ()tr ()tr
  Finished :: Pointers 0t []tr []tr
  ThisWay :: Pointers 1t head' head -> Pointers 0t tail' tail -> Pointers 1t [head'; tail']tr [head; tail]tr
  ElseWhere :: Pointers 1t tail' tail -> Pointers 1t [[]tr; tail']tr [head; tail]tr

-- substitute WHAT    WHERE   IN
substitute :: Tree ~> Tree ~> Tree ~> Tree
{substitute what ()tr ()tr} = what
{substitute what []tr []tr} = []tr
{substitute what [head'; tail']tr [head; tail]tr} = [{substitute what head' head}; {substitute what tail' tail}]tr


[DBFCDX] Fixes #86

[DBFCDX] Fixes #86


QtSerialPort: module updated (xHarbour compatibility)

Modified:
source/QtSerialPort/QSerialPortInfo.prg

/*

  Qt5xHb - bibliotecas de ligao entre Harbour/xHarbour e Qt Framework 5

  Copyright (C) 2017 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>

*/

#include "hbclass.ch"

CLASS QSerialPortInfo

   DATA pointer
   DATA self_destruction INIT .F.

   METHOD new1
   METHOD new2
   METHOD new3
   METHOD new4
   METHOD new
   METHOD delete
   METHOD swap
   METHOD portName
   METHOD systemLocation
   METHOD description
   METHOD manufacturer
   METHOD vendorIdentifier
   METHOD productIdentifier
   METHOD hasVendorIdentifier
   METHOD hasProductIdentifier
   METHOD isNull
   METHOD isBusy
   METHOD isValid
   METHOD standardBaudRates
   METHOD availablePorts

   METHOD newFrom
   METHOD newFromObject
   METHOD newFromPointer
   METHOD selfDestruction
   METHOD setSelfDestruction

   DESTRUCTOR destroyObject

END CLASS

PROCEDURE destroyObject () CLASS QSerialPortInfo
   IF ::self_destruction
      ::delete()
   ENDIF
RETURN

#pragma BEGINDUMP

#include <Qt>

#ifndef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
#include <QSerialPortInfo>
#endif
#endif

#include "qt5xhb_common.h"
#include "qt5xhb_macros.h"
#include "qt5xhb_utils.h"

#ifdef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
#include <QSerialPortInfo>
#endif
#endif

#include <QString>

/*
QSerialPortInfo()
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW1 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ();
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

/*
QSerialPortInfo(const QSerialPort &port)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW2 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ( *PQSERIALPORT(1) );
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

/*
QSerialPortInfo(const QString &name)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW3 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ( PQSTRING(1) );
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

/*
QSerialPortInfo(const QSerialPortInfo &other)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW4 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ( *PQSERIALPORTINFO(1) );
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

//[1]QSerialPortInfo()
//[2]QSerialPortInfo(const QSerialPort &port)
//[3]QSerialPortInfo(const QString &name)
//[4]QSerialPortInfo(const QSerialPortInfo &other)

HB_FUNC_STATIC( QSERIALPORTINFO_NEW )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  if( ISNUMPAR(0) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW1 );
  }
  else if( ISNUMPAR(1) && ISQSERIALPORT(1) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW2 );
  }
  else if( ISNUMPAR(1) && ISCHAR(1) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW3 );
  }
  else if( ISNUMPAR(1) && ISQSERIALPORTINFO(1) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW4 );
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
#endif
}

HB_FUNC_STATIC( QSERIALPORTINFO_DELETE )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) hb_itemGetPtr( hb_objSendMsg( hb_stackSelfItem(), "POINTER", 0 ) );
  if( obj )
  {
    delete obj;
    obj = NULL;
    PHB_ITEM self = hb_stackSelfItem();
    PHB_ITEM ptr = hb_itemPutPtr( NULL, NULL );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
  }
  hb_itemReturn( hb_stackSelfItem() );
#endif
}

/*
void swap(QSerialPortInfo &other)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_SWAP )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QSerialPortInfo * par1 = (QSerialPortInfo *) _qt5xhb_itemGetPtr(1);
    obj->swap ( *par1 );
  }
  hb_itemReturn( hb_stackSelfItem() );
#endif
}

/*
QString portName() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_PORTNAME )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->portName () );
  }
#endif
}

/*
QString systemLocation() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_SYSTEMLOCATION )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->systemLocation () );
  }
#endif
}

/*
QString description() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_DESCRIPTION )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->description () );
  }
#endif
}

/*
QString manufacturer() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_MANUFACTURER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->manufacturer () );
  }
#endif
}

/*
quint16 vendorIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_VENDORIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQUINT16( obj->vendorIdentifier () );
  }
#endif
}

/*
quint16 productIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_PRODUCTIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQUINT16( obj->productIdentifier () );
  }
#endif
}

/*
bool hasVendorIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_HASVENDORIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->hasVendorIdentifier () );
  }
#endif
}

/*
bool hasProductIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_HASPRODUCTIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->hasProductIdentifier () );
  }
#endif
}

/*
bool isNull() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_ISNULL )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->isNull () );
  }
#endif
}

/*
bool isBusy() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_ISBUSY )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->isBusy () );
  }
#endif
}

/*
bool isValid() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_ISVALID )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->isValid () );
  }
#endif
}

/*
static QList<qint32> standardBaudRates()
*/
HB_FUNC_STATIC( QSERIALPORTINFO_STANDARDBAUDRATES )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QList<qint32> list = QSerialPortInfo::standardBaudRates ();
  _qt5xhb_convert_qlist_qint32_to_array ( list );
#endif
}

/*
static QList<QSerialPortInfo> availablePorts()
*/
HB_FUNC_STATIC( QSERIALPORTINFO_AVAILABLEPORTS )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts ();
  PHB_DYNS pDynSym;
  pDynSym = hb_dynsymFindName( "QSERIALPORTINFO" );
  PHB_ITEM pArray;
  pArray = hb_itemArrayNew(0);
  int i;
  for(i=0;i<list.count();i++)
  {
    if( pDynSym )
    {
      #ifdef __XHARBOUR__
      hb_vmPushSymbol( pDynSym->pSymbol );
      #else
      hb_vmPushDynSym( pDynSym );
      #endif
      hb_vmPushNil();
      hb_vmDo( 0 );
      PHB_ITEM pObject = hb_itemNew( NULL );
      hb_itemCopy( pObject, hb_stackReturnItem() );
      PHB_ITEM pItem = hb_itemNew( NULL );
      hb_itemPutPtr( pItem, (QSerialPortInfo *) new QSerialPortInfo ( list[i] ) );
      hb_objSendMsg( pObject, "_POINTER", 1, pItem );
      hb_itemRelease( pItem );
      PHB_ITEM pDestroy = hb_itemNew( NULL );
      hb_itemPutL( pDestroy, true );
      hb_objSendMsg( pObject, "_SELF_DESTRUCTION", 1, pDestroy );
      hb_itemRelease( pDestroy );
      hb_arrayAddForward( pArray, pObject );
      hb_itemRelease( pObject );
    }
  }
  hb_itemReturnRelease(pArray);
#endif
}

HB_FUNC_STATIC( QSERIALPORTINFO_NEWFROM )
{
  PHB_ITEM self = hb_stackSelfItem();
  if( hb_pcount() == 1 && ISOBJECT(1) )
  {
    PHB_ITEM ptr = hb_itemPutPtr( NULL, (void *) hb_itemGetPtr( hb_objSendMsg( hb_param(1, HB_IT_OBJECT ), "POINTER", 0 ) ) );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
    PHB_ITEM des = hb_itemPutL( NULL, false );
    hb_objSendMsg( self, "_self_destruction", 1, des );
    hb_itemRelease( des );
  }
  else if( hb_pcount() == 1 && ISPOINTER(1) )
  {
    PHB_ITEM ptr = hb_itemPutPtr( NULL, (void *) hb_itemGetPtr( hb_param(1, HB_IT_POINTER ) ) );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
    PHB_ITEM des = hb_itemPutL( NULL, false );
    hb_objSendMsg( self, "_self_destruction", 1, des );
    hb_itemRelease( des );
  }
  hb_itemReturn( self );
}

HB_FUNC_STATIC( QSERIALPORTINFO_NEWFROMOBJECT )
{
  HB_FUNC_EXEC( QSERIALPORTINFO_NEWFROM );
}

HB_FUNC_STATIC( QSERIALPORTINFO_NEWFROMPOINTER )
{
  HB_FUNC_EXEC( QSERIALPORTINFO_NEWFROM );
}

HB_FUNC_STATIC( QSERIALPORTINFO_SELFDESTRUCTION )
{
  hb_retl( (bool) hb_itemGetL( hb_objSendMsg( hb_stackSelfItem(), "SELF_DESTRUCTION", 0 ) ) );
}

HB_FUNC_STATIC( QSERIALPORTINFO_SETSELFDESTRUCTION )
{
  PHB_ITEM self = hb_stackSelfItem();
  if( hb_pcount() == 1 && ISLOG(1) )
  {
    PHB_ITEM des = hb_itemPutL( NULL, hb_parl(1) );
    hb_objSendMsg( self, "_self_destruction", 1, des );
    hb_itemRelease( des );
  }
  hb_itemReturn( self );
}

#pragma ENDDUMP

/*

  Qt5xHb - bibliotecas de ligao entre Harbour/xHarbour e Qt Framework 5

  Copyright (C) 2017 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>

*/

#include "hbclass.ch"

CLASS QSerialPortInfo

   DATA pointer
   DATA self_destruction INIT .F.

   METHOD new1
   METHOD new2
   METHOD new3
   METHOD new4
   METHOD new
   METHOD delete
   METHOD swap
   METHOD portName
   METHOD systemLocation
   METHOD description
   METHOD manufacturer
   METHOD vendorIdentifier
   METHOD productIdentifier
   METHOD hasVendorIdentifier
   METHOD hasProductIdentifier
   METHOD isNull
   METHOD isBusy
   METHOD isValid
   METHOD standardBaudRates
   METHOD availablePorts

   METHOD newFrom
   METHOD newFromObject
   METHOD newFromPointer
   METHOD selfDestruction
   METHOD setSelfDestruction

   DESTRUCTOR destroyObject

END CLASS

PROCEDURE destroyObject () CLASS QSerialPortInfo
   IF ::self_destruction
      ::delete()
   ENDIF
RETURN

#pragma BEGINDUMP

#include <Qt>

#ifndef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
#include <QSerialPortInfo>
#endif
#endif

#include "qt5xhb_common.h"
#include "qt5xhb_macros.h"
#include "qt5xhb_utils.h"

#ifdef __XHARBOUR__
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
#include <QSerialPortInfo>
#endif
#endif

#include <QString>

/*
QSerialPortInfo()
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW1 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ();
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

/*
QSerialPortInfo(const QSerialPort &port)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW2 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ( *PQSERIALPORT(1) );
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

/*
QSerialPortInfo(const QString &name)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW3 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ( PQSTRING(1) );
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

/*
QSerialPortInfo(const QSerialPortInfo &other)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_NEW4 )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * o = new QSerialPortInfo ( *PQSERIALPORTINFO(1) );
  _qt5xhb_storePointerAndFlag( o, true );
#endif
}

//[1]QSerialPortInfo()
//[2]QSerialPortInfo(const QSerialPort &port)
//[3]QSerialPortInfo(const QString &name)
//[4]QSerialPortInfo(const QSerialPortInfo &other)

HB_FUNC_STATIC( QSERIALPORTINFO_NEW )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  if( ISNUMPAR(0) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW1 );
  }
  else if( ISNUMPAR(1) && ISQSERIALPORT(1) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW2 );
  }
  else if( ISNUMPAR(1) && ISCHAR(1) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW3 );
  }
  else if( ISNUMPAR(1) && ISQSERIALPORTINFO(1) )
  {
    HB_FUNC_EXEC( QSERIALPORTINFO_NEW4 );
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
#endif
}

HB_FUNC_STATIC( QSERIALPORTINFO_DELETE )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) hb_itemGetPtr( hb_objSendMsg( hb_stackSelfItem(), "POINTER", 0 ) );
  if( obj )
  {
    delete obj;
    obj = NULL;
    PHB_ITEM self = hb_stackSelfItem();
    PHB_ITEM ptr = hb_itemPutPtr( NULL, NULL );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
  }
  hb_itemReturn( hb_stackSelfItem() );
#endif
}

/*
void swap(QSerialPortInfo &other)
*/
HB_FUNC_STATIC( QSERIALPORTINFO_SWAP )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QSerialPortInfo * par1 = (QSerialPortInfo *) _qt5xhb_itemGetPtr(1);
    obj->swap ( *par1 );
  }
  hb_itemReturn( hb_stackSelfItem() );
#endif
}

/*
QString portName() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_PORTNAME )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->portName () );
  }
#endif
}

/*
QString systemLocation() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_SYSTEMLOCATION )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->systemLocation () );
  }
#endif
}

/*
QString description() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_DESCRIPTION )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->description () );
  }
#endif
}

/*
QString manufacturer() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_MANUFACTURER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQSTRING( obj->manufacturer () );
  }
#endif
}

/*
quint16 vendorIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_VENDORIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQUINT16( obj->vendorIdentifier () );
  }
#endif
}

/*
quint16 productIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_PRODUCTIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RQUINT16( obj->productIdentifier () );
  }
#endif
}

/*
bool hasVendorIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_HASVENDORIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->hasVendorIdentifier () );
  }
#endif
}

/*
bool hasProductIdentifier() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_HASPRODUCTIDENTIFIER )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->hasProductIdentifier () );
  }
#endif
}

/*
bool isNull() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_ISNULL )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->isNull () );
  }
#endif
}

/*
bool isBusy() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_ISBUSY )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->isBusy () );
  }
#endif
}

/*
bool isValid() const
*/
HB_FUNC_STATIC( QSERIALPORTINFO_ISVALID )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QSerialPortInfo * obj = (QSerialPortInfo *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    RBOOL( obj->isValid () );
  }
#endif
}

/*
static QList<qint32> standardBaudRates()
*/
HB_FUNC_STATIC( QSERIALPORTINFO_STANDARDBAUDRATES )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QList<qint32> list = QSerialPortInfo::standardBaudRates ();
  _qt5xhb_convert_qlist_qint32_to_array ( list );
#endif
}

/*
static QList<QSerialPortInfo> availablePorts()
*/
HB_FUNC_STATIC( QSERIALPORTINFO_AVAILABLEPORTS )
{
#if (QT_VERSION >= QT_VERSION_CHECK(5,1,0))
  QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts ();
  PHB_DYNS pDynSym;
  #ifdef __XHARBOUR__
  pDynSym = hb_dynsymFind( "QSERIALPORTINFO" );
  #else
  pDynSym = hb_dynsymFindName( "QSERIALPORTINFO" );
  #endif
  PHB_ITEM pArray;
  pArray = hb_itemArrayNew(0);
  int i;
  for(i=0;i<list.count();i++)
  {
    if( pDynSym )
    {
      #ifdef __XHARBOUR__
      hb_vmPushSymbol( pDynSym->pSymbol );
      #else
      hb_vmPushDynSym( pDynSym );
      #endif
      hb_vmPushNil();
      hb_vmDo( 0 );
      PHB_ITEM pObject = hb_itemNew( NULL );
      hb_itemCopy( pObject, hb_stackReturnItem() );
      PHB_ITEM pItem = hb_itemNew( NULL );
      hb_itemPutPtr( pItem, (QSerialPortInfo *) new QSerialPortInfo ( list[i] ) );
      hb_objSendMsg( pObject, "_POINTER", 1, pItem );
      hb_itemRelease( pItem );
      PHB_ITEM pDestroy = hb_itemNew( NULL );
      hb_itemPutL( pDestroy, true );
      hb_objSendMsg( pObject, "_SELF_DESTRUCTION", 1, pDestroy );
      hb_itemRelease( pDestroy );
      hb_arrayAddForward( pArray, pObject );
      hb_itemRelease( pObject );
    }
  }
  hb_itemReturnRelease(pArray);
#endif
}

HB_FUNC_STATIC( QSERIALPORTINFO_NEWFROM )
{
  PHB_ITEM self = hb_stackSelfItem();
  if( hb_pcount() == 1 && ISOBJECT(1) )
  {
    PHB_ITEM ptr = hb_itemPutPtr( NULL, (void *) hb_itemGetPtr( hb_objSendMsg( hb_param(1, HB_IT_OBJECT ), "POINTER", 0 ) ) );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
    PHB_ITEM des = hb_itemPutL( NULL, false );
    hb_objSendMsg( self, "_self_destruction", 1, des );
    hb_itemRelease( des );
  }
  else if( hb_pcount() == 1 && ISPOINTER(1) )
  {
    PHB_ITEM ptr = hb_itemPutPtr( NULL, (void *) hb_itemGetPtr( hb_param(1, HB_IT_POINTER ) ) );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
    PHB_ITEM des = hb_itemPutL( NULL, false );
    hb_objSendMsg( self, "_self_destruction", 1, des );
    hb_itemRelease( des );
  }
  hb_itemReturn( self );
}

HB_FUNC_STATIC( QSERIALPORTINFO_NEWFROMOBJECT )
{
  HB_FUNC_EXEC( QSERIALPORTINFO_NEWFROM );
}

HB_FUNC_STATIC( QSERIALPORTINFO_NEWFROMPOINTER )
{
  HB_FUNC_EXEC( QSERIALPORTINFO_NEWFROM );
}

HB_FUNC_STATIC( QSERIALPORTINFO_SELFDESTRUCTION )
{
  hb_retl( (bool) hb_itemGetL( hb_objSendMsg( hb_stackSelfItem(), "SELF_DESTRUCTION", 0 ) ) );
}

HB_FUNC_STATIC( QSERIALPORTINFO_SETSELFDESTRUCTION )
{
  PHB_ITEM self = hb_stackSelfItem();
  if( hb_pcount() == 1 && ISLOG(1) )
  {
    PHB_ITEM des = hb_itemPutL( NULL, hb_parl(1) );
    hb_objSendMsg( self, "_self_destruction", 1, des );
    hb_itemRelease( des );
  }
  hb_itemReturn( self );
}

#pragma ENDDUMP