using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using OrderAbnReqSampleCodeCS.OrderSubmissionWebService;
using System.Web.Services.Protocols;
using System.IO;
using System.Diagnostics;
using Newtonsoft.Json;

namespace OrderAbnReqSampleCodeCS
{
    /// <summary>
    /// Class OrderAbnReqSample submits lab order (HL7 messages) to the MedPlus
    /// Hub platform.
    ///
    /// Upon its construction, this class will send an order to the OrderSubmissionService.
    /// </summary>
    class OrderAbnReqSample
    {
        // USERNAME designates the Hub user name used to
        // authenticate to the Hub web service
        private const string USERNAME = "test";

        // PASSWORD designates the password associated with
        // the Hub user when authenticating to the web service
        private const string PASSWORD = "customer1";   // default password

        // WEB_SERVICE_URL designates the end point used to
        // connect to the Hub's Orders rest web service
        private const string WEB_SERVICE_URL = "https://cert.hub.care360.com/rest/orders/v1/document";

        // SENDING_APPLICATION designates the application that 
        // is sending the order message to Hub
        private const string SENDING_APPLICATION = "HUBWS";

        // SENDING_FACILITY designates the account number provided to you 
        // by Quest for the businessunit you are ordering tests with
        private const string SENDING_FACILITY = "2135800";

        // RECEIVING_FACILITY designates the business unit 
        // within Quest from which the labs are being ordered
        private const string RECEIVING_FACILITY = "HOU";

        private Boolean abn = true;
        private Boolean req = true;
        private Boolean aoe = true;

        private const char CR = (char)13;
        private const char LF = (char)10;

        private String NEWLINE = String.Format("{0}{1}", CR, LF);
        private String HL7_LINEBREAK = String.Format("{0}", CR);

        /// <summary>
        /// The HL7 Order message template
        /// The following "template" is used in constucting the Order.
        /// Replacement fields are:
        /// 0 = sending application (field 3)
        /// 1 = sending facility (field 4) represents the account with Quest Diagnostics
        /// 2 = receiving facility (field 6) The Quest Business Unit for above account
        /// 3 = date time (field 7)
        /// 4 = message control id (field 10) Unique Number identifying this order message
        /// </summary>
        private string ORDER_MESSAGE = "MSH|^~\\&|{0}|{1}||{2}|{3:yyyyMMddHHmm}||ORM^O01|{4}|P|2.3\r" +
                                       "PID|1|11111||{4}|TEST^WIFE||19451212|M|||||3102222222||||||123456789|\r" +
                                       "IN1|1||AUHSC|AETNA|123 ANYSTREET^2^CHICAGO^IL^60305|||A12345||||||||TEST^HUSBAND^|2||123 ANYSTREET^^CHICAGO^IL^60305|||||||||||||||||P123456R|||||||||||T|\r" +
                                       "GT1|1||TEST^HUSBAND^||123 ANYSTREET^^CHICAGO^IL^60305|3102222222||19451212|M|\r" +
                                       "ORC|NW|{4}||||||||||OTH030^MICHIGAN^JOHN^^^^^UPIN|\r" +
                                       "OBR|1|{4}||^^^6399^CBC|||20051223094800|||||||||OTH030^MICHIGAN^JOHN^^^^^UPIN|||||||||||1^^^^^R|\r" +
                                       "DG1|1|ICD|0039|SALMONELLA INFECTION NOS|\r" +
                                       "OBX|1||^^^A123^SOME OBSERVATION||||||||P\r" +
                                       "ORC|NW|{4}||||||||||OTH030^MICHIGAN^JOHN^^^^^UPIN|\r" +
                                       "OBR|1|{4}||^^^10809^TISSUE|||20051223094800|||||||||OTH030^MICHIGAN^JOHN^^^^^UPIN|||||||||||1^^^^^R|\r";

        public OrderAbnReqSample()
        {
            try
            {
                // calling sendOrder sends the order to the hub
                Console.WriteLine("Calling getRestOrderDocuments...");
                sendOrder();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }

        private String buildJSON(String hl7, Boolean abnSelected, Boolean reqSelected, Boolean aoeSelected) {
        // Build json string to wrap the request
            String json;

            json = "{\"orderHl7\":\"";
            json = json + System.Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(hl7));
            json = json + "\"";
            json = json + ",";
            json = json + "\"documentTypes\":[";

            Boolean first = true;

            if (abnSelected) {
                if (!first)
                    json += ",";
                json += "\"ABN\"";
                first = false;
            }

            if (reqSelected)
            {
                if (!first)
                    json += ",";
                json += "\"REQ\"";
                first = false;
            }
            if (aoeSelected)
            {
                if (!first)
                    json += ",";
                json += "\"AOE\"";
                first = false;
            }

            json = json + "]}";
            return json;
        }

        public void sendOrder()
        {
            try
            {
                //-------------------------------------------------------
                //STEP 1: CREATE WEB SERVICE REFERENCE
                //-------------------------------------------------------
                String orderMessage = buildJSON(buildOrderMessage(SENDING_APPLICATION, SENDING_FACILITY, RECEIVING_FACILITY), abn, req, aoe);
                submitOrderViaRest(orderMessage);
            }
            catch (Exception ex)
            {
                Console.Write(ex.StackTrace);
            }
        }

