﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.Imaging;

namespace zComp.Wpf
{
#warning mettre ça dans zComp.Tools
    public static class BitmapSourceExtensions
    {
        /// <summary>
        /// Change the size of image in fonction of the needed weight
        /// </summary>
        /// <param name="originalBmp"></param>
        /// <param name="tailleMinKo"></param>
        /// <param name="tailleMaxKo"></param>
        /// <returns></returns>
        public static Bitmap ResizeImage(this Bitmap originalBmp, int tailleMinKo, int tailleMaxKo)
        {
            return ResizeImage(originalBmp, originalBmp, tailleMinKo, tailleMaxKo, 0, 200);
        }

        private static int GetImageJpegWeightInKB(this Bitmap bitmapJpg)
        {
            using (var sourceStream = bitmapJpg.GetBitmapSource().ImageToByte(new JpegBitmapEncoder()))
            using (var memoryStream = new MemoryStream((int)sourceStream.Length))
                {
                    sourceStream.CopyTo(memoryStream);
                    return (int)((double)memoryStream.ToArray().Length / 1024.0);
                }
        }

        private static Bitmap ResizeImage(Bitmap originalBmp, Bitmap courantBmp, int tailleMinKo, int tailleMaxKo, double pourcentMin, double pourcentMax)
        {
            Bitmap bitmapJpg = new Bitmap(courantBmp.GetBitmapSource().ImageToByte(new JpegBitmapEncoder()));
            int tailleJpg = bitmapJpg.GetImageJpegWeightInKB();
            double pourcentCourant = (pourcentMin + pourcentMax) / 2;
#if DEBUG
            Debug.WriteLine("### Resolution : " + pourcentCourant + "% # (" + courantBmp.Width + "x" + courantBmp.Height + ")  poids : " + tailleJpg + "KO");
#endif
            if ((tailleJpg >= tailleMinKo && tailleJpg <= tailleMaxKo
                || (tailleJpg <= tailleMinKo && pourcentCourant >= 100)))
                return bitmapJpg;

            // Nouvelle plage
            if (tailleJpg > tailleMaxKo) pourcentMax = pourcentCourant;
            else pourcentMin = pourcentCourant;

            double milieu = (pourcentMin + pourcentMax) / 2;
            int newWidth = (int)(originalBmp.Width * (milieu / 100));
            int newHeight = (int)(originalBmp.Height * (milieu / 100));

            // La taille en pixels de l'image ne bouge plus ? => on arrête
            if (newWidth == courantBmp.Width || newHeight == courantBmp.Height)
                return bitmapJpg;

            courantBmp = originalBmp.ResizeImage(newWidth, newHeight);
            return ResizeImage(originalBmp, courantBmp, tailleMinKo, tailleMaxKo, pourcentMin, pourcentMax);
        }

        /// <summary>
        /// Write BitmapSource to stream
        /// </summary>
        /// <param name="stream">stream for write to</param>
        /// <param name="encoder">encoder</param>
        public static Stream ImageToByte(this BitmapSource bitmapSource, BitmapEncoder encoder)
        {
            var stream = new MemoryStream();
            encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
            encoder.Save(stream);
            stream.Flush();
            return stream;
        }

        /// <summary>
        /// Convert image to file
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="PathOfFile"></param>
        /// <param name="encoder"></param>
        public static void ImageToFile(this Bitmap bitmap, string PathOfFile, BitmapEncoder encoder)
        {
            encoder.Frames.Add(BitmapFrame.Create(bitmap.GetBitmapSource()));
            using (Stream stream = File.Create(PathOfFile))
            {
                encoder.Save(stream);
            }
        }

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);

        /// <summary>
        /// Get the BitmapSource
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static BitmapSource GetBitmapSource(this Bitmap bitmap)
        {
            //if you use GetHbitmap : You are responsible for calling the GDI DeleteObject method to free the memory used by the GDI bitmap object. For more information about GDI bitmaps, see Bitmaps in the Windows GDI documentation.
            IntPtr intPtr = bitmap.GetHbitmap();
            BitmapSource bitmapSourceFromHBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(intPtr, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(intPtr);
            return bitmapSourceFromHBitmap;
        }


        public static byte[] GetEncodedImage(this System.Windows.Controls.Image image, BitmapEncoder encoder)
        {
            var bs = image.Source as BitmapSource;

            if (bs == null)
                throw new Exception("La source de l'image n'est pas de type BitmapSource");

            var r = new Int32Rect(0, 0, bs.PixelWidth, bs.PixelHeight);

            using (var mStream = new MemoryStream())
            {
                encoder.Frames.Add(BitmapFrame.Create(new CroppedBitmap(bs, r))); 
                encoder.Save(mStream);

                byte[] buffer = mStream.ToArray();

                return buffer;
            }
        }
    }
}
