Imports System
Imports System.Net
Imports System.Web.Services.Protocols
Imports HL7ResultsSampleCode.HL7ResultsWebService

' Class HL7ResultsSample requests lab order (HL7 messages) from the MedPlus
' Hub platform.
'
' Upon its construction, this class will exercise the functions relating to the
' HL7 Results Service, which includes:
'
' 1. Performing a new results search (batch size 5),
'    for all provider accounts the hub user has access to,
'    acknowledging the results, and getting more results.
'
' 2. Getting an array of provider accounts for the hub user.
'    This represents a subset of provider accounts.
'
' 3. Performing a new results search (batch size 5),
'    with a single provider account, 
'    acknowledging the results, and getting more results.
' 
' 4. Performing a date range search (batch size 5), 
'    acknowledging the results, and getting more results.

Public Class HL7ResultsSample
    ' USERNAME designates the Hub user name used to
    ' authenticate to the Hub web service
    Private Const USERNAME As String = "test"

    ' PASSWORD designates the password associated with
    ' the Hub user when authenticating to the web service
    Private Const PASSWORD As String = "customer1"

    ' WEB_SERVICE_URL designates the end point used to
    ' connect to the Hub's HL7 Results web service
    Private Const WEB_SERVICE_URL As String = "https://cert.hub.care360.com/resultsHub/observations/hl7"

    Private Const MAX_MESSAGES As String = "5"

    Private proxy As ResultsService

    Public Sub New()
        Try
            proxy = getWebServiceObject()

            ' EXAMPLE 1:
            ' Perform a new results search using all provider accounts.  
            ' This is the most common scenario for developing vendors.
            ' Return max of 5 results.
            Console.WriteLine("Performing new results search...")
            getResults(Nothing, MAX_MESSAGES, "", "")
            Console.WriteLine("Done with date range results search.")

            ' EXAMPLE 2:
            ' Perform a new results search using just one provider account.  
            ' Return max of 5 results.
            Dim providerAccountsArray As String()
            providerAccountsArray = getProviderAccounts()
            Console.WriteLine("Performing new results search...")
            getResults(providerAccountsArray, MAX_MESSAGES, "", "")
            Console.WriteLine("Done with date range results search.")

            ' EXAMPLE 3:
            ' Date range search using all provider accounts.  Max of 5 results, will 
            ' acknowledge those results and then get more until they're all processed
            Console.WriteLine("Performing date range search...")
            getResults(Nothing, MAX_MESSAGES, "01/01/2004", "01/01/2009")
            Console.WriteLine("Done with date range results search.")

        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Sub

    Private Function getWebServiceObject() As ResultsService
        Dim webService As ResultsService

        Try
            '-------------------------------------------------------
            'STEP 1: CREATE WEB SERVICE REFERENCE
            '-------------------------------------------------------
            webService = New ResultsService
        Catch except As Exception
            Console.Write(except.StackTrace)
            webService = Nothing
            Throw except
        End Try

        If Not (webService Is Nothing) Then
            '------------------------------------------------------------------
            'STEP 2: CREATE CREDENTIALS OBJECT CONTAINING USERNAME AND PASSWORD
            '------------------------------------------------------------------
            webService.Credentials = New NetworkCredential(USERNAME, PASSWORD)

            ' By default the client will attempt to call the web service without 
            ' sending the credentials. If the server returns a 401 HTTP response, 
            ' the client makes the call again with the credentials. If we set 
            ' PreAuthenticate to True, the client will include the credentials on 
            ' the initial call and eliminate this extra processing.
            '
            ' This should probably be set in the web service object's constructor,
            ' but has been included here to demonstrate.
            webService.PreAuthenticate = True

            '------------------------------------------------------------------
            'STEP 3: SET WEB SERVICE URL
            '------------------------------------------------------------------
            If WEB_SERVICE_URL.Length > 0 Then
                webService.Url = WEB_SERVICE_URL
            End If
        End If

        getWebServiceObject = webService
    End Function


    ' The buildResultsRequest function will take the parameters for a results request and gernerate the object
    ' to pass to the web method
    Private Function buildResultsRequest(ByVal myProviderAccounts As String(), ByVal maxMessages As String, _
                                         ByVal startDate As String, ByVal endDate As String) As ResultsRequest

        Dim uReq As New ResultsRequest

        '------------------------------------------------------------------
        'STEP 1: SET PROVIDER ACCOUNTS
        '------------------------------------------------------------------
        If Not myProviderAccounts Is Nothing Then
            uReq.providerAccountIds = myProviderAccounts
        End If

        '------------------------------------------------------------------
        'STEP 2: SET MAXIMUM NUMBER OF MESSAGES TO RETRIEVE AT ONCE
        '------------------------------------------------------------------
        If (maxMessages.Length > 0) Then
            uReq.maxMessages = Integer.Parse(maxMessages)
        End If

        '------------------------------------------------------------------
        'STEP 3: SET DATE RANGE TO GET RESULTS
        '------------------------------------------------------------------
        If (endDate.Length > 0) Then
            uReq.endDate = endDate
        End If

        If (startDate.Length > 0) Then
            uReq.startDate = startDate
        End If

        Return uReq
    End Function

    ' The genHL7AckMessages function will generate an acknowledgement object to pass to
    ' the Hub for the given HL7 Messages
    Private Function genHL7AckMessages(ByVal asHL7Messages As String()) As HL7Message()
        Const ACK_MESSAGE_FORMAT As String = _
            "MSH|^~\&|{0}|{1}|{2}|{3}|{4:yyyyMMddHHmm}||ACK|{5:#####}|D|2.3" + vbLf + _
            "MSA|CA|{6}" + vbLf
        Dim sHL7Message As String
        Dim asHL7Segs As String()
        Dim sHL7Header As String
        Dim asHL7HdrElements() As String
        Dim asHL7ACKMessageParams() As Object
        Dim ahl7HL7ACKMessages As HL7Message()
        Dim iMsgCounter As Integer
        Dim sMessage As String
        Dim abMessage As Byte()
        ReDim asHL7ACKMessageParams(6)
        ReDim ahl7HL7ACKMessages(asHL7Messages.Length - 1)

        'Seed random generator for ACK Message Id generation.
        Randomize()

        ' Process messages, build ACK string array.
        iMsgCounter = 0

        For Each sHL7Message In asHL7Messages
            Dim hl7Message As New HL7Message
            ' Split HL7 message into lines on the newline character.
            asHL7Segs = Split(sHL7Message, vbLf)
            ' Assign the header using first line.
            sHL7Header = asHL7Segs(0)
            ' Split the header into elements using the pipe character for this example - Note
            ' that other characters can be used as separators.
            asHL7HdrElements = Split(sHL7Header, "|")
            ' Format this ACK message and add to array.
            asHL7ACKMessageParams(0) = asHL7HdrElements(4) ' receiving app
            asHL7ACKMessageParams(1) = asHL7HdrElements(5) ' receiving fac
            asHL7ACKMessageParams(2) = asHL7HdrElements(2) ' sending app
            asHL7ACKMessageParams(3) = asHL7HdrElements(3) ' sending fac
            asHL7ACKMessageParams(4) = System.DateTime.Now ' set ACK time to current time
            asHL7ACKMessageParams(5) = Int((10000000) * Rnd() + 1000) ' generate a random unique(id)
            asHL7ACKMessageParams(6) = asHL7HdrElements(9) ' control Id of HL7 message
            sMessage = String.Format(ACK_MESSAGE_FORMAT, asHL7ACKMessageParams)
            abMessage = System.Text.Encoding.UTF8.GetBytes(sMessage)
            hl7Message.message = abMessage
            ' Easier to track for debug purposes.
            hl7Message.controlId = asHL7HdrElements(9)
            ahl7HL7ACKMessages(iMsgCounter) = hl7Message
            iMsgCounter = iMsgCounter + 1
        Next

        Return ahl7HL7ACKMessages
    End Function

    Private Sub getResults(ByVal myProviderAccounts As String(), ByVal maxMessages As String, ByVal startDate As String, ByVal endDate As String)
        Dim bInitialRequest As Boolean = True
        Dim bContinue As Boolean = True
        Dim requestID As String = ""
        Dim myHL7Response As HL7ResultsResponse = Nothing
        Dim hl7ResultsRequest As ResultsRequest

        While bContinue
            If bInitialRequest Then
                bInitialRequest = False
                Console.WriteLine("Making a first pass...")

                '------------------------------------------------------------------
                'STEP 1: GENERATE RESULTS REQUEST OBJECT
                '------------------------------------------------------------------
                hl7ResultsRequest = buildResultsRequest(myProviderAccounts, maxMessages, startDate, endDate)

                '--------------------------------------------------------------
                'STEP 2: SUBMIT REQUEST TO THE HUB
                '--------------------------------------------------------------
                myHL7Response = proxy.getHL7Results(hl7ResultsRequest)

                If myHL7Response Is Nothing Then
                    Console.WriteLine("Failed to properly call getHL7Results WebService method.")
                End If
            Else
                Console.WriteLine("Making another pass...")
                myHL7Response = proxy.getMoreHL7Results(requestID)
            End If

            requestID = myHL7Response.requestId
            Console.WriteLine("Request ID: " + requestID)

            If myHL7Response.HL7Messages Is Nothing Then
                ' empty array, no HL7 messages returned
                Console.WriteLine("# of Messages on Pass: 0")
                bContinue = False
            Else
                Console.WriteLine("# of Messages on Pass: " + myHL7Response.HL7Messages.Length.ToString)

                Dim asHL7Messages As String()
                Dim ahl7Messages As HL7Message()
                Dim hl7Message As HL7Message
                ahl7Messages = myHL7Response.HL7Messages
                Dim i As Integer = 0
                ReDim asHL7Messages(myHL7Response.HL7Messages.Length - 1)
                For Each hl7Message In ahl7Messages
                    Dim abMessage As Byte() = hl7Message.message
                    Dim sMessage As String = System.Text.Encoding.UTF8.GetString(abMessage)
                    asHL7Messages(i) = sMessage
                    i = i + 1
                Next

                Dim ahl7HL7ACKMessages As HL7Message() = genHL7AckMessages(asHL7Messages)

                Console.WriteLine("Acknowledging HL7 Messages...")
                proxy.acknowledgeHL7Results(requestID, ahl7HL7ACKMessages)

                bContinue = CBool(myHL7Response.isMore)
            End If
        End While

    End Sub

    ' The getProviderAccounts method will call the Hub and get a list
    ' of provider accounts the hub user has access to.  It then places
    ' the first one in a String array and returns the array, which can 
    ' be passed to the getHL7Results method to get results for a subset 
    ' of the provider accounts the hub user has access to.
    Public Function getProviderAccounts() As String()
        Dim asProvAccts(0) As String

        Try
            ' Get Provider Accounts associated with this hub account
            Console.WriteLine("Getting Provider Accounts...")

            Dim myProviderAccounts As ProviderAccount() = proxy.getProviderAccounts()
            Dim myAccount As ProviderAccount

            If Not myProviderAccounts Is Nothing Then
                If myProviderAccounts.Length > 0 Then
                    For Each myAccount In myProviderAccounts
                        Console.WriteLine("ID: " + myAccount.accountId + _
                                          ", Name: " + myAccount.accountName + _
                                          ", Provider: " + myAccount.provider.name)
                    Next

                    asProvAccts(0) = Trim(myProviderAccounts(0).accountId)
                End If
            End If

            getProviderAccounts = asProvAccts

        Catch ex As Exception
            Console.WriteLine(ex.Message)

        End Try
        Return asProvAccts
    End Function

End Class
