using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Imaging;

namespace CssSpriteGenerator
{
    public class PixelFormatUtils
    {
        /// <summary>
        /// Compares two pixel formats, and returns the one the with the highest bits per pixel.
        /// </summary>
        /// <param name="pf1"></param>
        /// <param name="pf2"></param>
        /// <returns></returns>
        public static PixelFormat HigherPixelFormat(PixelFormat pf1, PixelFormat pf2)
        {
            // If they are the same, than just return one of them
            if (pf1 == pf2) { return pf1; }

            //----------------------------
            //Int values of the PixelFormat enum values in hex, followed by their names

            // 10000 - Indexed
            // 20000 - Gdi
            // 21005 - Format16bppRgb555
            // 21006 - Format16bppRgb565
            // 21808 - Format24bppRgb
            // 22009 - Format32bppRgb

            // 30101 - Format1bppIndexed
            // 30402 - Format4bppIndexed
            // 30803 - Format8bppIndexed

            // 40000 - Alpha
            // 61007 - Format16bppArgb1555
            // 80000 - PAlpha
            // e200b - Format32bppPArgb
            //100000 - Extended
            //101004 - Format16bppGrayScale
            //10300c - Format48bppRgb
            //1c400e - Format64bppPArgb
            //200000 - Canonical
            //26200a - Format32bppArgb
            //34400d - Format64bppArgb

            //------------------------------
            //Enums sorted by last 4 digits
            //Note that the format with the highest number of bits, etc. is always the one with the highest
            //last 4 digits (the least significant 32 bits)
            //(except for Format16bppGrayScale).

            // 30101 - Format1bppIndexed
            // 30402 - Format4bppIndexed
            // 30803 - Format8bppIndexed

            //101004 - Format16bppGrayScale

            // 21005 - Format16bppRgb555
            // 21006 - Format16bppRgb565
            // 61007 - Format16bppArgb1555

            // 21808 - Format24bppRgb

            // 22009 - Format32bppRgb
            //26200a - Format32bppArgb
            // e200b - Format32bppPArgb

            //10300c - Format48bppRgb

            //1c400e - Format64bppPArgb
            //34400d - Format64bppArgb

            // PixelFormat.Format16bppGrayScale has 16 bits for gray scale.
            // To convert that to colour, you need 48bpp (16 bits for R,G,B)
            // Note that at this stage, we know that not both pixel format are grey scale, because than they would be the same
            // and we would already have returned out of this method.

            if (pf1 == PixelFormat.Format16bppGrayScale) { pf1 = PixelFormat.Format48bppRgb; }
            if (pf2 == PixelFormat.Format16bppGrayScale) { pf2 = PixelFormat.Format48bppRgb; }

            int pf1LeastSignificant32bits = ((int)pf1) & 0xffff;
            int pf2LeastSignificant32bits = ((int)pf2) & 0xffff;

            if (pf1LeastSignificant32bits > pf2LeastSignificant32bits)
            {
                return pf1;
            }

            return pf2;
        }

        /// <summary>
        /// Returns the number of bits per pixel of a pixel format.
        /// </summary>
        /// <param name="pf"></param>
        /// <returns></returns>
        public static int BitsPerPixel(PixelFormat pf)
        {
            int bitsPerPixel = 1;
            switch (pf)
            {
                case PixelFormat.Format1bppIndexed:
                    bitsPerPixel = 1;
                    break;

                case PixelFormat.Format4bppIndexed:
                    bitsPerPixel = 4;
                    break;

                case PixelFormat.Format8bppIndexed:
                    bitsPerPixel = 8;
                    break;

                case PixelFormat.Format16bppGrayScale:
                case PixelFormat.Format16bppRgb555:
                case PixelFormat.Format16bppRgb565:
                case PixelFormat.Format16bppArgb1555:
                    bitsPerPixel = 16;
                    break;

                case PixelFormat.Format24bppRgb:
                    bitsPerPixel = 24;
                    break;

                case PixelFormat.Format32bppRgb:
                case PixelFormat.Format32bppArgb:
                case PixelFormat.Format32bppPArgb:
                    bitsPerPixel = 32;
                    break;

                case PixelFormat.Format48bppRgb:
                    bitsPerPixel = 48;
                    break;

                case PixelFormat.Format64bppArgb:
                case PixelFormat.Format64bppPArgb:
                    bitsPerPixel = 64;
                    break;
            }

            return bitsPerPixel;
        }

        /// <summary>
        /// Returns the number of distinct colors that can be represented by the
        /// given pixel format.
        /// 
        /// Because the number of colors for Format64bppArgb and Format64bppPArgb
        /// doesn't fit in a Int64, the method returns Int64.MaxValue for them.
        /// </summary>
        /// <param name="pf"></param>
        /// <returns></returns>
        public static Int64 ColorsPerPixel(PixelFormat pf)
        {
            int bitsPerPixel = BitsPerPixel(pf);

            if (bitsPerPixel == 64) { return Int64.MaxValue; }

            Int64 nbrColors = 1 << bitsPerPixel;
            return nbrColors;
        }

        /// <summary>
        /// Returns true if the given pixel format is indexed.
        /// </summary>
        /// <param name="pf"></param>
        /// <returns></returns>
        public static bool IsIndexedPixelFormat(PixelFormat pf)
        {
            return ((pf == PixelFormat.Format1bppIndexed) ||
                    (pf == PixelFormat.Format4bppIndexed) ||
                    (pf == PixelFormat.Format8bppIndexed));
        }
    }
}
