using System;
using System.IO;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO;

namespace skyscraper5.Scorcher
{
	internal class TdtGenerator : PsiGenerator
	{

		private static long MilliSecPerDay = (24 * 3600) * 1000;
		private static long JulianEpochOffset = -40587 * MilliSecPerDay;

		internal static byte[] EncodeMjd(DateTime dt)
		{
			//shamelessly stolen from TSDuck's tsMJD.cpp
			long time_ms = dt.ToUnixTime() * 1000;

			if (time_ms < JulianEpochOffset)
			{
				return null;
			}

			long d = (time_ms - JulianEpochOffset) / 1000;	//seconds since MJD epoch
			byte[] days = BitConverter.GetBytes((ushort)(d / (24 * 3600)));
			if (BitConverter.IsLittleEndian)
				(days[1], days[0]) = (days[0], days[1]);
			byte[] result = new byte[5];
			result[0] = days[0];
			result[1] = days[1];
			result[2] = EncodeBCD((int)((d / 3600) % 24));
			result[3] = EncodeBCD((int)((d / 60) % 60));
			result[4] = EncodeBCD((int)(d % 60));
			return result;
		}

		private static byte EncodeBCD(int value)
		{
			byte result = 0;
			result += (byte)(value % 10);
			value /= 10;
			result += (byte)((value % 10) << 4);
			return result;
		}

		public TdtGenerator() : base(new TimeSpan(0,0,0,1), 0x0014)
		{
		}

		public override byte[] BuildPsi()
		{
			MemoryStream ms = new MemoryStream();
			ms.WriteUInt8(0x70);

			byte byte1 = 0;
			//section syntax indicator = 0
			byte1 |= 0x40;	//reserved future_use
			byte1 |= 0x30;
			ms.WriteUInt8(byte1);

			ms.WriteUInt8(5);	//Section_length (always 5)
			ms.Write(EncodeMjd(DateTime.Now), 0, 5);
			return ms.ToArray();
		}
	}
}
