using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Text.RegularExpressions;

namespace FindLinx
{
	public partial class frmFindLinx : Form
	{
		public frmFindLinx()
		{
			InitializeComponent();
		}
		public string MyStatus
		{
			get { return tsslStatus.Text; }
			set { tsslStatus.Text = value; Application.DoEvents(); }
		}
		private static string _SelectedDatabase = null;
		public static string SelectedDatabase
		{
			get { return frmFindLinx._SelectedDatabase; }
			set 
			{ 
				frmFindLinx._SelectedDatabase = value;
				_ConnectionString = _MenuConnectionString.Replace("{MENU}", SelectedDatabase);
			}
		}
		private static string _MenuConnectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog={MENU};Integrated Security=True";
		private static string _ConnectionString = null;
		private Dictionary<int, string> _MyContents = null;
		private void chooseDBToolStripMenuItem_Click(object sender, EventArgs e)
		{
			ChooseDatabase();
			findLinxToolStripMenuItem.Enabled = true;
			LoadContents();
			ResetLinks();
			FindLinks();
			ShowLinks(SelectedDatabase);
		}
		private void ChooseDatabase()
		{
			System.Windows.Forms.ContextMenuStrip cms = BuildDatabaseMenu();
			SelectedDatabase = null;
			while (SelectedDatabase == null)
			{
				cms.Show(new System.Drawing.Point((System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - cms.Width) / 2, (System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - cms.Height) / 2));
				System.Windows.Forms.Application.DoEvents();
			}
		}
		private static System.Windows.Forms.ContextMenuStrip BuildDatabaseMenu()
		{
			System.Windows.Forms.ContextMenuStrip cms = new System.Windows.Forms.ContextMenuStrip();
			cms.Items.Add("Choose Database");
			System.Windows.Forms.ToolStripMenuItem tsmi = cms.Items[0] as System.Windows.Forms.ToolStripMenuItem;
			tsmi.BackColor = System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.ActiveCaption);// System.Drawing.Color.Pink;
			tsmi.ForeColor = System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.ActiveCaptionText);
			tsmi.Font = new System.Drawing.Font(tsmi.Font, System.Drawing.FontStyle.Bold);
			foreach (string name in DBNames)
				cms.Items.Add(name, null, new EventHandler(Database_Click));
			return cms;
		}
		private static List<string> _DBNames;
		public static List<string> DBNames
		{
			get 
			{
				if (_DBNames == null)
					_DBNames = GetDatabases();
				return _DBNames; 
			}
		}
		private static List<string> GetDatabases()
		{
			List<string> dbNames;
			dbNames = new List<string>();
			SelectedDatabase = "master";
			SqlConnection cn = new SqlConnection(_ConnectionString);
			cn.Open();
			//			SqlDataAdapter da = new SqlDataAdapter("select name from sysdatabases where name like 'VEP%' order by name", cn);
			//SqlDataAdapter da = new SqlDataAdapter("select name, case when object_id('[' + name + ']..Items') is null then 'Not PROMS' when object_id('[' + name + ']..Revisions') is not null then 'Approval' when object_id('[' + name + ']..ContentAudits') is not null then 'Change Manager' else 'Original' end functionality from sysdatabases where name not in ('master','model','msdb','tempdb') order by name", cn);
			SqlDataAdapter da = new SqlDataAdapter("select name from sysdatabases where name not in ('master','model','msdb','tempdb') and name like 'VEPROMS%' order by name", cn);
			da.SelectCommand.CommandTimeout = 300; // 300 sec timeout
			DataSet ds = new DataSet();
			try
			{
				da.Fill(ds);
			}
			catch (Exception ex)
			{
				System.Windows.Forms.MessageBox.Show(ex.GetType().Name, ex.Message);
				throw (new Exception("Cannot Load Data List", ex));
			}
			cn.Close();
			foreach (DataRow dr in ds.Tables[0].Rows)
				dbNames.Add(dr["name"].ToString());
			return dbNames;
		}
		private static void Database_Click(object sender, EventArgs e)
		{
			System.Windows.Forms.ToolStripMenuItem tsmi = sender as System.Windows.Forms.ToolStripMenuItem;
			if (tsmi != null)
			{
				SelectedDatabase = tsmi.Text;
			}
		}
		private void findLinxToolStripMenuItem_Click(object sender, EventArgs e)
		{
			FindLinks();
		}
		private	Dictionary<string, int> DicPrefix;
		private Dictionary<string, int> DicSuffix;
		private void ResetLinks()
		{
			DicPrefix = new Dictionary<string, int>();
			DicSuffix = new Dictionary<string, int>();
		}
		private void ShowLinks(string selectedDatabase)
		{
			tbResults.Clear();
			SortedList<int, string> srtPrefixes = new SortedList<int, string>(new DegreeComparer());
			foreach (string pre in DicPrefix.Keys)
			{
				srtPrefixes.Add(-DicPrefix[pre], pre);
			}
			tbResults.AppendText(string.Format("{0} Prefixes\r\n", selectedDatabase));
			foreach (string pre in srtPrefixes.Values)
			{
				tbResults.AppendText(string.Format("{0},'{1}'\r\n", DicPrefix[pre], pre));
			}
			SortedList<int, string> srtSuffixes = new SortedList<int, string>(new DegreeComparer());
			foreach (string suf in DicSuffix.Keys)
			{
				srtSuffixes.Add(-DicSuffix[suf], suf);
			}
			tbResults.AppendText(string.Format("\r\n{0} Suffixes\r\n", selectedDatabase));
			foreach (string suf in srtSuffixes.Values)
			{
				tbResults.AppendText(string.Format("{0},'{1}'\r\n", DicSuffix[suf], suf));
			}
		}
		private void FindLinks()
		{
			// loop through contents
			foreach (int ic in _MyContents.Keys)// for each content record
			{
				string Text = _MyContents[ic];
				// find all links
				string findLink = @"<START\].*?\[END>";
				MatchCollection ms = Regex.Matches(Text, findLink);
				int lastlink = 0;
				int ii = 0;
				foreach (Match mlink in ms)// for each link
				{
					string key = string.Format("{0}.{1}.{2}", _SelectedDatabase, ic, ii);
					if (key == "VEPROMS_BWD.16964.0") Console.WriteLine("Here");
					//tbResults.AppendText(mlink.ToString() + "\r\n");
					// get the prefix and the suffix
					string prefix = GetPrefix(Text, mlink, lastlink);
					//if (prefix.Contains("Pumps")) Console.WriteLine("here");
					string prefix1 = PrefixPattern(prefix);
					if (prefix == "\\v0\\v ")
					{
						Console.WriteLine(key);
					}
					if (!DicPrefix.ContainsKey(prefix1))
						DicPrefix.Add(prefix1, 1);
					else
						DicPrefix[prefix1]++;
					string suffix = GetSuffix(Text, mlink,((ii+1)<ms.Count) ? ms[ii+1].Index : Text.Length);
					string suffix1 = SuffixPattern(suffix);
					if (!DicSuffix.ContainsKey(suffix1))
						DicSuffix.Add(suffix1, 1);
					else
						DicSuffix[suffix1]++;
					lastlink = mlink.Index + mlink.Length;
					ii++;
					if (ii < ms.Count && ms[ii].Index > lastlink + suffix.Length)
						lastlink += suffix.Length;
				}
			}
		}
		private string SuffixPattern(string suffix)
		{
			string firstchar = "";
			suffix = suffix.Replace("\r", "{CR}");
			suffix = suffix.Replace("\n", "{LF}");
			if (Regex.IsMatch(suffix, @"^(\\(b0|b|ulnone|ul))+\\"))
			{
				firstchar = "{RTFCommand}";
				suffix = Regex.Replace(suffix, @"^(\\(b0|b|ulnone|ul))+", "");
			}
			if (suffix == @"\v0 ")
				return @"Pattern','" + firstchar + @"\v0{Space}";
			if (suffix == @"\v0")
				return @"Pattern','" + firstchar + @"\v0";
			return _SelectedDatabase + "','" + suffix;
		}
		private string GetSuffix(string Text, Match mlink, int iEnd)
		{
			int iStart = mlink.Index + mlink.Length;
			//int iEnd = (mlink.NextMatch() == null) ? Text.Length : mlink.NextMatch().Index;
			string follows = Text.Substring(iStart,iEnd-iStart);
			int iEndComment = follows.IndexOf("\\v0");
			if (follows.Length > 3 + iEndComment)
			{
				if (follows.Substring(iEndComment + 3, 1) == " ")
					return follows.Substring(0, iEndComment + 4);
				if (follows.Substring(iEndComment + 3, 1) == "\\")
					return follows.Substring(0, iEndComment + 3);
				return follows.Substring(0, iEndComment + 3);
			}
			return follows;
		}
		public class DegreeComparer : IComparer<int>
		{
			#region IComparer<int> Members
			public int Compare(int x, int y)
			{
				if (x < y)
					return -1;
				else
					return 1;
			}
			#endregion
		}
		private string PrefixPattern(string prefix)
		{
			string firstchar = "";
			if(prefix.StartsWith(" "))
			{
				firstchar = "{Space}";
				prefix = prefix.Substring(1);
			}
			else if (prefix.StartsWith("\n"))
			{
				firstchar = "{Newline}";
				prefix = prefix.Substring(1);
			}
			else if (prefix.StartsWith("\xa0"))
			{
				firstchar = "{HardSpace}";
				prefix = prefix.Substring(1);
			}
			else if (Regex.IsMatch(prefix, @"^\\u[0-9]{1,4}\?"))
			{
				firstchar = "{Unicode}";
				prefix=Regex.Replace(prefix, @"^\\u[0-9]{1,4}\?","");
			}
			else if (Regex.IsMatch(prefix, @"^\\'[0-9a-fA-F]{2}"))
			{
				firstchar = "{Hexcode}";
				prefix = Regex.Replace(prefix, @"^\\'[0-9a-fA-F]{2}", "");
			}
			else if (Regex.IsMatch(prefix, @"^[:.()\[\]""*=<>]"))
			{
				firstchar = "{Punctuation}";
				prefix = Regex.Replace(prefix, @"^[:.()\[\]""*=<>]", "");
			}
			else if (Regex.IsMatch(prefix, @"^\\[{}~]"))
			{
				firstchar = "{Special}";
				prefix = Regex.Replace(prefix, @"^\\[{}~]", "");
			}
			else if (Regex.IsMatch(prefix, @"^\\(b0|b|ulnone|ul|line)\\"))
			{
				firstchar = "{RTFCommand}";
				prefix = Regex.Replace(prefix, @"^\\(b0|b|ulnone|ul|line)", "");
			}
			if (prefix == @"\v ")
				return @"Pattern','" + firstchar +@"\v ";
			//if (prefix == @" \v ")
			//  return @"Pattern-{Space}\v ";
			//if (prefix == "\xA0\\v ")
			//  return @"Pattern-{HardSpace}\v ";
			//if (Regex.IsMatch(prefix, @"^\\u[0-9]{1,4}\?\\v $"))
			//	return @"Pattern-" + firstchar + @"{Unicode}\v ";
			//if (Regex.IsMatch(prefix, @"^\\u[0-9]{1,4}\?.*\\v $"))
			//	return @"Pattern-" + firstchar + @"{Unicode}{Text}\v ";
//			if (Regex.IsMatch(prefix, @"^\\[{}~]\\v $"))
//				return @"Pattern-" + firstchar + @"{Special}\v ";
//			if (Regex.IsMatch(prefix, @"^ ?[()""\[\]]\\v $"))
//				return @"Pattern-" + firstchar + @"{Puctuation}\v ";
			if (Regex.IsMatch(prefix, @"^ ?[-%A-Za-z0-9.,/()\[\]]+\\v $"))
				return @"Pattern','" + firstchar + @"{Text}\v ";
			//if (prefix == "\n\\v ")
			//  return @"Pattern-{Newline}\v ";
			return SelectedDatabase + "','" + prefix;
		}
		private string GetPrefix(string Text, Match mlink, int lastlink)
		{
			string precedes = Text.Substring(lastlink, mlink.Index - lastlink);
				if(mlink.Index - lastlink <= 3)
					return precedes;

			if (precedes.EndsWith(@"\v "))
			{
				//int indexSpace = Text.LastIndexOf(' ', mlink.Index - 4);
				////if (indexSpace > mlink.Index) indexSpace = 0;
				//int indexCR = Text.LastIndexOf('\n', mlink.Index - 4);
				////if (indexCR > mlink.Index) indexCR = 0;
				//if (indexCR >= 0 && indexCR > indexSpace)
				//  indexSpace = indexCR;
				//int indexHS = Text.LastIndexOf('\xA0', mlink.Index - 4);
				////if (indexHS > mlink.Index) indexHS = 0;
				//if (indexHS >= 0 && indexHS > indexSpace)
				//  indexSpace = indexHS;
				int indexSpace = Text.LastIndexOfAny(" \n\xA0:.()[]\"<>*=".ToCharArray(), mlink.Index - 4);
				int indexSlash = Text.LastIndexOf('\\', mlink.Index - 4);
				if (indexSlash >= 0)
				{
					if (indexSlash > indexSpace)
						return Text.Substring(indexSlash, mlink.Index - indexSlash);
				}
				if (indexSpace >= 0)
				{
					return Text.Substring(indexSpace, mlink.Index - indexSpace);
				}
			}
			return precedes;
		}
		private void LoadContents()
		{
			SqlConnection cn = new SqlConnection(_ConnectionString);
			cn.Open();
			SqlDataAdapter da = new SqlDataAdapter("select ContentID,Text from Contents where ContentID in(select fromID from transitions union select contentid from rousages)", cn);
			da.SelectCommand.CommandTimeout = 300; // 300 sec timeout
			DataSet ds = new DataSet();
			try
			{
				da.Fill(ds);
				_MyContents = new Dictionary<int, string>();
				foreach (DataRow dr in ds.Tables[0].Rows)
				{
					_MyContents.Add((int)dr["ContentID"], dr["Text"].ToString());
				}
				//MessageBox.Show(string.Format("{0} Content Records Found", ds.Tables[0].Rows.Count), "Contents Loaded", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			catch (Exception ex)
			{
				System.Windows.Forms.MessageBox.Show(ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
				throw (new Exception("Cannot Load Data List", ex));
			}
			cn.Close();
		}

		private void allDBsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			DateTime tStart = DateTime.Now;
			ResetLinks();
			foreach (string dbName in DBNames)
			{
				SelectedDatabase = dbName;
				LoadContents();
				MyStatus = string.Format("{0} - {1} Contents", SelectedDatabase, _MyContents.Count);
				FindLinks();
			}
			ShowLinks("All Databases");
			DateTime tEnd = DateTime.Now;
			TimeSpan ts = TimeSpan.FromTicks(tEnd.Ticks - tStart.Ticks);
			MyStatus = string.Format("{0:0.000} Seconds", ts.TotalSeconds);
		}
		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Close();
		}
	}
}