PSFlowchart.psm1

using namespace System.Management.Automation.Language

class nodeutility {

    [node[]] static ParseFile ([string]$File) {
        $x = [System.Collections.Generic.list[node]]@()
        $ParsedFile = [Parser]::ParseFile($file, [ref]$null, [ref]$Null)
        # $ParsedFile = [Parser]::ParseFile('C:\Temp\FLowChart-test_new_base_parsing\Code\Tests\testingforeach.ps1', [ref]$null, [ref]$Null)
        $RawAstDocument = $ParsedFile.FindAll( { $args[0] -is [Ast] }, $false)
        $LinkedList = [System.Collections.Generic.LinkedList[string]]::new()
        $i=2
        $tmp = $false
        while ( $i -lt $RawAstDocument.count ) {
            if ( $null -eq $RawAstDocument[$i].parent.parent.parent ) {
                If ( $RawAstDocument[$i].GetType() -in [nodeutility]::GetASTitems() ) {
                    $tmp = $true
                    $node = [nodeutility]::SetNode($RawAstDocument[$i])
                    $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                    $LinkedList.AddLast($LinkedNode)
                    $node.LinkedBrothers = $LinkedList
                    $node.LinkedNodeId = $LinkedNode
                    $LinkedNodeNext = [System.Collections.Generic.LinkedListNode[string]]::new("End_" + $node.Nodeid)
                    $LinkedList.AddAfter($LinkedNode, $LinkedNodeNext)
                    $x.Add($node)
                } else {
                    if ( ( $tmp -and ($i -gt 2) ) -or ( ($i -eq 2) -or ($i -eq $RawAstDocument.count) ) ) {
                        $tmp = $false
                        $node = [BlockProcess]::new()
                        $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                        $LinkedList.AddLast($LinkedNode)
                        $node.LinkedBrothers = $LinkedList
                        $node.LinkedNodeId = $LinkedNode
                        $x.Add($node)
                    }
                }
            }
            $i++
        }
        return $x
    }

    [node] static SetNode ([object]$e) {
        $node = $null
        Switch ( $e ) {
            { $psitem -is [IfStatementAst] } { $node = [IfNode]::new($PSItem) }
            { $psitem -is [ForEachStatementAst] } { $node = [ForeachNode]::new($PSItem) }
            { $psitem -is [WhileStatementAst] } { $node = [WhileNode]::new($PSItem) }
            { $psitem -is [SwitchStatementAst] } { $node = [SwitchNode]::new($PSItem) }
            { $psitem -is [ForStatementAst] } { $node = [ForNode]::new($PSItem) }
            { $psitem -is [DoUntilStatementAst] } { $node = [DoUntilNode]::new($PSItem) }
            { $psitem -is [DoWhileStatementAst] } { $node = [DoWhileNode]::new($PSItem) }
        }
        return $node
    }

    ## override with parent, for sublevels
    [node] static SetNode ([object]$e, [node]$f) {
        $node = $null
        Switch ( $e ) {
            { $psitem -is [IfStatementAst] } { $node = [IfNode]::new($PSItem, $f) }
            { $psitem -is [ForEachStatementAst] } { $node = [ForeachNode]::new($PSItem, $f) }
            { $psitem -is [WhileStatementAst] } { $node = [WhileNode]::new($PSItem, $f) }
            { $psitem -is [SwitchStatementAst] } { $node = [SwitchNode]::new($PSItem, $f) }
            { $psitem -is [ForStatementAst] } { $node = [ForNode]::new($PSItem, $f) }
            { $psitem -is [DoUntilStatementAst] } { $node = [DoUntilNode]::new($PSItem, $f) }
            { $psitem -is [DoWhileStatementAst] } { $node = [DoWhileNode]::new($PSItem, $f) }
        
        }
        return $node
    }

    [object[]] static GetASTitems () {
        return @(
            [ForEachStatementAst],
            [IfStatementAst],
            [WhileStatementAst],
            [SwitchStatementAst],
            [ForStatementAst],
            [DoUntilStatementAst],
            [DoWhileStatementAst]
        )
    }

    [String] static SetDefaultShape ([String]$e) {
        $Shape = $Null
        Switch ( $e ) {
            "If" { $Shape = "diamond" }
            "ElseIf" { $Shape = "diamond" }
            "Foreach" { $Shape = "parallelogram" }
            "While" { $Shape = "parallelogram" }
            "DoWhile" { $Shape = "parallelogram" }
            "DoUntil" { $Shape = "parallelogram" }
            "For" { $Shape = "parallelogram" }
            Defaut { $Shape = "box" }
        
        }
        return $Shape
    }

}

class node {
    [string]$Type
    [string]$Statement
    [String]$Description
    $Children = [System.Collections.Generic.List[node]]::new()
    [node]$Parent
    [int]$Depth
    $File
    hidden $Nodeid
    hidden $EndNodeid
    hidden $LinkedBrothers
    hidden $LinkedNodeId
    hidden $code
    hidden $NewContent
    hidden $raw
    hidden $DefaultShape

    node () {
        $this.SetDepth()
        $this.Guid()
        $this.EndNodeid = $this.Nodeid
    }

    node ([node]$f) {
        $this.Parent = $f
        $this.SetDepth()
        $this.Guid()
        $this.EndNodeid = $this.Nodeid
    }

    node ([Ast]$e) {
        $this.raw = $e
        $this.file = $e.extent.file
        $this.SetDepth()
        $this.Guid()
        $this.DefaultShape = [nodeutility]::SetDefaultShape($this.Type)
        $this.EndNodeid = "End_" + $this.Nodeid
    }

