Imports System
Imports System.IO
Imports System.Net
Imports System.Web.Services.Protocols
Imports RetrieveResultsSampleCode.RetrieveResultsWebService

Public Class RetrieveResultsSample


    ' Constants that define the three result service types.
    Private Const RESULT_SERVICE_TYPE_HL7 As String = "HL7"
    Private Const RESULT_SERVICE_TYPE_PRINTABLE As String = "Printable"
    Private Const RESULT_SERVICE_TYPE_OBSERVATION As String = "Observation"

    ' Constants that define request parameter names.
    Private Const REQUEST_PARAMETER_NAME_MAX_MESSAGES As String = "maxMessages"
    Private Const REQUEST_PARAMETER_NAME_MESSAGE_CONTROL_ID As String = "messageControlId"
    Private Const REQUEST_PARAMETER_NAME_PROVIDER_ACCT_ID As String = "providerAcctId"

    ' The HL7/Observation ACK message template - The following "template" is
    ' used in constructing an ACK request message. After calling getResults()
    ' for HL7 or Observation results, you will acknowledge receipt of the
    ' results by calling acknowledgeResults(). The acknowledgeResults() request
    ' contains an acknowledge message constructed from the HL7 message
    ' retrieved.
    ' 
    ' 0 = sending application (field MSH.03) 
    ' 1 = sending facility (field MSH.04) 
    ' 2 = receiving application (field MSH.05) 
    ' 3 = receiving facility (field MSH.06) 
    ' 4 = date time (field MSH.07) 
    ' 5 = message control id (field MSH.10) 
    ' 6 = hl7 version (field MSH.12)
    ' 7 = message control id of message (field MSA.02)
    Const ACK_MESSAGE_FORMAT As String = _
         "MSH|^~\&|{0}|{1}|{2}|{3}|{4:yyyyMMddHHmm}||ACK|{5:#####}|D|{6}" + vbCr + _
         "MSA|CA|{7}" + vbCr

    ' USERNAME designates the Hub user name used to
    ' authenticate to the Hub web service
    Private Const USERNAME As String = "HORI3670test"

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

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

    ' Maximum number of messages to retrieve
    Private Const MAX_MESSAGES As String = "5"

    ' can be "observation", "printable", or "hl7".  The constants defined above can be used for this
    Private resultServiceType As String = RESULT_SERVICE_TYPE_HL7

    Private proxy As RetrieveResultsService

    Public Sub New()
        Try
            proxy = getWebServiceObject()

            ' 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()
            Console.WriteLine("Done with new results search.")

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

        End Try
    End Sub

    Private Function getWebServiceObject() As RetrieveResultsService
        Dim webService As RetrieveResultsService

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

        If Not (webService Is Nothing) Then

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

            '------------------------------------------------------------------
            'STEP 3: 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
        End If

        Return webService
    End Function

    ' The getResults method will:
    ' 
    ' 1. On the first pass, create a RetrieveResultsRequest object and call 
    '    getResults() to get the RetrieveResultsResponse object containing 
    '    the first batch of results. 
    ' 2. Generate an acknowledgment message for the returned results (if any). 
    ' 3. Acknowledge the results with the acknowledgeResults method. 
    ' 4. Output the number of results acknowledged on this pass. 
    ' 5. If more results are available, call getResults() again. Repeat from step 2.
    Private Sub getResults()
        Dim bInitialRequest As Boolean = True
        Dim bContinue As Boolean = True
        Dim numResults As Integer = 0
        Dim requestID As String = ""
        Dim myRetrieveResponse As retrieveResultsResponse = Nothing
        Dim myRetrieveResultsRequest As retrieveResultsRequest = Nothing

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

                '------------------------------------------------------------------
                'STEP 1: GENERATE RESULTS REQUEST OBJECT
                '------------------------------------------------------------------
                myRetrieveResultsRequest = buildResultsRequest()

                '--------------------------------------------------------------
                'STEP 2: SUBMIT REQUEST TO THE HUB
                '--------------------------------------------------------------
                myRetrieveResponse = proxy.getResults(myRetrieveResultsRequest)

                If myRetrieveResponse Is Nothing Then
                    Console.WriteLine("Failed to properly call getResults WebService method.")
                End If
            Else
                ' If there are more results available, fetch more.
                Console.WriteLine("Making another pass...")
                myRetrieveResponse = proxy.getResults(myRetrieveResultsRequest)

                If myRetrieveResponse Is Nothing Then
                    Console.WriteLine("Failed to properly call getResults WebService method.")
                End If
            End If

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

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

                ' send Acks
                If numResults > 0 Then
                    ' write PDF files to disk (optional)
                    writeResultDataToFile(myRetrieveResponse.results)

                    ' STEP 3: BUILD ACKNOWLEDGEMENT
                    Dim acks As ackResultsRequest = buildAcknowledgment(myRetrieveResponse)

                    ' STEP 4: SEND ACKNOWLEDGEMENT
                    proxy.acknowledgeResults(acks)


                    ' STEP 5: Print the number of messages ACKed
                    Console.WriteLine("# of Messages acknowledged: " + numResults.ToString)


                    bContinue = myRetrieveResponse.isMore
                Else
                    bContinue = False
                End If
            End If
        End While

        Console.WriteLine("Total results found: " + numResults.ToString)
    End Sub

    ' The getWebServicePrintableMessage function will take the parameters for a results request and gernerate the object
    ' to pass to the web method
    Private Function buildResultsRequest() As retrieveResultsRequest
        Dim uReq As New retrieveResultsRequest

        '------------------------------------------------------------------
        ' STEP 1: SET UP REQUEST PARAMETERS
        '------------------------------------------------------------------
        If Not MAX_MESSAGES Is Nothing Then
            Dim requestParams(0) As requestParameter
            Dim requestParameter As New requestParameter
            requestParameter.parameterName = REQUEST_PARAMETER_NAME_MAX_MESSAGES
            requestParameter.parameterValue = MAX_MESSAGES
            requestParams(0) = requestParameter
            uReq.requestParameters = requestParams
        End If

        '------------------------------------------------------------------
        ' STEP 2: SET SERVICE TYPE (observation, hl7, printable)
        '------------------------------------------------------------------
        uReq.resultServiceType = resultServiceType

        Return uReq
    End Function

    ' Constructs a message to acknowledge a set of results.
    Private Function buildAcknowledgment(ByVal response As retrieveResultsResponse) As ackResultsRequest

        Dim acknowledgment As New ackResultsRequest

        acknowledgment.requestId = response.requestId
        acknowledgment.resultServiceType = resultServiceType

        Console.WriteLine("Acknowledging " + response.results.Length.ToString + " " + resultServiceType + " results.")

        Dim i As Integer = 0
        Dim result As result
        If (resultServiceType = RESULT_SERVICE_TYPE_HL7) Or (resultServiceType = RESULT_SERVICE_TYPE_OBSERVATION) Then
            ' acknowlegement for HL7 or Observation

            Dim numResults As Integer = response.results.Length
            Dim ackMessages(numResults - 1) As hl7Message
            acknowledgment.ackMessages = ackMessages
            For Each result In response.results

                Console.WriteLine("Message: " + i.ToString)
                Console.WriteLine("---------")

                Dim currentHL7 As String = System.Text.Encoding.UTF8.GetString(result.HL7Message.message)
                Dim pdfCount As Integer = 0
                If Not result.documents Is Nothing Then
                    pdfCount = result.documents.Length
                End If


                Console.WriteLine("The HL7 Message:" + vbCrLf + currentHL7)
                Console.WriteLine("There are " + pdfCount.ToString + " attached PDFs." + vbCrLf + vbCrLf)

                Dim ackMessage As hl7Message = buildHl7ObsAckMessage(currentHL7)

                If (resultServiceType = RESULT_SERVICE_TYPE_OBSERVATION) Then
                    ackMessage.controlId = result.resultId
                End If

                acknowledgment.ackMessages(i) = ackMessage
                i += 1
            Next
        Else
            ' acknowlegement for Printable
            Dim requestParams(1) As requestParameter

            requestParams(0) = New requestParameter()
            requestParams(0).parameterName = "providerAcctId"
            requestParams(0).parameterValue = response.results(0).documents(0).resultInfo.providerAcctId


            requestParams(1) = New requestParameter()
            requestParams(1).parameterName = "messageControlId"
            requestParams(1).parameterValue = response.results(0).documents(0).resultInfo.messageControlId

            acknowledgment.requestParameters = requestParams

            Console.WriteLine("Printable ACK: providerAcctId = " + requestParams(0).parameterValue + ", messageControlId = " + requestParams(1).parameterValue)

        End If

        Return acknowledgment
    End Function

    ' Build an HL7 Ack message for a single result
    Public Function buildHl7ObsAckMessage(ByVal sHL7Message As String) As hl7Message
        Dim asHL7Segs As String()
        Dim sHL7Header As String
        Dim asHL7HdrElements() As String
        Dim asHL7ACKMessageParams() As Object
        Dim sMessage As String
        Dim abMessage As Byte()
        ReDim asHL7ACKMessageParams(7)

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

        Dim hl7Message As New hl7Message
        ' Split HL7 message into lines on the newline character.
        asHL7Segs = Split(sHL7Message, vbCr)
        ' 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
        ' When HL7 2.5.1 {2} needs to be sending 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(11) ' HL7 version of HL7 message
        asHL7ACKMessageParams(7) = 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)

        Return hl7Message
    End Function

    ' Write the PDF out to a file
    Private Sub writeResultDataToFile(ByVal results As result())
        Try
            For Each theResult As result In results
                If ((theResult.documents IsNot Nothing) AndAlso (theResult.documents.Length > 0)) Then
                    For Each document As resultDocument In theResult.documents
                        ' Open a file with the file name provided in the response object.  
                        Dim fs As New FileStream(document.documentId + "-" + document.fileName, FileMode.OpenOrCreate)
                        Dim bw As New BinaryWriter(fs)
                        '  Use a BinaryWriter to copy the Byte array to a file
                        Console.WriteLine("Writing " + fs.Name + " to disk")
                        bw.Write(document.documentData)
                        bw.Close()
                        fs.Close()
                    Next
                End If
            Next
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Sub
End Class

