using System;
using System.IO;
using System.Windows.Forms;
using System.Xml;

namespace TeslaConsole.BattleTech;

/// <summary>
/// Operator defaults for the two BattleTech game modes, persisted to
/// BTDefaults.btd in the common app-data directory (mirrors
/// <c>RPDefaults</c>/.rpd). Both modes share one defaults shape — they differ
/// only by role, which comes from the mode, not from a default. There is no
/// defaults dialog yet (RPDefaultsDialog's counterpart is a later phase); the
/// file is import/export round-trippable in the meantime.
/// </summary>
internal static class BTDefaults
{
	public class BattleDefaults
	{
		private readonly string mNodeName;

		private bool mAdvancedDamage = true;

		private TimeSpan mMissionLength = new TimeSpan(0, 10, 0);

		private string mMapKey;

		private string mVehicleKey;

		private string mTimeOfDayKey;

		private string mWeatherKey;

		private string mExperienceKey;

		private string mCamoKey;

		private string mPatchKey;

		private string mEmblemKey;

		private int mLaunchDelay = 15;

		public bool AdvancedDamage
		{
			get
			{
				return mAdvancedDamage;
			}
			set
			{
				mAdvancedDamage = value;
			}
		}

		public TimeSpan MissionLength
		{
			get
			{
				return mMissionLength;
			}
			set
			{
				mMissionLength = value;
			}
		}

		public string MapKey
		{
			get
			{
				return mMapKey;
			}
			set
			{
				mMapKey = value;
			}
		}

		public string VehicleKey
		{
			get
			{
				return mVehicleKey;
			}
			set
			{
				mVehicleKey = value;
			}
		}

		public string TimeOfDayKey
		{
			get
			{
				return mTimeOfDayKey;
			}
			set
			{
				mTimeOfDayKey = value;
			}
		}

		public string WeatherKey
		{
			get
			{
				return mWeatherKey;
			}
			set
			{
				mWeatherKey = value;
			}
		}

		public string ExperienceKey
		{
			get
			{
				return mExperienceKey;
			}
			set
			{
				mExperienceKey = value;
			}
		}

		public string CamoKey
		{
			get
			{
				return mCamoKey;
			}
			set
			{
				mCamoKey = value;
			}
		}

		public string PatchKey
		{
			get
			{
				return mPatchKey;
			}
			set
			{
				mPatchKey = value;
			}
		}

		public string EmblemKey
		{
			get
			{
				return mEmblemKey;
			}
			set
			{
				mEmblemKey = value;
			}
		}

		public int LaunchDelay
		{
			get
			{
				return mLaunchDelay;
			}
			set
			{
				mLaunchDelay = value;
			}
		}

		internal BattleDefaults(string nodeName)
		{
			mNodeName = nodeName;
		}

		public void Save(XmlNode parrentNode)
		{
			XmlNode xmlNode = parrentNode.AppendChild(parrentNode.OwnerDocument.CreateElement(mNodeName));
			xmlNode.AppendChild(xmlNode.OwnerDocument.CreateElement("AdvancedDamage")).InnerText = mAdvancedDamage.ToString();
			xmlNode.AppendChild(xmlNode.OwnerDocument.CreateElement("MissionLength")).InnerText = mMissionLength.ToString();
			SaveKey(xmlNode, "MapKey", mMapKey);
			SaveKey(xmlNode, "VehicleKey", mVehicleKey);
			SaveKey(xmlNode, "TimeOfDayKey", mTimeOfDayKey);
			SaveKey(xmlNode, "WeatherKey", mWeatherKey);
			SaveKey(xmlNode, "ExperienceKey", mExperienceKey);
			SaveKey(xmlNode, "CamoKey", mCamoKey);
			SaveKey(xmlNode, "PatchKey", mPatchKey);
			SaveKey(xmlNode, "EmblemKey", mEmblemKey);
			xmlNode.AppendChild(xmlNode.OwnerDocument.CreateElement("LaunchDelay")).InnerText = mLaunchDelay.ToString();
		}

		private static void SaveKey(XmlNode parentNode, string elementName, string value)
		{
			if (!string.IsNullOrEmpty(value))
			{
				parentNode.AppendChild(parentNode.OwnerDocument.CreateElement(elementName)).InnerText = value;
			}
		}