    node ([Ast]$e, [node]$f) {
        Write-Verbose $("File:" + $e.extent.file )
        $this.raw = $e
        $this.parent = $f
        $this.file = $e.extent.file
        $this.SetDepth()
        $this.Guid()
        $this.DefaultShape = [nodeutility]::SetDefaultShape($this.Type)
        $this.EndNodeid = "End_" + $this.Nodeid
    }

    ## override with parent, for sublevels
    [void] FindChildren ([Ast[]]$e, [node]$f) {
        $LinkedList = [System.Collections.Generic.LinkedList[string]]::new()
    
        $i=0
        $tmp = $false
        while ( $i -lt $e.count ) {
            If ( $e[$i].GetType() -in [nodeutility]::GetASTitems() ) {
                Write-Verbose "FINDCHILDREN: AST Type NODE TROUVEE, $($this.Statement)"
                $tmp = $true
                $node = [nodeutility]::SetNode($e[$i], $f)
                $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                $LinkedList.AddLast($LinkedNode)
                $node.LinkedBrothers = $LinkedList
                $node.LinkedNodeId = $LinkedNode
                $this.Children.add($node)
                If ( $node.Type -NotIn ("Else", "ElseIf", "SwitchCase", "SwitchDefault")) {
                    $LinkedNodeNext = [System.Collections.Generic.LinkedListNode[string]]::new("End_" + $node.Nodeid)
                    $LinkedList.AddAfter($LinkedNode, $LinkedNodeNext)
                }
            } else {
                Write-Verbose "FINDCHILDREN: AST Type NOK, TEST PROCESS, $($this.Statement)"
                if ( ( $tmp -and ($i -gt 0) ) -or ( ($i -eq 0) -or ($i -eq $e.count) ) ) {
                    Write-Verbose "FINDCHILDREN: AST Type NOK CACA BOUDIN, $($this.Statement)"
                    $tmp = $false
                    $node = [BlockProcess]::new($f)
                    $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                    $LinkedList.AddLast($LinkedNode)
                    $node.LinkedBrothers = $LinkedList
                    $node.LinkedNodeId = $LinkedNode
                    $this.Children.add($node)
                }
            }
            $i++
        }

        If ( $this.Children.count -eq 0 ) {
            $node = [BlockProcess]::new($f)
            $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
            $LinkedList.AddLast($LinkedNode)
            $node.LinkedBrothers = $LinkedList
            $node.LinkedNodeId = $LinkedNode
            $this.Children.add($node)
        }
    }

    ## override pour le if
    [void] FindChildren ([Ast[]]$e, [node]$f, $LinkedList) {
    
        $i=0
        $tmp = $false
        while ( $i -lt $e.count ) {
            If ( $e[$i].GetType() -in [nodeutility]::GetASTitems() ) {
                Write-Verbose "FINDCHILDREN: AST Type NODE TROUVEE, $($this.Statement)"
                $tmp = $true
                $node = [nodeutility]::SetNode($e[$i], $f)
                $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                $LinkedList.AddLast($LinkedNode)
                $node.LinkedBrothers = $LinkedList
                $node.LinkedNodeId = $LinkedNode
                $this.Children.add($node)
                If ( $node.Type -NotIn ("Else", "ElseIf", "SwitchCase", "SwitchDefault")) {
                    $LinkedNodeNext = [System.Collections.Generic.LinkedListNode[string]]::new("End_" + $node.Nodeid)
                    $LinkedList.AddAfter($LinkedNode, $LinkedNodeNext)
                }
            } else {
                Write-Verbose "FINDCHILDREN: AST Type NOK, TEST PROCESS, $($this.Statement)"
                if ( ( $tmp -and ($i -gt 0) ) -or ( ($i -eq 0) -or ($i -eq $e.count) ) ) {
                    Write-Verbose "FINDCHILDREN: AST Type NOK CACA BOUDIN, $($this.Statement)"
                    $tmp = $false
                    $node = [BlockProcess]::new($f)
                    $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                    $LinkedList.AddLast($LinkedNode)
                    $node.LinkedBrothers = $LinkedList
                    $node.LinkedNodeId = $LinkedNode
                    $this.Children.add($node)
                }
            }
            $i++
        }

        If ( $this.Children.count -eq 0 ) {
            $node = [BlockProcess]::new($f)
            $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
            $LinkedList.AddLast($LinkedNode)
            $node.LinkedBrothers = $LinkedList
            $node.LinkedNodeId = $LinkedNode
            $this.Children.add($node)
        }
    }

    ## Method to find description
    ## Description should be right beneath a statement an look like this:
    ## # Description: Something to describe
    [void] FindDescription () {
        Write-Verbose "Node: FinDescription()..."
        $comment = [System.Management.Automation.PSParser]::Tokenize($this.Code, [ref]$null) | Where-Object { $_.type -eq "comment" -And $_.StartLine -eq 2 }

        If ( $comment ) {
            Write-Verbose "Node: FinDescription, Comment Found.."
            If ( $comment[0].Content -match "Description:(?<description>\s?[\w\s]+)" ) {
                $this.Description = $Matches.description.Trim() 
            } Else {
                Write-Verbose "Node: FinDescription, Comment does not Match Description KeyWord, Setting Statement as Description.."
                $this.Description = $this.Statement
            }
        }
    
    }

