//#define DebugDraw // If this is uncommented, all triangles will have a set-color border drawn. This is useful to debug polygon drawing code. 
//#define SqrtWorks // Only uncomment this when the square-root works 

using System;
using System.Collections.Generic;
using System.Text;

namespace Orvid.Graphics
{
    /// <summary>
    /// This class is used to describe an image.
    /// </summary>
    public class Image
    {
        /// <summary>
        /// The raw data in the image.
        /// </summary>
        public Pixel[] Data;
        /// <summary>
        /// The height of the image.
        /// </summary>
        public int Height;
        /// <summary>
        /// The width of the image.
        /// </summary>
        public int Width;

        ///// <summary>
        ///// Creates an image from a bitmap.
        ///// </summary>
        ///// <param name="b">The input bitmap.</param>
        //public Image(System.Drawing.Bitmap b)
        //{
        //    this.Width = b.Width;
        //    this.Height = b.Height;
        //    this.Data = new Pixel[(Height + 1) * (Width + 1)];
        //    for (int height = 0; height < this.Height; height++)
        //    {
        //        for (int width = 0; width < this.Width; width++)
        //        {
        //            System.Drawing.Color pc = b.GetPixel(width, height);
        //            Pixel p = new Pixel(pc.R, pc.G, pc.B, pc.A);
        //            Data[((height * Width) + width)] = p;
        //        }
        //    }
        //}

        /// <summary>
        /// Creates a new image with the specified height and width.
        /// </summary>
        /// <param name="height">The height of the new image.</param>
        /// <param name="width">The width of the new image.</param>
        public Image(int width, int height)
        {
            this.Width = width;
            this.Height = height;
            this.Data = new Pixel[(Height + 1) * (Width + 1)];
            this.Data.Initialize();
        }

        /// <summary>
        /// The default Disposer.
        /// </summary>
        ~Image()
        {
            this.Data = null;
        }

        #region Clear
        public void Clear(Pixel color)
        {
            for (uint i = 0; i < Data.Length; i++)
            {
                Data[i] = color;
            }
        }
        #endregion
        


        #region DON'T WORK!!!

        #region DrawElipse
        /// <summary>
        /// Draws and fills an elipse.
        /// </summary>
        /// <param name="CenterPoint">The center of the elipse</param>
        /// <param name="height">The height of the elipse.</param>
        /// <param name="width">The width of the elipse.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawElipse(Vec2 CenterPoint, int height, int width, Pixel color)
        {
            double angle = 0;
            double range = (360 * (Math.PI / 180));
            double x = (width * Math.Cos(angle));
            double y = (height * Math.Sin(angle));
            do
            {
                int X = (int)(CenterPoint.X + x + 0.5);
                int Y = (int)(CenterPoint.Y - y + 0.5);
                SetPixel((uint)(X), (uint)(Y), color);
                DrawLine(CenterPoint, new Vec2(X, Y), color);
                angle += 0.001;
                x = (width * Math.Cos(angle));
                y = (height * Math.Sin(angle));
            }
            while (angle <= range);
        }

        /// <summary>
        /// Draws and fills an elipse.
        /// </summary>
        /// <param name="CenterPoint">The center of the elipse</param>
        /// <param name="height">The height of the elipse.</param>
        /// <param name="width">The width of the elipse.</param>
        /// <param name="fillColor">The color to fill in.</param>
        /// <param name="borderColor">The color to draw the border in.</param>
        public void DrawElipse(Vec2 CenterPoint, int height, int width, Pixel fillColor, Pixel borderColor)
        {
            DrawElipse(CenterPoint, height, width, fillColor);
            DrawElipseOutline(CenterPoint, height, width, borderColor);
        }
        #endregion

        #region DrawElipseOutline
        /// <summary>
        /// Draws an elipse outline.
        /// </summary>
        /// <param name="CenterPoint">The center of the elipse</param>
        /// <param name="height">The height of the elipse.</param>
        /// <param name="width">The width of the elipse.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawElipseOutline(Vec2 CenterPoint, int height, int width, Pixel color)
        {
            DrawElipticalArc(CenterPoint, height, width, 0, 360, color);
        }
        #endregion

