using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;

namespace QCRPG.Framework;

public sealed class Configurer
{
	private Dictionary<IConfigurable, string> configurableObjectToSectionNameMap = new Dictionary<IConfigurable, string>();

	private readonly Dictionary<IConfigurable, bool> configurableObjectToConfigurationSetMap = new Dictionary<IConfigurable, bool>();

	private string tempDir = "C:\\Temp";

	public void RegisterConfigurableObject(IConfigurable configurableObject, string sectionName)
	{
		if (configurableObjectToSectionNameMap.ContainsKey(configurableObject))
		{
			if (configurableObjectToSectionNameMap[configurableObject] != sectionName)
			{
				throw new Exception("Can't re-register the same object with a different section name");
			}
			return;
		}
		foreach (IConfigurable key in configurableObjectToSectionNameMap.Keys)
		{
			if (configurableObjectToSectionNameMap[key] == sectionName)
			{
				throw new Exception("Section name " + sectionName + " already used by another registered object");
			}
		}
		configurableObjectToSectionNameMap.Add(configurableObject, sectionName);
	}

	public void UnregisterConfigurableObject(IConfigurable configurableObject)
	{
		if (configurableObjectToSectionNameMap.ContainsKey(configurableObject))
		{
			configurableObjectToSectionNameMap.Remove(configurableObject);
		}
	}

	public void LoadAndSetConfigurations(string filename, XmlSerializer providedXmlSerializer = null)
	{
		ConfigurationListWrapper configurationListWrapper = new ConfigurationListWrapper();
		try
		{
			using FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
			if (providedXmlSerializer == null)
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ConfigurationListWrapper), new XmlRootAttribute("Configurations"));
				configurationListWrapper = (ConfigurationListWrapper)xmlSerializer.Deserialize(stream);
			}
			else
			{
				configurationListWrapper = (ConfigurationListWrapper)providedXmlSerializer.Deserialize(stream);
			}
		}
		catch (Exception)
		{
			try
			{
				string path = Path.Combine(tempDir, Path.GetFileName(filename) + ".backup");
				using FileStream stream2 = new FileStream(path, FileMode.Open, FileAccess.Read);
				if (providedXmlSerializer == null)
				{
					XmlSerializer xmlSerializer2 = new XmlSerializer(typeof(ConfigurationListWrapper), new XmlRootAttribute("Configurations"));
					configurationListWrapper = (ConfigurationListWrapper)xmlSerializer2.Deserialize(stream2);
				}
				else
				{
					configurationListWrapper = (ConfigurationListWrapper)providedXmlSerializer.Deserialize(stream2);
				}
			}
			catch (Exception)
			{
			}
		}
		foreach (IConfigurable key in configurableObjectToSectionNameMap.Keys)
		{
			configurableObjectToConfigurationSetMap[key] = false;
		}
		foreach (IConfigurable key2 in configurableObjectToSectionNameMap.Keys)
		{
			foreach (Configuration configuration in configurationListWrapper.configurationList)
			{
				if (configurableObjectToSectionNameMap[key2] == configuration.name)
				{
					key2.SetConfiguration(configuration);
					configurableObjectToConfigurationSetMap[key2] = true;
				}
			}
		}
		foreach (IConfigurable key3 in configurableObjectToSectionNameMap.Keys)
		{
			if (!configurableObjectToConfigurationSetMap[key3])
			{
				key3.SetConfiguration(new Configuration());
				configurableObjectToConfigurationSetMap[key3] = true;
			}
		}
	}

	public void LoadDefaultConfigurationForNonConfiguredObjects()
	{
		foreach (IConfigurable key in configurableObjectToSectionNameMap.Keys)
		{
			if (!configurableObjectToConfigurationSetMap.ContainsKey(key) || !configurableObjectToConfigurationSetMap[key])
			{
				key.SetConfiguration(new Configuration());
				configurableObjectToConfigurationSetMap[key] = true;
			}
		}
	}

	public string GetAndSaveConfigurations(string filename, XmlSerializer providedXmlSerializer = null)
	{
		ConfigurationListWrapper configurationListWrapper = new ConfigurationListWrapper();
		foreach (IConfigurable key in configurableObjectToSectionNameMap.Keys)
		{
			Configuration configuration = key.GetConfiguration();
			configuration.name = configurableObjectToSectionNameMap[key];
			configurationListWrapper.configurationList.Add(configuration);
		}
		try
		{
			using MemoryStream memoryStream = new MemoryStream();
			if (providedXmlSerializer == null)
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ConfigurationListWrapper), new XmlRootAttribute("Configurations"));
				xmlSerializer.Serialize(memoryStream, configurationListWrapper);
			}
			else
			{
				providedXmlSerializer.Serialize(memoryStream, configurationListWrapper);
			}
			string @string = Encoding.UTF8.GetString(memoryStream.ToArray());
			WriteAllTextWithBackup(filename, @string);
			return @string;
		}
		catch (Exception)
		{
		}
		return "";
	}

	public void WriteAllTextWithBackup(string path, string contents)
	{
		string tempFileName = Path.GetTempFileName();
		if (!Directory.Exists(tempDir))
		{
			Directory.CreateDirectory(tempDir);
		}
		string destinationBackupFileName = Path.Combine(tempDir, Path.GetFileName(path) + ".backup");
		byte[] bytes = Encoding.UTF8.GetBytes(contents);
		using (FileStream fileStream = File.Create(tempFileName, 4096, FileOptions.WriteThrough))
		{
			fileStream.Write(bytes, 0, bytes.Length);
		}
		if (File.Exists(path))
		{
			File.Replace(tempFileName, path, destinationBackupFileName);
		}
		else
		{
			File.Move(tempFileName, path);
		}
		File.Delete(tempFileName);
	}
}