    ## Override Method to find description, Do it Recursively
    [void] FindDescription ([Bool]$Recurse) {
        Write-Verbose "Node: FinDescription([Bool]`$Recurse)..."
        $comment = [System.Management.Automation.PSParser]::Tokenize($this.Code, [ref]$null) | Where-Object { $_.type -eq "comment" -And $_.StartLine -eq 2 }

        If ( $comment ) {
            Write-Verbose "Node: FinDescription, Comment Found.."
            If ( $comment[0].Content -match "Description:(?<description>\s?[\w\s]+)" ) {
                Write-Verbose "Node: FinDescription, Comment does Match Description KeyWord.."
                $this.Description = $Matches.description.Trim() 
            }
        } Else {
            Write-Verbose "Node: FinDescription, Comment does not Match Description KeyWord, Setting Statement as Description.."
            $this.Description = $this.Statement
        }
        $this.Children.FindDescription($Recurse)
    }

    ## Override Method to find description, Do it Recursively, with a specific keyword
    [void] FindDescription ([Bool]$Recurse, [string]$KeyWord) {
        Write-Verbose "Node: FinDescription([Bool]`$Recurse, [string]`$KeyWord)..."
        $comment = [System.Management.Automation.PSParser]::Tokenize($this.Code, [ref]$null) | Where-Object { $_.type -eq "comment" -And $_.StartLine -eq 2 }
        # $this.Description = $this.Statement

        If ( $comment ) {
            Write-Verbose "Node: FinDescription, Comment Found.."
            If ( $comment[0].Content -match "$($KeyWord):(?<description>\s?[\w\s]+)" ) {
                Write-Verbose "Node: FinDescription, Comment does Match $KeyWord KeyWord.."
                $this.Description = $Matches.description.Trim() 
            }
        } else {
            Write-Verbose "Node: FinDescription, Comment does not Match Description $KeyWord, Setting Statement as Description.."
            $this.Description = $this.Statement
        }
    
        $this.Children.FindDescription($Recurse, $KeyWord)
    
    }

    ## Method to set a description, recursively or not
    [void] SetDescription ([Bool]$Recurse) {

        $this.FindDescription()

        If ( $null -eq $this.Description ) {
            $d = Read-Host -Prompt $("Set description for {0}" -f $this.Statement)
        }
        Else {
            $d = Read-Host -Prompt $("Actual description for {0} is {1}" -f $this.Statement, $this.Description)
        }

        if ( $null -ne $d ) {
            $this.Description = $d
        }
        else {
            If ( $this.Description -eq $this.Statement ) {
                $this.Description = $this.Statement
            } else {
                $this.Description = $this.Statement
            }
        }

        If ( $Recurse ) {
            If ( $this.Children ) {
                $this.Children.SetDescription($True)
            }
        }
    
    }

    [node[]] GetChildren ([bool]$recurse) {
        $a = @()
        If ( $recurse ) {
            If ( $this.Children.count -gt 0 ) {
                foreach ( $child in $this.Children ) {
                    $a += $child.getchildren($true)
                }
                $a += $this.Children
            }
            else {
                break;
            }
        }
        else {
            $a = $this.Children
        }
            
        return $a
    }

    ## Need override in case of switchnodecase, elseif, and else
    [void] SetDepth () {
        If ( $null -eq $this.parent ) {
            $this.Depth = 1
        }
        Else {
            $this.Depth = $this.Parent.Depth + 1
        }

    }

    hidden [void] Guid () {
        $this.Nodeid = ([guid]::NewGuid()).Guid
    }

}