        #region DrawElipticalArc
        /// <summary>
        /// Draws an eliptical arc.
        /// </summary>
        /// <param name="CenterPoint">The center-point of the elipse to use.</param>
        /// <param name="height">The height of the elipse to use.</param>
        /// <param name="width">The width of the elipse to use.</param>
        /// <param name="startAngle">The angle to start drawing at.</param>
        /// <param name="endAngle">The angle to stop drawing at.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawElipticalArc(Vec2 CenterPoint, int height, int width, int startAngle, int endAngle, Pixel color)
        {
            double angle = (((startAngle <= endAngle) ? startAngle : endAngle) * (Math.PI / 180));
            double range = (((endAngle > startAngle) ? endAngle : startAngle) * (Math.PI / 180));
            double x = (width * Math.Cos(angle));
            double y = (height * Math.Sin(angle));
            do
            {
                SetPixel((uint)((int)(CenterPoint.X + x + 0.5)), (uint)((int)(CenterPoint.Y - y + 0.5)), color);
                angle += 0.001;
                x = (width * Math.Cos(angle));
                y = (height * Math.Sin(angle));
            }
            while (angle <= range);
        }
        #endregion

        #region DrawQuad
        /// <summary>
        /// Draws a quadrilateral with the specified points.
        /// </summary>
        /// <param name="p1">The first point.</param>
        /// <param name="p2">The second point.</param>
        /// <param name="p3">The third point.</param>
        /// <param name="p4">The fourth point.</param>
        /// <param name="FillColor">The color to fill in the rectangle with.</param>
        /// <param name="BorderColor">The color to draw the border in.</param>
        public void DrawQuad(Vec2 p1, Vec2 p2, Vec2 p3, Vec2 p4, Pixel FillColor, Pixel BorderColor)
        {
            DrawPolygon(new Vec2[] { p1, p2, p3, p4 }, FillColor);
            DrawPolygonOutline(new Vec2[] { p1, p2, p3, p4 }, BorderColor);
        }

        /// <summary>
        /// Draws a quadrilateral with the specified points.
        /// </summary>
        /// <param name="p1">The first point.</param>
        /// <param name="p2">The second point.</param>
        /// <param name="p3">The third point.</param>
        /// <param name="p4">The fourth point.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawQuad(Vec2 p1, Vec2 p2, Vec2 p3, Vec2 p4, Pixel color)
        {
            DrawPolygon(new Vec2[] { p1, p2, p3, p4 }, color);
        }
        #endregion

        #endregion


        // This SHOULD work. (I can't gaurentee it though.)
        #region DrawCircle
        /// <summary>
        /// Draws a filled circle.
        /// </summary>
        /// <param name="Center">The center of the circle.</param>
        /// <param name="radius">The radius of the circle.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawCircle(Vec2 Center, int radius, Pixel color)
        {
#if SqrtWorks
            int x1;
            int x2;
            int rSquared = radius * radius;
            int counter = (Center.Y + radius);
            for (int count = (Center.Y - radius); count <= counter; count++)
            {
                int ySquared = (count - Center.Y) * (count - Center.Y);
                double sqrt = Math.Sqrt(rSquared - ySquared) + 0.5;
                x1 = (int)(Center.X + sqrt);
                x2 = (int)(Center.X - sqrt);
                Vec2 p1 = new Vec2(x1, count);
                Vec2 p2 = new Vec2(x2, count);
                DrawLine(p1, p2, color);
            }
            DrawCircleOutline(Center, radius, color);
#else
            Vec2 tlcorn = new Vec2(Center.X - radius, Center.Y - radius);
            Image i = new Image(radius * 2 + 2, radius * 2 + 2);
            i.DrawCircleOutline(Center - tlcorn, radius, color);
            i.FloodFill(Center - tlcorn, new Pixel(true), color);
            DrawImage(tlcorn, i);
#endif
        }
        #endregion


