using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TEST_DecodePng
{
    public class PngMetaData
    {
        private static readonly sbyte[] ValidByteDepth = new sbyte[] { 1, 2, 4, 8, 16 };
        private static readonly sbyte[] ValidColorTypes = new sbyte[] { 0, 2, 3, 4, 6 };

        private int height;
        private int width;
        private sbyte bitDepth;
        private sbyte colorType;
        private sbyte compressionMethod;
        private sbyte filterMethod;
        private sbyte interlaceMethod;

        public int Height { get => height; set => height = value; }
        public int Width { get => width; set => width = value; }
        public sbyte BitDepth { get => bitDepth; set => bitDepth = value; }
        public sbyte ColorType { get => colorType; set => colorType = value; }
        public sbyte CompressionMethod { get => compressionMethod; set => compressionMethod = value; }
        public sbyte FilterMethod { get => filterMethod; set => filterMethod = value; }
        public sbyte InterlaceMethod { get => interlaceMethod; set => interlaceMethod = value; }

        public PngMetaData(int height, int width, sbyte bitDepth, sbyte colorType, sbyte compressionMethod, sbyte filterMethod, sbyte interlaceMethod)
        {
            Height = height;
            Width = width;
            BitDepth = bitDepth;
            ColorType = colorType;
            CompressionMethod = compressionMethod;
            FilterMethod = filterMethod;
            InterlaceMethod = interlaceMethod;
        }
        public bool IsValid()
        {
            // All those tests have been set up by following the PNG guidelines of the W3C for PNG file format.
            // More info at : https://www.w3.org/TR/PNG-Chunks.html

            //Width and Height cant be 0 (or negative obviously) so we test it 
            if (Width <= 0 || Height <= 0)
                return false;
            //There are only a few authorized bitDepths so we test if it complies
            if (!Array.Exists(ValidByteDepth, element => element == BitDepth))
                return false;
            //There are only a few authorited colortypes so we test if it complies
            if (!Array.Exists(ValidColorTypes, element => element == ColorType))
                return false;
            //Compression method indicates the algorythm used, for now only 0 is implemented for the deflate algorythm so we test it
            if (CompressionMethod != 0)
                return false;
            //Filter Method just like Compression method only is implemented with the 0 value so we test it
            if (FilterMethod != 0)
                return false;
            //Interlace method can be 0 for no Interlacing or 1 for Adam7 interlace
            if (InterlaceMethod != 0 && InterlaceMethod != 1)
                return false;

            //Now the tricky part, depending on the color type, only certain bit depth are allowed
            switch (colorType)
            {
                case 0:
                    //Each pixel is a grayscale sample.
                    if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16)
                        return false;
                    break;
                case 2:
                    //Each pixel is an R,G,B triple.
                    if (bitDepth != 8 && bitDepth != 16)
                        return false;
                    break;
                case 3:
                    //Each pixel is a palette index, a PLTE chunk must appear.
                    if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8)
                        return false;
                    break;
                case 4:
                    //Each pixel is a grayscale sample, followed by an alpha sample.
                    if (bitDepth != 8 && bitDepth != 16)
                        return false;
                    break;
                case 6:
                    //Each pixel is an R,G,B triple, followed by an alpha sample.
                    if (bitDepth != 8 && bitDepth != 16)
                        return false;
                    break;
                default:
                    return false;
            }

            return true;
        }
    }
}
