using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.IO;
namespace bindingGen
{
	/// 
	/// 输入目录,在目录下生成./binding目录,存放导出的binding代码
	/// 
	class Program
	{
		// {0} 文件名
		// {1} 第一个名称空间
		// {2} 第二个名称空间
		// {3} 内容
		static string output = @"#include ""../{0}.h""
using namespace std;
using namespace Luax;
namespace {1} 
{{
	namespace {2} 
	{{
		{3}
	}}
}}
";
		// {0} 类名
		// {1} 内容
		static string registry = @"
		LUAX_REGISTRY({0})
		{{
{1}
		}}
";
		// {0} 类名
		// {1} 内容
		static string postprocess = @"
		LUAX_POSTPROCESS({0})
		{{
{1}
		}}
";
		// {0} 类名
		// {1} 去掉_的函数名
		// {2} 小写的类名
		static string method = @"
		// {2}:{1}()
		LUAX_IMPL_METHOD({0}, _{1})
		{{
			LUAX_PREPARE(L, {0});
			return 0;
		}}
";
		// {0} 类名
		// {1} 去掉_的函数名
		static string method_new = @"
		// {0}.{1}()
		LUAX_IMPL_METHOD({0}, _{1})
		{{
			LUAX_STATE(L);
			return 0;
		}}
";
		static string make_register_methods(MatchCollection methods)
		{
			if (methods.Count == 0)
				return "";
			string register_methods = "";
			register_methods += "\t\t\tLUAX_REGISTER_METHODS(state,\n";
			int maxlen = 0;
			foreach (var m in methods)
			{
				string method = m.ToString();
				if (method.Count() > maxlen)
					maxlen = method.Count();
			}
			for (int i = 0; i < methods.Count; ++i)
			{
				Match m = methods[i];
				string method = m.ToString();
				register_methods += "\t\t\t\t";
				register_methods += "{ ";
				register_methods += ('"' + method.Substring(1, method.Count() - 1) + "\",").PadRight(maxlen + 3, ' ');
				register_methods += method.PadRight(maxlen + 1, ' ');
				register_methods += "}";
				if (i != methods.Count - 1)
					register_methods += ',';
				register_methods += '\n';
			}
			register_methods += "\t\t\t);";
			return register_methods;
		}
		static string make_impl_methods(MatchCollection mc, string cname)
		{
			if (mc.Count == 0)
				return "";
			string methods = "";
			foreach (var m in mc)
			{
				string name = m.ToString();
				if (name != "_New")
				{
					methods += String.Format(method, cname, name.Substring(1, name.Count() - 1), cname.ToLower());
				}
				else
				{
					methods += String.Format(method_new, cname, name.Substring(1, name.Count() - 1));
				}
			}
			return methods;
		}
		static int IndexOfChar(string str, char c, int n)
		{
			int j = 0;
			for (int i = 0; i < str.Count(); ++i)
			{
				char ch = str[i];
				if (ch == c)
				{
					if (j == n)
						return i;
					++j;
				}
			}
			return -1;
		}
		static string make_register_enum(MatchCollection mc, string src)
		{
			if (mc.Count == 0)
				return "";
			string reg_enum_l = @"(?<=enum\s*";
			string reg_enum_r = @"[\s\n]*\{((?!\})[\s\S])*\s)[A-Z_0-9]+(?=[\s\=,]+)";
			string enums = "";
			// 尝试查找下划线索引号,如果没有,代表这个枚举字符串全部都是key
			string reg_under_line_l = @"(?<=LUAX_DECL_ENUM\s*\(\s*";
			string reg_under_line_r = @"\s*,\s*)[0-9]+(?=\s*\))";
			foreach (var m in mc)
			{
				string name = m.ToString();
				enums += "\t\t\tLUAX_REGISTER_ENUM(state, ";
				enums += "\"E" + name + "\",\n";
				MatchCollection values = Regex.Matches(src, reg_enum_l + name + reg_enum_r);
				string[] enames = new string[values.Count];
				string[] keys = new string[values.Count];
				int underline_index = -1;
				Match underline = Regex.Match(src, reg_under_line_l + name + reg_under_line_r);
				if (underline.Success)
				{
					underline_index = int.Parse(underline.ToString());
				}
				int maxEname = 0, maxKey = 0;
				for (int i = 0; i < values.Count; ++i)
				{
					enames[i] = values[i].ToString();
					if(underline_index != -1)
					{
						int start = IndexOfChar(enames[i], '_', underline_index) + 1;
						keys[i] = enames[i].Substring(start, enames[i].Count() - start);
					}
					else
					{
						// 表明全部都是key
						keys[i] = enames[i];
					}
					if (enames[i].Count() > maxEname) maxEname = enames[i].Count();
					if (keys[i].Count() > maxKey) maxKey = keys[i].Count();
				}
				for (int i = 0; i < values.Count; ++i)
				{
					enums += "\t\t\t\t{ ";
					enums += ('"' + keys[i] + "\",").PadRight(maxKey + 4);
					enums += enames[i].PadRight(maxEname + 1);
					enums += "}";
					if (i != values.Count - 1)
						enums += ",";
					enums += "\n";
				}
				enums += "\t\t\t);\n";
			}
			return enums;
		}
		/// 
		/// 用法: 
		///	bindingGen <目录>
		/// 
		/// 
		static void Main(string[] args)
		{
			if (args.Length < 1)
				return;
			string dir = args[0];
			Console.WriteLine("源目录: " + dir);
			if (!Directory.Exists(dir))
				return;
			string reg_class = @"(?<=Portable\<)[0-9a-zA-Z]+(?=\>)";
			string reg_abclass = @"(?<=LUAX_DECL_ABSTRACT_FACTORY\s*\(\s*)[0-9a-zA-Z]+(?=\s*\))";
			string reg_methods = @"(?<=LUAX_DECL_METHOD\()[0-9a-zA-Z_]+(?=\))";
			string reg_enums = @"(?<=LUAX_DECL_ENUM\()[0-9a-zA-Z_]+(?=\s*[\),]+)";
			string reg_namespace = @"(?<=namespace\s)[0-9a-zA-Z]+(?=[\s\n]*\{)";
			if (!Directory.Exists(dir + "/binding"))
			{
				Directory.CreateDirectory(dir + "/binding");
			}
			string[] files = Directory.GetFiles(dir);
			for (int i = 0; i < files.Count(); ++i)
			{
				string file = files[i];
				if (!File.Exists(file))
					continue;
				file = file.Replace('\\', '/');
				string name = file.Substring(file.LastIndexOf('/') + 1, file.LastIndexOf('.') - file.LastIndexOf('/') - 1);
				string bindingFile = dir + "/binding/_" + name + ".cpp";
				if (File.Exists(bindingFile))
					continue;
				string code = File.ReadAllText(file);
				// 工厂和单例
				Match m = Regex.Match(code, reg_class);
				string className = "";
				if (m.Success)
				{
					className = m.ToString();
				}
				if (!m.Success)
				{
					// 抽象类,不会继承Portable模板
					Match abstract_m = Regex.Match(code, reg_abclass);
					if (!abstract_m.Success)
						continue;
					className = abstract_m.ToString();
				}
				MatchCollection mc = Regex.Matches(code, reg_namespace);
				// 应该两个名称空间
				if (mc.Count != 2)
				{
					Console.WriteLine("Error: 源文件没有两个名称空间 " + file);
					continue;
				}
				string namespace1 = mc[0].ToString();
				string namespace2 = mc[1].ToString();
				// 名称空间内的内容
				string content = "";
				mc = Regex.Matches(code, reg_methods);
				content += String.Format(registry, className, make_register_methods(mc));
				mc = Regex.Matches(code, reg_enums);
				content += String.Format(postprocess, className, make_register_enum(mc, code));
				mc = Regex.Matches(code, reg_methods);
				content += make_impl_methods(mc, className);
				string binding = String.Format(output, name, namespace1, namespace2, content);
				Console.WriteLine("输出: " + bindingFile);
				File.WriteAllText(bindingFile, binding);
			}
		}
	}
}