Class IfNode : node {

    [string]$Type = "If"

    IfNode ([Ast]$e) : base ($e) {
        Write-Verbose "If : Constructor : 1"

        $LinkedList = [System.Collections.Generic.LinkedList[string]]::new()

        $this.FindChildren($this.raw.Clauses[0].Item2.Statements, $this, $LinkedList)

        If ( $e.Clauses.Count -ge 1 ) {
            for ( $i = 0; $i -lt $e.Clauses.Count ; $i++ ) {
                if ( $i -eq 0 ) {
                    $this.Statement = "If ( {0} )" -f $e.Clauses[$i].Item1.Extent.Text
                    $this.Code = $e.Clauses[$i].Item2.Extent.Text
                }
                else {
                    Write-Verbose "If: Constructeur1: Ajout d un ElseIf ..."
                    $node = [ElseIfNode]::new($e.clauses[$i].Item1, $this, $this.Statement)
                    $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                    $LinkedList.AddLast($LinkedNode)
                    $node.LinkedBrothers = $LinkedList
                    $node.LinkedNodeId = $LinkedNode
                    $this.Children.add($node)
                }
            }
        }

        If ( $null -ne $e.ElseClause ) {
            Write-Verbose "If: Constructeur1: Ajout d un Else ..."
            $node = [ElseNode]::new($e.ElseClause, $this, $this.Statement)
            $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
            $LinkedList.AddLast($LinkedNode)
            $node.LinkedBrothers = $LinkedList
            $node.LinkedNodeId = $LinkedNode
            $this.Children.Add($node)
        }
    
    }

    IfNode ([Ast]$e, [node]$f) : base ($e, $f) {

        $LinkedList = [System.Collections.Generic.LinkedList[string]]::new()

        $this.FindChildren($this.raw.Clauses[0].Item2.Statements, $this, $LinkedList)

        If ( $e.Clauses.Count -ge 1 ) {
            for ( $i = 0; $i -lt $e.Clauses.Count ; $i++ ) {
                if ( $i -eq 0 ) {
                    $this.Statement = "If ( {0} )" -f $e.Clauses[$i].Item1.Extent.Text
                    $this.Code = $e.Clauses[$i].Item2.Extent.Text
                }
                else {
                    Write-Verbose "If: Constructeur2: Ajout d un ElseIf ..."
                    $node = [ElseIfNode]::new($e.clauses[$i].Item1, $this, $this.Statement)
                    $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
                    $LinkedList.AddLast($LinkedNode)
                    $node.LinkedBrothers = $LinkedList
                    $node.LinkedNodeId = $LinkedNode
                    $this.Children.add($node)
                }
            }
        }

        If ( $null -ne $e.ElseClause ) {
            Write-Verbose "If: Constructeur2: Ajout d un Else ..."
            $node = [ElseNode]::new($e.ElseClause, $this, $this.Statement)
            $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
            $LinkedList.AddLast($LinkedNode)
            $node.LinkedBrothers = $LinkedList
            $node.LinkedNodeId = $LinkedNode
            $this.Children.Add($node)
        }
    

    }

    [string] graph ($UseDescription) {

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)
        $string=""

        ## Creation des noeuds de base
        ## si on a pas de previous node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: If: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        write-verbose "GRAPH: IF: DRAWING IF NODE"
        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        ## on cree les bases
        If ( $UseDescription ) {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        write-verbose "GRAPH: IF: DRAWING ENDIF NODE"
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{shape='point'}"

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: If: Drawing END NODE"
            $string = $string + ";Edge -from " + $this.EndNodeid + " -to END"
        }

        If ( $this.Children.count -gt 0 ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.Children[0].NodeId + " -attributes @{Label='True'}"
            $LastEdgeTrue = $this.Children.Where{ ($_.type -notin ('ElseIf', 'Else')) } | Select-Object -last 1

            If ( $LastEdgeTrue.Type -in ("Foreach", "For", "While", "DoWhile", "DoUntil") ) {
                ## c'est ici le probleme ...
                # $string = $string + ";Edge -from " + $LastEdgeTrue.LinkedBrothers.Last.Value + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
                $string = $string + ";Edge -from " + $LastEdgeTrue.EndNodeId + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
            }
            Else {
                $string = $string + ";Edge -from " + $LastEdgeTrue.Endnodeid + " -to " + $this.EndNodeid
            }

            # $string = $string +";Edge -from "+$LastEdgeTrue.EndnodeId+" -to "+$this.EndNodeid

            ## si on au au moins un else ou un elseif, on trace le premier edgefalse
            If ( ($this.Children.type -contains "Elseif") -or ($this.Children.type -contains "Else") ) {
                $FirstFalseEdge = $this.Children.Where{ ($_.type -in ('ElseIf', 'Else')) } | Select-Object -first 1
                $string = $string + ";Edge -from " + $this.NodeId + " -to " + $FirstFalseEdge.nodeId + " -attributes @{Label='False'}"
            }
            else {
                $string = $string + ";Edge -from " + $this.NodeId + " -to " + $this.EndnodeId + " -attributes @{Label='False'}"
            }

            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.Graph($UseDescription) }

        }

        If ( $null -ne $EndIfNode.Next ) {
            Write-Verbose "Graph: If: there is a node after the EndIf"
            $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $EndIfNode.Next.Value
        }

        return $string
    }

}

Class ElseIfNode : node {
    [String]$Type = "ElseIf"


    ElseIfNode ([Ast]$e, [node]$j, [string]$d) : base ($e, $j) {
        $this.Statement = "ElseIf ( {0} ) From {1}" -f $e.Extent.Text, $d
        $item1ToSearch = $this.raw.extent.text
        $this.Code = ($this.raw.Parent.Clauses.where( { $_.Item1.extent.text -eq $item1ToSearch })).Item2.Extent.Text

        $this.FindChildren($this.raw.Parent.Clauses.where( { $_.item1.extent.text -eq $this.raw.extent.text }).item2.Statements, $this)
    }

    [string] graph ($UseDescription) {

        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }

        If ( $null -ne $This.LinkedNodeId.Next ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.LinkedNodeId.Next.Value + " -attributes @{Label='False'}"
        }
        Else {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.Parent.EndNodeid + " -attributes @{Label='False'}"
        }

        If ( $this.Children.count -gt 0 ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.Children[0].NodeId + " -attributes @{Label='True'}"
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.Graph($UseDescription) }
            $string = $string + ";Edge -from " + $this.Children[-1].EndnodeId + " -to " + $this.Parent.EndNodeid
        }

        return $string
    }

}

Class ElseNode : node {
    [String]$Type = "Else"

    ElseNode ([Ast]$e, [string]$d)  : base ($e) {
        $this.Statement = "Else From {0}" -f $d
        $this.code = $e.extent.Text
        $this.FindChildren($this.raw.statements, $this)
    }

    ElseNode ([Ast]$e, [node]$f, [string]$d)  : base ($e, $f) {
        $this.Statement = "Else From {0}" -f $d
        $this.code = $e.extent.Text
        $this.FindChildren($this.raw.statements, $this)
    }

    [string] graph ($UseDescription) {

        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }

        If ( $this.Children.count -gt 0 ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.Graph($UseDescription) }
            $string = $string + ";Edge -from " + $this.Children[-1].EndnodeId + " -to " + $this.Parent.EndNodeid
        }

        return $string
    }
}

