using System;
using System.Data;
using System.Configuration;
using System.Drawing.Imaging;
using System.Drawing;
using System.Collections.Generic;
using System.IO;
using System.Web;

namespace ImageTemplateNet
{
    /// <summary>
    /// Used to draw images from files onto a generated image.
    /// </summary>
    public class ImageTemplateElement : TemplateElement
    {
        #region "Constructors"
        public ImageTemplateElement()
        {
        }
        #endregion

        public override void Draw(DrawContext context)
        {
            ImageElementConfig imageConfig = (ImageElementConfig)context.ElementConfig;

            string imageUrl;
            Antlr.StringTemplate.StringTemplate stImageUrl = new Antlr.StringTemplate.StringTemplate(imageConfig.ImageUrl);

            string sDefaultImageDir = ConfigurationManager.AppSettings["DefaultImageDir"];
            if (imageConfig.BaseImageDir != null)
            {
                sDefaultImageDir = GetFullPath(imageConfig.BaseImageDir);
                if ((context.Template.ImageDirectory == null)
                    || (context.Template.ImageDirectory.FullName != imageConfig.BaseImageDir)) 
                {
                    context.Template.ImageDirectory = new DirectoryInfo(imageConfig.BaseImageDir);
                }
            }
            else
            {
                if (context.Template.ImageDirectory == null) 
                {
                    context.Template.ImageDirectory = context.Template.BaseDirectory;
                }
            }
            stImageUrl.SetAttribute("config", imageConfig);
            stImageUrl.SetAttribute("template", context.Template);
            stImageUrl.SetAttribute("DefaultImageDir", sDefaultImageDir);


            if (imageConfig.Parameters != null)
            {
                for (int paramIdx = 0; paramIdx < imageConfig.Parameters.Length; paramIdx++)
                {
                    stImageUrl.SetAttribute("param" + (paramIdx+1), imageConfig.Parameters[paramIdx]);
                }
            }

            imageUrl = stImageUrl.ToString();

            if (imageUrl.StartsWith("~"))
            {
                imageUrl = HttpContext.Current.Server.MapPath(imageUrl); // Turn ~/xx/xx into a physical path relative to this web app
            }

            FileInfo file = new FileInfo(imageUrl);

            /*
            if (!file.Exists)
            {
                file = new FileInfo (Path.Combine(sDefaultImageDir, imageUrl));
            }
            */

            // Check the image is comming from one of the allowed paths
            if (imageUrl.Contains("..") || imageUrl.Contains(":"))
            {
                // If the image is not coming from allowed base directory
                if (!file.FullName.StartsWith(context.Template.BaseDirectory.FullName) 
                    && (sDefaultImageDir != null)
                    && (!file.FullName.StartsWith(sDefaultImageDir)))
                    //&& !file.FullName.StartsWith(tsDefaultImageDir))
                {
                    throw new ApplicationException("Security Violation.  The Image URL cannot access parent paths.");
                }
            }
            
            // If the file does not exist then design the default image if specified
            if (imageConfig.DefaultImageUrl !=null && file.Exists == false)
            {
                String defaultImageUrl;
                if (imageConfig.DefaultImageUrl.StartsWith("~"))
                {
                    defaultImageUrl = HttpContext.Current.Server.MapPath(imageConfig.DefaultImageUrl);
                }
                else
                {
                    defaultImageUrl = imageConfig.DefaultImageUrl;
                }
                file = new FileInfo(defaultImageUrl);
            }

            int revise = 0; // ????

            if (file.Exists)
            {
                Bitmap productImage=null;
                try
                {
                    productImage = new Bitmap(file.FullName);
                    Rectangle outputPanel = context.GetBounds();
                    Rectangle result = outputPanel;

                    if (imageConfig.SizeMode == System.Windows.Forms.PictureBoxSizeMode.AutoSize)
                    {
                        if (productImage.Width > outputPanel.Width || productImage.Height > outputPanel.Height)
                        {
                            productImage = Resize(productImage, outputPanel.Size);
                        }
                    }

                    if (imageConfig.ContentAlignment == ContentAlignment.BottomCenter)
                    {
                        result = new Rectangle(result.X + intGZ(result.Width - productImage.Width) / 2, result.Y + intGZ(result.Height - productImage.Height - revise), productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.BottomLeft)
                    {
                        result = new Rectangle(result.X, result.Y + intGZ(result.Height - productImage.Height - revise), productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.BottomRight)
                    {
                        result = new Rectangle(result.X + intGZ(result.Width - productImage.Width), result.Y + intGZ(result.Height - productImage.Height - revise), productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.MiddleCenter)
                    {
                        result = new Rectangle(result.X + intGZ(result.Width - productImage.Width) / 2, result.Y + intGZ(result.Height - productImage.Height - revise) / 2, productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.MiddleLeft)
                    {
                        result = new Rectangle(result.X, result.Y + intGZ(result.Height - productImage.Height - revise) / 2, productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.MiddleRight)
                    {
                        result = new Rectangle(result.X + intGZ(result.Width - productImage.Width), result.Y + intGZ(result.Height - productImage.Height - revise) / 2, productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.TopCenter)
                    {
                        result = new Rectangle(result.X + intGZ(result.Width - productImage.Width) / 2, result.Y, productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.TopLeft)
                    {
                        result = new Rectangle(result.X, result.Y, productImage.Width, productImage.Height);
                    }
                    else if (imageConfig.ContentAlignment == ContentAlignment.TopRight)
                    {
                        result = new Rectangle(result.X + intGZ(result.Width - productImage.Width), result.Y, productImage.Width, productImage.Height);
                    }
                    //g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                    //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    //g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
                    Graphics g = context.Graphics;

                    if (imageConfig.SizeMode == System.Windows.Forms.PictureBoxSizeMode.StretchImage)
                    { // Strech the image to the size defined
                        g.DrawImage(productImage, result);
                    }
                    else if (imageConfig.SizeMode == System.Windows.Forms.PictureBoxSizeMode.Normal)
                    {
                        g.DrawImageUnscaled(productImage, result);
                    }
                    else if (imageConfig.SizeMode == System.Windows.Forms.PictureBoxSizeMode.AutoSize)
                    {
                        g.DrawImage(productImage, result);
                    }
                    else
                    {
                        g.DrawImageUnscaled(productImage, result);
                    }
                }
                finally
                {
                    if (productImage != null) { productImage.Dispose(); }
                }
            }
        }

        #region "Private Methods"

        /// <summary>
        /// 
        /// </summary>
        /// <param name="imageUrl"></param>
        /// <returns></returns>
        private string GetFullPath(string imageUrl)
        {
            if (imageUrl.StartsWith("~"))
            {
                return HttpContext.Current.Server.MapPath(imageUrl);
            }
            else
            {
                return imageUrl;
            }
        }


        private int intGZ(int input)
        {
            return input > 0 ? input : 0;
        }

        private Bitmap Resize(Bitmap image, Size targetSize)
        {
            return new Bitmap(image, this.ScaleToFit(image.Size, targetSize.Width, targetSize.Height));
        }

        private Size ScaleToFit(Size sourceImgSize, int targetImgWidth, int targetImgHeight)
        {
            Size TargetImgSize = sourceImgSize;
            int sourceWidth = sourceImgSize.Width;
            int sourceHeight = sourceImgSize.Height;
            int destX = 0;
            int destY = 0;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)targetImgWidth / (float)sourceWidth);
            nPercentH = ((float)targetImgHeight / (float)sourceHeight);
            if (nPercentH < nPercentW)
            {
                nPercent = nPercentH;
                destX = System.Convert.ToInt16((targetImgWidth - (sourceWidth * nPercent)) / 2);
            }
            else
            {
                nPercent = nPercentW;
                destY = System.Convert.ToInt16((targetImgHeight - (sourceHeight * nPercent)) / 2);
            }

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);
            TargetImgSize.Width = destWidth;
            TargetImgSize.Height = destHeight;
            return TargetImgSize;
        }
        #endregion

    }
}