using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Drawing;
using r13.Helpers;
using System.Drawing.Drawing2D;
using System.IO;
using System.Drawing.Imaging;

namespace r13.Controllers
{
    public class CaptchaImageController : Controller
    {
        private const int ImageWidth = 200, ImageHeight = 70;
        private const string FontFamily = "Rockwell";
        private readonly static Brush Foreground = Brushes.Navy;
        private readonly static Color Background = Color.Silver;

        private const int WarpFactor = 5;
        private const Double xAmp = WarpFactor * ImageWidth / 100;
        private const Double yAmp = WarpFactor * ImageHeight / 85;
        private const Double xFreq = 2 * Math.PI / ImageWidth;
        private const Double yFreq = 2 * Math.PI / ImageHeight;

        private GraphicsPath DeformPath(GraphicsPath path)
        {
            PointF[] deformed = new PointF[path.PathPoints.Length];
            Random rng = new Random();
            Double xSeed = rng.NextDouble() * 2 * Math.PI;
            Double ySeed = rng.NextDouble() * 2 * Math.PI;
            for (int i = 0; i < path.PathPoints.Length; i++)
            {
                PointF original = path.PathPoints[i];
                Double val = xFreq * original.X + yFreq * original.Y;
                int xOffset = (int)(xAmp * Math.Sin(val + xSeed));
                int yOffset = (int)(yAmp * Math.Sin(val + ySeed));
                deformed[i] = new PointF(original.X + xOffset, original.Y + yOffset);
            }
            return new GraphicsPath(deformed, path.PathTypes);
        }


        public void Render(string challengeGuid)
        {
            // Pobranie tekstu rozwiązania z Session[] 
            string key = CaptchaHelper.SessionKeyPrefix + challengeGuid;
            string solution = (string)HttpContext.Session[key];

            if (solution != null)
            {
                // Utworzenie pustego płótna, na którym powstanie CAPTCHA 
                using (Bitmap bmp = new Bitmap(ImageWidth, ImageHeight))
                using (Graphics g = Graphics.FromImage(bmp))
                using (Font font = new Font(FontFamily, 1f))
                {
                    g.Clear(Background);

                    // Próbne wygenerowanie obrazu w celu określenia najlepszej wielkości czcionki
                    SizeF finalSize;
                    SizeF testSize = g.MeasureString(solution, font);
                    float bestFontSize = Math.Min(ImageWidth / testSize.Width,
                                            ImageHeight / testSize.Height) * 0.95f;

                    using (Font finalFont = new Font(FontFamily, bestFontSize))
                    {
                        finalSize = g.MeasureString(solution, finalFont);
                    }

                    // Pobranie ścieżki reprezentującej tekst wycentrowany na płótnie 
                    g.PageUnit = GraphicsUnit.Point;
                    PointF textTopLeft = new PointF((ImageWidth - finalSize.Width) / 2,
                                                  (ImageHeight - finalSize.Height) / 2);
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddString(solution, new FontFamily(FontFamily), 0,
                            bestFontSize, textTopLeft, StringFormat.GenericDefault);

                        // Wygenerowanie ścieżki na mapie bitowej 
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        
                        g.FillPath(Foreground, DeformPath(path)); 
                        g.Flush();

                        // Wysłanie obrazu w formacie PNG do strumienia odpowiedzi
                        Response.ContentType = "image/png";
                        using (var memoryStream = new MemoryStream())
                        {
                            bmp.Save(memoryStream, ImageFormat.Png);
                            memoryStream.WriteTo(Response.OutputStream);
                        }
                    }
                }
            }
        }
    }

}
