using Newtonsoft.Json;
using System.Net;
using System.IO;
using System.Net.Security;
using System.Configuration;
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Collections.Generic;
using System.IO.Compression;

namespace memoQSampleCMSConnector
{
	static class mQCMSAPICommInterface
	{
		private static readonly Encoding encoding = Encoding.UTF8;

		public static string SendRequest(byte[] data, string method, string URLextension, bool isCompressed, ref TimeSpan duration)
		{
			HttpWebRequest request = GetWebRequest(data, method, URLextension);

			Stopwatch sw = Stopwatch.StartNew();
			HttpWebResponse response = (HttpWebResponse)request.GetResponse();
			sw.Stop();
			duration = new TimeSpan(sw.ElapsedTicks);
			return GetResponseString(response, isCompressed);
		}

		public static string SendRequest(byte[] data, string method, string URLextension, bool isCompressed)
		{
			HttpWebRequest request = GetWebRequest(data, method, URLextension);
			HttpWebResponse response = (HttpWebResponse)request.GetResponse();
			return GetResponseString(response, isCompressed);
		}

		private static string GetResponseString(HttpWebResponse response, bool isCompressed)
		{
			string result = "";
			if (isCompressed)
			{
				StreamReader sr = new StreamReader(new GZipStream(response.GetResponseStream(), CompressionMode.Decompress));
				result = sr.ReadToEnd();
			}
			else
			{
				result = new StreamReader(response.GetResponseStream()).ReadToEnd();
			}

			return result;

		}

		private static HttpWebRequest GetWebRequest(byte[] data, string method, string uRLextension)
		{
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ConfigurationHelper.Config.cmsApiUrl + uRLextension);
			request.Headers.Add(HttpRequestHeader.Authorization, ConfigurationHelper.Config.cmsApiSecret);
			ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) =>
			{
				return true;
			};

			request.Method = method;
			string dataString = "";

			if (method != "GET")
			{

				request.ContentType = "application/json; charset=utf-8";
				request.Accept = "application/json";
				if (data != null)
				{
					request.ContentLength = data.Length;

					foreach (byte x in data)
					{
						dataString += Convert.ToChar(x);
					}
					
					using (var stream = request.GetRequestStream())
					{
						stream.Write(data, 0, data.Length);
					}
				}
				else
				{
					request.ContentLength = 0;
				}
			}

			
			Log.AddLog("Web request info: " + request.Address + " - " + request.ContentType + " - " + request.Accept + " - " + request.ContentLength + " - " + request.RequestUri + " - " + request.Headers[HttpRequestHeader.Authorization] + " - " + request.Method + " - " + dataString);

			return request;
		}

		public static string MultipartFormDataPost(string projectID, Dictionary<string, object> postParameters)
		{
			string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
			string contentType = "multipart/form-data; boundary=" + formDataBoundary;
			byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);
			string postUrl = ConfigurationHelper.Config.cmsApiUrl + "/projects/" + projectID + "/jobs";
			HttpWebResponse response = PostForm(postUrl, contentType, formData);
			return new StreamReader(response.GetResponseStream()).ReadToEnd();

		}

		private static HttpWebResponse PostForm(string postUrl, string contentType, byte[] formData)
		{
			HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;

			if (request == null)
			{
				throw new NullReferenceException("request is not a http request");
			}

			// Set up the request properties.
			request.Method = "POST";
			request.CookieContainer = new CookieContainer();
			request.ContentType = contentType;
			request.ContentLength = formData.Length;
			request.Headers.Add(HttpRequestHeader.Authorization, ConfigurationHelper.Config.cmsApiSecret);
			string dataString = "";

			foreach (byte x in formData)
			{
				dataString += Convert.ToChar(x);
			}


			// Send the form data to the request.
			using (Stream requestStream = request.GetRequestStream())
			{
				requestStream.Write(formData, 0, formData.Length);
				requestStream.Close();
			}

			Log.AddLog("Web request info: " + request.Address + " - " + request.ContentType + " - " + request.Accept + " - " + request.ContentLength + " - " + request.RequestUri + " - " + request.Headers[HttpRequestHeader.Authorization] + " - " + request.Method + " - " + dataString);


			return request.GetResponse() as HttpWebResponse;
		}

		private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
		{
			Stream formDataStream = new System.IO.MemoryStream();
			bool needsCLRF = false;

			foreach (var param in postParameters)
			{

				if (needsCLRF)
					formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));

				needsCLRF = true;
				if (param.Value is FileParameter)
				{
					FileParameter fileToUpload = (FileParameter)param.Value;

					// Add just the first part of this param, since we will write the file data directly to the Stream
					string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
						boundary,
						param.Key,
						fileToUpload.FileName ?? param.Key,
						fileToUpload.ContentType ?? "application/octet-stream");

					formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));

					// Write the file data directly to the Stream, rather than serializing it to a string.
					formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
				}
				else
				{
					string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
						boundary,
						param.Key,
						JsonConvert.SerializeObject(param.Value));
					formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
				}
			}

			// Add the end of the request.  Start with a newline
			string footer = "\r\n--" + boundary + "--\r\n";
			formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));

			// Dump the Stream into a byte[]
			formDataStream.Position = 0;
			byte[] formData = new byte[formDataStream.Length];
			formDataStream.Read(formData, 0, formData.Length);
			formDataStream.Close();

			return formData;
		}
	}
}