#=========================================================#
# Standardbibliothek für CoreShell Scripte                #
#=========================================================#

#
# Zeigt eine Kurzhilfe für die DynamicNodes-spezifischen Befehle an
#
function Help-DynamicNodes {
@"
Kurz-Hilfe
----------
quit      Quit-DynamicNodes
nn        New-Node <type> <name>
rn        Remove-Node <nodePath>
cn        Connect-Ports <portPath1> <portPath2>
dcn       Disconnect-Ports <portPath1> <portPath2>
cancn     Check-Connectability <portPath1> <portPath2>
iscn      Check-Connection <portPath1> <portPath2>
log       Write-DNLog <msg> [<type>] [<id>]
up        Set-PortValue <portPath> <value>
act       Activate-Node <nodePath>
"@
}

#
# Einen Script-Block im GUI-Thread ausführen
#
function Invoke-ForGui {
	param (
		[bool] $sync = $false, 
		[de.mastersign.shell.ScriptMethod] $method
	)
	
	$control = $mainForm
	if ($hostControl) { $control = $hostControl }
	
	if ($sync) {
		$method.InvokeForGuiSync($control)
	} else {
		$method.InvokeForGuiAsync($control)
	}
}

# Einen Script-Block asynchron im GUI-Thread ausführen
function guii ([de.mastersign.shell.ScriptMethod] $method) {
	Invoke-ForGui $false $method
}

# Einen Script-Block synchron im GUI-Thread ausführen
function guiis ([de.mastersign.shell.ScriptMethod] $method) {
	Invoke-ForGui $true $method
}

#
# DynamicNodes beenden
#
function Quit-DynamicNodes {
	guiis { 
		if ($mainForm) { 
			$mainForm.Close() 
		} elseif ($hostControl) {
			$hostControl.OnExitRequest()
		} else {
			Write-Warning "Dieser Befehl wird nicht unterstützt."
		}
	}
}

#
# Sendet eine Fehlernachricht an das Systemprotokoll
#
function Write-DNLog {
	param (
		[string] $msg,
		[Diagnostics.TraceEventType] $type = "Information",
		[int] $id = 0
	)
	
	switch ($type)
	{
		"Error" { [DynamicNode.Ext.Shell.ShellTrace]::Error($id, $msg) }
		"Warning" { [DynamicNode.Ext.Shell.ShellTrace]::Warning($id, $msg) }
		"Information" { [DynamicNode.Ext.Shell.ShellTrace]::Info($id, $msg) }
		"Verbose" { [DynamicNode.Ext.Shell.ShellTrace]::Verbose($msg) }
		default { [DynamicNode.Ext.Shell.ShellTrace]::Info($id, $msg) }
	}
}
function Write-DNInfo([string] $msg) {
	[DynamicNode.Ext.Shell.ShellTrace]::Info(0, $msg)
}

#
# Einen neuen Knoten erzeugen
#
function New-Node([string] $typeName, [string] $name) {
	return New-Item $name -ItemType $typeName
}

#
# Einen Knoten löschen
#
function Remove-Node([string] $path) {
	$n = Get-Item $path
	if (-not $n -is [DynamicNode.Core.INode]) {
		throw "Der angegebene Pfad beschreibt keinen Knoten.`n`t$path"
	}
	$n.Parent.Children.Remove($n)
}

#
# Prüfen, ob zwei Anschlüsse verbunden werden dürfen
#
function Check-Connectability([string] $portPath1, [string] $portPath2) {
	$p1 = Get-Item $portPath1
	$p2 = Get-Item $portPath2
	if (-not $p1) {
		throw "Anschluss '$portPath1' wurde nicht gefunden."
	}
	if (-not $p2) {
		throw "Anschluss '$portPath2' wurde nicht gefunden."
	}
	$selectedType = $null
	return $p1.IsConnectableTo($p2, ([REF]$selectedType))
}

#
# Zwei Anschlüsse verbinden
#
function Connect-Ports([string] $portPath1, [string] $portPath2) {
	$p1 = Get-Item $portPath1
	$p2 = Get-Item $portPath2
	if (-not $p1) {
		throw "Anschluss '$portPath1' wurde nicht gefunden."
	}
	if (-not $p2) {
		throw "Anschluss '$portPath2' wurde nicht gefunden."
	}
	return $p1.TryConnect($p2)
}

#
# Prüft, ob zwei Anschlüsse verbunden sind
#
function Check-Connection([string] $portPath1, [string] $portPath2) {
	$p1 = Get-Item $portPath1
	$p2 = Get-Item $portPath2
	if (-not $p1) {
		throw "Anschluss '$portPath1' wurde nicht gefunden."
	}
	if (-not $p2) {
		throw "Anschluss '$portPath2' wurde nicht gefunden."
	}
	if (($p1 -is [DynamicNode.Core.InPort]) `
		-and ($p2 -is [DynamicNode.Core.OutPort])) {
		return $p1.ConnectedOutPort -eq $p2
	} elseif (($p1 -is [DynamicNode.Core.OutPort]) `
		-and ($p2 -is [DynamicNode.Core.InPort])) {
		return $p2.ConnectedOutPort -eq $p1
	} else {
		return $false
	}
}