Class SwitchNode : node {
    [String]$Type = "Switch"

    SwitchNode ([Ast]$e) : base ($e) {
        $this.Statement = "Switch ( " + $e.Condition.extent.Text + " )"

        $LinkedList = [System.Collections.Generic.LinkedList[string]]::new()

        ## Case nodes
        for ( $i = 0; $i -lt $e.Clauses.Count ; $i++ ) {
        
            $node = [SwitchCaseNode]::new($e.clauses[$i].Item1, $this, $this.Statement, $e.clauses[$i].Item2)
            $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
            $LinkedList.AddLast($LinkedNode)
            $node.LinkedNodeId = $LinkedNode
            $node.LinkedBrothers = $LinkedList
            $this.Children.Add($node)
        }

        ## Default Node
        $node = [SwitchDefaultNode]::new($e.default, $this, $this.Statement, $e.default.statements)
        $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
        $LinkedList.AddLast($LinkedNode)
        $node.LinkedNodeId = $LinkedNode
        $node.LinkedBrothers = $LinkedList
        $this.Children.Add($node)
    }

    SwitchNode ([Ast]$e, [node]$f) : base ($e, $f) {
        $this.Statement = "Switch ( " + $e.Condition.extent.Text + " )"

        $LinkedList = [System.Collections.Generic.LinkedList[string]]::new()

        ## Case nodes
        for ( $i = 0; $i -lt $e.Clauses.Count ; $i++ ) {
        
            $node = [SwitchCaseNode]::new($e.clauses[$i].Item1, $this, $this.Statement, $e.clauses[$i].Item2)
            $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
            $LinkedList.AddLast($LinkedNode)
            $node.LinkedNodeId = $LinkedNode
            $node.LinkedBrothers = $LinkedList
            $this.Children.Add($node)
        }

        ## Default Node
        $node = [SwitchDefaultNode]::new($e.default, $this, $this.Statement, $e.default.statements)
        $LinkedNode = [System.Collections.Generic.LinkedListNode[string]]::new($node.Nodeid)
        $LinkedList.AddLast($LinkedNode)
        $node.LinkedNodeId = $LinkedNode
        $node.LinkedBrothers = $LinkedList
        $this.Children.Add($node)
    

    }

    ## pas réussi a chopper le "code" du switch .. du coup la description ne sra pas settable dans le script
    ## la description ne sera utilisable que pour le graph
    [void]SetDescription([string]$e) {
        $this.Description = $e
    }

    [string] graph ($UseDescription) {
        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)

        $string = ""

        ## si on a pas de previous node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: Switch: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        ## Creation des noeuds de base
        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = $string + ";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string + ";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{shape='point'}"

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: Switch: Drawing END NODE"
            $string = $string + ";Edge -from " + $this.EndNodeid + " -to END"
        }

        For ( $i = 0; $i -lt $this.Children.Count; $i++) {
            If ( $i -eq 0 ) {
                $string = $string + ";edge -from " + $this.nodeId + " -to " + $this.Children[$i].NodeId + " @{label='Testing "+$this.raw.Condition.Extent.Text+"'}"
                $string = $string + ";" + $this.Children[$i].graph($UseDescription)
            }
            else {
                $string = $string + ";edge -from " + $this.Children[$i - 1].NodeId + " -to " + $this.Children[$i].NodeId + " -attributes @{label='False'}"
                $string = $string + ";" + $this.Children[$i].graph($UseDescription)
                #$string = $string + ";edge -from "+$this.Children[$i].NodeId+" -to "+$this.Children[$i].EndNodeId
            }
        }

        If ( $EndIfNode.Next ) {
            $string = $string + ";edge -from " + $EndIfNode.Value + " -to " + $EndIfNode.Next.Value
        }
        return $string
    }

    ## On cherche pas de description
    [void]FindDescription() {
        $this.Description = $this.Statement
    }
    [void]FindDescription([Bool]$Recurse) {
        $this.Description = $this.Statement
        $this.Children.FindDescription($Recurse)
    }
    [void]FindDescription([Bool]$Recurse, [String]$KeyWord) {
        $this.Description = $this.Statement
        $this.Children.FindDescription($Recurse)
    }
}

Class SwitchDefaultNode : node {
    [String]$Type = "SwitchDefault"

    SwitchDefaultNode ([Ast]$e, [node]$j, [string]$d, [Ast[]]$f) : base ($e, $j) {
        Write-Verbose ("Default Switch, statements count:" + $f.count)
        $this.Statement = "Default for {0}" -f $d
        $this.Code = $this.raw.extent.Text
        $this.FindChildren($f, $this)
    }

    [String] graph ($UseDescription) {
        ## Creation des noeuds de base
        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
       
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{shape='point'}"
        $string = $string + ";Edge -from " + $this.EndNodeId + " -to " + $this.Parent.EndNodeid

        If ( $this.Children.count -gt 0 ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.graph($UseDescription) }
            $string = $string + ";Edge -from " + $this.Children[-1].EndNodeId + " -to " + $this.EndNodeid
        }



        return $string
    }

}

Class SwitchCaseNode : node {
    [String]$Type = "SwitchCase"

    SwitchCaseNode ([Ast]$e, [node]$j, [string]$d, [Ast]$f) : base ($e, $j) {
        $this.Statement = "Case: {1} for Switch {0}" -f $d, $this.raw.Extent.Text

        $item1ToSearch = $this.raw.Value
        $this.Code = ($this.raw.Parent.Clauses.where( { $_.Item1.Value -eq $item1ToSearch })).Item2.Extent.Text

        $this.FindChildren($f.Statements, $this)
    }

    [String] graph ($UseDescription) {
        ## Creation des noeuds de base
        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{shape='point'}"
        $string = $string + ";Edge -from " + $this.EndNodeId + " -to " + $this.Parent.EndNodeid

        If ( $this.Children.count -gt 0 ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $This.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.graph($UseDescription) }
            $string = $string + ";Edge -from " + $this.Children[-1].EndNodeId + " -to " + $this.EndNodeid
        }



        return $string
    }

}

