using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;
using System.Security.Cryptography;
using System.Net;
using RestSharp;
using Newtonsoft.Json;

namespace ChecksumTool
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
                                                  SecurityProtocolType.Tls11 |
                                                  SecurityProtocolType.Tls12 |
                                                  SecurityProtocolType.Ssl3;
        }

        private void btnCalculate_Click(object sender, RoutedEventArgs e)
        {
            tbMessageLine.Text = "";

            // Do some limited checking to make sure the values we need are there.

            if (String.IsNullOrWhiteSpace(tbFileName.Text) || String.IsNullOrWhiteSpace(tbXMLFileType.Text) || String.IsNullOrWhiteSpace(tbDocSeqNbr.Text) || String.IsNullOrWhiteSpace(tbDocCount.Text))
            {
                tbMessageLine.Text = "Missing required entries. (XML File Name or XML File Type or Doc Seq# or Total Docs)";
            }
            else
            {
                int nDocSeqNbr = 0;
                int nDocCount = 0;

                if (Int32.TryParse(tbDocSeqNbr.Text, out nDocSeqNbr))
                {
                    if (Int32.TryParse(tbDocCount.Text, out nDocCount))
                    {
                        // Must be a valid sequence number.

                        if (nDocSeqNbr <= nDocCount && nDocSeqNbr > 0)
                        {
                            FileStream fs = new FileStream(tbFileName.Text, FileMode.Open, FileAccess.Read);

                            XmlDocument xmlDoc = new XmlDocument();

                            xmlDoc.Load(fs);

                            string strEmbeddedFilePath = null;

                            if (tbXMLFileType.Text == "Request")
                            {
                                strEmbeddedFilePath = "/REQUEST_GROUP/REQUEST/PRIA_REQUEST/PACKAGE/PRIA_DOCUMENT/EMBEDDED_FILE";
                            }
                            else
                            {
                                strEmbeddedFilePath = "/RESPONSE_GROUP/RESPONSE/RESPONSE_DATA/PRIA_RESPONSE/PACKAGE/PRIA_DOCUMENT/EMBEDDED_FILE";
                            }

                            XmlNodeList xmlDocNodes = xmlDoc.SelectNodes(strEmbeddedFilePath);

                            int nCtr = 1;

                            foreach (XmlNode xmlNode1 in xmlDocNodes)
                            {
                                if (nCtr == nDocSeqNbr)
                                {
                                    XmlNode docNode = xmlNode1.SelectSingleNode("DOCUMENT");

                                    string strBase64String = docNode.InnerText;
                                    tbChecksumValue.Text = getBase64Hash(strBase64String);
                                }
                                nCtr++;
                            }
                        }
                        else
                        {
                            tbMessageLine.Text = "Doc Seq# is invalid.";
                        }
                    }
                }
            }
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            cbAlgorithm.SelectedIndex = 3;
            tbUserName.Text = "";
            tbPassword.Clear();
            tbFileName.Text = "";
            tbSubmitterID.Text = "";
            tbSubmitterName.Text = "";
            tbPrimaryReference.Text = "";
            tbDocSeqNbr.Text = "";
            tbDocCount.Text = ""; 
            tbChecksumValue.Text = "";
            tbChecksumKey.Text = "";
            tbValidationResult.Text = "";
            tbMessageLine.Text = "";
        }

        private void btnValidate_Click(object sender, RoutedEventArgs e)
        {
            tbMessageLine.Text = "";

            // Do some limited checking to make sure the values we need are there.

            if (String.IsNullOrWhiteSpace(tbUserName.Text) || String.IsNullOrWhiteSpace(tbPassword.Password) || String.IsNullOrWhiteSpace(tbChecksumKey.Text) || String.IsNullOrWhiteSpace(tbChecksumValue.Text))
            {
                tbMessageLine.Text = "Missing required entries. (User Name or Password or ChecksumKey or Checksum Value)";
            }
            else
            {
                RestClient client = null;
                RestRequest request = null;
                IRestResponse response = null;

                string strURL = "https://apex-prd.certna.org/APEX/Service/APEXPublicServer.svc/user/login"; // Production Platform

                // Password has to be hashed.
                // New convention uses a Salt value from the user record

                string strSalt = GetSalt(tbUserName.Text);
                string strPassword = tbPassword.Password.ToString();

                string strHashedPassword = HashPassword(strPassword, strSalt);

                string strParms = "{\n\t\"user_name\" : \"";
                strParms += tbUserName.Text;
                strParms += "\",\n\t\"password\" : \"";
                strParms += strHashedPassword;
                strParms += "\"\n}";

                client = new RestClient(strURL);
                request = new RestRequest(Method.POST);

                request.AddHeader("Cache-Control", "no-cache");
                request.AddHeader("Content-Type", "application/json");

                request.AddParameter("Login", strParms, ParameterType.RequestBody);
                response = client.Execute(request);

                if (response.IsSuccessful)
                {
                    var jsonResult1 = JsonConvert.DeserializeObject<dynamic>(response.Content);
                    string token = jsonResult1.access_token;

                    strURL = null;
                    client = null;
                    request = null;
                    response = null;

                    strURL = "https://apex-prd.certna.org/APEX/Service/APEXPublicServer.svc/ValidateChecksum";  // Production Platform 

                    client = new RestClient(strURL);
                    request = new RestRequest(Method.POST);

                    strParms = "{\n\t\"checksum_key\" : \"";
                    strParms += tbChecksumKey.Text;
                    strParms += "\",\n\t\"checksum\" : \"";
                    strParms += tbChecksumValue.Text;
                    strParms += "\"\n}";

                    request.AddHeader("Cache-Control", "no-cache");
                    request.AddHeader("Content-Type", "application/json");
                    request.AddHeader("access_token", token);
                    request.AddParameter("Validation", strParms, ParameterType.RequestBody);
                    response = client.Execute(request);

                    if (response.IsSuccessful)
                    {
                        var jsonResult2 = JsonConvert.DeserializeObject<dynamic>(response.Content);
                        string strIsValid = jsonResult2.is_valid;

                        tbValidationResult.Text = strIsValid;
                    }
                    else
                    {
                        string str_ResultCode = "Web service call failed. (" + response.StatusDescription + ")";
                        tbValidationResult.Text = str_ResultCode;
                    }
                }
                else
                {
                    var jsonResult2 = JsonConvert.DeserializeObject<dynamic>(response.Content);
                    string rcVerify = jsonResult2.ToString();

                    tbValidationResult.Text = rcVerify;
                }
            }
        }

        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            // Create OpenFileDialog 
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();

            // Set filter for file extension and default file extension 
            dlg.DefaultExt = ".xml";
            dlg.Filter = "XML Files (*.xml)|*.xml";

            // Display OpenFileDialog by calling ShowDialog method 
            Nullable<bool> result = dlg.ShowDialog();

            // Get the selected file name and display in a TextBox 
            if (result == true)
            {
                // Open the XML document and gather some info from it. 
                string strFileName = dlg.FileName;
                tbFileName.Text = strFileName;

                // This would typically be wrapped in a try/catch block.
                // But this code is simplified for demonstration purposes.

                FileStream fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read);

                XmlDocument xmlDoc = new XmlDocument();

                xmlDoc.Load(fs);

                // If this is a Request or Response XML, look up some of the various values...

                XmlNode nodeXmlType = xmlDoc.SelectSingleNode("/REQUEST_GROUP");

                if (nodeXmlType != null)
                {
                    getRequestValues(xmlDoc);
                }
                else
                {
                    nodeXmlType = xmlDoc.SelectSingleNode("/RESPONSE_GROUP");

                    if (nodeXmlType != null)
                    {
                        getResponseValues(xmlDoc);
                    }
                }
            }
        }

        private void getRequestValues(XmlDocument xmlRequest)
        {
            tbXMLFileType.Text = "Request";

            XmlNode nodeRequestingParty = xmlRequest.SelectSingleNode("/REQUEST_GROUP/REQUESTING_PARTY");
            tbSubmitterID.Text = nodeRequestingParty.Attributes.GetNamedItem("_Identifier").Value;
            tbSubmitterName.Text = nodeRequestingParty.Attributes.GetNamedItem("_Name").Value;

            XmlNode nodeRecordingTransactionIdentifier = xmlRequest.SelectSingleNode("/REQUEST_GROUP/REQUEST/PRIA_REQUEST/RECORDING_TRANSACTION_IDENTIFIER");
            tbPrimaryReference.Text = nodeRecordingTransactionIdentifier.Attributes.GetNamedItem("_Value").Value;

            XmlNodeList nlPriaDocs = xmlRequest.SelectNodes("/REQUEST_GROUP/REQUEST/PRIA_REQUEST/PACKAGE/PRIA_DOCUMENT");
            tbDocCount.Text = nlPriaDocs.Count.ToString();
        }

        private void getResponseValues(XmlDocument xmlResponse)
        {
            tbXMLFileType.Text = "Response";

            XmlNode nodeRequestingParty = xmlResponse.SelectSingleNode("/RESPONSE_GROUP/REQUESTING_PARTY");
            tbSubmitterID.Text = nodeRequestingParty.Attributes.GetNamedItem("_Identifier").Value;
            tbSubmitterName.Text = nodeRequestingParty.Attributes.GetNamedItem("_Name").Value;

            XmlNode nodeRecordingTransactionIdentifier = xmlResponse.SelectSingleNode("/RESPONSE_GROUP/RESPONSE/RESPONSE_DATA/PRIA_RESPONSE/RECORDING_TRANSACTION_IDENTIFIER");
            tbPrimaryReference.Text = nodeRecordingTransactionIdentifier.Attributes.GetNamedItem("_Value").Value;

            XmlNodeList nlPriaDocs = xmlResponse.SelectNodes("/RESPONSE_GROUP/RESPONSE/RESPONSE_DATA/PRIA_RESPONSE/PACKAGE/PRIA_DOCUMENT");
            tbDocCount.Text = nlPriaDocs.Count.ToString();

        }

        public static string getBase64Hash(string strB64Source)
        {
            Encoding u8 = Encoding.UTF8; // We use UTF8 encoding

            byte[] b64Bytes = u8.GetBytes(strB64Source); // Put the Document B64 string into a byte array

            byte[] b64HashBytes = SHA384.Create().ComputeHash(b64Bytes);  // Compute the SHA384 hash

            //Convert the SHA384 hash to a Base64 string

            string strB64Value = System.Convert.ToBase64String(b64HashBytes, 0, b64HashBytes.Length);

            return strB64Value;
        }

        public static string GetSalt(string srcUserName)
        {
            RestClient client = null;
            RestRequest request = null;
            IRestResponse response = null;

            string strSalt = null; 

            string strURL = "https://apex-prd.certna.org/APEX/Service/APEXPublicServer.svc/user/" + srcUserName + "/salt"; //Production Platform

            client = new RestClient(strURL);
            request = new RestRequest(Method.GET);

            request.AddHeader("Cache-Control", "no-cache");
            request.AddHeader("Content-Type", "application/json");
            response = client.Execute(request);

            if (response.IsSuccessful)
            {

                var jsonResult1 = JsonConvert.DeserializeObject<dynamic>(response.Content);
                strSalt = jsonResult1.salt;
            }

            return strSalt;
        }


        public static string HashPassword(string srcPassword, string srcSalt)
        {
            var combinedPassword = srcPassword + srcSalt;

            SHA256Managed sha256Managed = new SHA256Managed();
            UTF8Encoding utf8Encoding = new UTF8Encoding();

            // Would normally be enclosedin a try/catch block.

           return Convert.ToBase64String(sha256Managed.ComputeHash(utf8Encoding.GetBytes(combinedPassword)));
        }

        private void btnStore_Click(object sender, RoutedEventArgs e)
        {
            tbMessageLine.Text = "";

            // Do some limited checking to make sure the values we need are there.

            if (String.IsNullOrWhiteSpace(tbUserName.Text) || String.IsNullOrWhiteSpace(tbPassword.Password) || String.IsNullOrWhiteSpace(tbChecksumValue.Text))
            {
                tbMessageLine.Text = "Missing required entries. (User Name or Password or ChecksumValue)";
            }
            else
            {
                RestClient client = null;
                RestRequest request = null;
                IRestResponse response = null;

                string strURL = "https://apex-prd.certna.org/APEX/Service/APEXPublicServer.svc/user/login"; // Production Platform

                // Password has to be hashed.
                // New convention uses a Salt value from the user record

                string strSalt = GetSalt(tbUserName.Text);
                string strPassword = tbPassword.Password.ToString();

                string strHashedPassword = HashPassword(strPassword, strSalt);

                string strParms = "{\n\t\"user_name\" : \"";
                strParms += tbUserName.Text;
                strParms += "\",\n\t\"password\" : \"";
                strParms += strHashedPassword;
                strParms += "\"\n}";

                client = new RestClient(strURL);
                request = new RestRequest(Method.POST);

                request.AddHeader("Cache-Control", "no-cache");
                request.AddHeader("Content-Type", "application/json");

                request.AddParameter("Login", strParms, ParameterType.RequestBody);
                response = client.Execute(request);

                if (response.IsSuccessful)
                {
                    var jsonResult1 = JsonConvert.DeserializeObject<dynamic>(response.Content);
                    string token = jsonResult1.access_token;

                    strURL = null;
                    client = null;
                    request = null;
                    response = null;

                    strURL = "https://apex-prd.certna.org/APEX/Service/APEXPublicServer.svc/StoreChecksum";  // Production Platform 

                    client = new RestClient(strURL);
                    request = new RestRequest(Method.POST);

                    strParms = "{\n\t\"checksum\" : \"";
                    strParms += tbChecksumValue.Text;
                    strParms += "\"\n}";

                    request.AddHeader("Cache-Control", "no-cache");
                    request.AddHeader("Content-Type", "application/json");
                    request.AddHeader("access_token", token);
                    request.AddParameter("StoreChecksum", strParms, ParameterType.RequestBody);
                    response = client.Execute(request);

                    if (response.IsSuccessful)
                    {
                        var jsonResult2 = JsonConvert.DeserializeObject<dynamic>(response.Content);

                        string strChecksumKey = jsonResult2.checksum_key;

                        tbChecksumKey.Text = strChecksumKey;
                    }
                    else
                    {
                        string str_ResultCode = "Web service call failed. (" + response.StatusDescription + ")";
                        tbMessageLine.Text = str_ResultCode;
                    }
                }
                else
                {
                    var jsonResult2 = JsonConvert.DeserializeObject<dynamic>(response.Content);
                    string rcVerify = jsonResult2.ToString();

                    tbValidationResult.Text = rcVerify;
                }
            }
        }
    }
}
