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

namespace skyscraper5.Dvb.SystemSoftwareUpdate.Descriptors
{
	[SkyscraperPlugin]
	[TsDescriptor(0x01,"UNT")]
    class SchedulingDescriptor : TsDescriptor
    {
        public SchedulingDescriptor(byte[] buffer)
        {
            DateTime? tmp;

            MemoryStream ms = new MemoryStream(buffer, false);
            tmp = ms.ReadEtsiEn300468AnnexCDateTime();
            if (tmp == null)
            {
                Valid = false;
                return;
            }
            StartDateTime = tmp.Value;


            tmp = ms.ReadEtsiEn300468AnnexCDateTime();
            if (tmp == null)
            {
                Valid = false;
                return;
            }
            EndDateTime = tmp.Value;

            byte readUInt8 = ms.ReadUInt8();
            FinalAvailability = (readUInt8 & 0x80) != 0;
            PeriodicityFlag = (readUInt8 & 0x40) != 0;
            int periodUnit = (readUInt8 & 0x30);
            int durationUnit = (readUInt8 & 0x0c);
            int estimatedCycleTimeUnit = (readUInt8 & 0x03);
            Period = DecodeTiming(periodUnit, ms.ReadUInt8());
            Duration = DecodeTiming(durationUnit, ms.ReadUInt8());
            EstimatedCycleTime = DecodeTiming(durationUnit, ms.ReadUInt8());
            PrivateData = ms.ReadBytes(ms.GetAvailableBytes());
        }

        public byte[] PrivateData { get; private set; }

        public TimeSpan EstimatedCycleTime { get; private set; }

        public TimeSpan Duration { get; private set; }

        public TimeSpan Period { get; private set; }

        private TimeSpan DecodeTiming(int periodUnit, byte _base)
        {
            int totalSeconds = _base;
            switch (periodUnit)
            {
                case 0b00:
                    break;
                case 0b01:
                    totalSeconds *= 60;
                    break;
                case 0b10:
                    totalSeconds *= 3600;
                    break;
                case 0b11:
                    totalSeconds *= 3600;
                    totalSeconds *= 24;
                    break;
                default:
                    throw new NotImplementedException(String.Format("{0} {1:X2}", nameof(periodUnit), periodUnit));
            }

            return new TimeSpan(0, 0, totalSeconds);
        }


        public bool PeriodicityFlag { get; private set; }

        public bool FinalAvailability { get; private set; }

        public DateTime? EndDateTime { get; private set; }

        public DateTime? StartDateTime { get; private set; }
    }
}