Class ForeachNode : node {
    [String]$Type = "Foreach"

    ForeachNode ([Ast]$e) : base ($e) {
        Write-Verbose "FORECH"
        $this.Statement = "Foreach ( " + $e.Variable.extent.Text + " in " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.Extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    ForeachNode ([Ast]$e, [node]$f) : base ($e, $f) {
        $this.Statement = "Foreach ( " + $e.Variable.extent.Text + " in " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    [string] graph ($UseDescription) {

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)

        $string = ''
        ## si on a pas de previous node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: Foreach: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        ## Noeud et edge de base
        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{Label='Next " + $this.raw.Condition + "'}"
        $string = $string + ";Edge -from " + $this.EndNodeid + " -to " + $this.nodeId + " -attributes @{Label='Loop'}"

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: Foreach: Drawing END NODE"
            $string = $string+";Edge -from " + $this.EndNodeid + " -to END -attributes @{Label='LoopEnded'}"
        }


        If ( $this.Children.count -gt 0 ) {
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $this.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.Graph($UseDescription) }

            ## Si le dernier noeud est de type LOOP
            If ( $this.Children[-1].Type -in ("Foreach", "For", "While", "DoWhile", "DoUntil") ) {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
            }
            Else {
                write-Verbose "Graph: Foreach: Drawing EDGE from Child last value to EndNodeId"
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid
            }
        
        }

        If ( $null -ne $EndIfNode.Next ) {
            Write-Verbose "Graph: foreach: there is a node after the EndNodeId"
            ## Si le noeud suivant est un else/elseif On ne fait rien, le edge doit être dessiner vers ENDIF, et il est fait par la methode Graph du IF
            $NextNode = $this.parent.Children.where({$_.NodeID -eq $EndIfNode.Next.Value})
            If ( $NextNode.Type -notlike "Else*" ) {
                Write-Verbose "Graph: foreach: the next node is not a else/elseif"
                $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $EndIfNode.Next.Value + " -attributes @{label='LoopEnded'}"
            }
            
        }

        return $string
    }
}

Class WhileNode : node {
    [string]$Type = "While"

    WhileNode ([Ast]$e) : base ($e) {
        $this.Statement = "While ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    
    }

    WhileNode ([Ast]$e, [node]$f) : base ($e, $f) {
        $this.Statement = "While ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    
    }

    [string] graph ($UseDescription) {

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)

        $string = ''
        ## si on a pas de previous node, et niveau 0
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: While: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }
        
        ## on cree les bases
        If ( $UseDescription ) {
            $string = $string +";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string +";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{Label='If " + $this.raw.Condition + "';shape='diamond'}"
        $string = $string + ";Edge -from " + $this.EndNodeid + " -to " + $this.nodeId + " -attributes @{Label='True, Loop'}"

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: While: Drawing END NODE"
            $string = $string+";Edge -from " + $this.EndNodeid + " -to END -attributes @{Label='LoopEnded'}"
        }

        ## si on a des enfants
        If ( $this.Children.count -gt 0 ) {
            Write-Verbose "Graph: While: Graph while children"
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $this.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.graph($UseDescription) }

            ## Si le dernier noeud est de type LOOP
            If ( $this.Children[-1].Type -in ("Foreach", "For", "While", "DoWhile", "DoUntil") ) {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
            }
            Else {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid
            }
        }
        
        If ( $null -ne $EndIfNode.Next ) {
            Write-Verbose "Graph: foreach: there is a node after the EndNodeId"
            ## Si le noeud suivant est un else/elseif On ne fait rien, le edge doit être dessiner vers ENDIF, et il est fait par la methode Graph du IF
            $NextNode = $this.parent.Children.where({$_.NodeID -eq $EndIfNode.Next.Value})
            If ( $NextNode.Type -notlike "Else*" ) {
                Write-Verbose "Graph: foreach: the next node is not a else/elseif"
                $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $EndIfNode.Next.Value + " -attributes @{label='LoopEnded'}"
            }
            
        }

        return $string
    }
}

Class ForNode : node {
    [string]$Type = "For"

    ForNode ([Ast]$e) : base ($e) {
        $this.Statement = "For ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    ForNode ([Ast]$e, [node]$f) : base($e, $f) {
        $this.Statement = "For ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    [string] graph ($UseDescription) {

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)

        $string = ''
        ## si on a pas de previous node, et niveau 0
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: For: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        ## on cree les bases
        If ( $UseDescription ) {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{Label='If " + $this.raw.Condition + "';shape='diamond'}"
        $string = $string + ";Edge -from " + $this.EndNodeid + " -to " + $this.nodeId + " -attributes @{Label='" + $this.raw.Iterator.Extent.Text + "'}"

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: For: Drawing END NODE"
            $string = $string+";Edge -from " + $this.EndNodeid + " -to END -attributes @{Label='LoopEnded'}"
        }

        ## Si il y a des enfants
        If ( $this.Children.count -gt 0 ) {
            Write-Verbose "Graph: For: Graph while children"
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $this.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.graph($UseDescription) }

            ## Si le dernier noeud est de type LOOP
            If ( $this.Children[-1].Type -in ("Foreach", "For", "While", "DoWhile", "DoUntil") ) {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
            }
            Else {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid
            }
        }

        If ( $null -ne $EndIfNode.Next ) {
            Write-Verbose "Graph: foreach: there is a node after the EndNodeId"
            ## Si le noeud suivant est un else/elseif On ne fait rien, le edge doit être dessiner vers ENDIF, et il est fait par la methode Graph du IF
            $NextNode = $this.parent.Children.where({$_.NodeID -eq $EndIfNode.Next.Value})
            If ( $NextNode.Type -notlike "Else*" ) {
                Write-Verbose "Graph: foreach: the next node is not a else/elseif"
                $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $EndIfNode.Next.Value + " -attributes @{label='LoopEnded'}"
            }
            
        }

        return $string
    }
}

