using System;
using System.Net;
using System.Web.Services.Protocols;
using ObservationResultsSampleCodeCS.ObservationResultsWebService;

namespace ObservationResultsSampleCodeCS
{
    /// <summary>
    /// Class ObservationResultsSample requests lab order results from the MedPlus
    /// Hub platform.
    ///
    /// Upon its construction, this class will exercise the functions relating to the
    /// Observation 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.
    ///    
    /// </summary>
    class ObservationResultsSample
    {
        /**
         * Replace "test" and "customer1" with the username and password MedPlus has
         * assigned to you.
         * 
         * You will pass the username and password when you get the stub later in
         * this example. Via the stub, you'll make the method calls to the Results
         * Web Service to retrieve lab results.
         */
        private const string USERNAME = "test";
        private const string PASSWORD = "customer1";

        // WEB_SERVICE_URL designates the end point used to
        // connect to the Hub's Results web service
        private const string WEB_SERVICE_URL = "https://cert.hub.care360.com/observation/result/service";

        
        private const int MAX_MESSAGES = 5;
        private const String START_DATE = "01/01/2004";
        private const String END_DATE = "01/01/2009";

        private ObservationResultService proxy;

        public ObservationResultsSample()
        {
            try {
                // Get the stub.
                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, using all provider accounts...");
                getResults(null, MAX_MESSAGES, null, null);
                Console.WriteLine("Done with new results search using all provider accounts.");

                // EXAMPLE 2:
                // Perform a new results search using just one provider account. 
                // Return max of 5 results.
                ProviderAccount[] providerAccountsArray;
                providerAccountsArray = proxy.getProviderAccounts();
                
                ProviderAccount[] subset = new ProviderAccount[1];
                subset[0] = providerAccountsArray[0];
                
                Console.WriteLine("Performing new results search, using one provider account...");
                getResults(subset, MAX_MESSAGES, null, null);
                Console.WriteLine("Done with new results search using one provider account.");
                
                // 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 limited date range search...");
                getResults(null, MAX_MESSAGES, START_DATE, END_DATE);
                Console.WriteLine("Done with date range results search.");

            } catch (Exception e) {
                Console.WriteLine(e.StackTrace);
            }
        }

        private ObservationResultService getWebServiceObject()
        {
            ObservationResultService webService;

            try
            {
                //-------------------------------------------------------
                //STEP 1: CREATE WEB SERVICE REFERENCE
                //-------------------------------------------------------
                webService = new ObservationResultService();
            }
            catch (Exception ex)
            {
                Console.Write(ex.StackTrace);
                webService = null;
                throw ex;
            }

            if (!(webService == null))
            {
                //------------------------------------------------------------------
                //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)
                {
                    webService.Url = WEB_SERVICE_URL;
                }
            }

            return webService;
        }

        private void getResults(ProviderAccount[] myProviderAccounts, int maxMessages, String startDate, String endDate)
        {
            bool bInitialRequest = true;
            bool bContinue = true;
            string requestID = "";
            ObservationResultResponse myResponse = null;
            ObservationResultRequest myResultsRequest;

            while (bContinue)
            {
                if (bInitialRequest)
                {
                    bInitialRequest = false;
                    Console.WriteLine("Making a first pass...");

                    //------------------------------------------------------------------
                    //STEP 1: GENERATE RESULTS REQUEST OBJECT
                    //------------------------------------------------------------------
                    myResultsRequest = buildResultsRequest(myProviderAccounts, maxMessages, startDate, endDate);

                    //--------------------------------------------------------------
                    //STEP 2: SUBMIT REQUEST TO THE HUB
                    //--------------------------------------------------------------
                    myResponse = proxy.getResults(myResultsRequest);

                    if (myResponse == null)
                    {
                        Console.WriteLine("Failed to properly call getResults WebService method.");
                    }
                }
                else
                {
                    Console.WriteLine("Making another pass...");
                    myResponse = proxy.getMoreResults(requestID);
                }

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

                if (myResponse.observationResults == null)
                {
                    // empty array, no result messages returned
                    Console.WriteLine("# of Messages on Pass: 0");
                    bContinue = false;
                }
                else
                {
                    Console.WriteLine("# of Messages on Pass: " + myResponse.observationResults.Length.ToString());

                    Acknowledgment ack = new Acknowledgment();
                    ack.requestId = requestID;
                    ack.acknowledgedResults = generateAckMessages(myResponse);

                    proxy.acknowledgeResults(ack);

                    bContinue = (bool)myResponse.isMore;
                }
            }
        }

        private ObservationResultRequest buildResultsRequest(ProviderAccount[] providerAccountsArray, int maxMessages, string startDate, string endDate)
        {
            ObservationResultRequest request = new ObservationResultRequest();

            // ------------------------------------------------------------------
            // STEP 1: SET PROVIDER ACCOUNTS
            // ------------------------------------------------------------------
            if (providerAccountsArray != null)
            {
                request.providerAccounts = providerAccountsArray;
            }

            // ------------------------------------------------------------------
            // STEP 2: SET MAXIMUM NUMBER OF MESSAGES TO RETRIEVE AT ONCE
            // ------------------------------------------------------------------
            if (maxMessages > 0)
            {
                request.maxMessages = maxMessages;
            }

            // ------------------------------------------------------------------
            // STEP 3: SET DATE RANGE TO GET RESULTS
            // ------------------------------------------------------------------
            request.endDate = endDate;
            request.startDate = startDate;

            return request;
        }

        private AcknowledgedResult[] generateAckMessages(ObservationResultResponse myResponse)
        {
            // Get the results from the response object.
            ObservationResult[] results = myResponse.observationResults;
            

		    Console.WriteLine("Acknowledging " + results.Length + " results.");

            AcknowledgedResult[] ackMessages = new AcknowledgedResult[results.Length];

            for (int i = 0; i < results.Length; i++)
            {
			    // Process each message and build an Acknowledgement object to
			    // acknowledge the result.
                String currentHL7 = System.Text.Encoding.UTF8.GetString(results[i].HL7Message);
			    Console.WriteLine("Message: " + i);
			    Console.WriteLine("---------");
			    Console.WriteLine("The HL7 Message: " + currentHL7);
                String pdfCount = results[i].documents != null ? "" + results[i].documents.Length : "0";
                Console.WriteLine("There are " + pdfCount + " attached PDFs.\n\n");
			    // Process Result.
			    // Send an Ack/Nack message back for each result received.
			    ackMessages[i] = buildAcknowledgement(results[i]);
		    }

		    return ackMessages;
        }

        private AcknowledgedResult buildAcknowledgement(ObservationResult result)
        {
            AcknowledgedResult ack = new AcknowledgedResult();
            ack.resultId = result.resultId;
            ack.ackCode = "ACK";

            int pdfCount = result.documents != null ? result.documents.Length : 1;

            if (result.documents != null)
            {
                String[] docIds = new String[pdfCount];
                for (int i = 0; i < result.documents.Length; i++)
                {
                    docIds[i] = result.documents[i].documentId;
                }
                ack.documentIds = docIds;
            }

            return ack;
        }
    }
}
