using System;
using System.Collections;
using System.IO;
using System.Text.RegularExpressions;
using System.Data;
using Orciid.Media.Util;
using NUnit.Framework;

namespace Localization
{
	[TestFixture]
	public class LocalizationCheck
	{
		static string[] FindFiles(DirectoryInfo dir, string pattern)
		{
			ArrayList files = new ArrayList();
			foreach (DirectoryInfo subdir in dir.GetDirectories())
				files.AddRange(FindFiles(subdir, pattern));
			foreach (FileInfo file in dir.GetFiles(pattern))
				files.Add(file.FullName);
			return (string[])files.ToArray(typeof(string));
		}

		static string[] FindIdentifiersInPage(string file)
		{
			string prefix = Path.GetFileNameWithoutExtension(file).ToLower();
			if (file.EndsWith(".ascx"))
				prefix = "_" + prefix;
			string content;
			using (StreamReader reader = File.OpenText(file))
				content = reader.ReadToEnd().Replace('\n', ' ').Replace('\r', ' ');
			Regex regex = new Regex(
				"<(asp:(Label|Button|LinkButton|HyperLink|CheckBox|RangeValidator|RadioButton|" +
				"RequiredFieldValidator|RegularExpressionValidator|CustomValidator)" +
				"|[a-z0-9]+)\\s[^>]*(runat=\"server\"[^>]*\\sid=\"(?'a'[^\"]+)\"|" +
				"id=\"(?'b'[^\"]+)\"[^>]*\\srunat=\"server\")",
				RegexOptions.IgnoreCase);
			ArrayList hits = new ArrayList();
			foreach (Match m in regex.Matches(content))
				if (m.Groups[1].Value.ToLower() != "img") // ignore image tags
				{
					string hit = String.Format("{0}_{1}", prefix, 
						m.Groups[m.Groups["a"].Success ? "a" : "b"].Value);
					if (!hits.Contains(hit))
						hits.Add(hit);
				}
			return (string[])hits.ToArray(typeof(string));
		}

		static string[] FindIdentifiersInCode(string file)
		{
			string prefix = Path.GetFileNameWithoutExtension(file).ToLower();
			string pattern = "[^a-z]GetLocalString\\s*\\([^,)]+,\\s*\"([^\"]+)\"";
			if (file.EndsWith(".ascx.cs"))
			{
				prefix = "_" + Path.GetFileNameWithoutExtension(prefix);
				pattern = "[^a-z](?:GetLocalString|ShowError)\\s*\\((?:[^,)]+,\\s*)??\"([^\"]+)\"";
			}
			else if (file.EndsWith(".aspx.cs"))
				prefix = Path.GetFileNameWithoutExtension(prefix);
			string content;
			using (StreamReader reader = File.OpenText(file))
				content = reader.ReadToEnd().Replace('\n', ' ').Replace('\r', ' ');
			Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
			ArrayList hits = new ArrayList();
			foreach (Match m in regex.Matches(content))
			{
				string hit = String.Format("{0}_{1}", prefix, m.Groups[1].Value);
				if (!hits.Contains(hit))
					hits.Add(hit);
			}
			return (string[])hits.ToArray(typeof(string));
		}

		static string[] FindIdentifiers(string file)
		{
			if (file.EndsWith(".cs"))
				return FindIdentifiersInCode(file);
			else
				return FindIdentifiersInPage(file);
		}

		static string[] AvailableTranslations(string file)
		{
			ArrayList available = new ArrayList();
			DataTable table;
			using (StreamReader reader = new StreamReader(file, System.Text.Encoding.Default))
				table = CsvParser.Parse(reader, true);
			foreach (DataRow row in table.Rows)
				available.Add(row[0].ToString());
			available.Sort();
			return (string[])available.ToArray(typeof(string));
		}

		static string[] ReadIgnoreFile(string file)
		{
			ArrayList ignores = new ArrayList();
			using (StreamReader reader = File.OpenText(file))
				ignores.AddRange(reader.ReadToEnd().Split('\n', '\r'));
			return (string[])ignores.ToArray(typeof(string));
		}

		[Test]
		public void CheckLocalization()
		{
			string directory = Path.GetFullPath(@"..\..");
			string webdirectory = Path.Combine(directory, @"..\wwwroot");
			string localizationfile = Path.Combine(directory, "localization.csv");
			string ignorefile = Path.Combine(directory, "ignore.txt");

			Console.WriteLine("Current path: {0}", Directory.GetCurrentDirectory());
			Console.WriteLine("Directory: {0}", directory);
			Console.WriteLine("Web Directory: {0}", webdirectory);

			Assert.IsTrue(File.Exists(localizationfile));
			Assert.IsTrue(File.Exists(ignorefile));
			Assert.IsTrue(Directory.Exists(webdirectory));

			string[] ignores = ReadIgnoreFile(ignorefile);

			DirectoryInfo rootdir = new DirectoryInfo(webdirectory);
			
			ArrayList result = new ArrayList();
			foreach (string file in FindFiles(rootdir, "*.cs"))
				result.AddRange(FindIdentifiers(file));
			foreach (string file in FindFiles(rootdir, "*.as?x"))
				result.AddRange(FindIdentifiers(file));
			result.Sort();

			Console.WriteLine("*** Found {0} translateable terms", result.Count);

			string[] available = AvailableTranslations(localizationfile);
			ArrayList unused = new ArrayList(available);

			foreach (string r in result)
				unused.Remove(r);
			foreach (string a in available)
				result.Remove(a);
			foreach (string i in ignores)
			{
				result.Remove(i);
				unused.Remove(i);
			}

			Console.WriteLine("*** Found {0} unused translations:", unused.Count);
			foreach (string u in unused)
				Console.WriteLine(u);

			Console.WriteLine("*** Found {0} missing translations:", result.Count);
			foreach (string s in result)
				Console.WriteLine(s);

			Assert.AreEqual(0, unused.Count);
			Assert.AreEqual(0, result.Count);
		}
	}
}