        /// <summary>
        /// the buildOrderMessage function replaces values in the ORDER_MESSAGE template to
        /// create a valid HL7 Order message
        /// </summary>
        /// <param name="sendingApplication"></param>
        /// <param name="sendingFacility"></param>
        /// <param name="receivingFacility"></param>
        /// <returns></returns>
        private String buildOrderMessage(
            String sendingApplication,
            String sendingFacility,
            String receivingFacility)
        {
            //'now' is used for 2 purposes here
            //1 to specify the time that the message was created
            //2 to create a unique message control ID and order number
            System.DateTime now = System.DateTime.Now;
            // parameters for replacement in the template
            Object[] msgParams = new Object[7];
            msgParams[0] = sendingApplication;
            msgParams[1] = sendingFacility;
            msgParams[2] = receivingFacility;
            msgParams[3] = now;
            msgParams[4] = now.Ticks;
            return string.Format(ORDER_MESSAGE, msgParams);
        }
        
        public void submitOrderViaRest(string orderMessage)
        {
            HttpWebResponse response = null;
            Stream postStream = null;

            //------------------------------------------------------------------------
            //STEP 1: CONFIGURE CONNECTION TO REST ENDPOINT WITH BASIC AUTHENTICATION
            //------------------------------------------------------------------------
            HttpWebRequest request = getWebRequest(new Uri(WEB_SERVICE_URL));
            request.Method = "POST";
            request.ContentType = "application/json";
            request.Credentials = new NetworkCredential(USERNAME, PASSWORD);

            //----------------------------------------------------
            //STEP 2: FORMAT THE ORDER SUBMISSION REQUEST MESSAGE
            //----------------------------------------------------
            
            byte [] encodedText = UTF8Encoding.UTF8.GetBytes(orderMessage);

            //----------------------------------------------------
            //STEP 3: SUBMIT THE REQUEST TO THE HUB REST SERVICE
            //----------------------------------------------------
            try
            {
                postStream = request.GetRequestStream();
                postStream.Write(UTF8Encoding.UTF8.GetBytes(orderMessage), 0, encodedText.Length);
            }
            finally
            {
                if (postStream != null) postStream.Close();
            }

            //---------------------------------------------------------------
            //STEP 4: READ RESPONSE FROM THE HUB, DECODE AND ECHO TO CONSOLE
            //---------------------------------------------------------------
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream());
                String lines = parseResponse(reader.ReadToEnd());
                Console.Write(lines);
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
            }
            finally {
                if (response != null) response.Close();
            }
        }

        /// <summary>
        /// Returns an HttpWebRequest object to use to communicate with the REST web
        /// service. Broken out here just because it can throw an exception which has
        /// the potential to halt the run.
        /// </summary>
        private HttpWebRequest getWebRequest(Uri target)
        {
            HttpWebRequest result = null;
            try
            {
                result = (HttpWebRequest)WebRequest.Create(target);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Environment.Exit(0);
            }
            return result;
        }

        private String parseResponse(String responseString) {
            String lines = "";

            Newtonsoft.Json.JsonTextReader jsonReader = new Newtonsoft.Json.JsonTextReader(new StringReader(responseString));
            while (jsonReader.Read()) {

                if (jsonReader.TokenType.ToString().StartsWith("PropertyName")) {
                    String tokenName = jsonReader.Value.ToString();
                    jsonReader.Read();
                    if (tokenName.Equals("ackhl7")) {
                        Byte [] decoded = System.Convert.FromBase64String(jsonReader.Value.ToString());
                        lines = tokenName + " : " + NEWLINE + System.Text.Encoding.Default.GetString(decoded).Replace(HL7_LINEBREAK, NEWLINE) + NEWLINE + NEWLINE;
                    } else if (tokenName.Equals("documentData") &&  (jsonReader.Value!=null)) {
                        Byte [] p1 = System.Convert.FromBase64String(jsonReader.Value.ToString());
                        String s1 = System.Text.Encoding.ASCII.GetString(p1);
                        Byte [] p2 = System.Convert.FromBase64String(s1);
                        // String s2 = System.Text.Encoding.ASCII.GetString(p2);
                        displayPDF(p2);
                    }
                    else {
                        if (jsonReader.Value==null) {
                            lines = lines + tokenName + " : null" + NEWLINE;
                        } else {
                            lines = lines + tokenName + " : " + jsonReader.Value.ToString() + NEWLINE;
                        }
                    }
                }
            }

            return lines;
        }

        private void displayPDF(byte[] pdfBytes)
        {
            try
            {
                string sFileName = "tmp.PDF";
                FileStream fs = new FileStream(sFileName, FileMode.OpenOrCreate, FileAccess.Write);
                BinaryWriter bw = new BinaryWriter(fs);

                bw.Write(pdfBytes);
                bw.Close();
                fs.Close();

                Process openPDF = new Process();
                openPDF.StartInfo.FileName = "tmp.PDF";
                openPDF.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error displaying pdf:" + "\r\n" + ex.Message);
            }
        }
    }

}
