using System;
using System.Collections.Generic;
using System.Collections;
using HTM;

namespace HtmTest
{
	using NUnit.Framework;
	[TestFixture]
	public class Program
	{
		public static void Main(string[] args) {
			System.Console.Out.WriteLine("Main {0} = {1}", 2 * 2, 4);
			Program p = (new Program());
			p.T1();
			try {
				int inc = System.Console.In.Read();
			} catch {
			}
		}

		public static int ComparisonRanges(Int64Pair a, Int64Pair b) {
			return a.lo.CompareTo(b.lo);
		}
		public static void addrange(List<Int64Pair> range, Int64 x, Int64 y) {
			Int64Pair a;
			a.lo = x;
			a.hi = y;
			range.Add(a);
		}

		[Test]
		public void TZSort() {

			Interval foo = new Interval();
			List<Int64Pair> bar = new List<Int64Pair>();

			foo.AddRange(1L, 2L);
			addrange(bar, 3L, 4L);
			foo.merge(bar);
			//List<Int64Pair> xx = new List<Int64Pair>();

			//addrange(xx, 101L, 102L);
			//addrange(xx, 1L, 2L);
			//xx.Sort(ComparisonRanges);
			//foreach (Int64Pair i in xx) {
			//    System.Console.WriteLine("({0}, {1})", i.lo, i.hi);
			//}
			Assert.IsTrue(true);
		}
		[Test]
		public void TSortConvex() {
			Convex c = new Convex();
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, 0.1));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, -0.1));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, 0.4));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, -0.6));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, 0.8));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, -0.5));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, 1.0));
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, -1.0));
			// ConvexTrixel.sort(c);
			foreach (Halfspace h in c.halfspaceList) {
				System.Console.WriteLine(h.cos0);
			}
			Assert.IsTrue(true);
		}
		[Test]
		public void T0() {
			Region r = new Region();
			Convex c = new Convex();
			c.halfspaceList.Add(new Halfspace(
				0.0, 0.0, 1.0, false, 0.984807753012208
				));
			c.halfspaceList.Add(new Halfspace(
				0.0, 0.0, -1.0, false, -0.985109326154774
				));
			c.halfspaceList.Add(new Halfspace(
				-0.4067366430758, 0.913545457642601, 0.0, false, 0.0
				));
			c.halfspaceList.Add(new Halfspace(
				0.408330460381385, -0.912834177233043, 0.0, false, 0.0));


			System.Console.Out.WriteLine("Convex Before {0}", c);
			System.Console.Out.WriteLine("Convex After {0}", c);

			r.convexList.Add(c);
			SuperRegion sr = new SuperRegion(r, false, false);
			Patch pat = sr.convexList[0].patchList[0];
			System.Console.Out.WriteLine("Patch 0 is length {0}", pat.arcList.Length);
			for (int i = 0; i < pat.arcList.Length; i++) {
				System.Console.Out.WriteLine("{0} ", pat.arcList[i].p1);
				System.Console.Out.WriteLine("{0} ", pat.arcList[i].p2);
				System.Console.Out.WriteLine("--------");
			}

			Assert.IsTrue(true);

		}
		[Test]
		public void T1() {
			Region r = new Region();
			Convex c = new Convex();
			int n;
			//c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, -0.6));
			//c.halfspaceList.Add(new Halfspace(0.0, 1.0, 0.0, false, -0.6));
			//c.halfspaceList.Add(new Halfspace(0.0, 0.0, 1.0, false, -0.6));

			//c.halfspaceList.Add(new Halfspace(-1.0, 0.0, 0.0, false, -0.6));
			//c.halfspaceList.Add(new Halfspace(0.0, -1.0, 0.0, false, -0.6));
			//c.halfspaceList.Add(new Halfspace(0.0, 0.0, -1.0, false, -0.6));

			//c.halfspaceList.Add(new Halfspace(0.997564050259824, 0.000000000000000, 0.069756473744125, true, 0.998308158271268));
			//c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, 0.998308158271265));
			//REGION CONVEX CARTESIAN    
			//0.997564050259824    0.000000000000000    0.069756473744125    0.998308158271268    
			// 1.000000000000000    0.000000000000000    0.000000000000000    0.998308158271268 

			c.halfspaceList.Add(new Halfspace(
				0.0, 0.0, 1.0, false, 0.984807753012208
				));
			c.halfspaceList.Add(new Halfspace(
				0.0, 0.0, -1.0, false, -0.985109326154774
				));
			c.halfspaceList.Add(new Halfspace(
				-0.4067366430758, 0.913545457642601, 0.0, false, 0.0
				));
			c.halfspaceList.Add(new Halfspace(
				0.408330460381385, -0.912834177233043, 0.0, false, 0.0));
			//REGION CONVEX CARTESIAN 
			// 0 0 1 0.984807753012208
			// 0 0 -1 -0.985109326154774
			// -0.4067366430758 0.913545457642601 0 0
			// 0.408330460381385 -0.912834177233043 0 0 

			r.convexList.Add(c);

			System.Console.Out.WriteLine(r);

			SuperRegion sr = new SuperRegion(r, false, false);

			System.Console.Out.WriteLine("There are {0} pathces",
				n = sr.convexList[0].patchList.Count);

			//    for (int i = 0; i < n; i++) {
			//      System.Console.Out.WriteLine("Patch {0}:######################## ", i);
			//      System.Console.Out.WriteLine("{0}", sr.convexList[0].patchList[i]);
			//		System.Console.Out.WriteLine("BC    {0}: {1}", i, sr.convexList[0].patchList[i]
			//    }

			Patch pat = sr.convexList[0].patchList[0];
			System.Console.Out.WriteLine("Patch 0 is length {0}", pat.arcList.Length);
			for (int i = 0; i < pat.arcList.Length; i++) {
				System.Console.Out.WriteLine("{0} ", pat.arcList[i].p1);
				System.Console.Out.WriteLine("{0} ", pat.arcList[i].p2);
				System.Console.Out.WriteLine("--------");
			}

			Assert.IsTrue(true);
		}
		public void run(String regionspec, Int64[,] gt) {
			// 227490 is not in colorado
			List<Int64Pair> table = null;
			Region reg = Convex.Parser.compile(regionspec, true);
			table = Cover.HidRange(reg, false);
			Assert.IsTrue(table.Count == gt.Length / 2, "Tables are not the same length {0} instead of {1}",
				table.Count, gt.Length / 2);
			for (int i = 0; i < table.Count; i++) {
				Assert.IsTrue((table[i].lo == gt[i, 0]), "row {2}: {0} Should be {1} ", table[i].lo, gt[i, 0], i);
				Assert.IsTrue((table[i].hi == gt[i, 1]), "row {2}: {0} Should be {1} ", table[i].hi, gt[i, 1], i);
			}
			List<Int64Pair> hidlist = LegacyCover.HidList(reg);

			hidlist.Sort(Interval.ComparisonRanges);

			foreach (Int64Pair hidpair in hidlist) {
				Assert.IsTrue(LegacyCover.IsHidInCoverlist(hidpair.lo, table),
					"isHidInCoverlist error");
			}

			// check to include impossible trixel
			Assert.IsFalse(LegacyCover.IsHidInCoverlist(15616L, table),
				"external trixel allowed to pass IsHidInCoverlist");

		}
		[Test]
		public void TCube() {

			String regionspec = "REGION CONVEX 1 0 0 -0.6 0 1 0 -0.6 0 0 1 -0.6 -1 0 0 -0.6 0 -1 0 -0.6 0 0 -1 -0.6";
			Int64[,] gt = { // ground truth
				{9878424780800,  9895604649983},
				{10977936408576,  10995116277759},
				{12077448036352,  12094627905535},
				{13176959664128,  13194139533311},
				{14276471291904,  14293651161087},
				{15375982919680,  15393162788863},
				{16475494547456,  16492674416639},
				{17575006175232,  17592186044415}
			};
			run(regionspec, gt);
		}
		[Test]
		public void T2Union() {
			String regionspec = "REGION CONVEX J2000 -2 -2 0.99 CONVEX J2000 2 2 0.99";
			Int64[,] gt = { // ground truth
			{8796093022208,  8813272891391},
			{8852196032512,  8852464467967},
			{8853001338880,  8854075080703}, 
			{8855685693440,  8855954128895}, 
			{8856759435264,  8857027870719},
			{8858370048000,  8859443789823},
			{8859712225280,  8859980660735},
			{12644383719424,  12661563588607}, 
			{12700218294272,  12713103196159},
			{13194139533312,  13211319402495}, 
			{13250242543616,  13250510979071}, 
			{13251047849984,  13252121591807},
			{13253732204544,  13254000639999},
			{13254805946368,  13255074381823},
			{13256416559104,  13257490300927},
			{13257758736384,  13258027171839},
			{17042430230528,  17059610099711},
			{17098264805376,  17111149707263}
			};
			run(regionspec, gt);
		}
		//[Test]
		public void TColoradoRect() {
			String regionspec = "RECT LATLON 37 -109.55  41 -102.05";
			Int64[,] gt = {
{14367202476032, 14367470911487},
{15264313769984, 15265387511807},
{15265655947264, 15266259927039},
{15266729689088, 15266998124543},
{15267132342272, 15267199451135},
{15267266560000, 15267333668863},
{15267534995456, 15268608737279},
{15295989153792, 15296056262655},
{15311558410240, 15312632152063},
{15312900587520, 15313705893887},
{15313974329344, 15314108547071},
{15314779635712, 15315853377535}
			};
			run(regionspec, gt);
		}
		[Test]
		public void TColoradoPoly() {
			String regionspec = "POLY J2000 -109.55 41 -102.05 41 -102.05 37 -109.55 37";
			Int64[,] gt = { // ground truth
			{14367202476032,  14367336693759},
			{14367403802624,  14367470911487},
			{15264313769984,  15265387511807},
			{15265655947264,  15265924382719},
			{15266058600448,  15266125709311},
			{15266192818176,  15266259927039},
			{15266729689088,  15266998124543},
			{15267132342272,  15267199451135},
			{15267266560000,  15267333668863},
			{15267534995456,  15268608737279},
			{15311558410240,  15313705893887},
			{15314779635712,  15315853377535}
			};
			run(regionspec, gt);

		}
		[Test]
		public void TMerges() {
			Interval interval = new Interval();
			interval.AddRange(10L, 20L);
			interval.AddRange(30L, 40L);
			interval.AddRange(50L, 60L);

			List<Int64Pair> newlist = new List<HTM.Int64Pair>();
			newlist.Add(new Int64Pair(30L, 100L));

			interval.merge(newlist);

			interval.check();

		}
		[Test]
		public void THuge() {

			String regionspec = Huge.regionspec;
			Int64[,] gt = Huge.gt;
			run(regionspec, gt);
		}
		//////////////////////////// THIS IS THE NEW STUFF:
		// Pad the end of a TimeSpan string with spaces if it does not 
		// contain milliseconds.
		static string Align(TimeSpan interval) {
			string intervalStr = interval.ToString();
			int pointIndex = intervalStr.IndexOf(':');

			pointIndex = intervalStr.IndexOf('.', pointIndex);
			if (pointIndex < 0) intervalStr += "        ";
			return intervalStr;
		}
		private void timestuff() {
			const string numberFmt = "{0,-22}{1,18:N0}";
			const string timeFmt = "{0,-22}{1,26}";


			Console.WriteLine(
				"This example of the fields of the TimeSpan class" +
				"\ngenerates the following output.\n");
			Console.WriteLine(numberFmt, "Field", "Value");
			Console.WriteLine(numberFmt, "-----", "-----");

			// Display the maximum, minimum, and zero TimeSpan values.
			Console.WriteLine(timeFmt, "Maximum TimeSpan",
				Align(TimeSpan.MaxValue));
			Console.WriteLine(timeFmt, "Minimum TimeSpan",
				Align(TimeSpan.MinValue));
			Console.WriteLine(timeFmt, "Zero TimeSpan",
				Align(TimeSpan.Zero));
			Console.WriteLine();
			// Display the ticks-per-time-unit fields.
			Console.WriteLine(numberFmt, "Ticks per day",
				TimeSpan.TicksPerDay);
			Console.WriteLine(numberFmt, "Ticks per hour",
				TimeSpan.TicksPerHour);
			Console.WriteLine(numberFmt, "Ticks per minute",
				TimeSpan.TicksPerMinute);
			Console.WriteLine(numberFmt, "Ticks per second",
				TimeSpan.TicksPerSecond);
			Console.WriteLine(numberFmt, "Ticks per millisecond",
				TimeSpan.TicksPerMillisecond);
		}

		// //////////////////////////////// TIMING SUPPORT
		//
		private long _start;
		private long _nticks;

		long ms {
			get {
				return _nticks / TimeSpan.TicksPerMillisecond;
			}
		}
		System.TimeSpan now {
			get {
				return DateTime.Now.TimeOfDay;
			}
		}
		public void start(bool verbose) {
			if (verbose) {
				Console.WriteLine("                                      Normal start {0}", now);
			}
			_start = DateTime.Now.Ticks;
		}

		public void stop(bool verbose) {
			_nticks = DateTime.Now.Ticks - _start;
			if (verbose) {
				Console.WriteLine("                                  Normal stop at {0}", now);
			}
		}
		public void Pov() {
			Region r = new Region();
			Convex c = new Convex();
			c.halfspaceList.Add(new Halfspace(1.0, 0.0, 0.0, false, 0.7));
			c.halfspaceList.Add(new Halfspace(1.0, 1.0, 0.0, true, 0.2));
			PovWriter pov = new PovWriter(Console.Out);

			r.convexList.Add(c);
			pov.Write(r);
			//			pov.Write(c, 12);
			Assert.IsTrue(true);
			return;
		}
		// /////////////////////////////// END TIMING SUPPORT

		public void TTiming() {
			Random ran;
			long looponly;
			/* **************************************************** BEGIN TIMING */
			start(true);
			ran = new Random(22);
			for (long i = 0; i < 2000000L; i++) {
				double y = Math.Cos(ran.NextDouble());
			}
			stop(true);
			/* ****************************************************   END TIMING */
			looponly = ms;
			Console.WriteLine("{0} milliseconds loop compute only", looponly);


			/* **************************************************** BEGIN TIMING */
			start(true);
			List<double> listdouble = new List<double>();
			ran = new Random(22);
			for (long i = 0; i < 2000000L; i++) {
				double y = Math.Cos(ran.NextDouble());
				listdouble.Add(y);
			}
			stop(true);
			/* ****************************************************   END TIMING */
			Console.WriteLine("{0} milliseconds List<double> setup", ms - looponly);

			/* **************************************************** BEGIN TIMING */
			start(true);
			ran = new Random(22);
			ArrayList arrlist = new ArrayList();
			for (long i = 0; i < 2000000L; i++) {
				double y = Math.Cos(ran.NextDouble());
				arrlist.Add(y);
			}
			stop(true);
			/* ****************************************************   END TIMING */
			Console.WriteLine("{0} milliseconds Arraylist setup", ms - looponly);

			/* **************************************************** BEGIN TIMING */
			start(true);
			double[] darr = new double[2000000];
			ran = new Random(22);
			for (long i = 0; i < 2000000L; i++) {
				double y = Math.Cos(ran.NextDouble());
				darr[i] = y;
			}
			stop(true);
			/* ****************************************************   END TIMING */
			Console.WriteLine("{0} milliseconds double[] setup", ms - looponly);

			/* <<<<<<<<<<<<<<<<<<<<<<< ACCCESS ALL ELTS *****************************/
			double yy;
			/* **************************************************** BEGIN TIMING */
			start(true);

			foreach (double d in listdouble) {
				yy = d + 1.0;
			}
			stop(true);
			Console.WriteLine("{0} milliseconds accessing List<double> with foreach", ms);
			/* **************************************************** BEGIN TIMING */
			Console.WriteLine("Max int = {0}", int.MaxValue);
			start(true);
			for (int i = 0; i < 20000000L; i++) {
				yy = listdouble[i] + 1.0;
			}
			stop(true);
			Console.WriteLine("{0} milliseconds accessing List<double> with [index]", ms);
			/* **************************************************** BEGIN TIMING */
			start(true);
			for (int i = 0; i < 2000000L; i++) {
				yy = darr[i] + 1.0;
			}
			stop(true);
			Console.WriteLine("{0} milliseconds accesing double[]", ms);
			/* ****************************************************   END TIMING */

			Assert.IsTrue(true);
		}
	}
}
