using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
using System.IO;
#if !MONO
using FastReport.DevComponents.DotNetBar;
#endif

namespace FastReport.Utils
{
    partial class Res
    {
        private class ImageInfo
        {
            private int dpi;
            private List<Bitmap> images;
            private ImageList imageList;
            private bool imagesLoaded = false;

            public List<Bitmap> Images 
            { 
                get 
                {
                    if (!imagesLoaded)
                        LoadImages();
                    return images; 
                } 
            }

            private Bitmap AddImage(Bitmap srcImage, int x, int y, int srcImageSize)
            {
                int destImageSize = (int)Math.Round(16 * dpi / 96f);
                Bitmap image = new Bitmap(destImageSize, destImageSize);
                
                // Upscaling images contained in buttons.png produces artifacts.
                // Copy the portion of image to slice then upscale it.
                Bitmap slice = null;
                if (srcImage.Width > srcImageSize)
                {
                    slice = new Bitmap(srcImageSize, srcImageSize);
                    using (Graphics g = Graphics.FromImage(slice))
                    {
                        g.DrawImage(srcImage, new Rectangle(0, 0, srcImageSize, srcImageSize), x, y, srcImageSize, srcImageSize, GraphicsUnit.Pixel);
                    }
                    x = 0; 
                    y = 0;
                    srcImage = slice;
                }
                
                using (Graphics g = Graphics.FromImage(image))
                {
                    g.DrawImage(srcImage, new Rectangle(0, 0, destImageSize, destImageSize), x, y, srcImageSize, srcImageSize, GraphicsUnit.Pixel);
                }
                
                images.Add(image);
                if (slice != null)
                    slice.Dispose();
                return image;
            }

            private void LoadImages()
            {
                imagesLoaded = true;
                images = new List<Bitmap>();

                const string resName = "buttons.png"; // the image must contain 10 icons in a row
                using (Bitmap allImages = LoadResourceImage(resName, dpi))
                {
                    int srcImageSize = allImages.Width / 10;
                    
                    int x = 0;
                    int y = 0;
                    bool done = false;

                    do
                    {
                        AddImage(allImages, x, y, srcImageSize);

                        x += srcImageSize;
                        if (x >= allImages.Width)
                        {
                            x = 0;
                            y += srcImageSize;
                        }
                        done = y > allImages.Height;
                    }
                    while (!done);
                }
            }

            private void CreateImageList()
            {
                imageList = new ImageList();
                int imageSize = images[0].Width;
                imageList.ImageSize = new Size(imageSize, imageSize);
                imageList.ColorDepth = ColorDepth.Depth32Bit;

                foreach (Bitmap bmp in images)
                {
                    imageList.Images.Add(bmp);
                }
            }

            public ImageList GetImages()
            {
                if (!imagesLoaded)
                    LoadImages();
                if (imageList == null)
                    CreateImageList();
                return imageList;
            }

            public Bitmap GetImage(int index)
            {
                if (index < 0)
                    return null;
                if (!imagesLoaded)
                    LoadImages();
                return images[index];
            }

            // for images added by user
            public int AddImage(Bitmap img)
            {
                // ensure everything is loaded
                GetImages();

                Bitmap image = AddImage(img, 0, 0, img.Width);
                imageList.Images.Add(image);
                return images.Count - 1;
            }

            public ImageInfo(int dpi)
            {
                this.dpi = dpi;
            }
        }

        private readonly static Dictionary<int, ImageInfo> dpiAwareImages = new Dictionary<int, ImageInfo>();

        private static Bitmap LoadResourceImage(string name, int dpi, bool scaleToTargetSize = false)
        {
            // loads appropriate image for given dpi and current icon pack
            // - original name: "name.png"
            // - high dpi: "name-hi.png"
            // - other image pack: "name-1.png", "name-1-hi.png"
            //
            // Notes:
            // - the image with original name (for 96dpi) must exist. It will be used to determine the target size.
            // - if no image pack or hi-version of image exists, the original image is used. Scaling is performed if needed.

            string originalName = name;
            Bitmap originalImage = ResourceLoader.GetBitmap(originalName);
            Bitmap srcImage = null;
            Size destImageSize = new Size((int)Math.Round(originalImage.Width * dpi / 96f), (int)Math.Round(originalImage.Height * dpi / 96f));

            int iconPack = Config.IconPack;
            if (iconPack != 0)
                name = Path.GetFileNameWithoutExtension(originalName) + "-" + iconPack.ToString() + Path.GetExtension(originalName);

            // high dpi images
            if (dpi >= 144)
                name = Path.GetFileNameWithoutExtension(name) + "-hi" + Path.GetExtension(originalName);

            srcImage = ResourceLoader.GetBitmap(name);
            if (srcImage == null)
            { 
                // no image exist, use the original one
                srcImage = originalImage;
            }

            // scale to target size
            if (scaleToTargetSize)
            {
                Bitmap destImage = new Bitmap(destImageSize.Width, destImageSize.Height);
                using (Graphics g = Graphics.FromImage(destImage))
                {
                    g.DrawImage(srcImage, new Rectangle(0, 0, destImageSize.Width, destImageSize.Height));
                }
                return destImage;
            }
            return srcImage;
        }

