Option Strict Off
Imports System
Imports System.IO
Imports System.Net
Imports Microsoft.VisualBasic
Imports System.Security.Permissions
Imports System.Text.RegularExpressions

Imports System.Collections
Imports Microsoft.Win32
Imports System.Runtime.InteropServices
Imports System.Threading
Imports System.Security
Imports System.ComponentModel
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.ConstrainedExecution
Imports System.Reflection

Public Class Class1
    Implements GOverlayPlugin.Interfaces.IPlugin

    Public GameType As String
    Public COHFolder As String = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "My Games\Company of Heroes 2\")
    Public COHReader As System.IO.StreamReader
    Public COHCurrentStatus As Integer = 0
    Public COHCurrentData As New Hashtable
    Public COHReading As Boolean = False
    Public COHFile As String = "warnings.log"
    Public COHFileLastSize As Integer
    Public infoReader As System.IO.FileInfo


    Private objHost As GOverlayPlugin.Interfaces.IHost
    Public PluginName As String = "COH2 Plugin"

    Public Cache As String
    Public LastCache As New System.Collections.Hashtable

    Public COHSensors As New Hashtable
    Public LOGFileOpen As System.IO.StreamWriter = Nothing
    Public LogEvery As Integer = 0

    Public Function clearSensors() As Boolean

        COHSensors = New Hashtable
        COHSensors("COH2.Team1_p1") = ""
        COHSensors("COH2.Team1_p2") = ""
        COHSensors("COH2.Team1_p3") = ""
        COHSensors("COH2.Team1_p4") = ""

        COHSensors("COH2.Team2_p1") = ""
        COHSensors("COH2.Team2_p2") = ""
        COHSensors("COH2.Team2_p3") = ""
        COHSensors("COH2.Team2_p4") = ""


        COHSensors("COH2.Team1_Info") = ""
        COHSensors("COH2.Team1_Name") = ""
        COHSensors("COH2.Team1_Wins") = ""
        COHSensors("COH2.Team1_Losses") = ""
        COHSensors("COH2.Team1_Rank") = ""

        COHSensors("COH2.Team2_Info") = ""
        COHSensors("COH2.Team2_Name") = ""
        COHSensors("COH2.Team2_Wins") = ""
        COHSensors("COH2.Team2_Losses") = ""
        COHSensors("COH2.Team2_Rank") = ""

        COHSensors("COH2.PlayersUpdated") = 0


        Return True
    End Function
    Public Sub Initialize(ByVal Host As GOverlayPlugin.Interfaces.IHost) Implements GOverlayPlugin.Interfaces.IPlugin.Initialize
        objHost = Host

        If Not System.IO.File.Exists(COHFolder & COHFile) Then
            objHost.DebugMessage("Coh2 - File missing: " & COHFolder & COHFile)
            Exit Sub
        End If


        Dim fs As New FileStream(COHFolder & COHFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
        COHReader = New StreamReader(fs)

        clearSensors()

    End Sub

    Public ReadOnly Property Description() As String Implements GOverlayPlugin.Interfaces.IPlugin.Description
        'Return your plugin name
        Get
            Return "This plugin allows to get the information about the players you find on matches (automatch), it can display rank, level, wins/losses and find out if you are facing a TEAM." & vbNewLine & vbNewLine & _
                "Make sure you set the proper COH2 file path." & vbNewLine & _
                "Developed by TheLaGmAn"
        End Get
    End Property

    Public ReadOnly Property Name() As String Implements GOverlayPlugin.Interfaces.IPlugin.Name
        'Return your plugin name
        Get
            Return PluginName
        End Get
    End Property

    Public ReadOnly Property Display() As String Implements GOverlayPlugin.Interfaces.IPlugin.Display
        'Return the display this plugin belongs to
        Get
            Return "lcdsys"
        End Get
    End Property

    Function CallBack(method As String) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.CallBacks
        'Send the request to upload all the files
        'objHost.DebugMessage("ETS2 Plugin - Callback Requested")
        'objHost.DebugMessage("ETS2 Plugin - " & method)

        Dim returnHT As Hashtable = New Hashtable

        Try


            Dim value = 0

            If method = "willrequestvalues" Then
                'Comes here once per run (only if sensors are used thru here)
                GrabData(0)
            ElseIf method = "willrequestvdisplay" Then
                'Comes here once per run (only if sensors are used thru here)                
            Else
                If method.IndexOf("COH2.") > -1 Then
                    value = COHSensors(method)
                End If
            End If

            returnHT("value") = value

            Return returnHT
        Catch ex As Exception
            objHost.DebugMessage("Coh2 - Error grabbing action : " & method)
            returnHT("value") = 0
            Return returnHT
        End Try
    End Function

    Function AvailableSensors(pluginOptions As Hashtable) As System.Collections.Generic.Dictionary(Of String, String) Implements GOverlayPlugin.Interfaces.IPlugin.AvailableSensors
        'Create the list of the sensors/elements this plugin has
        'You can access your pluginOptions here as pluginOptions(your_option)        
        Dim sensors As New System.Collections.Generic.Dictionary(Of String, String)

        Try
            'objHost.DebugMessage("called as")



            sensors.Add("COH2.Team1_Info", "Team 1 Information")
            sensors.Add("COH2.Team1_Name", "Team 1 Name")
            sensors.Add("COH2.Team1_Wins", "Team 1 Wins (If Team)")
            sensors.Add("COH2.Team1_Losses", "Team 1 Losses (If Team)")
            sensors.Add("COH2.Team1_Rank", "Team 1 Rank (If Team)")

            sensors.Add("COH2.Team2_Info", "Team 2 Information")
            sensors.Add("COH2.Team2_Name", "Team 2 Name")
            sensors.Add("COH2.Team2_Wins", "Team 2 Wins (If Team)")
            sensors.Add("COH2.Team2_Losses", "Team 2 Losses (If Team)")
            sensors.Add("COH2.Team2_Rank", "Team 2 Rank (If Team)")

            sensors.Add("COH2.Team1_p1", "Team 1: Player 1 Information")
            sensors.Add("COH2.Team1_p2", "Team 1: Player 2 Information")
            sensors.Add("COH2.Team1_p3", "Team 1: Player 3 Information")
            sensors.Add("COH2.Team1_p4", "Team 1: Player 4 Information")

            sensors.Add("COH2.Team2_p1", "Team 2: Player 1 Information")
            sensors.Add("COH2.Team2_p2", "Team 2: Player 2 Information")
            sensors.Add("COH2.Team2_p3", "Team 2: Player 3 Information")
            sensors.Add("COH2.Team2_p4", "Team 2: Player 4 Information")

            sensors.Add("COH2.PlayersUpdated", "Players Updated")

            Dim player As Integer = 0
            Dim team As Integer = 0

            For team = 1 To 2
                For player = 1 To 4
                    sensors.Add("COH2.Team" & team & "_p" & player & "_name", "Team " & team & ": Player " & player & " Name")
                    sensors.Add("COH2.Team" & team & "_p" & player & "_wins", "Team " & team & ": Player " & player & " Wins")
                    sensors.Add("COH2.Team" & team & "_p" & player & "_losses", "Team " & team & ": Player " & player & " Losses")
                    sensors.Add("COH2.Team" & team & "_p" & player & "_streak", "Team " & team & ": Player " & player & " Streak")
                    sensors.Add("COH2.Team" & team & "_p" & player & "_disputes", "Team " & team & ": Player " & player & " Disputes")
                    sensors.Add("COH2.Team" & team & "_p" & player & "_drops", "Team " & team & ": Player " & player & " Drops")
                    sensors.Add("COH2.Team" & team & "_p" & player & "_rank", "Team " & team & ": Player " & player & " Rank")
                Next

            Next

            Return sensors
        Catch ex As Exception
            objHost.DebugMessage("Coh2 - Error loading sensors:" & ex.Message & ": " & ex.StackTrace)
            Return sensors
            'MsgBox(ex.Message & ":: " & ex.StackTrace)
        End Try
    End Function

    Function LCDSys2_AvailableSensors(pluginOptions As Hashtable) As System.Collections.Generic.Dictionary(Of String, String) Implements GOverlayPlugin.Interfaces.IPlugin.LCDSys2_AvailableSensors
        Return AvailableSensors(pluginOptions)
    End Function

    Function SensorHasCustomDraw(sensor_name As String) As Boolean Implements GOverlayPlugin.Interfaces.IPlugin.SensorHasCustomDraw
        'All sensors are drawn with GOverlay default drawing
        Return False
    End Function

    Function ComboBoxes() As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.ComboBoxes
        'Create custom ComboBox for your configuration to use
        Dim boxes As New Hashtable
        Return boxes
    End Function

    Public Function SetDefaultOptions(sensorId As String, elementData As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.SetDefaultOptions
        'Set the default values you want to have on your sensor when its created, if the user doesnt change any option, he will have this settings

        elementData("width") = 240
        elementData("height") = 15
        elementData("font_style") = 1
        elementData("basic_color") = 0
        elementData("font_size") = 5
        elementData("font_color") = 65535
        elementData("font_transform") = 1

        Return elementData
    End Function

    Public Function CreateOptions(sensorId As String, elementData As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.CreateOptions
        'Set the options the user will have when clicking on the element
        'The available option_types are:
        'Text: Input text
        'Combo3: Combo with options (Enabled=0, Disabled=1)
        'Sensors: Combo with available sensors
        'ColorBasic: Combo with basic colors for the regular text font
        'ColorRGB: Combo with common RGB colors = 16bitinteger
        'ComboOnOff: Combo with options (Disabled=0, Enabled=1)
        'ComboYesNo: Combo with options (Yes=Yes, No=No)
        'TextSize: Combo with options (Extra Small=4, Very Small=5, Small=10, Normal=15, Big=20, Very Big=30, Extreme=40)
        'FontStyle2: Combo with options (Regular Font=0, Square Font=1, Numbers Font 1=2
        'Orientation: Combo with options (Horizontal=0, Vertical=1)
        'Here you can also load your custom comboboxes
        Return New Hashtable
    End Function

    Public Function LCDSys2_CreateOptions(sensorId As String, elementData As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.LCDSys2_CreateOptions
        'Set the options the user will have when clicking on the element
        'The available option_types are:
        'Text: Input text
        'Combo3: Combo with options (Enabled=0, Disabled=1)
        'Sensors: Combo with available sensors
        'ColorRGB: Combo with common RGB colors = 16bitinteger
        'ComboOnOff: Combo with options (Disabled=0, Enabled=1)
        'ComboYesNo: Combo with options (Yes=Yes, No=No)
        'FontStyle: Combo with options of the fonts the user has installed
        'Orientation: Combo with options (Horizontal=0, Vertical=1)
        'Alignment: Left=-1,Center=0,Right=1
        'Here you can also load your custom comboboxes

        'No options because GOverlay draws instead of us
        Return New Hashtable
    End Function

    Public Function PluginOptionsDefault() As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.PluginOptionsDefault
        'Set the default values you want to have on plugin, if the user doesnt change any option, he will have this settings
        Dim options As New Hashtable
        options("coh2path") = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "My Games\Company of Heroes 2\")
        Return options
    End Function
    Public Function PluginOptions(pluginCurrentOptions As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.PluginOptions
        'Set the options the user will have when going to the plugins tab and clicking on your plugin
        'The availalbe option_type are teh same as CreateOptions function
        Dim options As New Hashtable
        'Option: option_index as integer, option_data as ArrayList
        'Option_Data: option_type as string, option_label as string, option_name as string (no spaces, no _)
        'options.Add(0, New ArrayList({"TextMulti", "Temperature in C or F? (write C or F)", "metric"}))
        options.Add(0, New ArrayList({"TextMulti", "Path to the COH2 Documents Folder", "coh2path"}))
        Return options
    End Function

    Public Function DebugMessageSometimes(msg As String) As Boolean
        LogEvery = LogEvery + 1
        If LogEvery >= 5 Then
            objHost.DebugMessage(msg)
            LogEvery = 0
        End If
        Return True
    End Function
    Public Function GrabData(metric As String) As Boolean
        Try

            If Not System.IO.File.Exists(COHFolder & COHFile) Then
                DebugMessageSometimes("Coh2 - COH file missing: " & COHFolder & COHFile)
                Return False
            End If

            If COHReading = True Then
                DebugMessageSometimes("Coh2 - Overlapped coh2 gather data request")
                Return False
            End If

            COHReading = True

            infoReader = My.Computer.FileSystem.GetFileInfo(COHFolder & COHFile)
            If infoReader.Length < COHFileLastSize Then
                Dim fs As New FileStream(COHFolder & COHFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
                COHReader = New StreamReader(fs)
                objHost.DebugMessage("Coh2 - COH file reset, loading again")
                'File has smaller size than what we have, file probably reset by loading coh again
            End If


            While Not COHReader.EndOfStream
                Dim theLine As String = COHReader.ReadLine()
                COHProcessLine(theLine)
            End While

            COHFileLastSize = infoReader.Length

            COHReading = False

            Return True
        Catch ex As Exception
            objHost.DebugMessage("Coh2 - Error requesting data: " & ex.Message & " :: " & ex.StackTrace)
            COHReading = False
            Return False
        End Try
    End Function
    Public Function DisplayOnLCD(sensorId As String, elementData As Hashtable, pluginOptions As Hashtable, cacheRuns As Integer) As ArrayList Implements GOverlayPlugin.Interfaces.IPlugin.DisplayOnLCD
        Return New ArrayList
    End Function

    Public Function LCDSys2_DisplayOnLCD(sensorId As String, elementData As Hashtable, pluginOptions As Hashtable, cacheRuns As Integer) As ArrayList Implements GOverlayPlugin.Interfaces.IPlugin.LCDSys2_DisplayOnLCD
        'GOverlay draws instead of us
        Return New ArrayList
    End Function


    Public Function convertcolorto16bit(cr, cg, cb) As Integer

        Dim R As Double
        Dim G As Double
        Dim B As Double

        R = cr / 256 * 32
        G = cg / 256 * 64
        B = cb / 256 * 32

        R = Math.Floor(R)
        G = Math.Floor(G)
        B = Math.Floor(B)

        Dim final As Int32 = (CInt(R) << 11)
        final = final + Int(G << 5)
        final = final + Int(B)

        Return final

    End Function


    Public Function COHProcessLine(line As String) As Integer

        Select Case COHCurrentStatus
            Case 0
                'Not in game
                If line.IndexOf("- detected successful game start") > -1 Or line.IndexOf("ReasonDebug: Succeeded to start observing") > -1 Then

                    COHCurrentStatus = 1

                    Dim datePart = line.Split("   ")
                    COHCurrentData = New Hashtable
                    COHCurrentData("start_date") = datePart(0)

                    clearSensors()

                    COHSensors("COH2.PlayersUpdated") += 1

                    If line.IndexOf("ReasonDebug: Succeeded to start observing") > -1 Then
                        GameType = "replay"
                    Else
                        GameType = "game"
                    End If

                    objHost.DebugMessage("Coh2 ------------------------------------------------------------------------------------------------------------")
                    objHost.DebugMessage("Coh2 - Game starting (as " & GameType & ") - " & line.Split(" ")(0).ToString)

                End If
            Case 1
                'Loading screen init
                'MsgBox(line)
                If line.IndexOf("Match Started -") > -1 Then
                    'For true games only (replay does not have it)
                    'IMPORTANT: sometimes this comes AFTER human player, so we would we overwriting things in that case
                    objHost.DebugMessage("Coh2 - Player: " & line)

                    'Dim line = "18:15:12.70   Match Started - [00000000:000cbf2c /steam/76561197967206521], slot =  0, ranking =   -1"
                    Dim regex As Regex = New Regex("(.*)/steam/(.*)\], slot =(.*), ranking =(.*)")
                    Dim match As Match = regex.Match(line)

                    If match.Success Then
                        Dim steamId = match.Groups.Item(2).Value.Replace(" ", "")
                        Dim slot = match.Groups.Item(3).Value.Replace(" ", "")
                        Dim ranking = match.Groups.Item(4).Value.Replace(" ", "")
                        If ranking = "-1" Then ranking = "0"

                        If Not COHCurrentData.ContainsKey("player_" & slot) Then
                            'it came BEFORE human player, so we intialize it with fake data
                            COHCurrentData("player_" & slot) = New Hashtable
                            COHCurrentData("player_" & slot)("username") = "player " & slot
                            COHCurrentData("player_" & slot)("team") = 0
                            COHCurrentData("player_" & slot)("faction") = "soviet"
                        End If

                        COHCurrentData("player_" & slot)("ranking") = ranking
                        COHCurrentData("player_" & slot)("steamid") = steamId

                        COHSensors("COH2.PlayersUpdated") += 1
                    Else
                        objHost.DebugMessage("Player not found: " & line & " -- " & "(.*)/steam/(.*)\], slot =(.*), ranking =(.*)")
                    End If
                ElseIf line.IndexOf("GAME -- Human Player:") > -1 Then
                    'For true games and replays
                    'Dim line = "18:15:14.04   GAME -- Human Player: 0 Warashes 835372 0 german"
                    Dim regex As Regex = New Regex("(.*)Human Player: ([0-9]) (.*) (-1|[0-9]+) ([0|1]) (.*)")
                    Dim match As Match = regex.Match(line)
                    If match.Success Then
                        Dim slot = match.Groups.Item(2).Value
                        Dim username = match.Groups.Item(3).Value
                        Dim relicId = match.Groups.Item(4).Value
                        Dim team = match.Groups.Item(5).Value
                        Dim faction = match.Groups.Item(6).Value.Replace(" ", "")

                        If Not COHCurrentData.ContainsKey("player_" & slot) Then
                            COHCurrentData("player_" & slot) = New Hashtable
                        End If

                        If GameType = "replay" Then
                            'Replay does not have "Match Started" so we init the player here
                            If COHCurrentData("player_" & slot).containskey("steamid") Then
                                'In case its not actually a replay and was readed wrong, all the data is from match started
                            Else
                                'Its a true replay
                                'COHCurrentData("player_" & slot)("steamid") = findSteamIdFromUsername(username)
                                COHCurrentData("player_" & slot)("steamid") = findSteamIdFromRelicId(username, relicId)
                                COHCurrentData("player_" & slot)("ranking") = "0"
                            End If
                        End If

                        COHCurrentData("player_" & slot)("username") = username
                        COHCurrentData("player_" & slot)("team") = team
                        COHCurrentData("player_" & slot)("faction") = faction

                        COHSensors("COH2.PlayersUpdated") += 1
                    End If
                ElseIf line.IndexOf("GAME -- AI Player:") > -1 Then
                    'For true games and replays
                    'Dim line = "17:40:25.59   GAME -- AI Player: 1 CPU - Easy -1 1 german"
                    Dim regex As Regex = New Regex("(.*)AI Player: ([0-9]) (.*) (-1|[0-9]+) ([0|1]) (.*)")
                    Dim match As Match = regex.Match(line)
                    If match.Success Then
                        Dim slot = match.Groups.Item(2).Value
                        Dim username = match.Groups.Item(3).Value
                        Dim team = match.Groups.Item(5).Value
                        Dim faction = match.Groups.Item(6).Value.Replace(" ", "")

                        If Not COHCurrentData.ContainsKey("player_" & slot) Then
                            COHCurrentData("player_" & slot) = New Hashtable
                            COHCurrentData("player_" & slot)("steamid") = -1
                            COHCurrentData("player_" & slot)("ranking") = "0"
                            COHCurrentData("player_count") = slot + 1
                            COHCurrentData("is_ia") = True
                        End If

                        COHCurrentData("player_" & slot)("username") = username & "*"
                        COHCurrentData("player_" & slot)("team") = team
                        COHCurrentData("player_" & slot)("faction") = faction

                        COHSensors("COH2.PlayersUpdated") += 1
                    End If
                ElseIf line.IndexOf("GAME -- Scenario: DATA:scenarios\mp\") > -1 Then
                    'Dim line = "18:15:14.04   GAME -- Scenario: DATA:scenarios\mp\8p_essen_steelworks\8p_essen_steelworks"
                    Dim regex As Regex = New Regex("(.*)GAME -- Scenario: DATA:scenarios\\mp\\(.*)")
                    Dim match As Match = regex.Match(line)
                    If match.Success Then
                        If match.Groups(2).Value.IndexOf("\") Then
                            Dim mapdata = match.Groups(2).Value.Split("\")
                            COHCurrentData("map") = mapdata(1)
                        Else
                            COHCurrentData("map") = match.Groups(2).Value
                        End If
                    End If
                ElseIf line.IndexOf("GameObj::StartGameObj -") > -1 Then
                    'All players should be processed by then
                    objHost.DebugMessage("Coh2 - on loading screen " & line.Split(" ")(0).ToString)
                    COHCurrentStatus = 2
                    Dim playersdata As String = ""

                    'Update player count
                    If COHCurrentData.ContainsKey("player_7") Then
                        COHCurrentData("player_count") = 8
                    ElseIf COHCurrentData.ContainsKey("player_6") Then
                        COHCurrentData("player_count") = 7
                    ElseIf COHCurrentData.ContainsKey("player_5") Then
                        COHCurrentData("player_count") = 6
                    ElseIf COHCurrentData.ContainsKey("player_4") Then
                        COHCurrentData("player_count") = 5
                    ElseIf COHCurrentData.ContainsKey("player_3") Then
                        COHCurrentData("player_count") = 4
                    ElseIf COHCurrentData.ContainsKey("player_2") Then
                        COHCurrentData("player_count") = 3
                    ElseIf COHCurrentData.ContainsKey("player_1") Then
                        COHCurrentData("player_count") = 2
                    Else
                        COHCurrentData("player_count") = 1
                    End If

                    'objHost.DebugMessage("Player count: " & COHCurrentData("player_count"))

                    If COHCurrentData("player_0").containskey("username") Then
                        COHSensors("COH2.Team1_Info") = factionToTeam(COHCurrentData("player_0")("faction"))
                        COHSensors("COH2.Team1_Name") = factionToTeam(COHCurrentData("player_0")("faction"))
                    End If

                    If COHCurrentData("player_1").containskey("username") Then
                        COHSensors("COH2.Team2_Info") = factionToTeam(COHCurrentData("player_1")("faction"))
                        COHSensors("COH2.Team2_Name") = factionToTeam(COHCurrentData("player_1")("faction"))
                    End If

                    Dim playerId As Integer = 0

                    Dim atLeastOneHadNoProfile As Boolean = False

                    For playerId = 0 To 7
                        If COHCurrentData.ContainsKey("player_" & playerId) AndAlso COHCurrentData("player_" & playerId).containskey("username") Then
                            Dim thePlayerInfo As Hashtable = COHCurrentData("player_" & playerId)

                            Dim theTeam As String = ""
                            If playerId = 0 Then
                                theTeam = "Team1_p1"
                            ElseIf playerId = 1 Then
                                theTeam = "Team2_p1"
                            ElseIf playerId = 2 Then
                                theTeam = "Team1_p2"
                            ElseIf playerId = 3 Then
                                theTeam = "Team2_p2"
                            ElseIf playerId = 4 Then
                                theTeam = "Team1_p3"
                            ElseIf playerId = 5 Then
                                theTeam = "Team2_p3"
                            ElseIf playerId = 6 Then
                                theTeam = "Team1_p4"
                            ElseIf playerId = 7 Then
                                theTeam = "Team2_p4"
                            End If


                            COHSensors("COH2." & theTeam) = String.Format("{0,-10}", thePlayerInfo("username")).Substring(0, 10) & " - " & String.Format("{0,-4}", thePlayerInfo("ranking"))


                            If COHCurrentData("player_" & playerId)("steamid") = "" Then
                                'Didnt load profileId, this can happen if the game "started" before the log shows the players data
                                'objHost.DebugMessage("Player: " & COHCurrentData("player_" & playerId)("username") & " has no profile Id, looking for one")
                                COHCurrentData("player_" & playerId)("steamid") = findSteamIdFromUsername(COHCurrentData("player_" & playerId)("username"))
                                atLeastOneHadNoProfile = True
                            End If

                            'objHost.DebugMessage(COHCurrentData("player_" & playerId)("username") & " ---> " & COHCurrentData("player_" & playerId)("steamid"))

                            gatherUserInfo(playerId, theTeam)

                        End If
                    Next

                    checkTeams()

                    If atLeastOneHadNoProfile Then
                        objHost.DebugMessage("Coh2 - Processed data: " & "Player count: " & COHCurrentData("player_count") & " - " & "Map: " & COHCurrentData("map") & " -> Had missing profiles")
                    Else
                        objHost.DebugMessage("Coh2 - Processed data: " & "Player count: " & COHCurrentData("player_count") & " - " & "Map: " & COHCurrentData("map") & " -> All OK")
                    End If

                End If
            Case 2
                'Loading screen finished init
                If line.IndexOf("PerformanceRecorder::StartRecording for game") > -1 Then
                    objHost.DebugMessage("Coh2 - Game is now live - " & line.Split(" ")(0).ToString)
                    COHCurrentStatus = 3
                End If
            Case 3
                'In-game
                If line.IndexOf("GAME -- Starting mission") > -1 Then
                    'objHost.DebugMessage("Map: " & line)
                    objHost.DebugMessage("Coh2 - Starting mission - " & line.Split(" ")(0).ToString)
                ElseIf line.IndexOf("MOD -- Game Over") > -1 Then
                    objHost.DebugMessage("Coh2 - Game finished - " & line.Split(" ")(0).ToString)
                    COHCurrentStatus = 0
                End If
        End Select

        Return 1
    End Function

    Public Function Debug_isObject(o) As Boolean
        If o.GetType Is GetType(Hashtable) Or o.GetType Is GetType(Array) Or o.GetType Is GetType(ArrayList) Then
            Return True
        End If

        Return False
    End Function
    Public Function Debug_PrintValues(ByVal myArr, ByVal spacing) As String
        Dim printstring As String = ""
        Dim x As Integer = 0

        Dim space As String = ""
        For x = 0 To spacing
            space = space & vbTab
        Next

        If myArr.GetType Is GetType(Hashtable) Then
            If spacing > 0 Then : printstring = printstring & " => Hashtable (" & vbNewLine : End If
            Dim d
            For Each d In myArr
                If Debug_isObject(d.value) Then
                    printstring = printstring & space & d.key
                    printstring = printstring & Debug_PrintValues(d.value, spacing + 1)
                Else
                    printstring = printstring & space & d.key & " => " & d.value & vbNewLine
                End If
            Next
        ElseIf myArr.GetType Is GetType(Array) Or myArr.GetType Is GetType(ArrayList) Then
            printstring = printstring & " => Array[" & myArr.count & "] (" & vbNewLine

            For x = 0 To myArr.count - 1
                If Debug_isObject(myArr(x)) Then
                    printstring = printstring & space & x
                    printstring = printstring & Debug_PrintValues(myArr(x), spacing + 1)
                Else
                    printstring = printstring & space & x & " => " & myArr(x) & vbNewLine
                End If
            Next
        Else
            printstring = printstring & space & "??" & vbNewLine
        End If

        If spacing > 0 Then : printstring = printstring & space & ")" & vbNewLine : End If

        'Console.WriteLine()
        Return printstring

    End Function

    Public Function comparePlayers(ByVal ht1, ByVal ht2) As Boolean
        Dim d
        For Each d In ht2
            If Not ht1.containskey(d.key) Then
                Return False
            End If
        Next

        For Each d In ht1
            If Not ht2.containskey(d.key) Then
                Return False
            End If
        Next

        Return True
    End Function
    Public Function checkTeams() As Boolean
        objHost.DebugMessage("Coh2 - Checking if any of the players are in a team")

        Dim x As Integer = 0
        Dim pcount As Integer = CInt(COHCurrentData("player_count")) / 2

        Dim player0 = COHCurrentData("player_0")
        Dim player1 = COHCurrentData("player_1")

        Dim player0teamPlayers As Hashtable = New Hashtable
        Dim player1teamPlayers As Hashtable = New Hashtable
        Dim player0teamPlayersString As String = ""
        Dim player1teamPlayersString As String = ""

        If pcount = 1 Then
            player0teamPlayers(COHCurrentData("player_0")("username")) = 1

            player1teamPlayers(COHCurrentData("player_1")("username")) = 1
        ElseIf pcount = 2 Then
            player0teamPlayers(COHCurrentData("player_0")("username")) = 1
            player0teamPlayers(COHCurrentData("player_2")("username")) = 1

            player1teamPlayers(COHCurrentData("player_1")("username")) = 1
            player1teamPlayers(COHCurrentData("player_3")("username")) = 1
        ElseIf pcount = 3 Then
            player0teamPlayers(COHCurrentData("player_0")("username")) = 1
            player0teamPlayers(COHCurrentData("player_2")("username")) = 1
            player0teamPlayers(COHCurrentData("player_4")("username")) = 1

            player1teamPlayers(COHCurrentData("player_1")("username")) = 1
            player1teamPlayers(COHCurrentData("player_3")("username")) = 1
            player1teamPlayers(COHCurrentData("player_5")("username")) = 1
        ElseIf pcount = 4 Then
            player0teamPlayers(COHCurrentData("player_0")("username")) = 1
            player0teamPlayers(COHCurrentData("player_2")("username")) = 1
            player0teamPlayers(COHCurrentData("player_4")("username")) = 1
            player0teamPlayers(COHCurrentData("player_6")("username")) = 1

            player1teamPlayers(COHCurrentData("player_1")("username")) = 1
            player1teamPlayers(COHCurrentData("player_3")("username")) = 1
            player1teamPlayers(COHCurrentData("player_5")("username")) = 1
            player1teamPlayers(COHCurrentData("player_7")("username")) = 1
        End If

        Dim tt
        For Each tt In player0teamPlayers : player0teamPlayersString = player0teamPlayersString & tt.key & ", " : Next
        For Each tt In player1teamPlayers : player1teamPlayersString = player1teamPlayersString & tt.key & ", " : Next

        objHost.DebugMessage("Coh2 - Team A would be: " & player0teamPlayersString)
        objHost.DebugMessage("Coh2 - Team B would be: " & player1teamPlayersString)

        Dim pTeam0 As String = "Team " & pcount & "v" & pcount & " " & factionToTeam(player0("faction"))
        Dim pTeam1 As String = "Team " & pcount & "v" & pcount & " " & factionToTeam(player1("faction"))

        If player0.containskey("stats") AndAlso player0("stats").containskey("teams") AndAlso player0("stats")("teams").containskey(pTeam0) Then
            'Player 0 has custom teams
            Dim match As Integer = -1

            Dim playerTeamsInThisLadder As ArrayList = player0("stats")("teams")(pTeam0)
            For x = 0 To playerTeamsInThisLadder.Count - 1
                If comparePlayers(playerTeamsInThisLadder(x)("members"), player0teamPlayers) Then
                    'same players
                    match = x
                End If
            Next

            If match > -1 Then
                objHost.DebugMessage("Coh2 - Team A - is team - with: " & Debug_PrintValues(playerTeamsInThisLadder(match), 0))
                Dim t = playerTeamsInThisLadder(match)
                COHSensors("COH2.Team1_Wins") = t("wins")
                COHSensors("COH2.Team1_Losses") = t("losses")
                COHSensors("COH2.Team1_Rank") = t("rank")

                COHSensors("COH2.Team1_Info") = COHSensors("COH2.Team1_Name") & String.Format("{0,-4}", t("rank")) & " - " & String.Format("{0,-4}", t("wins")) & " " & String.Format("{0,-4}", t("losses"))

            Else
                objHost.DebugMessage("Coh2 - Team A - is no team")
                'MsgBox("for players: " & Debug_PrintValues(player0teamPlayers, 0) & vbNewLine & "no match")
            End If
        Else
            objHost.DebugMessage("Coh2 - Team A - is no team (first player doesnt have team exp in this ladder)")
        End If

        If player1.containskey("stats") AndAlso player1("stats").containskey("teams") AndAlso player1("stats")("teams").containskey(pTeam1) Then
            'Player 0 has custom teams
            Dim match As Integer = -1

            Dim playerTeamsInThisLadder As ArrayList = player1("stats")("teams")(pTeam1)
            For x = 0 To playerTeamsInThisLadder.Count - 1
                If comparePlayers(playerTeamsInThisLadder(x)("members"), player1teamPlayers) Then
                    'same players
                    match = x
                End If
            Next

            If match > -1 Then
                objHost.DebugMessage("Coh2 - Team B - is team - with: " & Debug_PrintValues(playerTeamsInThisLadder(match), 0))

                Dim t = playerTeamsInThisLadder(match)
                COHSensors("COH2.Team2_Wins") = t("wins")
                COHSensors("COH2.Team2_Losses") = t("losses")
                COHSensors("COH2.Team2_Rank") = t("rank")

                COHSensors("COH2.Team2_Info") = COHSensors("COH2.Team2_Name") & String.Format("{0,-4}", t("rank")) & " - " & String.Format("{0,-4}", t("wins")) & " " & String.Format("{0,-4}", t("losses"))

            Else
                objHost.DebugMessage("Coh2 - Team B - is no team")
                'MsgBox("for players: " & Debug_PrintValues(player1teamPlayers, 0) & vbNewLine & "no match")
            End If
        Else
            objHost.DebugMessage("Coh2 - Team B - is no team (first player doesnt have team exp in this ladder)")
        End If

        'MsgBox("cteamend")

        Return True

    End Function

    Public Function findSteamIdFromRelicId(relicUsername As String, relicId As String) As String
        '{"profile_id":984883,"name":"/steam/76561198022094732","alias":"Commander","personal_statgroup_id":981809,"xp":16347254,"level":282,"leaderboardregion_id":4,"country":"ar"}]},{"id":2646587,"name":"","type":2,"members":

        Dim request As HttpWebRequest
        Dim response As HttpWebResponse = Nothing
        Dim reader As StreamReader

        request = DirectCast(WebRequest.Create("https://coh2-api.reliclink.com/community/leaderboard/GetPersonalStat?title=coh2&profile_ids=[" & relicId.Trim() & "]"), HttpWebRequest)
        response = DirectCast(request.GetResponse(), HttpWebResponse)
        reader = New StreamReader(response.GetResponseStream())
        Dim rawresp As String
        rawresp = reader.ReadToEnd()

        'Dim searchRegex As String = """name"":""/steam/([0-9]+)"",""alias"":""" & relicUsername & """"
        Dim searchRegex As String = "profile_id"":" & relicId & ",""name"":""/steam/([0-9]+)"","
        Dim regexGroups As Regex = New Regex(searchRegex)

        Dim matchesG As MatchCollection = regexGroups.Matches(rawresp)
        For Each m As Match In matchesG
            objHost.DebugMessage("Coh2 - Player : " & relicUsername & " - Look for SteamID of relicId : " & relicId & " -> Found as " & m.Groups(1).Value)
            Return m.Groups(1).Value
        Next

        objHost.DebugMessage("Coh2 - Player : " & relicUsername & " -> steamId not found (" & relicId & ")")

        Return -1
    End Function
    Public Function findSteamIdFromUsername(steamUsername As String) As String
        Dim request As HttpWebRequest
        Dim response As HttpWebResponse = Nothing
        Dim reader As StreamReader

        request = DirectCast(WebRequest.Create("https://coh2-api.reliclink.com/community/leaderboard/GetPersonalStat?title=coh2&search=" & steamUsername), HttpWebRequest)
        response = DirectCast(request.GetResponse(), HttpWebResponse)
        reader = New StreamReader(response.GetResponseStream())
        Dim rawresp As String
        rawresp = reader.ReadToEnd()

        Dim searchRegex As String = """name"":""/steam/([0-9]+)"",""alias"":""" & steamUsername & """"

        'MsgBox(searchRegex)
        Dim regexGroups As Regex = New Regex(searchRegex)

        'Dim regexGroups As Regex = New Regex("{""id"":([0-9]+),""name"":"""",""type"":([0-9]+),""members"":\[(.*?)\]}")
        Dim matchesG As MatchCollection = regexGroups.Matches(rawresp)
        For Each m As Match In matchesG
            objHost.DebugMessage("Coh2 - Look for SteamID of username : " & steamUsername & " -> Found as " & m.Groups(1).Value)
            'objHost.DebugMessage("Found as " & m.Groups(1).Value)
            Return m.Groups(1).Value
        Next

        objHost.DebugMessage("Coh2 - Look for SteamID of username : " & steamUsername & " -> Not Found")

        Return -1
    End Function
    Public Function gatherUserInfo(playerSlotId As Integer, fullPlayerName As String) As Boolean

        COHSensors("COH2.PlayersUpdated") = 1

        Dim playerid As String = "player_" & playerSlotId

        Dim team As Integer = 1
        If playerSlotId >= 3 Then
            team = 2
        End If
        Dim player As Integer = playerSlotId + 1

        COHSensors("COH2." & fullPlayerName & "_name") = COHCurrentData(playerid)("username")
        COHSensors("COH2." & fullPlayerName & "_wins") = ""
        COHSensors("COH2." & fullPlayerName & "_losses") = ""
        COHSensors("COH2." & fullPlayerName & "_streak") = ""
        COHSensors("COH2." & fullPlayerName & "_disputes") = ""
        COHSensors("COH2." & fullPlayerName & "_drops") = ""
        COHSensors("COH2." & fullPlayerName & "_rank") = ""


        Try



            Dim steamid As String = COHCurrentData(playerid)("steamid")

            Dim userGroups As Hashtable = New Hashtable
            Dim userData As Hashtable = New Hashtable
            userData("personal") = New Hashtable
            userData("teams") = New Hashtable

            Dim request As HttpWebRequest
            Dim response As HttpWebResponse = Nothing
            Dim reader As StreamReader

            request = DirectCast(WebRequest.Create("https://coh2-api.reliclink.com/community/leaderboard/GetPersonalStat?profile_names=[%22/steam/" & steamid & "%22]&title=coh2"), HttpWebRequest)
            response = DirectCast(request.GetResponse(), HttpWebResponse)
            reader = New StreamReader(response.GetResponseStream())
            Dim rawresp As String
            rawresp = reader.ReadToEnd()

            'objHost.DebugMessage(rawresp)

            Dim regexGroups As Regex = New Regex("{""id"":([0-9]+),""name"":"""",""type"":([0-9]+),""members"":\[(.*?)\]}")
            Dim matchesG As MatchCollection = regexGroups.Matches(rawresp)

            For Each m As Match In matchesG
                Dim regexGroupsUser As Regex = New Regex("{""profile_id"":([0-9]+),""name"":""/steam/[0-9]+"",""alias"":""(.*?)"",""personal_statgroup_id"":[0-9]+,""xp"":[0-9]+,""level"":[0-9]+,""leaderboardregion_id"":[0-9]+,""country"":""[a-z]+""}")
                Dim matchesU As MatchCollection = regexGroupsUser.Matches(m.Groups.Item(3).Value)
                If matchesU.Count > 1 Then
                    Dim groupId As String = m.Groups.Item(1).Value

                    userGroups(groupId) = New Hashtable

                    For Each mU As Match In matchesU
                        Dim userName As String = mU.Groups.Item(2).Value
                        If Not userGroups(groupId).ContainsKey(userName) Then
                            userGroups(groupId).add(userName, userName)
                        End If
                    Next

                End If
            Next

            Dim regex As Regex = New Regex("{""statGroup_id"":([0-9]+),""leaderboard_id"":([0-9]+),""wins"":([0-9]+),""losses"":([0-9]+),""streak"":([\+\-0-9]+),""disputes"":([0-9]+),""drops"":([0-9]+),""rank"":([\-0-9]+),""rankTotal"":([\-0-9]+)")

            Dim matches As MatchCollection = regex.Matches(rawresp)

            'MsgBox(matches.Count)

            For Each m As Match In matches

                'objHost.DebugMessage(m.Groups.Item(2).Value & " : " & leaderboardToName(m.Groups.Item(2).Value) & " // " & m.Groups.Item(1).Value)

                Dim ladderName As String = leaderboardToName(m.Groups.Item(2).Value)
                Dim groupId As String = m.Groups.Item(1).Value

                Dim lData As Hashtable = New Hashtable

                lData("wins") = m.Groups.Item(3).Value
                lData("losses") = m.Groups.Item(4).Value
                lData("streak") = m.Groups.Item(5).Value
                lData("disputes") = m.Groups.Item(6).Value
                lData("drops") = m.Groups.Item(7).Value
                lData("rank") = m.Groups.Item(8).Value
                If lData("rank") = "-1" Or lData("rank") = "0" Then lData("rank") = "0"
                lData("rankTotal") = m.Groups.Item(9).Value

                If (userGroups.ContainsKey(groupId)) Then
                    'MsgBox("is team")
                    If Not userData("teams").containskey(ladderName) Then
                        userData("teams")(ladderName) = New ArrayList
                    End If

                    lData("members") = userGroups(m.Groups.Item(1).Value)
                    userData("teams")(ladderName).add(lData)

                Else
                    'MsgBox("is personal")
                    userData("personal")(ladderName) = lData
                End If

            Next

            COHCurrentData(playerid)("stats") = userData

            Dim leaderboardId As String = factionToLeaderboardName(COHCurrentData(playerid)("faction"), COHCurrentData("player_count"))

            If userData("personal").containskey(leaderboardId) Then
                COHCurrentData(playerid)("stats_now") = userData("personal")(leaderboardId)


                Dim theTeam As String = fullPlayerName

                'objHost.DebugMessage("Coh2 - " & COHCurrentData(playerid)("username") & " has personal data")
                objHost.DebugMessage("Coh2 - Setting: " & COHCurrentData(playerid)("username") & " - " & theTeam & " with: " & " - " & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("wins")) & "/" & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("losses")))

                'COHSensors("COH2." & theTeam) &= " - " & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("wins")) & "/" & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("losses"))
                COHSensors("COH2." & theTeam) = String.Format("{0,-10}", COHCurrentData(playerid)("username")).Substring(0, 10) & " - " & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("rank")) & " - " & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("wins")) & "/" & String.Format("{0,-4}", COHCurrentData(playerid)("stats_now")("losses"))

                COHSensors("COH2." & fullPlayerName & "_wins") = COHCurrentData(playerid)("stats_now")("wins")
                COHSensors("COH2." & fullPlayerName & "_losses") = COHCurrentData(playerid)("stats_now")("losses")
                COHSensors("COH2." & fullPlayerName & "_streak") = COHCurrentData(playerid)("stats_now")("streak")
                COHSensors("COH2." & fullPlayerName & "_disputes") = COHCurrentData(playerid)("stats_now")("disputes")
                COHSensors("COH2." & fullPlayerName & "_drops") = COHCurrentData(playerid)("stats_now")("drops")
                COHSensors("COH2." & fullPlayerName & "_rank") = COHCurrentData(playerid)("stats_now")("rank")

                Try
                    If LOGFileOpen Is Nothing Then
                        Dim p = Assembly.GetExecutingAssembly().Location
                        LOGFileOpen = My.Computer.FileSystem.OpenTextFileWriter(p & ".log", True)
                        LOGFileOpen.AutoFlush = True
                    End If
                    LOGFileOpen.Write(COHCurrentData(playerid)("username") & " - http://www.companyofheroes.com/leaderboards#profile/steam/" & COHCurrentData(playerid)("steamid") & "/standings" & vbNewLine)
                    LOGFileOpen.Close()
                    LOGFileOpen = Nothing
                Catch ex As Exception
                    objHost.DebugMessage("Coh2 - error storing log of players " & ex.Message & " :: " & ex.StackTrace)

                End Try

            Else                
                COHSensors("COH2." & fullPlayerName & "_rank") = COHCurrentData(playerid)("ranking") 'rank reported by file


                objHost.DebugMessage("Coh2 - Setting: " & COHCurrentData(playerid)("username") & " - no personal data in ladder " & leaderboardId & " - rank by steam: " & COHCurrentData(playerid)("ranking"))
            End If

            'MsgBox("checking: " & COHCurrentData(playerid)("username"))


        Catch ex As Exception
            objHost.DebugMessage("COH2 Plugin - Error fetching user data: " & ex.Message & " :: " & ex.StackTrace)
        End Try
        Return True
    End Function


    Public Function factionToLeaderboardName(fname, playercount) As String

        playercount = CInt(playercount)

        'MsgBox(playercount)
        'MsgBox((playercount / 2))
        Dim fnameReal As String = ""

        Select Case fname
            Case "soviet" : fnameReal = "Soviet"
            Case "west_german" : fnameReal = "Oberkommando West"
            Case "british" : fnameReal = "British Forces"
            Case "german" : fnameReal = "Wehrmacht"
            Case "aef" : fnameReal = "US Forces"
        End Select

        Dim ladderName As String = fnameReal & " " & (playercount / 2) & "v" & (playercount / 2)

        Return ladderName

    End Function
    Public Function factionToTeam(fname) As String
        Select Case fname
            Case "soviet" : Return "Allies"
            Case "west_german" : Return "Axis"
            Case "british" : Return "Allies"
            Case "german" : Return "Axis"
            Case "aef" : Return "Allies"
        End Select
        Return ""
    End Function

    Public Function leaderboardToName(lid) As String
        Select Case lid
            Case 4 : Return "Wehrmacht 1v1"
            Case 5 : Return "Soviet 1v1"
            Case 6 : Return "Oberkommando West 1v1"
            Case 7 : Return "US Forces 1v1"
            Case 51 : Return "British Forces 1v1"

            Case 8 : Return "Wehrmacht 2v2"
            Case 9 : Return "Soviet 2v2"
            Case 10 : Return "Oberkommando West 2v2"
            Case 11 : Return "US Forces 2v2"
            Case 52 : Return "British Forces 2v2"

            Case 12 : Return "Wehrmacht 3v3"
            Case 13 : Return "Soviet 3v3"
            Case 14 : Return "Oberkommando West 3v3"
            Case 15 : Return "US Forces 3v3"
            Case 53 : Return "British Forces 3v3"

            Case 16 : Return "Wehrmacht 4v4"
            Case 17 : Return "Soviet 4v4"
            Case 18 : Return "Oberkommando West 4v4"
            Case 19 : Return "US Forces 4v4"
            Case 54 : Return "British Forces 4v4"

            Case 20 : Return "Team 2v2 Axis"
            Case 21 : Return "Team 2v2 Allies"

            Case 22 : Return "Team 3v3 Axis"
            Case 23 : Return "Team 3v3 Allies"

            Case 24 : Return "Team 4v4 Axis"
            Case 25 : Return "Team 4v4 Allies"

        End Select

        Return ""
    End Function

#Region "Native API Signatures and Types"

    ''' <summary>
    ''' Access rights for file mapping objects
    ''' http://msdn.microsoft.com/en-us/library/aa366559.aspx
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum FileMapAccess
        FILE_MAP_COPY = 1
        FILE_MAP_WRITE = 2
        FILE_MAP_READ = 4
        FILE_MAP_ALL_ACCESS = &HF001F
    End Enum


    ''' <summary>
    ''' Represents a wrapper class for a file mapping handle. 
    ''' </summary>
    ''' <remarks></remarks>
    <SuppressUnmanagedCodeSecurity(), _
    HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort:=True)> _
    Friend NotInheritable Class SafeFileMappingHandle
        Inherits SafeHandleZeroOrMinusOneIsInvalid

        <SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode:=True)> _
        Private Sub New()
            MyBase.New(True)
        End Sub

        <SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode:=True)> _
        Public Sub New(ByVal handle As IntPtr, ByVal ownsHandle As Boolean)
            MyBase.New(ownsHandle)
            MyBase.SetHandle(handle)
        End Sub

        <ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), _
        DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function CloseHandle(ByVal handle As IntPtr) _
        As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

        Protected Overrides Function ReleaseHandle() As Boolean
            Return SafeFileMappingHandle.CloseHandle(MyBase.handle)
        End Function

    End Class


    Friend ReadOnly INVALID_HANDLE_VALUE As New IntPtr(-1)


    ''' <summary>
    ''' The class exposes Windows APIs used in this code sample.
    ''' </summary>
    ''' <remarks></remarks>
    <SuppressUnmanagedCodeSecurity()> _
    Friend Class NativeMethod

        ''' <summary>
        ''' Opens a named file mapping object.
        ''' </summary>
        ''' <param name="dwDesiredAccess">
        ''' The access to the file mapping object. This access is checked against 
        ''' any security descriptor on the target file mapping object.
        ''' </param>
        ''' <param name="bInheritHandle">
        ''' If this parameter is TRUE, a process created by the CreateProcess 
        ''' function can inherit the handle; otherwise, the handle cannot be 
        ''' inherited.
        ''' </param>
        ''' <param name="lpName">
        ''' The name of the file mapping object to be opened.
        ''' </param>
        ''' <returns>
        ''' If the function succeeds, the return value is an open handle to the 
        ''' specified file mapping object.
        ''' </returns>
        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function OpenFileMapping( _
            ByVal dwDesiredAccess As FileMapAccess, _
            ByVal bInheritHandle As Boolean, _
            ByVal lpName As String) _
            As SafeFileMappingHandle
        End Function


        ''' <summary>
        ''' Maps a view of a file mapping into the address space of a calling 
        ''' process.
        ''' </summary>
        ''' <param name="hFileMappingObject">
        ''' A handle to a file mapping object. The CreateFileMapping and 
        ''' OpenFileMapping functions return this handle.
        ''' </param>
        ''' <param name="dwDesiredAccess">
        ''' The type of access to a file mapping object, which determines the 
        ''' protection of the pages.
        ''' </param>
        ''' <param name="dwFileOffsetHigh">
        ''' A high-order DWORD of the file offset where the view begins.
        ''' </param>
        ''' <param name="dwFileOffsetLow">
        ''' A low-order DWORD of the file offset where the view is to begin.
        ''' </param>
        ''' <param name="dwNumberOfBytesToMap">
        ''' The number of bytes of a file mapping to map to the view. All bytes 
        ''' must be within the maximum size specified by CreateFileMapping.
        ''' </param>
        ''' <returns>
        ''' If the function succeeds, the return value is the starting address of
        ''' the mapped view.
        ''' </returns>
        <DllImport("Kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function MapViewOfFile( _
            ByVal hFileMappingObject As SafeFileMappingHandle, _
            ByVal dwDesiredAccess As FileMapAccess, _
            ByVal dwFileOffsetHigh As UInt32, _
            ByVal dwFileOffsetLow As UInt32, _
            ByVal dwNumberOfBytesToMap As UInt32) _
            As IntPtr
        End Function


        ''' <summary>
        ''' Unmaps a mapped view of a file from the calling process's address 
        ''' space.
        ''' </summary>
        ''' <param name="lpBaseAddress">
        ''' A pointer to the base address of the mapped view of a file that is to 
        ''' be unmapped.
        ''' </param>
        ''' <returns></returns>
        <DllImport("Kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function UnmapViewOfFile( _
            ByVal lpBaseAddress As IntPtr) _
            As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

    End Class

#End Region
End Class