function Get-RunningDte
{
    foreach ($progId in @('VisualStudio.DTE.17.0', 'VisualStudio.DTE.16.0'))
    {
        try
        {
            return [System.Runtime.InteropServices.Marshal]::GetActiveObject($progId)
        }
        catch
        {
        }
    }

    throw 'Could not get a running Visual Studio DTE instance.'
}

$path = Join-Path $PSScriptRoot 'MainShell.csproj'
$xml = New-Object System.Xml.XmlDocument
$xml.PreserveWhitespace = $true
$xml.Load($path)

$compileIncludes = @(
    'Manual\ViewModel\DeviceIoViewModel.cs',
    'DeviceMaintance\ViewModel\DeviceIoViewModel.cs',
    'Manual\ViewModel\State\DeviceIoPageState.cs',
    'DeviceMaintance\ViewModel\State\DeviceIoPageState.cs',
    'Manual\View\DeviceIoView.xaml.cs',
    'DeviceMaintance\View\DeviceIoView.xaml.cs'
)

$pageIncludes = @(
    'Manual\View\DeviceIoView.xaml',
    'DeviceMaintance\View\DeviceIoView.xaml'
)

foreach ($node in @($xml.SelectNodes("//*[local-name()='Compile']") | Where-Object { $compileIncludes -contains $_.GetAttribute('Include') }))
{
    [void]$node.ParentNode.RemoveChild($node)
}

foreach ($node in @($xml.SelectNodes("//*[local-name()='Page']") | Where-Object { $pageIncludes -contains $_.GetAttribute('Include') }))
{
    [void]$node.ParentNode.RemoveChild($node)
}

$compileAnchor = @($xml.SelectNodes("//*[local-name()='Compile']") | Where-Object { $_.GetAttribute('Include') -eq 'Manual\Model\OperateViewModelBase.cs' })[0]
if ($null -eq $compileAnchor)
{
    throw 'Could not find compile anchor.'
}

$ns = $xml.DocumentElement.NamespaceURI
$compileGroup = $compileAnchor.ParentNode

$deviceIoVmNode = $xml.CreateElement('Compile', $ns)
$deviceIoVmNode.SetAttribute('Include', 'DeviceMaintance\ViewModel\DeviceIoViewModel.cs')

$deviceIoStateNode = $xml.CreateElement('Compile', $ns)
$deviceIoStateNode.SetAttribute('Include', 'DeviceMaintance\ViewModel\State\DeviceIoPageState.cs')

$deviceIoViewCodeBehindNode = $xml.CreateElement('Compile', $ns)
$deviceIoViewCodeBehindNode.SetAttribute('Include', 'DeviceMaintance\View\DeviceIoView.xaml.cs')
$dependentUponNode = $xml.CreateElement('DependentUpon', $ns)
$dependentUponNode.InnerText = 'DeviceIoView.xaml'
[void]$deviceIoViewCodeBehindNode.AppendChild($dependentUponNode)

$referenceNode = $compileAnchor
foreach ($node in @($deviceIoVmNode, $deviceIoStateNode, $deviceIoViewCodeBehindNode))
{
    [void]$compileGroup.InsertAfter($node, $referenceNode)
    $referenceNode = $node
}

$pageAnchor = @($xml.SelectNodes("//*[local-name()='Page']") | Where-Object { $_.GetAttribute('Include') -eq 'DeviceMaintance\View\IOMonitorView.xaml' })[0]
if ($null -eq $pageAnchor)
{
    throw 'Could not find page anchor.'
}

$pageGroup = $pageAnchor.ParentNode
$deviceIoPageNode = $xml.CreateElement('Page', $ns)
$deviceIoPageNode.SetAttribute('Include', 'DeviceMaintance\View\DeviceIoView.xaml')
$generatorNode = $xml.CreateElement('Generator', $ns)
$generatorNode.InnerText = 'MSBuild:Compile'
[void]$deviceIoPageNode.AppendChild($generatorNode)
[void]$pageGroup.InsertAfter($deviceIoPageNode, $pageAnchor)

$settings = New-Object System.Xml.XmlWriterSettings
$settings.Indent = $true
$settings.Encoding = New-Object System.Text.UTF8Encoding($true)
$stringBuilder = New-Object System.Text.StringBuilder
$stringWriter = New-Object System.IO.StringWriter($stringBuilder)
$xmlWriter = [System.Xml.XmlWriter]::Create($stringWriter, $settings)
$xml.Save($xmlWriter)
$xmlWriter.Close()
$stringWriter.Close()
$newContent = $stringBuilder.ToString()

$dte = Get-RunningDte
$window = $dte.ItemOperations.OpenFile($path)
Start-Sleep -Milliseconds 500
$document = $window.Document
$textDocument = $document.Object('TextDocument')
$editPoint = $textDocument.StartPoint.CreateEditPoint()
$editPoint.Delete($textDocument.EndPoint)
$editPoint.Insert($newContent)
$document.Save()

Write-Output 'MainShell.csproj updated through Visual Studio.'
