#
# Common.ps1
#

# Override the built-in cmdlet with a custom version
function Write-ErrorMsg($message) {
    [Console]::ForegroundColor = 'red'
    Write-Output $message
    [Console]::ResetColor()
}

function Convert-ByteArrayToHex {
    [cmdletbinding()]
    param(
        [parameter(Mandatory=$true)]
        [Byte[]]
        $bytes
    )
    #$hexString = [System.Text.StringBuilder]::new($bytes.Length * 2)
    $hexString = New-Object System.Text.StringBuilder($bytes.Length * 2)
    ForEach($byte in $bytes){
        $hexString.AppendFormat("{0:x2}", $byte) | Out-Null
    }
    $hexString.ToString()
}

function Convert-HexToByteArray {
	[cmdletbinding()]
	param(
		[parameter(Mandatory=$true)]
		[String]
		$hexString)
#	$bytes = [byte[]]::new($hexString.Length / 2)
	$bytes = New-Object byte[]($hexString.Length / 2)
	For($i=0; $i -lt $hexString.Length; $i+=2){
		$bytes[$i/2] = [convert]::ToByte($hexString.Substring($i, 2), 16)
	}
	$bytes
}

function Build-SharesMessage {
	param(
		[string] $lniata,
		[string] $message)
	$bytes = Convert-HexToByteArray($lniata);
	#TODO: add message to LNIATA
	$bytes
}

function IsPortOpen {
	param(
		[parameter(Mandatory=$true)]
		[string]
		$hostName,
		[parameter(Mandatory=$true)]
		[int]
		$port,
		[parameter(Mandatory=$false)]
		[int]
		$timeout = 5000)
	
	$result = $null

	# REMOVED: TCPClient's ConnectAsync not available in older powershell
	# $client = New-Object System.Net.Sockets.TCPClient
	# $timeout = 
    # $isOpen = $client.ConnectAsync($hostName, $port).Wait($timeout)

	$client = New-Object System.Net.Sockets.TCPClient
	$isOpen = $false
	try {
		$asyncResult = $client.BeginConnect($hostName, $port, $null, $null)
		if (!$asyncResult.AsyncWaitHandle.WaitOne($timeout, $false))
		{
			throw [System.TimeoutException]::new();
		}
		$client.EndConnect($asyncResult) | Out-Null
		$isOpen = $client.Connected
	}
	catch {
		$isOpen = $false
	}
	finally {
		$client.Close();
	}

	if ($isOpen) {
		$result = "Success"
	}
	else {
		$result = "Fail"
	}
	"$($result): $($hostName):$($port)"
}

function Send-UdpDatagram {
	Param (
		[string] $ip,
		[int] $port)
	$address = [System.Net.IPAddress]::Parse($ip)
	$endPoints = New-Object System.Net.IPEndPoint($address, $port)
	$socket = New-Object System.Net.Sockets.UDPClient
	#$data = [Text.Encoding]::ASCII.GetBytes($message)
	$data = Build-SharesMessage("ba0252fe");
	#$sendMessage = $socket.Send($data, $data.Length, $endPoints)
	$socket.Send($data, $data.Length, $endPoints) > $null
	$Socket.Close()
}

function Read-Hosts-File-To-Hash {
	Param (
		[string] $fileName,
		[switch] $includeCommentedLines)

	$hostHash = @{}
	if (-not (Test-Path -Path $fileName)) {
		Write-ErrorMsg "Error: file not found: $($fileName)"
		return $null
	}
	# $lines = Get-Content -Path $fileName
	$lines = [IO.File]::ReadAllLines($fileName)
	foreach ($line in $lines) {
		$line = $line.Trim()
		$isCommented = $false
		if ($line.Length -lt 7) {
			continue
		}
		$chars = $line.ToCharArray()
		if ($chars[0] -eq '#') {
			if (-not $includeCommentedLines) {
				continue
			}
			$isCommented = $true
		}
		$line = $line.Trim('#')
		if ($line.Length -lt 7) {
			continue
		}
		$ix = $line.IndexOf('#')
		if ($ix -gt 0) {
			if ($ix -lt 7) {
				continue
			}
			$line = $line.Substring(0, $ix)
		}
		$words = ($line -split ' ')
		$ip = $words[0]
		try {
			[IPAddress]$ip > $null
		}
		catch {
			continue
		}
		if ($isCommented) {
			$hostHash.Add($ip, $null)
			continue
		}
		if ($words.Count -eq 1) {
			continue
		}
		$names = New-Object System.Collections.Generic.List[String]
		for ($i = 1; $i -lt $words.Count; ++$i) {
			$word = $words[$i].Trim()
			if ($word) {
				$names.Add($words[$i])
			}
		}
		if ($hostHash.ContainsKey($ip)) {
			foreach ($name in $names) {
				$hostHash[$ip].Add($name)
			}
		}
		else {
			$hostHash.Add($ip, $names)
		}
	}
	$hostHash
}

$workingDir = Get-Location
$uaHostsFileName = Join-Path -Path $workingDir -ChildPath 'ua_hosts.txt'
$hostsFileName = "$($Env:windir)\system32\drivers\etc\hosts"
if (Test-Path -Path $uaHostsFileName) {
	$ipHashTable = Read-Hosts-File-To-Hash $uaHostsFileName $true
	$uaHostHashTable = Read-Hosts-File-To-Hash $uaHostsFileName $false
} else {
	Write-ErrorMsg "UA host entry file missing: $uaHostsFileName"
	$ipHashTable = $null
	$uaHostHashTable = $null
}
if (Test-Path -Path $hostsFileName) {
	$hostHashTable = Read-Hosts-File-To-Hash $hostsFileName.ToString() $false
} else {
	Write-ErrorMsg "System hosts file missing: $hostsFileName"
	$hostHashTable = $null
}