//	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.Data;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace Spludlow
{
    public class Serialization
    {
		static Serialization()
		{
			Type[] extraAllowedTypes = new Type[]
			{
				typeof(Spludlow.CallSet),
			};

			AppDomain.CurrentDomain.SetData("System.Data.DataSetDefaultAllowedTypes", extraAllowedTypes);
		}

		public static string WriteDataSet(DataSet dataSet)
		{
			using (StringWriter writer = new StringWriter())
			{
				dataSet.WriteXml(writer, XmlWriteMode.WriteSchema);
				return writer.ToString();
			}
		}

		public static DataSet ReadDataSet(string xml)
		{
			DataSet dataSet = new DataSet();
			using (StringReader reader = new StringReader(xml))
			{
				dataSet.ReadXml(reader);
			}
			return dataSet;
		}


        public static string Write(object data)
        {
            Type type = data.GetType();

            XmlSerializer serializer = new XmlSerializer(type);


			using (StringWriter writer = new StringWriter())
            {
                serializer.Serialize(writer, data);
                return writer.ToString();
            }
        }

        public static void WriteFile(object data, string filename)
        {
            Type type = data.GetType();

            XmlSerializer serializer = new XmlSerializer(type);

            using (FileStream stream = new FileStream(filename, FileMode.Create))
                serializer.Serialize(stream, data);
        }

		public static void Write(object data, Stream stream)
		{
			Type type = data.GetType();

			XmlSerializer serializer = new XmlSerializer(type);

			serializer.Serialize(stream, data);
		}



		public static object Read(string xml, string typeName)
		{
			Type type = Type.GetType(typeName, true);
			return Read(xml, type);
		}

		public static object Read(string xml, Type type)
        {
            XmlSerializer serializer = new XmlSerializer(type);

			XmlReaderSettings settings = new XmlReaderSettings();       //	had problem with email containing 0x03 creating poisioned log message. It gets encoded fine '' but throws exception when Deserialize
			settings.CheckCharacters = false;

			using (StringReader reader = new StringReader(xml))
			{
				XmlReader xmlReader = XmlReader.Create(reader, settings);

				return serializer.Deserialize(xmlReader);
			}
        }

		public static object Read(Stream stream, Type type)
		{
			XmlSerializer serializer = new XmlSerializer(type);

			XmlReaderSettings settings = new XmlReaderSettings();       //	had problem with email containing 0x03 creating poisioned log message. It gets encoded fine '' but throws exception when Deserialize
			settings.CheckCharacters = false;

			using (XmlReader xmlReader = XmlReader.Create(stream, settings))
			{
				return serializer.Deserialize(xmlReader);
			}
		}

		public static object ReadCheckingCharacters(string xml, Type type)
		{
			XmlSerializer serializer = new XmlSerializer(type);

			using (StringReader reader = new StringReader(xml))
			{
				XmlReader xmlReader = XmlReader.Create(reader);

				return serializer.Deserialize(xmlReader);
			}
		}



		public static object ReadFile(string filename, Type type)
        {
            XmlSerializer serializer = new XmlSerializer(type);

			XmlReaderSettings settings = new XmlReaderSettings();
			settings.CheckCharacters = false;

			using (FileStream stream = new FileStream(filename, FileMode.Open))
			{
				XmlReader xmlReader = XmlReader.Create(stream, settings);

				return serializer.Deserialize(xmlReader);
			}
        }

		public static bool ValidateForXML(string text)
		{
			string xml = Spludlow.Serialization.Write(text);
			try
			{
				Spludlow.Serialization.ReadCheckingCharacters(xml, typeof(string));

				return true;
			}
			catch (InvalidOperationException ee)
			{
				if (ee.InnerException != null && !(ee.InnerException is System.Xml.XmlException))
					throw ee;

				System.Xml.XmlException xmlError = (System.Xml.XmlException)ee.InnerException;

				Spludlow.Log.Warning("ValidateForXML", xmlError, text);

				return false;
			}
		}

		public static string FixString(string text)
		{
			StringBuilder result = new StringBuilder();

			foreach (char ch in text)
			{
				if (ValidCharacter(ch) == true)
					result.Append(ch);
				else
					result.Append('?');
			}

			return result.ToString();

		}

		public static bool ValidCharacter(char ch)
		{
			if (ch < 0x20)
			{
				if (ch == 0x9 || ch == 0xA || ch == 0xD)
					return true;

				return false;
			}

			if (ch >= 0xD800 && ch <= 0xDFFF)
				return false;

			if (ch == 0xFFFE || ch == 0xFFFF)
				return false;

			return true;
		}
	}
}