Class DoUntilNode : node {
    [string]$Type = "DoUntil"

    DoUntilNode ([Ast]$e) : base($e) {
        $this.Statement = "Do Until ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    DoUntilNode ([Ast]$e, [node]$f) : base($e, $f) {
        $this.Statement = "Do Until ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    [string] graph ($UseDescription) {

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)
        $string = ""
        ## si on a pas de previous node, et niveau 0
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: DoUntil: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        ## on cree les bases
        # $string = "node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        If ( $UseDescription ) {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{Label='Is " + ($this.raw.Condition -replace "'|""|\*", '') + "';shape='diamond'}"
        $string = $string + ";Edge -from " + $this.EndNodeid + " -to " + $this.nodeId + " -attributes @{Label='False, Loop'}"


        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: DoUntil: Drawing END NODE"
            $string = $string + ";Edge -from " + $this.EndNodeid + " -to END"
        }

        If ( $this.Children.count -gt 0 ) {
            Write-Verbose "Graph: DoUntil: Graph DoUntil children"
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $this.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.graph($UseDescription) }

            ## Si le dernier noeud est de type LOOP
            If ( $this.Children[-1].Type -in ("Foreach", "For", "While", "DoWhile", "DoUntil") ) {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
            }
            Else {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid
            }
        }
        
        If ( $null -ne $EndIfNode.Next ) {
            Write-Verbose "Graph: foreach: there is a node after the EndNodeId"
            ## Si le noeud suivant est un else/elseif On ne fait rien, le edge doit être dessiner vers ENDIF, et il est fait par la methode Graph du IF
            $NextNode = $this.parent.Children.where({$_.NodeID -eq $EndIfNode.Next.Value})
            If ( $NextNode.Type -notlike "Else*" ) {
                Write-Verbose "Graph: foreach: the next node is not a else/elseif"
                $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $EndIfNode.Next.Value + " -attributes @{label='LoopEnded'}"
            }
            
        }

        return $string
    }
}

Class DoWhileNode : node {
    [string]$Type = "DoWhile"

    DoWhileNode ([Ast]$e) : base($e) {
        $this.Statement = "Do While ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    DoWhileNode ([Ast]$e, [node]$f) : base($e, $f) {
        $this.Statement = "Do While ( " + $e.Condition.extent.Text + " )"
        $this.code = $e.body.extent.Text
        $this.FindChildren($this.raw.Body.Statements, $this)
    }

    [string] graph ($UseDescription) {

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)

        $string = ""
        ## si on a pas de previous node, et niveau 0
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: DoWhile: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        ## on cree les bases
        If ( $UseDescription ) {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string+";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }
        $string = $string + ";node " + $this.EndNodeid + " -attributes @{Label='If " + ($this.raw.Condition -replace "'|""|\*", '') + "';shape='diamond'}"
        $string = $string + ";Edge -from " + $this.EndNodeid + " -to " + $this.nodeId + " -attributes @{Label='True, Loop'}"

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: DoWhile: Drawing END NODE"
            $string = $string + ";Edge -from " + $this.EndNodeid + " -to END"
        }

        If ( $this.Children.count -gt 0 ) {
            Write-Verbose "Graph: DoWhile: Graph DoWhile children"
            $string = $string + ";Edge -from " + $this.NodeId + " -to " + $this.Children[0].NodeId
            foreach ( $child in $this.Children ) { $string = $string + ";" + $child.graph($UseDescription) }

            ## Si le dernier noeud est de type LOOP
            If ( $this.Children[-1].Type -in ("Foreach", "For", "While", "DoWhile", "DoUntil") ) {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid + " -attributes @{label='LoopEnded'}"
            }
            Else {
                $string = $string + ";Edge -from " + $this.Children[-1].LinkedBrothers.Last.Value + " -to " + $this.EndNodeid
            }
        }

        If ( $null -ne $EndIfNode.Next ) {
            Write-Verbose "Graph: foreach: there is a node after the EndNodeId"
            ## Si le noeud suivant est un else/elseif On ne fait rien, le edge doit être dessiner vers ENDIF, et il est fait par la methode Graph du IF
            $NextNode = $this.parent.Children.where({$_.NodeID -eq $EndIfNode.Next.Value})
            If ( $NextNode.Type -notlike "Else*" ) {
                Write-Verbose "Graph: foreach: the next node is not a else/elseif"
                $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $EndIfNode.Next.Value + " -attributes @{label='LoopEnded'}"
            }
            
        }

        return $string
    }
}