#
# Zwei Anschlüsse trennen
#
function Disconnect-Ports([string] $portPath1, [string] $portPath2) {
	$p1 = Get-Item $portPath1
	$p2 = Get-Item $portPath2
	if (-not $p1) {
		throw "Anschluss '$portPath1' wurde nicht gefunden."
	}
	if (-not $p2) {
		throw "Anschluss '$portPath2' wurde nicht gefunden."
	}
	if ($p1 -is [DynamicNode.Core.InPort]) {
		$p1.Disconnect()
	} elseif ($p2 -is [DynamicNode.Core.InPort]) {
		$p2.Disconnect()
	}
}

#
# Einen Anschluss mit einer gültigen Marke neu belegen
#
function Set-PortValue([string] $portPath, $value) {
	#Set-Item $portPath $value
	$iP = Get-Item $portPath
	if ($iP) {
		$token = New-Object DynamicNode.Core.Token($value)
		$iP.UpdateToken($token)
		$iP.Parent.Activate()
	}
}

#
# Einen Anschluss mit einer leeren Marke belegen
#
function Clear-PortValue([string] $portPath) {
	Clear-Item $portPath
}

#
# Einen Knoten aktivieren
#
function Activate-Node([string] $nodePath) {
	$n = Get-Item $nodePath
	if (-not $n) {
		throw "Knoten '$nodePath' wurde nicht gefunden."
	}
	$n.Activate()
}

#
# Ein Token erzeugen
#
function Token {
	param (
		$value = $NULL, 
		[DynamicNode.Core.TokenState]$state = "Valid"
	)
	return New-Object "DynamicNode.Core.Token" -ArgumentList $value,$state
}

#
# Gibt ein GUI-Core-Asset eines bestimmten Types zurück
#
function Get-Asset([Type] $type) {
	$m = $gui.GetType().GetMethod("GetAsset").MakeGenericMethod($type)
	return $m.Invoke($gui, $null)
}

#
# Gibt den aktuellen Graphen oder $null zurück, wenn kein Graph geöffnet ist
#
function Get-CurrentGraph() {
	$currentDoc = $gui.CurrentDoc
	if ($currentDoc) {
		return $currentDoc.Graph
	} else {
		return $null
	}
}

#
# Springt in den aktuellen Graphen
#
function Set-LocationToCurrentGraph() {
	Set-Location $(Get-CurrentGraph).Path
}

#
# Schließt den aktuellen Graphen
#
function Close-CurrentGraph($interactive = $false) {	guiis {
	$graph = Get-CurrentGraph
	if ($graph) { $gui.Close($graph, $interactive) }
}}

#
# Blendet eine Ansicht ein
#
function Show-View([string] $id) {
	if (-not $id) {
		$gui.ViewDescriptors | % { $_.Id }
		return
	}
	if (-not $id.StartsWith("View.") -and -not $gui.GetView($id)) {
		$id = "View.$id"
	}
	$view = $gui.GetView($id)
	if (-not $view) {
		Write-Warning "Ansicht '$id' nicht gefunden."
		return
	}
	guiis {
		$view.Show($gui.GuiHost.DockPanel)
	}
}

#
# Blendet eine Ansicht aus
#
function Hide-View([string] $id) { 
	if (-not $id.StartsWith("View.") -and -not $gui.GetView($id)) {
		$id = "View.$id"
	}
	$view = $gui.GetView($id)
	if (-not $view) {
		Write-Warning "Ansicht '$id' nicht gefunden."
		return
	}
	guiis {
		$view.Hide()
	}
}

#
# Schaltet die Sichtbarkeit einer Ansicht um
#
function Toggle-View([string] $id) {
	if (-not $id.StartsWith("View.") -and -not $gui.GetView($id)) {
		$id = "View.$id"
	}
	$view = $gui.GetView($id)
	if (-not $view) {
		Write-Warning "Ansicht '$id' nicht gefunden."
		return
	}
	guiis {
		if ($view.Visible) {
			$view.Hide()
		} else {
			$view.Show($gui.GuiHost.DockPanel)
		}
	}
}

#
# Aliase
#
Set-Alias "new" "New-Object"
Set-Alias "dnhelp" "Help-DynamicNodes"
Set-Alias "quit" "Quit-DynamicNodes"
Set-Alias "nn" "New-Node"
Set-Alias "rn" "Remove-Node"
Set-Alias "cn" "Connect-Ports"
Set-Alias "dcn" "Disconnect-Ports"
Set-Alias "cancn" "Check-Connectability"
Set-Alias "iscn" "Check-Connection"
Set-Alias "log" "Write-DNLog"
Set-Alias "up" "Set-PortValue"
Set-Alias "act" "Activate-Node"
Set-Alias "cg" "Get-CurrentGraph"
Set-Alias "gocg" "Set-LocationToCurrentGraph"
Set-Alias "close" "Close-CurrentGraph"
Set-Alias "vw" "Show-View"
Set-Alias "info" "Write-DNInfo"