        private static int CheckDpi(int dpi)
        {
            if (!dpiAwareImages.ContainsKey(dpi))
                dpiAwareImages.Add(dpi, new ImageInfo(dpi));
            return dpi;
        }

        private static int CheckUserImages(int dpi)
        {
            if (dpi != 96)
            {
                // if image list has less images than 96-dpi image list, add user images to image list
                List<Bitmap> images96 = dpiAwareImages[CheckDpi(96)].Images;
                List<Bitmap> images = dpiAwareImages[CheckDpi(dpi)].Images;
                for (int i = images.Count; i < images96.Count; i++)
                    dpiAwareImages[dpi].AddImage(images96[i]);
            }
            return dpi;
        }

        /// <summary>
        /// Adds user image to 96 dpi images.
        /// </summary>
        /// <param name="img">User image (16x16 pixels).</param>
        /// <returns>Image index in the image list.</returns>
        internal static int AddImage(Bitmap img)
        {
            return dpiAwareImages[CheckDpi(96)].AddImage(img);
        }

        /// <summary>
        /// Gets the standard images used in FastReport as an <b>ImageList</b>.
        /// </summary>
        /// <returns><b>ImageList</b> object that contains standard images.</returns>
        /// <remarks>
        /// FastReport contains about 240 truecolor images of 16x16 size that are stored in one 
        /// big image side-by-side. This image can be found in FastReport resources (the "buttons.png" resource).
        /// </remarks>
        public static ImageList GetImages(int dpi)
        {
            return dpiAwareImages[CheckUserImages(CheckDpi(dpi))].GetImages();
        }

        /// <summary>
        /// Gets an image with specified index.
        /// </summary>
        /// <param name="index">Image index (zero-based).</param>
        /// <param name="dpi">Dpi value (96 for base dpi).</param>
        /// <returns>The image with specified index.</returns>
        /// <remarks>
        /// FastReport contains about 240 truecolor images of 16x16 size that are stored in one 
        /// big image side-by-side. This image can be found in FastReport resources (the "buttons.png" resource).
        /// </remarks>
        public static Bitmap GetImage(int index, int dpi)
        {
            return dpiAwareImages[CheckUserImages(CheckDpi(dpi))].GetImage(index);
        }

        /// <summary>
        /// Gets an image with specified name from resources.
        /// </summary>
        /// <param name="name">The name of image resource.</param>
        /// <param name="dpi">Dpi value (96 for base dpi).</param>
        /// <returns>The image.</returns>
        public static Bitmap GetImage(string name, int dpi)
        {
            return LoadResourceImage(name, dpi, true);
        }

        /// <summary>
        /// Gets an image with specified index and converts it to <b>Icon</b>.
        /// </summary>
        /// <param name="index">Image index (zero-based).</param>
        /// <param name="dpi">Dpi value (96 for base dpi).</param>
        /// <returns>The <b>Icon</b> object.</returns>
        public static Icon GetIcon(int index, int dpi)
        {
            return Icon.FromHandle(GetImage(index, dpi).GetHicon());
        }

#if !MONO
        static partial void ResDesignExt()
        {
            // for using FastReport.dll without FastReport.Bars.dll if the designer is not shown
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (a.ManifestModule.Name == "FastReport.Bars.dll")
                {
                    RegisterLocalizeStringEventHandler();
                    break;
                }
            }
        }

        private static void RegisterLocalizeStringEventHandler()
        {
            LocalizationKeys.LocalizeString += new DotNetBarManager.LocalizeStringEventHandler(LocalizationKeys_LocalizeString);
        }

        private static void LocalizationKeys_LocalizeString(object sender, LocalizeEventArgs e)
        {
            switch (e.Key)
            {
                case "barsys_autohide_tooltip":
                    e.LocalizedValue = Res.Get("Designer,ToolWindow,AutoHide");
                    e.Handled = true;
                    break;
                case "barsys_close_tooltip":
                    e.LocalizedValue = Res.Get("Designer,ToolWindow,Close");
                    e.Handled = true;
                    break;
                case "cust_mnu_addremove":
                    e.LocalizedValue = Res.Get("Designer,Toolbar,AddOrRemove");
                    e.Handled = true;
                    break;
                case "sys_morebuttons":
                    e.LocalizedValue = Res.Get("Designer,Toolbar,MoreButtons");
                    e.Handled = true;
                    break;
            }
        }
#endif
    }

}