        #region DrawCircleOutline
        /// <summary>
        /// Draws the outline of a circle.
        /// </summary>
        /// <param name="Center">The center of the circle.</param>
        /// <param name="radius">The radius of the circle.</param>
        /// <param name="color">The color to draw with.</param>
        public void DrawCircleOutline(Vec2 Center, int radius, Pixel color)
        {
            int x = 0;
            int y = radius;
            int p = (5 - radius * 4) / 4;

            SetPixel((uint)(Center.X), (uint)(Center.Y + y), color);
            SetPixel((uint)(Center.X), (uint)(Center.Y - y), color);
            SetPixel((uint)(Center.X + y), (uint)(Center.Y), color);
            SetPixel((uint)(Center.X - y), (uint)(Center.Y), color);
            while (x < y)
            {
                x++;
                if (p < 0)
                {
                    p += 2 * x + 1;
                }
                else
                {
                    y--;
                    p += 2 * (x - y) + 1;
                }
                if (x == y)
                {
                    SetPixel((uint)(Center.X + x), (uint)(Center.Y + y), color);
                    SetPixel((uint)(Center.X - x), (uint)(Center.Y + y), color);
                    SetPixel((uint)(Center.X + x), (uint)(Center.Y - y), color);
                    SetPixel((uint)(Center.X - x), (uint)(Center.Y - y), color);
                }
                else
                {
                    if (x < y)
                    {
                        SetPixel((uint)(Center.X + x), (uint)(Center.Y + y), color);
                        SetPixel((uint)(Center.X - x), (uint)(Center.Y + y), color);
                        SetPixel((uint)(Center.X + x), (uint)(Center.Y - y), color);
                        SetPixel((uint)(Center.X - x), (uint)(Center.Y - y), color);
                        SetPixel((uint)(Center.X + y), (uint)(Center.Y + x), color);
                        SetPixel((uint)(Center.X - y), (uint)(Center.Y + x), color);
                        SetPixel((uint)(Center.X + y), (uint)(Center.Y - x), color);
                        SetPixel((uint)(Center.X - y), (uint)(Center.Y - x), color);
                    }
                }
            }
        }
        #endregion

        #region DrawImage
        /// <summary>
        /// Draws the specified image, at the specified point.
        /// </summary>
        /// <param name="loc"></param>
        /// <param name="i"></param>
        public void DrawImage(Vec2 loc, Image i)
        {
            Pixel value;
            for (uint y = 0; y < i.Height; y++)
            {
                for (uint x = 0; x < i.Width; x++)
                {
                    value = i.GetPixel(x, y);
                    if (value != 0)
                        SetPixel((uint)(x + loc.X), (uint)(y + loc.Y), value);
                }
            }
        }
        #endregion

        #region DrawLine
        /// <summary>
        /// Draws a line between 2 points.
        /// </summary>
        /// <param name="Point1">The first point.</param>
        /// <param name="Point2">The first point.</param>
        /// <param name="color">The color to draw.</param>
        public void DrawLine(Vec2 Point1, Vec2 Point2, Pixel color)
        {
            int x0 = Point1.X;
            int x1 = Point2.X;
            int y0 = Point1.Y;
            int y1 = Point2.Y;
            bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
            if (steep)
            {
                int x3 = y0;
                y0 = x0;
                x0 = x3;
                int x4 = y1;
                y1 = x1;
                x1 = x4;
            }
            if (x0 > x1)
            {
                int x5 = x0;
                x0 = x1;
                x1 = x5;
                int x6 = y0;
                y0 = y1;
                y1 = x6;
            }
            int deltax = x1 - x0;
            int deltay = Math.Abs(y1 - y0);
            int error = deltax / 2;
            int ystep;
            int y = y0;
            if (y0 < y1)
            {
                ystep = 1;
            }
            else
            {
                ystep = -1;
            }
            for (int x = x0; x <= x1; x++)
            {
                if (steep)
                {
                    SetPixel((uint)y, (uint)x, color);
                }
                else
                {
                    SetPixel((uint)x, (uint)y, color);
                }
                error = error - deltay;
                if (error < 0)
                {
                    y = y + ystep;
                    error = error + deltax;
                }
            }
        }
        #endregion

        #region DrawLines
        /// <summary>
        /// Draws a set of connected lines.
        /// </summary>
        /// <param name="Points">
        /// An array of points to draw, in the order they need drawing.
        /// </param>
        /// <param name="color">The color to draw.</param>
        public void DrawLines(Vec2[] Points, Pixel color)
        {
            int n = Points.Length;
            if (n >= 2)
            {
                DrawLine(Points[0], Points[1], color);

                for (int count = 1; count < (n - 1); count++)
                {
                    DrawLine(Points[count], Points[count + 1], color);
                }
            }
            else
            {
                throw new Exception("Not enough points provided!");
            }
        }
        #endregion