Class BlockProcess : node {
    [string]$Type = "BlockProcess"

    BlockProcess () : base () {
        $this.Statement = "ProcessBlock"
    }

    BlockProcess ($f) : base ($f) {
        $this.Statement = "ProcessBlock"
    }

    [string] graph ($UseDescription) {
        $string = ""

        ## On stocke le noeud de fin
        $EndIfNode = $this.LinkedBrothers.Find($this.EndNodeid)

        ## si on a pas de previous node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $this.LinkedNodeId.Previous) ) {
            write-Verbose "Graph: If: Drawing START NODE"
            $string = ";Edge -from START -to " + $this.NodeId        
        }

        ## si on a pas de next node, et niveau 1
        If ( ($this.Depth -eq 1) -And ($null -eq $EndIfNode.Next) ) {
            write-Verbose "Graph: DoWhile: Drawing END NODE"
            $string = $string + ";Edge -from " + $this.EndNodeid + " -to END"
        }

        If ( $UseDescription ) {
            $string = $string +";node " + $this.Nodeid + " -attributes @{Label='" + $this.Description + "';shape='"+$this.DefaultShape+"'}"    
        } Else {
            $string = $string +";node " + $this.Nodeid + " -attributes @{Label='" + ($this.Statement -replace "'|""|\*", '') + "';shape='"+$this.DefaultShape+"'}"
        }

        ## OK çA MARCHE PAS PARCEQUE BLOCKPROCESS N A PAS DE PARENT !
        if ( $null -ne $this.LinkedNodeId.next ) {
            $NextNode = $this.parent.Children.where({$_.NodeID -eq $this.LinkedNodeId.next.Value})
            If ( $NextNode.Type -notlike "Else*" ) {
                Write-Verbose "Graph: BlockProcess: the next node is not a else/elseif"
                $string = $string + ";Edge -from " + $this.EndnodeId + " -to " + $this.LinkedNodeId.next.Value
            }
            
        }

        return $string
    }

    ## On cherche pas de description
    [void]FindDescription() { }
    [void]FindDescription([Bool]$Recurse) { }
    [void]FindDescription([Bool]$Recurse, [String]$KeyWord) { }
}
function Find-FCNode {
    <#
    .SYNOPSIS
        Find "nodes" present in script
    .DESCRIPTION
        Find "nodes" present in script
    .EXAMPLE
        PS C:\> Find-FCNode -File .\basic_example_1.ps1
 
        Type : If
        Statement : If ( $a -eq 10 )
        Description :
        Children : {ForeachNode, ElseNode}
        Parent :
        Depth : 1
        File : C:\basic_example_1.ps1
 
        Return all the nodes present in the basic_example_1.ps1
    .INPUTS
        ps1 file path
    .OUTPUTS
        [node[]]
    .NOTES
        Pipeline is accepted, so Gci c:\temp -filter "*.ps1" | Find-FCNode should Work
    #>


    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter(Mandatory=$True,
        ValueFromPipelineByPropertyName=$True,Position=1)]
        [Alias("FullName")]
        [String[]]
        $File,
        # Whether you want ton find associated node description
        [Parameter(Mandatory=$False,ParameterSetName='Description')]
        [Switch]
        $FindDescription,
        # The KeyWord representing the begining of your comment, default: Description
        [Parameter(Mandatory=$False,ParameterSetName='Description')]
        [String]
        $KeyWord = $null
    )
    
    begin {
        ## Check if PSGRAPH is loaded or available ?
    }
    
    process {

        $FileInfo = Get-Item $File
        $x=[nodeutility]::ParseFile($FileInfo.FullName)

        If ( $FindDescription ) {
            If ( $KeyWord ) {
                $X.FindDescription($True,$KeyWord)
            } Else {
                $X.FindDescription($True)
            }
        }
        return ,$x

    }
    
    end {
        
    }
}

function New-FCGraph {
    <#
    .SYNOPSIS
        Draw a script flowchart
    .DESCRIPTION
        Draw a script flowchart
    .EXAMPLE
        PS C:\> New-FCGraph -Node $a -Name test
        Draw a script flowchart. $a contains all the nodes present in a ps1 script file.
    .EXAMPLE
        PS C:\> Find-FCNode -File .\basic_example_1.ps1 -FindDescription | New-FCGraph -DescriptionAsLabe
        Draw a script flowchart. Will user node(s) descirption as Label(s).
    .INPUTS
        Inputs (if any)
    .OUTPUTS
        Output (if any)
    .NOTES
        General notes
    #>

    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter(Mandatory=$False,ValueFromPipeline=$True)]
        [Node[]]
        $Node,
        # Name of the graph
        [Parameter(Mandatory=$False)]
        [String]
        $Name="NewGraph",
        # Parameter help description
        [Parameter(Mandatory=$False)]
        [Switch]
        $DescriptionAsLabel,
        # Passthru
        [Parameter(Mandatory=$False)]
        [Switch]
        $PassThru
    )
    
    begin {

    }
    
    process {

        $GraphName = [System.Io.Path]::GetFileName(($node | Where-Object file -ne $null | Select-Object -first 1).File)

        If ( $DescriptionAsLabel ) {
            $string = $node.graph($True)
        } Else {
            $string=$node.graph($False)
        }

        $s = $string | out-string
        $plop = [scriptblock]::Create($s).invoke()
        $graph = graph "$Name" {
                $plop
        } -Attributes @{label="Script: $($GraphName.ToUpper())"}

        If ( $PassThru ) {
            $graph
        } Else {
            $graph | show-psgraph
        }
    }
    
    end {

    }
}

function Set-FCNodeDescription {
    <#
    .SYNOPSIS
        Set Description on nodes
    .DESCRIPTION
        Set Description on nodes
    .EXAMPLE
        PS C:\> Set-FCNodeDescription -Node $a -Recurse
        Set description for If ( $a -eq 10 ): Describe Me!
        Set description for Foreach ( $File in $CollectionsOfFiles ): stuff describing
        Set description for ProcessBlock: something
        Set description for Else From If ( $a -eq 10 ): !
        Set description for ProcessBlock:
 
 
        Type : If
        Statement : If ( $a -eq 10 )
        Description : Describe Me!
        Children : {ForeachNode, ElseNode}
        Parent :
        Depth : 1
        File : C:\Temp\FLowChart-test_new_base_parsing\Code\Tests\basic_example_1.ps1
 
        The function will prompt you for description!
    .INPUTS
        [node[]]
    .OUTPUTS
        [node[]]
    .NOTES
        General notes
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
        [Node[]]
        $Node,
        [Switch]$Recurse
    )
    
    begin {
        
    }
    
    process {
        $Node.SetDescription($Recurse)
        return ,$Node
    }
    
    end {
        
    }
}