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

namespace skyscraper5.Teletext
{
    public class EbuTeletextDataField : Validatable
    {
        public EbuTeletextDataField(byte[] dataFieldContent)
        {
            InversionTable.TeletextInversion(dataFieldContent,2);

            MemoryStream ms = new MemoryStream(dataFieldContent);
            byte readUInt8 = ms.ReadUInt8();
            FieldParity = (readUInt8 & 0x20) != 0;
            LineOffset = (readUInt8 & 0x1f);
            FramingCode = ms.ReadUInt8();

            byte mpag = ms.ReadHamming84();
            Magazine = mpag & 0x07;
            PacketNumber = (mpag >> 3) & 0x1f;


            if (PacketNumber != 0)
            {
                if (PacketNumber >= 26)
                {
                    //Non-Displayable Packet Y = 26 to 31
                    if (ms.GetAvailableBytes() == 0)
                    {
                        Valid = false;
                        return;
                    }
                    DesignationCode = ms.ReadUInt8();
                    if (ms.GetAvailableBytes() < 39)
                    {
                        Valid = false;
                        return;
                    }
                    CharacterCodes = ms.ReadBytes(39);
                }
                else
                {
                    //Normal Packet (Y = 1 to 25)
                    if (ms.GetAvailableBytes() < 40)
                    {
                        Valid = false;
                        return;
                    }
                    CharacterCodes = ms.ReadBytes(40);
                }
            }
            else
            {
                //Page Header Packet (Y = 0)
                //To-Do: Read Page No, Sub-code, and Control bits
                PageNumber = (byte)ms.ReadHamming84().UnpackBcd();

                Header = new PageHeader();
                ms.ReadUInt8(); //byte 8
                readUInt8 = ms.ReadUInt8();
                Header.ErasePage = (readUInt8 & 0x80) != 0;


                ms.ReadUInt8(); //byte 10
                readUInt8 = ms.ReadUInt8(); //byte 11
                Header.Newsflash = (readUInt8 & 0x60) != 0;
                Header.Subtitle = (readUInt8 & 0x80) != 0;
                readUInt8 = ms.ReadUInt8(); //byte 12
                Header.SurpressHeader = (readUInt8 & 0x02) != 0;
                Header.UpdateIndicator = (readUInt8 & 0x08) != 0;
                Header.InterruptedSequence = (readUInt8 & 0x20) != 0;
                Header.InhibitDisplay = (readUInt8 & 0x80) != 0;
                readUInt8 = ms.ReadUInt8(); //byte 13
                Header.SerialMode = (readUInt8 & 0x02) != 0;

                if (ms.GetAvailableBytes() < 32)
                {
                    Valid = false;
                    return;
                }
                CharacterCodes = ms.ReadBytes(32);
            }

            if (PacketNumber < 26)
            {
                for (int i = 0; i < CharacterCodes.Length; i++)
                {
                    CharacterCodes[i] &= 0x7f;
                }
            }
            Valid = true;
        }

        public byte DesignationCode { get; private set; }

        public byte PageNumber { get; set; }

        public class PageHeader
        {
            public bool ErasePage { get; internal set; }
            public bool Newsflash { get; internal set; }
            public bool Subtitle { get; internal set; }
            public bool SurpressHeader { get; internal set; }
            public bool UpdateIndicator { get; internal set; }
            public bool InterruptedSequence { get; internal set; }
            public bool InhibitDisplay { get; internal set; }
            public bool SerialMode { get; internal set; }
        }
        
        public PageHeader Header { get; private set; }
        public byte[] CharacterCodes { get; private set; }

        public int PacketNumber { get; private set; }

        public int Magazine { get; private set; }

        public byte FramingCode { get; private set; }

        public int LineOffset { get; private set; }

        public bool FieldParity { get; private set; }
        
    }
}
