using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Ietf.Rfc971;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Text;

namespace skyscraper5.Dvb.TvAnytime
{
    public class RctLinkInfo
    {
        public RctLinkInfo(byte[] linkInfoBytes)
        {
            //ETSI TS 102 323 V1.5.1 (2012-01), page 95
            MemoryStream ms = new MemoryStream(linkInfoBytes, false);
            byte readUInt8 = ms.ReadUInt8();
            LinkType = (LinkTypeValue)((readUInt8 >> 4) & 0x0f);
            HowRelatedClassificationSchemeId = (readUInt8 & 0x03);
            HowRelatedClassificationSchemeId <<= 2;

            ushort readUInt16Be = ms.ReadUInt16BE();
            HowRelatedClassificationSchemeId += ((readUInt16Be & 0xf000) >> 12);
            TermId = readUInt16Be & 0x0fff;

            readUInt8 = ms.ReadUInt8();
            GroupId = ((readUInt8 >> 4) & 0x0f);
            Precedence = (readUInt8 & 0x0f);

            if (LinkType == LinkTypeValue.Uri || LinkType == LinkTypeValue.BothBinaryUri)
            {
                byte uriLength = ms.ReadUInt8();
                MediaUri = Encoding.ASCII.GetString(ms.ReadBytes(uriLength));
            }

            if (LinkType == LinkTypeValue.Binary || LinkType == LinkTypeValue.BothBinaryUri)
            {
                this.DvbBinaryLocator = new DvbBinaryLocator(ms);
            }

            readUInt8 = ms.ReadUInt8();
            int numberItems = readUInt8 & 0x3f;
            Items = new KeyValuePair<string, string>[numberItems];
            for (int m = 0; m < numberItems; m++)
            {
                string key = Encoding.ASCII.GetString(ms.ReadBytes(3));
                byte promotionalTextLength = ms.ReadUInt8();
                string value = En300468AnnexATextDecoder.GetInstance().Decode(ms.ReadBytes(promotionalTextLength));
                Items[m] = new KeyValuePair<string, string>(key, value);
            }

            readUInt16Be = ms.ReadUInt16BE();
            DefaultIconFlag = (readUInt16Be & 0x8000) != 0;
            IconId = (readUInt16Be & 0x7000) >> 12;

            int descriptorLoopLength = readUInt16Be & 0x0fff;
            IEnumerable<TsDescriptor> unpackDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(ms.ReadBytes(descriptorLoopLength), "RCT");
            foreach (TsDescriptor unpackDescriptor in unpackDescriptors)
            {
                switch (unpackDescriptor.GetType().Name)
                {
                    case nameof(ShortEventDescriptor):
                        ShortEventDescriptor sed = (ShortEventDescriptor)unpackDescriptor;
                        this.EventName = sed.EventName;
                        this.EventLanguageCode = sed.Iso639LanguageCode;
                        this.EventText = sed.Text;
                        break;
                    default:
                        throw new NotImplementedException(unpackDescriptor.GetType().Name);
                }
            }
        }

        public string EventText { get; set; }

        public string EventLanguageCode { get; set; }

        public string EventName { get; set; }

        public int IconId { get; private set; }

        public bool DefaultIconFlag { get; private set; }

        public KeyValuePair<string, string>[] Items { get; set; }

        public DvbBinaryLocator DvbBinaryLocator { get; set; }

        public string MediaUri { get; private set; }

        public int Precedence { get; private set; }

        public int GroupId { get; private set; }

        public int TermId { get; private set; }

        public int HowRelatedClassificationSchemeId { get; private set; }

        public LinkTypeValue LinkType { get; private set; }

        public enum LinkTypeValue
        {
            Uri = 0,
            Binary = 1,
            BothBinaryUri = 2,
            Descriptor = 3,
            Reserved = 4,
        }

        public string GetIdentifierString()
        {
            switch (LinkType)
            {
                case LinkTypeValue.Uri:
                    return MediaUri;
                default:
                    throw new NotImplementedException(LinkType.ToString());
            }
        }
    }
}
