using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.Teletext
{
    public class TeletextMagazine
    {
        public TeletextMagazine(int magazineNumber)
        {
            MagazineNumber = magazineNumber;
            Lines = new byte[32][];
        }

        public int MagazineNumber { get; }
        public byte[][] Lines { get; }
        public EbuTeletextDataField.PageHeader Header { get; set; }
        public byte PageNumber { get; set; }

        public ushort HumanReadablePageNumber
        {
            get
            {
                if (Lines[0] == null)
                    return 0xffff;
                if (Lines[0][0] > 0x39 && Lines[0][0] < 0x30)
                    return 0xfffe;
                if (Lines[0][1] > 0x39 && Lines[0][1] < 0x30)
                    return 0xfffd;
                if (Lines[0][2] > 0x39 && Lines[0][2] < 0x30)
                    return 0xfffc;
                ushort result = Lines[0][0];
                result -= 48;
                result *= 100;
                result += (ushort)((Lines[0][1] - 48) * 10);
                result += (ushort)(Lines[0][2] - 48);
                return result;
            }
        }

        public byte[] GetUniqueFingerprint()
        {
            MemoryStream ms = new MemoryStream();
            ms.Write(BitConverter.GetBytes(HumanReadablePageNumber), 0, 2);
            for (int i = 1; i < 25; i++)
            {
                if (Lines[i] != null)
                    ms.Write(Lines[i], 0, 40);
            }

            ms.Position = 0;
            SHA256 sha256 = SHA256.Create();
            byte[] result = sha256.ComputeHash(ms);
            sha256.Dispose();
            return result;
        }

        public override string ToString()
        {
            return HumanReadablePageNumber.ToString();
        }

        public override bool Equals(object? obj)
        {
            if (ReferenceEquals(this, obj))
                return true;

            TeletextMagazine tm = obj as TeletextMagazine;
            if (tm == null)
                return false;

            for (int y = 1; y < 25; y++)
            {
                byte[] lLines = this.Lines[y];
                byte[] rLines = tm.Lines[y];
                if (lLines == null && rLines == null)
                    continue;
                if (lLines == null)
                    return false;
                if (rLines == null)
                    return false;

                for (int i = 0; i < 40; i++)
                {
                    if (lLines[i] != rLines[i])
                        return false;
                }
            }

            return true;
        }

        public override int GetHashCode()
        {
            return BitConverter.ToInt32(GetUniqueFingerprint(), 0);
        }

        public void WriteOut(Stream fileStream)
        {
            for (int i = 0; i < Lines.Length; i++)
            {
                if (Lines[i] != null)
                {
                    fileStream.Write(Lines[i], 0, Lines[i].Length);
                }

                fileStream.WriteByte(0x0a);
            }
        }

        public string FormatAsString()
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Lines.Length; i++)
            {
	            if (Lines[i] != null)
	            {
                    sb.Append(Encoding.Default.GetString(Lines[i]));
	            }
            }
            return sb.ToString();
        }

        public byte[] FormatAsByteArray()
        {
	        int len = 0;
	        for (int i = 0; i < Lines.Length; i++)
	        {
		        len += 2;
                if (Lines[i] == null)
                    continue;

                len += Lines[i].Length;
	        }

	        byte[] buffer = new byte[len];
	        int offset = 0;
	        for (int i = 0; i < Lines.Length; i++)
	        {
		        if (Lines[i] == null)
		        {
			        buffer[offset++] = 0x0d;
			        buffer[offset++] = 0x0a;
					continue;
		        }

		        byte[] line = Lines[i];
                Array.Copy(line, 0, buffer, offset, line.Length);
                offset += line.Length;
                buffer[offset++] = 0x0d;
                buffer[offset++] = 0x0a;
	        }

	        return buffer;
        }
    }
}
