using System;
using System.IO;
using System.Text;
using NUnit.Framework;

namespace Orciid.Media
{
	[TestFixture]
	public class TestDiskMediaCache
	{
		private string cachedirectory = null;

		[SetUp]
		public void Setup()
		{
			string temp = Path.GetTempPath();
			int i = 0;
			do
			{
				cachedirectory = Path.Combine(temp, "diskmediacache" + i.ToString());
				i++;
			} while (Directory.Exists(cachedirectory));
			Directory.CreateDirectory(cachedirectory);
			Console.WriteLine("Using {0} as cache directory", cachedirectory);
		}

		[TearDown] 
		public void Cleanup()
		{
			if (cachedirectory != null)
				Directory.Delete(cachedirectory, true);
		}

		[Test]
		public void TestSimpleCaching()
		{
			const string content = "Testing the disk media cache";
			const string testfile = "test.txt";
			DiskMediaCache cache = new DiskMediaCache(cachedirectory);
			// make sure file is not already cached
			Assert.IsNull(cache.ReadFile(testfile, DateTime.MinValue));
			// cache file
			using (StreamWriter writer = new StreamWriter(cache.WriteFile(testfile)))
				writer.WriteLine(content);
			// read from cache
			using (StreamReader reader = new StreamReader(
					   cache.ReadFile(testfile, DateTime.MinValue)))
				Assert.AreEqual(content, reader.ReadLine());
			// try reading from cache with impossible age requirement
			Assert.IsNull(cache.ReadFile(testfile, DateTime.Now + TimeSpan.FromMinutes(1)));
		}

		private int scorercounter;

		[Test]
		public void TestCleanup()
		{
			DiskMediaCache cache = new DiskMediaCache(cachedirectory);
			
			// create test file content
			StringBuilder sb = new StringBuilder(1024);
			for (int i = 0; i < 1024; i++)
				sb.Append('x');
			string kilobyte = sb.ToString();

			// create test files
			for (int f = 0; f < 20; f++)
			{
				string testfile = "test" + f.ToString();
				Console.Write("Creating test file " + testfile);
				using (StreamWriter writer = new StreamWriter(cache.WriteFile(testfile)))
					for (int c = 0; c < f; c++)
					{
						writer.Write(kilobyte);
						Console.Write(".");
					}
				Console.WriteLine();
			}

			// check file scorer with 1 GB cache size to not cause any deletions
			scorercounter = 0;
			cache.CleanUp(new CacheFileScorer(MyFileScorer), 1024 * 1024 * 1024);
			Assert.AreEqual(20, scorercounter);

			// make sure all files are still there
			for (int f = 0; f < 20; f++)
				using (Stream stream = cache.ReadFile("test" + f.ToString(), DateTime.MinValue))
					Assert.IsNotNull(stream);

			// clean up to a maximum cache size of 100 KB
			scorercounter = 0;
			cache.CleanUp(new CacheFileScorer(MyFileScorer), 100 * 1024);
			Assert.AreEqual(20, scorercounter);

			// check which files are still there and what total size is
			long totalsize = 0;
			for (int f = 0; f < 20; f++)
			{
				string testfile = "test" + f.ToString();
				Console.Write("Checking test file " + testfile);
				using (Stream stream = cache.ReadFile("test" + f.ToString(), DateTime.MinValue))
				{
					if (stream != null)
					{
						Console.WriteLine(" found");
						totalsize += stream.Length;
					}
					else
						Console.WriteLine(" not found");
				}
			}
			Assert.IsTrue(totalsize <= 100 * 1024);
		}

		private int MyFileScorer(
			DateTime created, DateTime lastread, int readcount, long size)
		{
			scorercounter++;
			return MediaCache.DefaultCacheFileScorer(created, lastread, readcount, size);
		}
	}
}
