using System;
using System.Collections.Generic;
using System.Text;
using DeadCode.WME.Core;
using DeadCode.WME.DefinitionFileParser;
using DeadCode.WME.Global;
using System.IO;

namespace DeadCode.WME.SpriteOptimizer
{
	public class Sprite
	{
		private WGame Game;
		private DefinitionFile DefFile;
		private string FileName;
		private SpriteOptimizer Optimizer;
		private bool IsChanged;

		//////////////////////////////////////////////////////////////////////////
		public Sprite(WGame Game, SpriteOptimizer optimizer)
		{
			this.Game = Game;
			this.Optimizer = optimizer;

			this.IsChanged = false;
		}

		//////////////////////////////////////////////////////////////////////////
		public bool LoadFromFile(string fileName)
		{
			DefFile = new DefinitionFile();
			if (!DefFile.ParseFile(fileName))
			{
				DefFile = null;
				return false;
			}
			else
			{
				FileName = fileName;
				return true;
			}
		}

		//////////////////////////////////////////////////////////////////////////
		public bool SaveToFile()
		{
			string content = ToString();

			try
			{
				using (StreamWriter sw = new StreamWriter(FileName, false, Encoding.Default))
				{
					sw.WriteLine(content);
				}
				Optimizer.AddLog(string.Format("Modified hotspots in sprite '{0}'.", FileName));

				return true;
			}
			catch (Exception e)
			{
				Optimizer.AddLog("Error saving sprite: " + e.Message);
				return false;
			}
		}

		//////////////////////////////////////////////////////////////////////////
		public bool Process()
		{
			IsChanged = false;
			ProcessNode(DefFile);
			return IsChanged;
		}

		//////////////////////////////////////////////////////////////////////////
		private void ProcessNode(DefinitionFileItem node)
		{
			if (node.Name != null && node.Name.ToUpper() == "IMAGE")
			{
				int modX, modY;
				Optimizer.CropImage(node.Value, out modX, out modY);

				if (modX != 0 || modY != 0) FixHotspot(node.Parent, modX, modY);
			}

			// the collection can grow by adding a missing hotspot, hence no foreach
			int numNodes = node.Children.Count;
			for (int i = 0; i < numNodes; i++)
			{
				DefinitionFileItem subNode = node.Children[i];
				ProcessNode(subNode);
			}
		}

		//////////////////////////////////////////////////////////////////////////
		private void FixHotspot(DefinitionFileItem node, int modX, int modY)
		{
			bool found = false;
			foreach (DefinitionFileItem subNode in node.Children)
			{
				if (subNode.Name.ToUpper() == "HOTSPOT")
				{
					found = true;
					int[] values = subNode.GetIntArray();
					if (values.Length > 1)
					{
						values[0] += modX;
						values[1] += modY;

						subNode.Value = string.Format("{0},{1}", values[0], values[1]);
					}
					break;
				}
			}

			if (!found)
			{
				DefinitionFileItem subNode = new DefinitionFileItem();
				subNode.Name = "HOTSPOT";
				subNode.Value = string.Format("{0},{1}", modX, modY);

				node.Children.Add(subNode);
			}
			IsChanged = true;
		}

		//////////////////////////////////////////////////////////////////////////
		public override string ToString()
		{
			string RelProjectPath = WmeUtils.GetRelativePath(FileName, Path.GetDirectoryName(Game.ProjectFile) + "\\");

			string str = "; generated by SpriteOptimizer\n\n";
			str += "; $EDITOR_PROJECT_ROOT_DIR$ " + RelProjectPath + "\n\n";

			NodeToString(DefFile, ref str, "");
			return str;
		}

		//////////////////////////////////////////////////////////////////////////
		private void NodeToString(DefinitionFileItem node, ref string str, string indent)
		{
			if (node.Name != null) str += indent + node.Name;

			if (node.Children.Count > 0)
			{
				if (node.Name != null) str += "\n" + indent + "{\n";

				foreach (DefinitionFileItem subNode in node.Children)
				{
					string newIndent = indent;
					if (node.Name != null) newIndent += "  ";
					NodeToString(subNode, ref str, newIndent);
				}

				if (node.Name != null) str += indent + "}\n";
			}
			else
			{
				if (IsNumberList(node.Value))
				{
					str += " { " + node.Value.Replace(",", ", ") + " } ";
				}
				else
				{
					bool needsQuotes = node.Value.Contains(" ") || node.Value.Contains("\\") || node.Value == "";
					
					str += " = ";
					if (needsQuotes) str += "\"";
					str += node.Value;
					if (needsQuotes) str += "\"";
				}
				str += "\n";
			}
		}

		//////////////////////////////////////////////////////////////////////////
		private bool IsNumberList(string str)
		{
			bool hasComma = false;
			bool hasDigit = false;

			foreach (char c in str)
			{
				if (c != ',' && !char.IsDigit(c) && c != ' ') return false;

				if (c == ',') hasComma = true;
				if (char.IsDigit(c)) hasDigit = true;
			}
			return hasComma && hasDigit;
		}

	}
}
