using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace m3uTool
{
	public class LongestCommonSubstrings
	{
		//def longest_common_substrings(S, T):
		//    maks = 0        # length of longest match
		//    ret = Set([""]) # the longest matches we have found
		//    last = {}       # length of matches ending at S[i-1] and
		//    next = {}       # at S[i] for T[0]...T[n-1]
		//    for i in xrange(len(S)):
		//        for j in xrange(len(T)):
		//            if S[i] == T[j]:
		//                if j-1 in last:
		//                    next[j] = last[j-1] + 1
		//                else:
		//                    next[j] = 1
		//                if next[j] > maks:
		//                    maks = next[j]
		//                    ret = Set()
		//                if next[j] == maks:
		//                    ret.add(S[i-maks+1:i+1]) # equals T[j-maks+1:j+1]
		//        last = next
		//        next = {}
		//    return ret
		
		public static List<string> GetLongestSubstring(string s, string t)
		{
			int maks = 0;
			List<string> ret = new List<string>();
			Dictionary<int, int> last = new Dictionary<int, int>();
			Dictionary<int, int> next = new Dictionary<int, int>();
			for (int i = 0; i < s.Length; i++)
			{
				for (int j = 0; j < t.Length; j++)
				{
					if (s[i] == t[j])
					{
						if (last.ContainsKey(j-1))
							next[j] = last[j - 1] + 1;
						else
							next[j] = 1;
						
						if (next[j] > maks)
						{
							maks = next[j];
							ret.Clear();
						}
						if (next[j] == maks)
							ret.Add(s.Substring(i - maks + 1, maks));
					}
				}
				last = next;
				next = new Dictionary<int, int>();
			}

			return ret;
		}
	}
	
	public class LongestCommonSequence<T> where T : IEnumerable
	{
		public enum BackTracking {
			NEITHER,
			UP,
			LEFT,
			UP_AND_LEFT
		}

		private static int ConsecutiveMeasure(int k)
		{
			//f(k)=k*a - b;
			return k*k;
		}
		
		//public T DoLCS(T list1, T list2)
		//{
			
		//}

		private object[] LCS(object[] list1, object[] list2) 
		{
			int m=list1.Length ;
			int n=list2.Length ;
			
			int[,] lcs=new int[m+1, n+1];
			BackTracking[ , ] backTracer=new BackTracking[m+1, n+1];
			int[,] w=new int[m+1, n+1];
			int i, j;

			for (i = 0; i <= m; i++) 
			{
				lcs[i,0] = 0;
				backTracer[i,0]=BackTracking.UP;
				
			}
			for (j = 0; j <= n; j++) 
			{
				lcs[0,j]=0;
				backTracer[0,j]=BackTracking.LEFT;				
			}

			for (i = 1; i <= m; i++) 
			{
				for (j = 1; j <= n; j++) 
				{ 
					if(list1[i-1] == list2[j-1]) 
					{
						int k = w[i-1, j-1];
						//lcs[i,j] = lcs[i-1,j-1] + 1;
						lcs[i,j]=lcs[i-1,j-1] + ConsecutiveMeasure(k+1) - ConsecutiveMeasure(k);
						backTracer[i,j] = BackTracking.UP_AND_LEFT;
						w[i,j] = k+1;						
					}
					else 
					{
						lcs[i,j] = lcs[i-1,j-1];
						backTracer[i,j] = BackTracking.NEITHER;
					}

					if(lcs[i-1,j] >= lcs[i,j]) 
					{	
						lcs[i,j] = lcs[i-1,j];
						backTracer[i,j] = BackTracking.UP;
						w[i,j] = 0;
					}

					if(lcs[i,j-1] >= lcs[i,j]) 
					{
						lcs[i,j] = lcs[i,j-1];
						backTracer [i,j] = BackTracking.LEFT;
						w[i,j] = 0;
					}
				}
			}
			
			i=m; 
			j=n;

			Stack<object> subseq = new Stack<object>();
			// int p=lcs[i,j];

			//trace the backtracking matrix.
			while( i > 0 || j > 0 ) 
			{
				if( backTracer[i,j] == BackTracking.UP_AND_LEFT ) 
				{
					i--;
					j--;
					subseq.Push(list1[i]);
					// subseq = list1[i] + subseq;
					Trace.WriteLine(i + " " + list1[i] + " " + j) ;
				}
	
				else if( backTracer[i,j] == BackTracking.UP ) 
				{
					i--;
				}
	
				else if( backTracer[i,j] == BackTracking.LEFT ) 
				{
					j--;
				}
			}
			
			
			return subseq.ToArray();
		}
	}
}
