//	Spludlow Software
//	Copyright © Samuel P. Ludlow 2020 All Rights Reserved
//	Distributed under the terms of the GNU General Public License version 3
//	Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
//	https://www.spludlow.co.uk/LICENCE.TXT
//	The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
//	v1.14

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;

namespace Spludlow
{
    public class Parameters
    {
		//	The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.

		public static long MinUploadLength = 32 * 1024;						// 	32 /64max K		the log body bust handle this useing MAX not 33 * 1024 (8000) is limit!!!!!!!!
		public static long MinCompressLength = 1440 * 1024;					// 1.44 MB		//	1474560

		public static void TestRecieve(object[] data)
		{
			string info = "";

			foreach (object item in data)
			{
				info += item.GetType().Name;
				info += ", ";
			}

			Spludlow.Log.Report(info);
		}

		public static string[][] EncodeParameters(object[] paramters, bool largeParamter, bool dontCompress)
        {
            if (paramters == null)
                paramters = new object[0];

			List<string[]> parameterPairs = new List<string[]>();

			foreach (object parameter in paramters)
				parameterPairs.Add(EncodeParameter(parameter, largeParamter, dontCompress));

            return parameterPairs.ToArray();
        }

		public static string[] EncodedNull
		{
			get
			{
				return new string [] { "null", "" };
			}
		}

		public static string[] EncodeParameter(object parameter, bool largeParamter, bool dontCompress)
		{
			if (parameter == null || parameter.GetType() == typeof(DBNull))     // ??? DBNull
				return EncodedNull;

			Type type = parameter.GetType();

			string objectArray = "";
			if (type.Name == "Object[]")
			{
				parameter = EncodeParameters((object[])parameter, largeParamter, dontCompress);
				type = parameter.GetType();
				objectArray = "[";
			}

			string[] parameterPair = new string[2];

			bool binary = false;
			if (type == typeof(byte[]))
				binary = true;

			if (largeParamter == true || binary == true)
			{
				string extention = ".txt";
				if (binary == true)
					extention = ".dat";

				string dataFilename = Spludlow.WebServices.CreateProgramDataTempFilename(extention);
				string archiveFilename = dataFilename + ".7z";

				if (binary == true)
					File.WriteAllBytes(dataFilename, (byte[])parameter);
				else
					Spludlow.Serialization.WriteFile(parameter, dataFilename);

				long dataLength = Spludlow.Io.Files.FileLength(dataFilename);
				
				if (dataLength >= MinUploadLength || binary == true)
				{
					if (dontCompress == false && dataLength >= MinCompressLength)			//	Don't need to compress in not going remote ???
					{
						string warnings = Spludlow.Archive.Create(archiveFilename, dataFilename);
						if (warnings != null)
							throw new ApplicationException("EncodeParameter; Create Archive Warnings:\t" + warnings);

						File.Delete(dataFilename);
					}
					else
					{
						archiveFilename = dataFilename;
					}

					parameterPair[0] = objectArray + "@" + type.AssemblyQualifiedName;
					parameterPair[1] = Path.GetFileName(archiveFilename);

					return parameterPair;
				}

				File.Delete(dataFilename);
			}

			parameterPair[0] = objectArray + type.AssemblyQualifiedName;
			parameterPair[1] = Spludlow.Serialization.Write(parameter);
			return parameterPair;
		}



		public static object[] DecodeParameters(string[][] parameterPairs)
        {
            List<object> parameters = new List<object>();

            if (parameterPairs != null && parameterPairs.Length > 0)
			{
				foreach (string[] parameterPair in parameterPairs)
					parameters.Add(DecodeParameter(parameterPair));

			}

            return parameters.ToArray();
        }

		//	Keep priority [, @

		public static object DecodeParameter(string[] parameterPair)
		{
			if (parameterPair[0].StartsWith("[") == true)
			{
				parameterPair[0] = parameterPair[0].Substring(1);
				string[][] encodedObjectArray = (string[][])DecodeParameterLow(parameterPair);

				return DecodeParameters(encodedObjectArray);
			}

			return DecodeParameterLow(parameterPair);
		}

		public static object DecodeParameterLow(string[] parameterPair)
		{
			string parameterType = parameterPair[0];
			string parameterData = parameterPair[1];

			if (parameterType == "null")
				return null;

			Type type;

			if (parameterType.StartsWith("@") == true)
			{
				parameterType = parameterType.Substring(1);

				try
				{
					type = Type.GetType(parameterType, true, false);
				}
				catch (Exception ee)
				{
					Spludlow.Log.Error("Decode Parameter: " + parameterType, ee);
					return ee.Message;
				}

				string localFilename = Spludlow.WebServices.GetProgramDataTempFile("@" + parameterData);

				if (localFilename.EndsWith(".7z") == true)
				{
					string extractFilename = localFilename.Substring(0, localFilename.Length - 3);
					if (File.Exists(extractFilename) == false)
					{
						Spludlow.Archive.Extract(localFilename, Spludlow.Config.ProgramData + @"\Temp");
						if (File.Exists(extractFilename) == false)
							throw new ApplicationException("DecodeParameter; Did not extract expected file from archive: " + localFilename + ", expected: " + extractFilename);
					}

					localFilename = extractFilename;
				}

				if (type == typeof(byte[]))
					return File.ReadAllBytes(localFilename);

				return Spludlow.Serialization.ReadFile(localFilename, type);
			}

			try
			{
				type = Type.GetType(parameterType, true, false);
			}
			catch (Exception ee)
			{
				Spludlow.Log.Error("Decode Parameter: " + parameterType, ee);
				return ee.Message;
			}

			return Spludlow.Serialization.Read(parameterData, type);
		}


		public static string[] EncodeResultsArray(string[][] resultsArray, bool largeParamter, bool dontCompress)	// Combine array of encoded items into encoded array that will decode into object[]
		{
			string[] result = Spludlow.Parameters.EncodeParameter(resultsArray, largeParamter, dontCompress);

			result[0] = "[" + result[0];

			return result;
		}

		public static string ShortText(string[][] paramters)
		{
			if (paramters == null)
				return "";

			List<object> items = new List<object>();

			foreach (string[] parameterPair in paramters)
			{
				if (parameterPair[0].StartsWith("@") == true)
					items.Add("@" + Path.GetFileName(parameterPair[1]));
				else
					items.Add(DecodeParameter(parameterPair));
			}

			return ShortText(items.ToArray());

		}

		public static string ShortText(object[] items)
		{
			if (items == null)
				return "";

			StringBuilder text = new StringBuilder();

			foreach (object paramter in items)
			{
				if (text.Length > 0)
					text.Append(", ");

				if (paramter == null)
				{
					text.Append("null");
					continue;
				}

				Type type = paramter.GetType();

				string result = "";

				if (Spludlow.SimpleEncoding.IsSimple(type) == true)
					result = Spludlow.SimpleEncoding.Encode(paramter, type.Name);
				else
					result = type.Name;

				if (result.Length > 32)
					result = result.Substring(0, 32);

				text.Append(result);
			}

			return text.ToString();
		}



    }
}