using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.src.Mpeg2.PacketFilter
{
	/// <summary>
	/// This filter lets all packets through, but writes them to disk.
	/// </summary>
	[PluginPriority(20)]
	public class TsRecorder : IPacketFilter, IDisposable
	{
		public bool PassPacket(TsPacket packet)
		{
			if (recordingBufferedStream != null)
			{
				byte[] rawPacket = packet.GetRawPacket();
				recordingBufferedStream.Write(rawPacket, 0, rawPacket.Length);
			}
			return true;
		}


		private const string RECORDING_FILENAME_MASK = "skyscraper_{0}.ts";
		public bool Recording { get; set; }
		public DirectoryInfo RecordingOutputDirectory { get; set; }
		
		private BufferedStream recordingBufferedStream;
		private FileStream recordingFileStream;
		private string recordingFilename;

		public bool PrepareRecording()
		{
			if (!Recording)
				return false;

			if (RecordingOutputDirectory == null)
				return false;

			DirectoryInfo rootDirectory = RecordingOutputDirectory.Root;
			DriveInfo driveInfo = new DriveInfo(rootDirectory.FullName);
			long driveFreeSpace = driveInfo.TotalFreeSpace;
			long driveTotalSize = driveInfo.TotalSize;
			long tenPercentOfDriveTotal = driveTotalSize / 10;
			if (driveFreeSpace > tenPercentOfDriveTotal)
				return true;

			FileInfo[] fileInfos = RecordingOutputDirectory.GetFiles(String.Format(RECORDING_FILENAME_MASK, "*"));
			Array.Sort(fileInfos, (x, y) => DateTime.Compare(x.CreationTimeUtc, y.CreationTimeUtc));
			long sizeOfAllKnown = fileInfos.Select(x => x.Length).Sum();
			long driveFreeSpaceAfterDeleting = driveFreeSpace + sizeOfAllKnown;
			if (driveFreeSpaceAfterDeleting < tenPercentOfDriveTotal)
				return false;

			for (int i = 0; i < fileInfos.Length; i++)
			{
				fileInfos[i].Delete();
				Console.WriteLine(String.Format("Deleted for rotation: {0}", fileInfos[i].Name), 8);
				fileInfos[i] = null;
				driveInfo = new DriveInfo(rootDirectory.FullName);
				driveFreeSpace = driveInfo.TotalFreeSpace;
				if (driveFreeSpace > tenPercentOfDriveTotal)
					return true;
			}

			driveInfo = new DriveInfo(rootDirectory.FullName);
			driveFreeSpace = driveInfo.TotalFreeSpace;
			if (driveFreeSpace > tenPercentOfDriveTotal)
				return true;
			else
				return false;
		}

		public void CreateBufferedStream()
		{
			FileInfo recordingFileInfo = new FileInfo(Path.Combine(RecordingOutputDirectory.FullName, recordingFilename));
			recordingFileInfo.Directory.EnsureExists();
			recordingFileStream = recordingFileInfo.OpenWrite();
			recordingBufferedStream = new BufferedStream(recordingFileStream);
		}

		public void Dispose()
		{
			if (recordingBufferedStream != null)
			{
				recordingBufferedStream.Flush();
				recordingBufferedStream.Close();
				recordingBufferedStream.Dispose();
				recordingBufferedStream = null;
				recordingFileStream.Close();
				recordingFileStream.Dispose();
				recordingFileStream = null;
			}
		}

		public void SetNextFilename(string recordingFilename)
		{
			this.recordingFilename = recordingFilename;
		}
	}
}
