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

namespace S04_Projet
{
    public class Pixel
    {
        public byte r { get; private set; }
        public byte g { get; private set; }
        public byte b { get; private set; }

        public double H { get; private set; }
        public double S { get; private set; }
        public double L { get; private set; }

        public void SetR(byte r) => this.r = r;
        public void SetG(byte g) => this.g = g;
        public void SetB(byte b) => this.b = b;

        /// <summary>
        /// Prend les trois couleurs en paramètres
        /// </summary>
        /// <param name="r">Rouge</param>
        /// <param name="g">Vert</param>
        /// <param name="b">Bleu</param>
        public Pixel(byte r, byte g, byte b)
        {
            this.r = r;
            this.g = g;
            this.b = b;
        }

        public unsafe Pixel(byte* r, byte* g, byte* b)
        {
            this.r = *r;
            this.g = *g;
            this.b = *b;
        }

        /// <summary>
        /// Assigne une même valeur à toutes les couleurs
        /// </summary>
        /// <param name="unifiedColors">Valeur souhaitée pour toutes les couleurs</param>
        public Pixel(byte unifiedColors)
        {
            r = unifiedColors;
            g = unifiedColors;
            b = unifiedColors;
        }

        /// <summary>
        /// Créer un pixel à partir d'un tableau contenant les couleurs rouge, vert, bleu (respectivement)
        /// </summary>
        /// <param name="rgb">Tableau composé dans cet ordre des couleurs rouge, vert, bleu</param>
        public Pixel(byte[] rgb)
        {
            r = rgb[0];
            g = rgb[1];
            b = rgb[2];
        }

        /// <summary>
        /// Créer un pixel à partir d'un tableau contenant les couleurs rouge, vert, bleu (respectivement)
        /// </summary>
        /// <param name="rgb">Tableau composé dans cet ordre des couleurs rouge, vert, bleu</param>
        public Pixel(int[] rgb)
        {
            r = (byte)rgb[0];
            g = (byte)rgb[1];
            b = (byte)rgb[2];
        }

        /// <summary>
        /// Retourne un tableau contenant les valeurs RGB du pixel
        /// </summary>
        /// <returns>Composantes rouge, verte et bleue du pixel</returns>
        public byte[] getRGB()
        {
            return new byte[] { r, g, b };
        }

        public unsafe byte* getRGBPtr()
        {
            unsafe
            {
                fixed (byte* ptr = new byte[] { r, g, b })
                    return ptr;
            }
        }

        public byte[] getBGR()
        {
            return new byte[] { b, g, r };
        }

        /// <summary>
        /// Retourne l'équavalent gris d'un pixel
        /// </summary>
        /// <param name="scale">Nombre de nuances de gris</param>
        /// <returns>Pixel en échelle de gris</returns>
        public Pixel getGrayScale(byte scale)
        {
            byte total = (byte)((r + g + b) / 3);
            total = (byte)(Math.Round((double)total / (255 / (scale - 1))) * (255 / (scale - 1)));
            return new Pixel(total); 
        }

        /// <summary>
        /// Retourne l'équivalent gris d'un pixel en prenant en compte les coefficients de luminosité
        /// des couleurs RGB
        /// </summary>
        /// <param name="scale"></param>
        /// <returns></returns>
        public Pixel getGrayScaleLuminosity(byte scale)
        {
            byte total = (byte)(0.21 * r + 0.72 * g + 0.07 * b);
            total = (byte)(Math.Round((double)total / (255 / (scale - 1))) * (255 / (scale - 1)));
            return new Pixel(total);
        }

        /// <summary>
        /// Calcul les valeurs de variables HSL (Hue, Saturation, Lightness)
        /// </summary>
        private void computeHSL()
        {
            double rH = r / 255.0;
            double gH = g / 255.0;
            double bH = b / 255.0;

            double Cmax = Math.Max(Math.Max(rH, gH), bH);
            double Cmin = Math.Min(Math.Min(rH, gH), bH);

            double delta = Cmax - Cmin;

            L = (Cmin + Cmax) / 2.0;

            if (delta == 0) S = 0;
            else S = delta / (1.0 - Math.Abs(2.0 * L - 1));

            if (delta == 0) H = 0;
            else if (Cmax == rH) H = 60 * (((gH - bH) / delta) % 6);
            else if (Cmax == gH) H = 60 * (((bH - rH) / delta) + 2);
            else H = 60 * (((rH - gH) / delta) + 4);
        }
    }
}