        #region DrawPolygon
        /// <summary>
        /// Draws a polygon with the specified points.
        /// </summary>
        /// <param name="points">The points of the polygon.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawPolygon(Vec2[] points, Pixel color)
        {
            Vec2[] contour = points;
            List<Vec2> result = new List<Vec2>();
            int cnt = 0;
            #region Process
            {
#warning TODO: Change these back to floats when their implemented fully.
                double EPSILON = 0.0000000001f;
                int n = contour.Length;
                if (n < 3)
                {
                    throw new Exception("Not enough Verticies!");
                }
                int[] V = new int[n];
                int Area;
                {
                    int n2 = contour.Length;
                    double A = 0.0f;
                    for (int p = n2 - 1, q = 0; q < n2; p = q++)
                    {
                        A += contour[p].X * contour[q].Y - contour[q].X * contour[p].Y;
                    }
                    Area = (Int32)(A * 0.5f);
                }
                if (0.0f < Area)
                {
                    for (int v = 0; v < n; v++)
                    {
                        V[v] = v;
                    }
                }
                else
                {
                    for (int v = 0; v < n; v++)
                    {
                        V[v] = (n - 1) - v;
                    }
                }
                int nv = n;
                int count = 2 * nv;
                for (int m = 0, v = nv - 1; nv > 2; )
                {
                    if (0 >= (count--))
                    {
                        throw new Exception("Invalid polygon!");
                    }
                    int u = v;
                    if (nv <= u)
                    {
                        u = 0;
                    }
                    v = u + 1;
                    if (nv <= v)
                    {
                        v = 0;
                    }
                    int w = v + 1;
                    if (nv <= w)
                    {
                        w = 0;
                    }
                    bool Snip;
                    {
                        int p;
                        double Ax, Ay, Bx, By, Cx, Cy, Px, Py;
                        Ax = contour[V[u]].X;
                        Ay = contour[V[u]].Y;
                        Bx = contour[V[v]].X;
                        By = contour[V[v]].Y;
                        Cx = contour[V[w]].X;
                        Cy = contour[V[w]].Y;
                        if (EPSILON > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax))))
                        {
                            Snip = false;
                        }
                        for (p = 0; p < nv; p++)
                        {
                            if ((p == u) || (p == v) || (p == w))
                            {
                                continue;
                            }
                            Px = contour[V[p]].X;
                            Py = contour[V[p]].Y;
                            bool InsideTriangle;
                            {
                                double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
                                double cCROSSap, bCROSScp, aCROSSbp;
                                ax = Cx - Bx;
                                ay = Cy - By;
                                bx = Ax - Cx;
                                by = Ay - Cy;
                                cx = Bx - Ax;
                                cy = By - Ay;
                                apx = Px - Ax;
                                apy = Py - Ay;
                                bpx = Px - Bx;
                                bpy = Py - By;
                                cpx = Px - Cx;
                                cpy = Py - Cy;
                                aCROSSbp = ax * bpy - ay * bpx;
                                cCROSSap = cx * apy - cy * apx;
                                bCROSScp = bx * cpy - by * cpx;
                                InsideTriangle = ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
                            }
                            if (InsideTriangle)
                            {
                                Snip = false;
                            }
                        }
                        Snip = true;
                    }
                    if (Snip)
                    {
                        int a, b, c, s, t;
                        a = V[u];
                        b = V[v];
                        c = V[w];
                        result.Add(contour[a]);
                        result.Add(contour[b]);
                        result.Add(contour[c]);
                        m++;
                        for (s = v, t = v + 1; t < nv; s++, t++)
                        {
                            V[s] = V[t];
                        }
                        nv--;
                        count = 2 * nv;
                    }
                }
            }
            #endregion
            while (cnt < (result.Count / 3))
            {
                DrawTriangle(result[(cnt * 3)], result[(cnt * 3) + 1], result[(cnt * 3) + 2], color);
                cnt++;
            }
        }
        #endregion

        #region DrawPolygonOutline
        /// <summary>
        /// Draws the outline of a polygon.
        /// The last point connects to the first point.
        /// </summary>
        /// <param name="points">An array containing the points to draw.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawPolygonOutline(Vec2[] points, Pixel color)
        {
            Vec2[] pts = new Vec2[points.Length + 1];
            points.CopyTo(pts, 0);
            pts[pts.Length - 1] = points[0];
            DrawLines(pts, color);
        }
        #endregion

        #region DrawRectangle
        /// <summary>
        /// This method fills in the space between
        /// the 2 points specified in a rectangle.
        /// </summary>
        /// <param name="TopLeftCorner">
        /// The point that specifies the top left 
        /// corner of the rectangle being drawn.
        /// </param>
        /// <param name="BottomRightCorner">
        /// The point that specifies the bottom right
        /// corner of the rectangle being drawn.
        /// </param>
        /// <param name="color">The color to draw.</param>
        public void DrawRectangle(Vec2 TopLeftCorner, Vec2 BottomRightCorner, Pixel color)
        {
            int height = BottomRightCorner.Y - TopLeftCorner.Y;
            int width = BottomRightCorner.X - TopLeftCorner.X;
            Image i = new Image(width, height);
            i.Clear(color);
            DrawImage(TopLeftCorner, i);
            //DrawQuad(TopLeftCorner, new Vec2(BottomRightCorner.X, TopLeftCorner.Y), BottomRightCorner, new Vec2(TopLeftCorner.X, BottomRightCorner.Y), color);
        }
        #endregion

        #region DrawReverseRectangle
        /// <summary>
        /// This method fills in the space between
        /// the 2 points specified in a rectangle.
        /// </summary>
        /// <param name="TopRightCorner">
        /// The point that specifies the top right 
        /// corner of the rectangle being drawn.
        /// </param>
        /// <param name="BottomLeftCorner">
        /// The point that specifies the bottom left
        /// corner of the rectangle being drawn.
        /// </param>
        /// <param name="color">The color to draw.</param>
        public void ReverseDrawRectangle(Vec2 TopRightCorner, Vec2 BottomLeftCorner, Pixel color)
        {
            int height = BottomLeftCorner.Y - TopRightCorner.Y;
            int width = TopRightCorner.X - BottomLeftCorner.X;
            Image i = new Image(width, height);
            i.Clear(color);
            Vec2 TopLeftCorner = new Vec2(BottomLeftCorner.X, TopRightCorner.Y);
            DrawImage(TopLeftCorner, i);
            //DrawQuad(new Vec2(BottomLeftCorner.X, TopRightCorner.Y), TopRightCorner, new Vec2(TopRightCorner.X, BottomLeftCorner.Y), BottomLeftCorner, color);
        }
        #endregion

        #region DrawTriangle
        /// <summary>
        /// Draws a triangle and fills it in.
        /// </summary>
        /// <param name="p1">The first point of the triangle.</param>
        /// <param name="p2">The second point of the triangle.</param>
        /// <param name="p3">The third point of the triangle.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawTriangle(Vec2 p1, Vec2 p2, Vec2 p3, Pixel color)
        {

            int l; // The farthest left 
            int r;
            int t;
            int b;
            #region Organize points
            if (p1.Y > p2.Y && p1.Y > p3.Y)
            {
                t = p1.Y;
                if (p2.Y < p3.Y)
                {
                    b = p2.Y;
                }
                else
                {
                    b = p3.Y;
                }
            }
            else if (p2.Y > p1.Y && p2.Y > p3.Y)
            {
                t = p2.Y;
                if (p1.Y < p3.Y)
                {
                    b = p1.Y;
                }
                else
                {
                    b = p3.Y;
                }
            }
            else // This means p3 is the highest point
            {
                t = p3.Y;
                if (p1.Y < p2.Y)
                {
                    b = p1.Y;
                }
                else
                {
                    b = p2.Y;
                }
            }

            // Now organize in the width direction.
            if (p1.X > p3.X && p1.X > p2.X)
            {
                l = p1.X;
                if (p2.X < p3.X)
                {
                    r = p2.X;
                }
                else
                {
                    r = p3.X;
                }
            }
            else if (p2.X > p3.X && p2.X > p1.X)
            {
                l = p2.X;
                if (p1.X < p3.X)
                {
                    r = p1.X;
                }
                else
                {
                    r = p3.X;
                }
            }
            else
            {
                l = p3.X;
                if (p2.X < p1.X)
                {
                    r = p2.X;
                }
                else
                {
                    r = p1.X;
                }
            }
            #endregion
            int h;
            int w;
            if (t - b + 1 > 0)
            {
                h = t - b + 1;
            }
            else
            {
                h = b - t + 1;
            }
            if (l - r + 1 > 0)
            {
                w = l - r + 1;
            }
            else
            {
                w = r - l + 1;
            }
            Image i = new Image(w, h);
            // Get the location of the points within the image.
            Vec2 p4 = new Vec2(p1.X - r, p1.Y - b);
            Vec2 p5 = new Vec2(p2.X - r, p2.Y - b);
            Vec2 p6 = new Vec2(p3.X - r, p3.Y - b);
#if DebugDraw
            Pixel p9 = new Pixel();
            p9.B = 200;
            i.DrawLine(p4, p5, p9);
            i.DrawLine(p5, p6, p9);
            i.DrawLine(p6, p4, p9);
#else
            i.DrawLine(p4, p5, color);
            i.DrawLine(p5, p6, color);
            i.DrawLine(p6, p4, color);
#endif
            Vec2 center = (p4 + p5 + p6) / 3;
            i.FloodFill(center, new Pixel(true), color);

            /*

            NOTE TO SELF: Draw a line from each corner to the middle of the opposite line,
                          so as to fill in the holes that this flood fill method might leave,
                          when dealing with small angles. Some acute triangles have this problem.
            
            */
            Vec2 m1 = (p4 + p5) / 2;
            Vec2 m2 = (p5 + p6) / 2;
            Vec2 m3 = (p4 + p6) / 2;
#if DebugDraw
            Pixel p9 = new Pixel();
            p9.B = 200;
            i.DrawLine(p4, p5, p9);
            i.DrawLine(p5, p6, p9);
            i.DrawLine(p6, p4, p9);
#else
            i.DrawLine(p6, m1, color);
            i.DrawLine(p4, m2, color);
            i.DrawLine(p5, m3, color);
#endif

            Vec2 v = new Vec2(r, b);
            DrawImage(v, i);
        }

        /// <summary>
        /// Draws a triangle with the specified fill color, and the specified border color.
        /// </summary>
        /// <param name="p1">The first point.</param>
        /// <param name="p2">The second point.</param>
        /// <param name="p3">The third point.</param>
        /// <param name="FillColor">The color to fill the triangle with.</param>
        /// <param name="BorderColor">The color to draw the border of the triangle.</param>
        public void DrawTriangle(Vec2 p1, Vec2 p2, Vec2 p3, Pixel FillColor, Pixel BorderColor)
        {
            DrawTriangle(p1, p2, p3, FillColor);
            DrawTriangleOutline(p1, p2, p3, BorderColor);
        }
        #endregion

        #region DrawTriangleOutline
        /// <summary>
        /// Draw a triangle's outline.
        /// </summary>
        /// <param name="p1">The first point of the triangle.</param>
        /// <param name="p2">The second point of the triangle.</param>
        /// <param name="p3">The third point of the triangle.</param>
        /// <param name="color">The color to draw in.</param>
        public void DrawTriangleOutline(Vec2 p1, Vec2 p2, Vec2 p3, Pixel color)
        {
            DrawLines(new Vec2[] { p1, p2, p3, p1 }, color);
        }
        #endregion

        #region FloodFill
        private bool[] Visiteds;
        /// <summary>
        /// Returns true if the given pixel has
        /// been visited with the flood-fill algorithm.
        /// </summary>
        /// <param name="height"></param>
        /// <param name="width"></param>
        /// <returns></returns>
        public bool Visited(int y, int x)
        {
            if (x >= 0 && y >= 0 && y <= Height && x <= Width)
                return Visiteds[((y * Width) + x)];
            return true;
        }

        /// <summary>
        /// Implements a flood fill algorithm.
        /// </summary>
        /// <param name="startPoint">The point to start filling from.</param>
        /// <param name="sColor">The color to search for.</param>
        /// <param name="dColor">The color to change it to.</param>
        public void FloodFill(Vec2 startPoint, Pixel sColor, Pixel dColor)
        {
            int x = startPoint.X;
            int y = startPoint.Y;
            if ((GetPixel((uint)x, (uint)y).Empty) || GetPixel((uint)x, (uint)y) == sColor)
            {
                SetPixel((uint)x, (uint)y, dColor);
            }
            Stack<Vec2> q = new Stack<Vec2>();
            Visiteds = new bool[(Height + 1) * (Width + 1)];

            #region Setup Start of queue
            Pixel p;
            Vec2 v;
            p = GetPixel((uint)x + 1, (uint)y);
            if ((p.Empty || p == sColor) && p != dColor)
            {
                v = new Vec2(x + 1, y);
                q.Push(v);
                Visiteds[((y * Width) + x + 1)] = true;
                SetPixel((uint)x + 1, (uint)y, dColor);
            }
            p = GetPixel((uint)x, (uint)y + 1);
            if ((p.Empty || p == sColor) && p != dColor)
            {
                v = new Vec2(x, y + 1);
                q.Push(v);
                Visiteds[(((y + 1) * Width) + x)] = true;
                SetPixel((uint)x, (uint)y + 1, dColor);
            }
            p = GetPixel((uint)x - 1, (uint)y);
            if ((p.Empty || p == sColor) && p != dColor)
            {
                v = new Vec2(x - 1, y);
                q.Push(v);
                Visiteds[((y * Width) + x - 1)] = true;
                SetPixel((uint)(x - 1), (uint)y, dColor);
            }
            p = GetPixel((uint)x, (uint)y - 1);
            if ((p.Empty || p == sColor) && p != dColor)
            {
                v = new Vec2(x, y - 1);
                q.Push(v);
                Visiteds[(((y - 1) * Width) + x)] = true;
                SetPixel((uint)x, (uint)(y - 1), dColor);
            }
            #endregion

            while (q.Count > 0)
            {
                v = q.Pop();
                x = v.X;
                y = v.Y;
                #region Check

                p = GetPixel((uint)x + 1, (uint)y);
                if (p != dColor && (p.Empty || p == sColor))
                {
                    v = new Vec2(x + 1, y);
                    if (x >= 0 && !(Visited(y, x + 1)))
                    {
                        q.Push(v);
                        Visiteds[((y * Width) + x + 1)] = true;
                        SetPixel((uint)x + 1, (uint)y, dColor);
                    }
                }
                p = GetPixel((uint)x, (uint)y + 1);
                if (p != dColor && (p.Empty || p == sColor))
                {
                    v = new Vec2(x, y + 1);
                    if (x >= 0 && !(Visited(y + 1, x)))
                    {
                        q.Push(v);
                        Visiteds[(((y + 1) * Width) + x)] = true;
                        SetPixel((uint)x, (uint)y + 1, dColor);
                    }
                }
                p = GetPixel((uint)x - 1, (uint)y);
                if (p != dColor && (p.Empty || p == sColor))
                {
                    v = new Vec2(x - 1, y);
                    if (x >= 0 && !(Visited(y, x - 1)))
                    {
                        q.Push(v);
                        Visiteds[((y * Width) + x - 1)] = true;
                        SetPixel((uint)x - 1, (uint)y, dColor);
                    }
                }
                p = GetPixel((uint)x, (uint)y - 1);
                if (p != dColor && (p.Empty || p == sColor))
                {
                    v = new Vec2(x, y - 1);
                    if (!(Visited(y - 1, x)))
                    {
                        q.Push(v);
                        Visiteds[(((y - 1) * Width) + x)] = true;
                        SetPixel((uint)x, (uint)y - 1, dColor);
                    }
                }
                #endregion
            }
            // And finally empty the visiteds array.
            Visiteds = new bool[0];
        }
        #endregion

        /// <summary>
        /// Get's the pixel a the specified location.
        /// </summary>
        /// <param name="width">The width position of the pixel.</param>
        /// <param name="height">The height position of the pixel.</param>
        /// <returns>The Pixel at the specified position.</returns>
        public Pixel GetPixel(uint x, uint y)
        {
            return Data[(y * Width) + x];
        }

        //public List<Vec2> Modified = new List<Vec2>();

        /// <summary>
        /// Set's the pixel at the specified location, 
        /// to the specified pixel.
        /// </summary>
        /// <param name="width">The width position of the pixel.</param>
        /// <param name="height">The height position of the pixel.</param>
        /// <param name="p">The pixel to set to.</param>
        public void SetPixel(uint x, uint y, Pixel p)
        {
            //Modified.Add(new Vec2(width, height));
            Data[((y * Width) + x)] = p;
        }

        //private int curXConsole = 0;
        //private int curYConsole = 0;

        //private void WriteChar(char c)
        //{

        //}

        //internal void WriteToConsole(string s)
        //{
        //    for (int i = 0; i < s.Length; i++)
        //    {
        //        char c = s[i];
        //        WriteChar(c);
        //    }
        //}
    }
}
