using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Imaging;
using System.Drawing;
using System.Collections;
using nft.framework;
using System.Drawing.Drawing2D;
using nft.framework.drawing;

namespace nft.util {
    /// <summary>
    /// represent several properties for a pixel format.
    /// </summary>
    public class ImageColorFormat {
        public readonly int PaletteBits; // 0 for non pallete-based colors
        public readonly int ColorBits; // 0 for palette-based colors
        public readonly int AlphaBits;
        public readonly bool HasPalette;
        public readonly bool GrayScaled;
        public readonly string Name;

        internal ImageColorFormat(PixelFormat pf) :
            this(pf, (pf == PixelFormat.Format16bppGrayScale)) {
        }

        internal ImageColorFormat(PixelFormat pf, bool grayscale) {
            this.HasPalette = 0 != (pf & PixelFormat.Indexed);
            this.GrayScaled = grayscale;
            string s = pf.ToString();
            int pos = s.IndexOf("bpp", 6);
            int bits = int.Parse(s.Substring(6, pos - 6));
            if (this.HasPalette) {
                this.PaletteBits = bits;
                this.ColorBits = 0;
                this.AlphaBits = 0;
            } else {
                this.PaletteBits = 0;
                this.ColorBits = bits;
                if (s.IndexOf("Argb") > 0) {
                    this.AlphaBits =
                        (pf == PixelFormat.Format16bppArgb1555 ? 1 : bits);
                } else {
                    this.AlphaBits = 0;
                }
            }
            this.Name = ImageUtil.GetColorFormatText(this);
        }

        internal ImageColorFormat(ImageColorFormat src, bool grayscale) {
            this.HasPalette = src.HasPalette;
            this.GrayScaled = grayscale;
            this.PaletteBits = src.PaletteBits;
            this.ColorBits = src.ColorBits;
            this.AlphaBits = src.AlphaBits;
            this.Name = ImageUtil.GetColorFormatText(this);
        }

        public override string ToString() {
            return Name;
        }
    }
    public class ImageUtil {
        static private readonly Dictionary<PixelFormat, ImageColorFormat> formatTable;
        static private readonly string fmt_type_rgb;
        static private readonly string fmt_type_argb;
        static private readonly string fmt_type_indexed_color;
        static private readonly string fmt_type_indexed_grayscale;
        static private readonly string fmt_type_grayscale;

        static ImageUtil() {
            fmt_type_rgb = Main.resources["imageutil.type_rgb"].stringValue;
            fmt_type_argb = Main.resources["imageutil.type_argb"].stringValue;
            fmt_type_indexed_color = Main.resources["imageutil.type_indexed_color"].stringValue;
            fmt_type_indexed_grayscale = Main.resources["imageutil.type_indexed_grayscale"].stringValue;
            fmt_type_grayscale = Main.resources["imageutil.type_grayscale"].stringValue;

            Array arr = Enum.GetValues(typeof(PixelFormat));
            formatTable = new Dictionary<PixelFormat, ImageColorFormat>(arr.Length);
            foreach (PixelFormat pf in arr) {
                string s = pf.ToString();
                if (s.StartsWith("Format"))
                    formatTable.Add(pf, new ImageColorFormat(pf));
            }
        }

        /// <summary>
        /// retruns description text for a pixel format of the image.
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static string GetColorFormatText(Image img) {
            return GetColorFormat(img).Name;
        }

        internal static string GetColorFormatText(ImageColorFormat fmt) {
            int bits = Math.Max(fmt.ColorBits, fmt.PaletteBits);
            int cols = 1 << bits;
            string tmpl;
            if (fmt.HasPalette) {
                tmpl = (fmt.GrayScaled) ? fmt_type_indexed_grayscale : fmt_type_indexed_color;
            } else if (fmt.AlphaBits == bits) {
                tmpl = fmt_type_argb;
            } else {
                tmpl = (fmt.GrayScaled) ? fmt_type_grayscale : fmt_type_rgb;
            }
            return string.Format(tmpl, bits, cols);
        }

        /// <summary>
        /// returns ImageColorFormat corresponds to a pixel format of the image.
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static ImageColorFormat GetColorFormat(Image img) {
            PixelFormat pf = img.PixelFormat;
            ImageColorFormat ret = formatTable[pf];
            if (pf == PixelFormat.Format8bppIndexed) {
                if (0 != (img.Palette.Flags & 2)) {
                    ret = new ImageColorFormat(ret, true);
                }
            }
            return ret;
        }

        /// <summary>
        /// create thumbnail image with default pixelformat and interpolation.
        /// </summary>
        /// <param name="img"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public static Bitmap CreateThumbnail(Image img, Size size) {
            Bitmap bmp = new Bitmap(size.Width, size.Height);
            Graphics g = Graphics.FromImage(bmp);
            DrawThumbnail(img, g, new Rectangle(0, 0, size.Width, size.Height));
            return bmp;
        }

        /// <summary>
        /// create thumbnail image with specified pixelformat and interpolation.
        /// </summary>
        /// <param name="img"></param>
        /// <param name="size"></param>
        /// <param name="fmt"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public static Bitmap CreateThumbnail(Image img, Size size, PixelFormat fmt, InterpolationMode mode) {
            Bitmap bmp = new Bitmap(size.Width, size.Height, fmt);
            Graphics g = Graphics.FromImage(bmp);
            g.InterpolationMode = mode;
            DrawThumbnail(img, g, new Rectangle(0, 0, size.Width, size.Height));
            return bmp;
        }

        /// <summary>
        /// draws isometric thumbnail of the image to fit in the range.
        /// </summary>
        /// <param name="img"></param>
        /// <param name="dest"></param>
        /// <param name="range"></param>
        /// <param name="mode"></param>
        public static void DrawThumbnail(Image img, Graphics dest, Rectangle range) {
            int iw = img.Width;
            int ih = img.Height;
            if (iw * ih == 0 || range.Width * range.Height == 0) {
                return;
            }
            double rx = (double)range.Width / (double)img.Width;
            double ry = (double)range.Height / (double)img.Height;
            if (rx > ry) {
                rx = ry;
            }
            iw = (int)(iw * rx);
            ih = (int)(ih * rx);
            int x = range.X + (range.Width - iw) / 2;
            int y = range.Y + (range.Height - ih) / 2;
            dest.DrawImage(img, x, y, iw, ih);
        }
    }
}
