using System;
using System.Globalization;
using System.Windows;
using System.Windows.Media;

namespace Microscopic_Traffic_Simulator.Renderers
{
    class ZoomValuesGenerator
    {
        /// <summary>
        /// Gets Y Value for X value for Ferguson cubics.
        /// </summary>
        /// <param name="x">Value in X axis.</param>
        /// <returns>Value in Y axis.</returns>
        public double GetYValue(double x)
        {            
            Point P0 = new Point(0.0, 0.01);
            Point P1 = new Point(50.0, 1.0);
            Point P2 = P1;
            Point P3 = new Point(100.0, 100.0);
            Point V0 = new Point(125.0, 0);
            Point V1 = new Point(1.0, 0.1);
            Point V2 = V1;
            Point V3 = new Point(0.0, 287.0);

            double eps = 0.000001;

            if (x <= 0.0)
                return 0.01;
            else if (x == 50.0)
                return 1.0;
            else if (x >= 100.0)
                return 100.0;
            //assign value t to 0.5
            double t = 0.5;
            //number to add or subtract to t
            double toAddOrSubtract = 0.25;
            //determine which part of curve to search
            Point p0, p1, v0, v1;
            if (x < 50.0)
            {   //lower part 0-5
                p0 = P0;
                p1 = P1;
                v0 = V0;
                v1 = V1;
            }
            else
            {   //higher part 5-10
                p0 = P2;
                p1 = P3;
                v0 = V2;
                v1 = V3;
            }
            //ofdResult point
            Point point = new Point();
            //coefficients
            double f1, f2, f3, f4;
            //search for linear number
            do
            {
                //compute coefficients
                f1 = F1(t);
                f2 = F2(t);
                f3 = F3(t);
                f4 = F4(t);
                //compute X ofdResult
                point.X = p0.X * f1 + p1.X * f2 + v0.X * f3 + v1.X * f4;
                //adjust t
                if (x > point.X)
                    t += toAddOrSubtract;
                else
                    t -= toAddOrSubtract;
                toAddOrSubtract /= 2;
            } while (Math.Abs(x - point.X) > eps);//end if we are too close
            //return Y value
            double Yvalue = p0.Y * f1 + p1.Y * f2 + v0.Y * f3 + v1.Y * f4;
            return Yvalue;
        }

        /// <summary>
        /// Method as part of computing value in X axis for Ferguson cubic.
        /// </summary>
        /// <param name="t">t parameter.</param>
        /// <returns>Partial result for computing value in X axis.</returns>
        protected double F1(double t)
        {
            return 2 * Math.Pow(t, 3) - 3 * Math.Pow(t, 2) + 1;
        }

        /// <summary>
        /// Method as part of computing value in X axis for Ferguson cubic.
        /// </summary>
        /// <param name="t">t parameter.</param>
        /// <returns>Partial result for computing value in X axis.</returns>
        protected double F2(double t)
        {
            return -2 * Math.Pow(t, 3) + 3 * Math.Pow(t, 2);
        }

        /// <summary>
        /// Method as part of computing value in X axis for Ferguson cubic.
        /// </summary>
        /// <param name="t">t parameter.</param>
        /// <returns>Partial result for computing value in X axis.</returns>
        protected double F3(double t)
        {
            return Math.Pow(t, 3) - 2 * Math.Pow(t, 2) + t;
        }

        /// <summary>
        /// Method as part of computing value in X axis for Ferguson cubic.
        /// </summary>
        /// <param name="t">t parameter.</param>
        /// <returns>Partial result for computing value in X axis.</returns>
        protected double F4(double t)
        {
            return Math.Pow(t, 3) - Math.Pow(t, 2);
        }

        /// <summary>
        /// Draw points to visualize Ferguson cubic used for determining zoom rates from some interval.
        /// </summary>
        /// <param name="dc">Drawing context used to visualize the Ferguson cubic.</param>
        public void Draw(DrawingContext dc)
        {
            double ellipseRadius = 2.0;
            double enhancer = 8.0;
            double enhancerX = 1.0;
            double enhancerY = 1.0;
            for (int x = 0; x <= 100; x++)
            {
                double y = GetYValue(x);
                Brush br = Brushes.Black;
                if (x == 50 || x == 0 || x == 100)
                {
                    br = Brushes.Red;
                }
                //Console.WriteLine("X: " + x + ", Y: " + y);
                Console.Write(y.ToString(CultureInfo.InvariantCulture) + ",");
                dc.DrawEllipse(br, null, new Point(x * enhancer * enhancerX, (100.0 * enhancer * enhancerY) - 
                    (y * enhancer * enhancerY)), ellipseRadius, ellipseRadius);
            }

            enhancer = 8.0;
            enhancerX = 1.0;
            enhancerY = 48.0;
            for (int x = 0; x <= 55; x++)
            {
                double y = GetYValue(x);
                Brush br = Brushes.Green;
                if (x == 50 || x == 0 || x == 100)
                {
                    br = Brushes.Red;
                }                    
                dc.DrawEllipse(br, null, new Point(x * enhancer * enhancerX, (100.0 * enhancer) - 
                    ((100.0 * enhancer * enhancerY) - ((100 - y) * enhancer * enhancerY))), 
                    ellipseRadius, ellipseRadius);
            }
        }
    }
}
