using System;
using System.Collections;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using NUnit.Framework;
using Orciid.Core;

namespace webtests
{
	[TestFixture]
	public class TestCollectionFieldOrder
	{
		private ArrayList collections = new ArrayList();
		private Utilities util;

		[SetUp]
		protected void SetUp()
		{
			// current directory should be webtests/bin/Debug
			string dsdir = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\datasets");

			util = new Utilities(dsdir);

			User.GetByLogin("admin", "admin").Activate(null);
		}

		[TearDown]
		protected void TearDown()
		{
			foreach (Collection c in collections)
				if (c != null)
					c.Delete();
		}

		private Collection GetTempCollection()
		{
			Collection coll = new Collection();
			coll.Title = "temp_" + Guid.NewGuid().ToString();
			coll.Description = coll.Title;
			coll.ResourcePath = @"\\invalid\resourcepath";
			coll.Update();
			collections.Add(coll);
			return coll;
		}

		private Field GetNewField(string name)
		{
			Field field = new Field();
			field.Name = name;
			field.Label = name;
			return field;
		}

		private void CheckDatabaseDisplayOrder(Collection coll)
		{
			// make sure DisplayOrder values are unique for all fields in collection
			
			using (DBConnection conn = DBConnector.GetConnection(true))
			{
				Query query = new Query(conn, 
					@"
SELECT	COUNT(*) AS Expr1
FROM	FieldDefinitions
WHERE	(CollectionID = {collid})
GROUP BY	DisplayOrder
HAVING	(COUNT(*) > 1)");
				query.AddParam("collid", coll.ID);
				Assert.AreEqual(null, conn.ExecScalar(query));

				query = new Query(conn, 
					@"
SELECT	COUNT(*) AS Expr1
FROM	FieldDefinitions
WHERE	(CollectionID = {collid})
AND     DisplayOrder < 1");
				query.AddParam("collid", coll.ID);
				Assert.AreEqual(0, conn.ExecScalar(query));
			}
		}

		[Test]
		public void TestIndividualFieldCreation()
		{
			Collection coll = GetTempCollection();
			coll.AddField(GetNewField("A"));
			coll.AddField(GetNewField("B"));
			coll.AddField(GetNewField("C"));

			Field[] f = coll.GetFields();
			Assert.AreEqual(3, f.Length);
			Assert.AreEqual("A", f[0].Name);
			Assert.AreEqual("B", f[1].Name);
			Assert.AreEqual("C", f[2].Name);

			CheckDatabaseDisplayOrder(coll);

			// reverse field order
			coll.MoveField(f[2], f[0]);
			coll.MoveField(f[0], null);

			f = coll.GetFields();
			Assert.AreEqual(3, f.Length);
			Assert.AreEqual("C", f[0].Name);
			Assert.AreEqual("B", f[1].Name);
			Assert.AreEqual("A", f[2].Name);

			CheckDatabaseDisplayOrder(coll);

			coll.AddField(GetNewField("D"));

			f = coll.GetFields();
			Assert.AreEqual(4, f.Length);
			Assert.AreEqual("C", f[0].Name);
			Assert.AreEqual("B", f[1].Name);
			Assert.AreEqual("A", f[2].Name);
			Assert.AreEqual("D", f[3].Name);

			CheckDatabaseDisplayOrder(coll);
		}

		[Test]
		public void TestDublinCoreFieldCreation()
		{
			Collection coll = GetTempCollection();
			coll.CreateDublinCoreFields();

			Field[] f = coll.GetFields();
			Assert.AreEqual(15, f.Length);
			Assert.AreEqual("Title", f[0].Name);
			Assert.AreEqual("Creator", f[1].Name);
			Assert.AreEqual("Subject", f[2].Name);
			Assert.AreEqual("Description", f[3].Name);
			Assert.AreEqual("Publisher", f[4].Name);
			Assert.AreEqual("Contributor", f[5].Name);
			Assert.AreEqual("Date", f[6].Name);
			Assert.AreEqual("Type", f[7].Name);
			Assert.AreEqual("Format", f[8].Name);
			Assert.AreEqual("Identifier", f[9].Name);
			Assert.AreEqual("Source", f[10].Name);
			Assert.AreEqual("Language", f[11].Name);
			Assert.AreEqual("Relation", f[12].Name);
			Assert.AreEqual("Coverage", f[13].Name);
			Assert.AreEqual("Rights", f[14].Name);

			CheckDatabaseDisplayOrder(coll);

			// move description to end of list
			coll.MoveField(f[3], null);

			f = coll.GetFields();
			Assert.AreEqual(15, f.Length);
			Assert.AreEqual("Title", f[0].Name);
			Assert.AreEqual("Creator", f[1].Name);
			Assert.AreEqual("Subject", f[2].Name);			
			Assert.AreEqual("Publisher", f[3].Name);
			Assert.AreEqual("Contributor", f[4].Name);
			Assert.AreEqual("Date", f[5].Name);
			Assert.AreEqual("Type", f[6].Name);
			Assert.AreEqual("Format", f[7].Name);
			Assert.AreEqual("Identifier", f[8].Name);
			Assert.AreEqual("Source", f[9].Name);
			Assert.AreEqual("Language", f[10].Name);
			Assert.AreEqual("Relation", f[11].Name);
			Assert.AreEqual("Coverage", f[12].Name);
			Assert.AreEqual("Rights", f[13].Name);
			Assert.AreEqual("Description", f[14].Name);

			CheckDatabaseDisplayOrder(coll);

			// move Publisher before Relation
			coll.MoveField(f[3], f[11]);
			// move Coverage before Title
			coll.MoveField(f[12], f[0]);

			f = coll.GetFields();
			Assert.AreEqual(15, f.Length);
			Assert.AreEqual("Coverage", f[0].Name);
			Assert.AreEqual("Title", f[1].Name);
			Assert.AreEqual("Creator", f[2].Name);
			Assert.AreEqual("Subject", f[3].Name);			
			Assert.AreEqual("Contributor", f[4].Name);
			Assert.AreEqual("Date", f[5].Name);
			Assert.AreEqual("Type", f[6].Name);
			Assert.AreEqual("Format", f[7].Name);
			Assert.AreEqual("Identifier", f[8].Name);
			Assert.AreEqual("Source", f[9].Name);
			Assert.AreEqual("Language", f[10].Name);
			Assert.AreEqual("Publisher", f[11].Name);
			Assert.AreEqual("Relation", f[12].Name);			
			Assert.AreEqual("Rights", f[13].Name);
			Assert.AreEqual("Description", f[14].Name);

			CheckDatabaseDisplayOrder(coll);
		}

		[Test]
		public void TestFieldOrderLegacyCorruption()
		{
			Collection coll = GetTempCollection();
			coll.AddField(GetNewField("A"));
			coll.AddField(GetNewField("B"));
			coll.AddField(GetNewField("C"));

			// artificially destroy DisplayOrder
			
			using (DBConnection conn = DBConnector.GetConnection(true))
			{
				Query query = new Query(conn, 
					"UPDATE FieldDefinitions SET DisplayOrder=0 WHERE CollectionID={collid}");
				query.AddParam("collid", coll.ID);
				conn.ExecQuery(query);
			}
			
			// Clear object cache
			CachableObject.ResetThreadCache();

			// read collection back from database
			coll = Collection.GetByID(coll.ID);

			Field[] f = coll.GetFields();
			Assert.AreEqual(3, f.Length);

			CheckDatabaseDisplayOrder(coll);
		}
	}
}