		public void Parse(XmlNode scenarioNode)
		{
			foreach (XmlNode childNode in scenarioNode.ChildNodes)
			{
				switch (childNode.Name)
				{
				case "AdvancedDamage":
				{
					if (bool.TryParse(childNode.InnerText, out var result2))
					{
						mAdvancedDamage = result2;
					}
					break;
				}
				case "MissionLength":
				{
					if (TimeSpan.TryParse(childNode.InnerText, out var result3))
					{
						mMissionLength = result3;
					}
					break;
				}
				case "MapKey":
					ParseKey(childNode, ref mMapKey);
					break;
				case "VehicleKey":
					ParseKey(childNode, ref mVehicleKey);
					break;
				case "TimeOfDayKey":
					ParseKey(childNode, ref mTimeOfDayKey);
					break;
				case "WeatherKey":
					ParseKey(childNode, ref mWeatherKey);
					break;
				case "ExperienceKey":
					ParseKey(childNode, ref mExperienceKey);
					break;
				case "CamoKey":
					ParseKey(childNode, ref mCamoKey);
					break;
				case "PatchKey":
					ParseKey(childNode, ref mPatchKey);
					break;
				case "EmblemKey":
					ParseKey(childNode, ref mEmblemKey);
					break;
				case "LaunchDelay":
				{
					if (int.TryParse(childNode.InnerText, out var result))
					{
						mLaunchDelay = result;
					}
					break;
				}
				}
			}
		}

		private static void ParseKey(XmlNode node, ref string field)
		{
			if (!string.IsNullOrEmpty(node.InnerText))
			{
				field = node.InnerText;
			}
		}
	}

	public const string FreeForAllNode = "FreeForAllDefaults";

	public const string NoReturnNode = "NoReturnDefaults";

	private static readonly string sDefaultsFilePath;

	private static readonly BattleDefaults sFreeForAll;

	private static readonly BattleDefaults sNoReturn;

	public static BattleDefaults FreeForAll => sFreeForAll;

	public static BattleDefaults NoReturn => sNoReturn;

	/// <summary>
	/// When set, the BattleTech game pages target each pod's DOSBox-X guest
	/// (last octet +100) instead of the pod itself. A machine-level setting for
	/// the emulator preservation pods, so it is stored once per defaults file
	/// rather than per mode.
	/// </summary>
	public static bool DosBoxAddressShift { get; set; }

	static BTDefaults()
	{
		sDefaultsFilePath = Path.Combine(Program.GetCommonAppDataDirectory(), "BTDefaults.btd");
		sFreeForAll = new BattleDefaults("FreeForAllDefaults");
		sNoReturn = new BattleDefaults("NoReturnDefaults");
		if (File.Exists(sDefaultsFilePath))
		{
			try
			{
				Import(sDefaultsFilePath);
			}
			catch (Exception)
			{
				MessageBox.Show("The BattleTech defaults file appears to be corrupt.  Please delete it or export a new one to replace it.", "Error Loading BattleTech Defaults!", MessageBoxButtons.OK);
			}
		}
	}

	public static void Import(string fileName)
	{
		XmlDocument xmlDocument = new XmlDocument();
		xmlDocument.Load(fileName);
		foreach (XmlNode childNode in xmlDocument.DocumentElement.ChildNodes)
		{
			switch (childNode.Name)
			{
			case "FreeForAllDefaults":
				sFreeForAll.Parse(childNode);
				break;
			case "NoReturnDefaults":
				sNoReturn.Parse(childNode);
				break;
			case "DosBoxAddressShift":
			{
				if (bool.TryParse(childNode.InnerText, out var result))
				{
					DosBoxAddressShift = result;
				}
				break;
			}
			}
		}
	}

	public static void Save()
	{
		try
		{
			Export(sDefaultsFilePath);
		}
		catch (Exception)
		{
			MessageBox.Show("The BattleTech defaults file could not be saved.  These defaults will only be remembered until the application is closed.", "Error Saving BattleTech Defaults!", MessageBoxButtons.OK);
		}
	}

	public static void Export(string filePath)
	{
		XmlDocument xmlDocument = new XmlDocument();
		xmlDocument.AppendChild(xmlDocument.CreateElement("BTDefaults"));
		sFreeForAll.Save(xmlDocument.DocumentElement);
		sNoReturn.Save(xmlDocument.DocumentElement);
		xmlDocument.DocumentElement.AppendChild(xmlDocument.CreateElement("DosBoxAddressShift")).InnerText = DosBoxAddressShift.ToString();
		string directoryName = Path.GetDirectoryName(filePath);
		if (!Directory.Exists(directoryName))
		{
			Directory.CreateDirectory(directoryName);
		}
		xmlDocument.Save(filePath);
	}
}
