using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using System.IO;

using edu.jhu.Cas.Util;

namespace edu.jhu.Cas.Test{
	public abstract class BaseTest{
		protected string tName,qry,cString;
		protected int threads,iterations;
		
		public BaseTest(string tName_,string cString_,string qry_, int threads_,int iterations_){
			tName = tName_;
			qry = qry_;
				threads = threads_;
			cString = cString_;
			iterations = iterations_;
		}
		public abstract TimedTest GetTest();

		public void Go(){
			int f = 15;
			qry = qry.Trim();
			StreamWriter writer = new StreamWriter((qry.Remove(f,qry.Length-f)+"_"+threads+".csv").Replace("*","star"));
			
			for(int x=0;x<threads;x++){
				writer.Write("test_"+x);
				if(x != threads-1)
					writer.Write(",");
			}
			writer.WriteLine();
			for(int y=0;y<iterations;y++){
				Thread[] all = new Thread[threads];
				TimedTest[] tests = new TimedTest[threads];
				for(int x=0;x<all.Length;x++){
					tests[x] = GetTest();
					all[x] = new Thread(new ThreadStart(tests[x].Go));
				}
				for(int x=0;x<all.Length;x++)
					all[x].Start();
				Console.WriteLine(threads+" threads started.");
				foreach(Thread t in all)
					t.Join();
				TimeSpan Max = tests[0].Elapsed;
				TimeSpan Min = tests[0].Elapsed;
				for(int x=0; x< tests.Length;x++){
					TimedTest t = tests[x];
					if(t.Elapsed > Max) Max = t.Elapsed;
					if(t.Elapsed < Min) Min = t.Elapsed;
					writer.Write(t.Elapsed.ToString());
					if(x != threads-1)
						writer.Write(",");
				}
				Console.WriteLine(Max);
				writer.WriteLine();
				Console.WriteLine("iteration complete");
			}
			writer.Close();
			Console.WriteLine("all iterations complete");
			
		}
	}

	public class NormalTest:BaseTest{
		
		public NormalTest(string a,string b, string c,int d,int e):base(a,b,c,d,e){}
		public override TimedTest GetTest(){
			return new NormalObject(cString,qry,tName);
		}

		class NormalObject:TimedTest{
			private string cString,qry,tName;
				
			public NormalObject(string cString_,string qry_,string tName_):base(){
				cString = cString_;
				tName = tName_+"_"+this_cnt.ToString();
				qry = qry_.Replace(tName_,tName);
			}
			public override void Work(){
				SqlConnection con = new SqlConnection(cString);
				con.Open();
				SqlCommand com = new SqlCommand(cString,con);
				com.CommandTimeout = 0;
				com.CommandText = qry;
				com.ExecuteNonQuery();
				com.CommandText = "drop table "+tName.Split('.')[2];
				com.ExecuteNonQuery();
				con.Close();
			}
		}
	}
	
	public class DRTest:BaseTest{
		public string mydb_string;
		public DRTest(string a,string b, string mydb_string_,string c,int d,int e):base(a,b,c,d,e){
			mydb_string = mydb_string_;
		}
		
		public override TimedTest GetTest(){
			return new DRObject(cString,mydb_string,qry,tName);
		}
		
		class DRObject:TimedTest{
			private string cString,qry,tName,mydb_string;
				
			public DRObject(string cString_,string mydb,string qry_,string tName_):base(){
				cString = cString_;
				mydb_string = mydb;
				tName = tName_+"_"+this_cnt.ToString();
				qry = qry_;
			}

			public override void Work(){
			
				DataReaderTest tst = new DataReaderTest(cString,mydb_string);
				tst.Run(tName,qry);
				SqlConnection con = new SqlConnection(mydb_string);
				con.Open();
				SqlCommand com = new SqlCommand(qry,con);
				com.CommandText = "drop table "+tName.Split('.')[2];
				com.ExecuteNonQuery();
				con.Close();
			}
		}
	}
	
	public class SPDRTest:DRTest{
		public string mydb_string;
		
		public SPDRTest(string a,string b, string mydb_string_,string c,int d,int e):base(a,b,mydb_string_,c,d,e){
			mydb_string = mydb_string_;
		}
		
		public override TimedTest GetTest(){
			return new SPDRObject(cString,mydb_string,qry,tName);
		}
		
		class SPDRObject:TimedTest{
			private string cString,qry,tName,mydb_string;
				
			public SPDRObject(string cString_,string mydb,string qry_,string tName_):base(){
				cString = cString_;
				mydb_string = mydb;
				tName = tName_+"_"+this_cnt.ToString();
				qry = qry_;
			}

			public override void Work(){
			
				DataReaderTest tst = new DataReaderTest(cString,mydb_string);
				tst.SPRun(tName,qry);
				SqlConnection con = new SqlConnection(mydb_string);
				con.Open();
				SqlCommand com = new SqlCommand(qry,con);
				com.CommandText = "drop table "+tName;
				com.ExecuteNonQuery();
				con.Close();
			}
		}
	}
	public class TimedTest{
		public TimeSpan Elapsed;
		protected static int all_cnt;
		protected int this_cnt;
			
		public TimedTest(){
			++all_cnt;
			this_cnt = all_cnt;
		}
		public virtual void Go(){
			DateTime start = DateTime.Now;
			Work();
			Elapsed = DateTime.Now - start;
			Console.WriteLine("Test "+this_cnt+" Elapsed: "+Elapsed.ToString());
		}
		public virtual void Work(){}
		
	}

}