using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;

namespace SpriteLibrary
{
    /// <summary>
    /// An EventArgs that contains information about Sprites.  Most of the Sprite events use
    /// this SpriteEventArgs.
    /// </summary>
    public class SpriteEventArgs : EventArgs
    {
        /// <summary>
        /// If another Sprite is involved in the event (Collision), than that Sprite is included here.
        /// It will be null if no other Sprite is involved.
        /// </summary>
        public Sprite TargetSprite=null;
        /// <summary>
        /// The CollisionMethod used in the event.  Currently, only rectangle collisions are used
        /// </summary>
        public SpriteCollisionMethod CollisionMethod = SpriteCollisionMethod.rectangle;
        /// <summary>
        /// For the CheckBeforeMove event, newlocation will be the location the sprite is trying
        /// to move to. You can adjust the point (move it left, right, up, down) and it will affect
        /// the placement of the sprite.
        /// </summary>
        public Point NewLocation = new Point(-1,-1);
        /// <summary>
        /// Used primarily in the CheckBeforeMove event.  If you set cancel to true, then the move fails.
        /// You can use this to keep a Sprite from going places where it ought not to go.
        /// </summary>
        public bool Cancel = false;
    }
    /// <summary>
    /// A Sprite is an animated image that has a size, position, rotation, and possible vector
    /// It tracks where in the animation sequence it is, can report colisions, etc.  This SpriteController
    /// draws, moves, and deals with most graphical aspects of the sprites for you.
    /// </summary>
    public class Sprite
    {
        int _ID = -1;
        /// <summary>
        /// The Sprite ID as specified by the sprite controller.
        /// </summary>
        public int ID { get { return _ID; } private set { _ID = value; } }
        private bool SpriteHasInitialized = false;
        /// <summary>
        /// The name of the sprite.  Use SetSpriteName(Name) to change this name.  Most Named sprites
        /// are used to define what a sprite is.  Once you have created a named sprite, you usually use
        /// <see cref="SpriteController.DuplicateSprite(String)"/> to clone the sprite for use.  The basic rule of thumb is
        /// to load your sprites from images once, and name the initial sprites.  Then, when you go to use
        /// those sprites, get duplicates of them.  The reason for this is because it takes more processing time to initially
        /// create the sprites than it takes to duplicate them.
        /// </summary>
        public string SpriteName { get; private set; }
        /// <summary>
        /// Set the opacity of the sprite.  The value should be between 0 and 1.  1 is solid, 0 is transparent.
        /// Sometimes you want to drag a sprite around the map, or show a sprite that "could be there."  Setting
        /// the sprite opacity is usually how you do that.  One warning, however.  The opacity value takes effect the
        /// next time it is drawn.  If the sprite is animating rapidly, it will take effect nearly emmediately.  If
        /// it is not animating, not moving, or just sitting there, then it may not take effect for quite some time.
        /// </summary>
        public float Opacity { get { return _opacity; } set { if (value <= 1 && value >= 0) _opacity = value; } }
        private float _opacity = 1;

        /// <summary>
        /// Return the name of the sprite that this was duplicated from.  A duplicated sprite will have
        /// no name, but will have a SpriteOriginName.
        /// </summary>
        public string SpriteOriginName { get; private set; }
        SmartImage MyImage;
        private double SpeedAdjust = 1;
        DateTime LastResetImage = DateTime.UtcNow;
        int _FrameIndex = -1;
        /// <summary>
        /// This is the frame of the current animation sequence.  You can use this if you need to figure out what frame index
        /// to resume something at, or something like that.
        /// </summary>
        public int FrameIndex
        {
            get { return _FrameIndex; }
            private set { _FrameIndex = value; }
        } //We start out with -1 so we know we need to draw from the begining.
        int _AnimationIndex = 0;
        int AnimationNumberCount = 0;

        /// <summary>
        /// The final frame is the one that gets displayed once the animation has finished.
        /// </summary>
        private int _FinalFrameAfterAnimation = -1;
        private bool SetToAnimateOnce = false;
        private bool _AnimationDone = false;
        /// <summary>
        /// Report whether or not the animation has been completed.  When you tell a Sprite to AnimateOnce,
        /// this will report "false" until the animation sequence has been finished.  At that time, the value
        /// will be "True."  The tricky bit is that this is a boolean.  If you have not told a sprite to
        /// animate once, it will always return "false."  If a sprite is paused, this returns "false."  The only
        /// time this returns "true" is when you tell a sprite to animate once, or animate a few times, and those
        /// times have completed.  At that time, this will report "True".  If you have a sprite with only one frame,
        /// it may not look like it is "animating", but it is.  It is simply animating that one frame over and over.
        /// So, AnimationDone reports false, unless you have told it to animate_once.
        /// </summary>
        public bool AnimationDone { get { return _AnimationDone; } private set { _AnimationDone = value; } }
        private bool ForceRedraw = false;
        private bool NeedsDrawingAtEndOfTick = false; //We use this to say that we need to draw at end
        private System.Windows.Vector SpriteVector;
        /// <summary>
        /// The movement speed of the sprite.  To make a Sprite move, you need to set the MovementSpeed,
        /// the direction (using 
        /// <see cref="SpriteLibrary.Sprite.SetSpriteDirection(System.Windows.Vector)"/>, 
        /// <see cref="SpriteLibrary.Sprite.SetSpriteDirectionToPoint(Point)"/>, 
        /// <see cref="SpriteLibrary.Sprite.SetSpriteDirectionRadians(double)"/>,
        /// or <see cref="SpriteLibrary.Sprite.SetSpriteDirectionDegrees(double)"/>), and the 
        /// <see cref="SpriteLibrary.Sprite.AutomaticallyMoves"/> property.
        /// The speed is calculated in pixels per amount of time.  A higher number is faster than a lower number.
        /// </summary>
        public int MovementSpeed = 0; //Used in calculating when to move next.
        private DateTime LastMovement = DateTime.UtcNow;

        //For tracking if we are moving along a set of points
        private List<Point> MovementDestinations = new List<Point>();
        /// <summary>
        /// Tells us if we are in the process of doing a MoveTo operation.  This boolean should be the 
        /// opposite of SpriteReachedEndpoint, but that boolean is poorly named.  This is usually the easier
        /// one to use.
        /// </summary>
        public bool MovingToPoint { get { return _MovingToPoint; } private set { _MovingToPoint = value; } }
        private bool _MovingToPoint = false;

        /// <summary>
        /// If we are trying to collide with a sprite, we store that sprite here.
        /// </summary>
        private Sprite MovingToSprite = null;

        private bool _AutomaticallyMoves = false; //Does the sprite move in the direction it has been set?
        /// <summary>
        /// Determine if the sprite automatically moves (you need to give it a direction [using one of the
        /// SetSpriteDirection functions] and speed [MovementSpeed = X] also)
        /// </summary>     
        public bool AutomaticallyMoves
        {
            get { return _AutomaticallyMoves; }
            set
            {
                _AutomaticallyMoves = value;
                LastMovement = DateTime.UtcNow;
            }
        }
        private int _Zvalue = 50;
        /// <summary>
        /// A number from 0 to 100.  Default = 50. Higher numbers print on top of lower numbers.  If you want a sprite to 
        /// always be drawn on top of other sprites, give it a number higher than 50.  If you want a sprite to go under 
        /// other sprites, make its number lower than 50.
        /// </summary>
        public int Zvalue
        {
            get { return _Zvalue; }
            set { _Zvalue = value; if (_Zvalue < 0) _Zvalue = 0; if (_Zvalue > 100) _Zvalue = 100; MySpriteController.SortSprites(); }
        }
        private bool PausedAnimation = false;
        private bool PausedMovement = false;
        private bool PausedEvents = false;
        private DateTime PausedAnimationTime = DateTime.UtcNow;
        private DateTime PausedMovementTime = DateTime.UtcNow;
        /// <summary>
        /// Determine if the sprite will automatically move outside the box.  If not, it will hit the side of the box and stick
        /// </summary>
        public bool CannotMoveOutsideBox = false; //If set to true, it will not automatically move outside the picture box.

        /// <summary>
        /// Get or set the animation nimber.  It is best to change the animation using ChangeAnimation.
        /// It is safer.
        /// </summary>
        public int AnimationIndex
        {
            get { return _AnimationIndex; }
            set { if (value > -1 && value < MyImage.AnimationCount) _AnimationIndex = value; }
        }

        /// <summary>
        /// The number of animations this sprite has
        /// </summary>
        public int AnimationCount
        {
            get { return MyImage.AnimationCount; }
        }

        //The location and size of the sprite
        int xPositionOnImage = -1;
        int yPositionOnImage = -1;
        int xPositionOnPictureBox = -1;
        int yPositionOnPictureBox = -1;
        double xOnVector = -1;
        double yOnVector = -1;
        int Width = -1;
        int Height = -1;
        Rectangle MyRectangle { get { return new Rectangle(xPositionOnImage, yPositionOnImage, Width, Height); } }
        bool _HasBeenDrawn = false;
        /// <summary>
        /// Report whether or not this Sprite has been drawn.  If it has, then it needs to be erased at
        /// some point in time.
        /// </summary>
        public bool HasBeenDrawn { get { return _HasBeenDrawn; } private set { _HasBeenDrawn = value; } }
        /// <summary>
        /// The sprite location as found on the base image.  This is usually the easiest location to use.
        /// </summary>
        public Point BaseImageLocation { get { return new Point(xPositionOnImage, yPositionOnImage); } }
        /// <summary>
        /// The sprite location as found on the picture-box that this sprite is associated with.  Used when dealing with mouse-clicks
        /// </summary>
        public Point PictureBoxLocation { get { return new Point(xPositionOnPictureBox, yPositionOnPictureBox); } }
        /// <summary>
        /// Return the size of the sprite in reference to the image on which it is drawn.  To get the
        /// size of the Sprite in relation to the PictureBox, use GetVisibleSize
        /// </summary>
        public Size GetSize { get { return new Size(Width, Height); } }
        /// <summary>
        /// Return the relative size of the Sprite in relation to the PictureBox.  If the box has been 
        /// stretched or shrunk, that affects the visible size of the sprite.
        /// </summary>
        public Size GetVisibleSize { get { return new Size(VisibleWidth, VisibleHeight); } }

        //This is the rotation of the item.  If we change this, we will draw the sprite rotated.
        int _Rotation = 0;

        /// <summary>
        /// Change the rotation of the sprite, using degrees.  0 degrees is to the right.  90 is up.  
        /// 180 left, 270 down.  But, if your sprite was drawn facing up, then rotating it 90 degrees
        /// will have it pointing left.  The angle goes counter-clockwise.  The image will be scaled
        /// such that it continues to fit within the rectangle that it was originally in.  This results
        /// in a little bit of shrinking at times, but you should rarely notice that.
        /// </summary>
        public int Rotation { set { if (value >= 0 && value <= 360) _Rotation = value; } get { return _Rotation; } }

        /// <summary>
        /// Flip the image when it gets printed.  If your sprite is walking left, flipping it will
        /// make it look like it is going right.
        /// This works great for many things.  But, if your program is gobbling memory or CPU, you may need to
        /// consider using <see cref="SpriteLibrary.Sprite.AddAnimation(int, bool, bool)">Sprite.AddAnimation</see>
        /// </summary>
        public bool MirrorHorizontally = false;

        /// <summary>
        /// Flip the image when it gets printed.  If your sprite looks like it is facing up, doing 
        /// this will make it look like it faces down.
        /// This works great for many things.  But, if your program is gobbling memory or CPU, you may need to
        /// consider using <see cref="SpriteLibrary.Sprite.AddAnimation(int, bool, bool)">Sprite.AddAnimation</see>
        /// </summary>
        public bool MirrorVertically = false;

        SpriteController MySpriteController;
        private bool _Destroying = false;
        /// <summary>
        /// If the Sprite is in the middle of being Destroyed, this is set to true.  When a Sprite is
        /// Destroyed, it needs to erase itself and do some house-cleaning before it actually vanishes.
        /// During this time, you may not want to use it.  It is always a good thing to verify a Sprite
        /// is not in the middle of being destroyed before you do something important with it.  To Destroy
        /// a Sprite, use the Sprite.Destroy() function.
        /// </summary>
        public bool Destroying { get { return _Destroying; } }

        /// <summary>
        /// This is true unless we are using MoveTo(point) or MoveTo(list of points) to tell the sprite to move
        /// from one place to the next.  This boolean tells us if it has finished or not.
        /// </summary>
        public bool SpriteReachedEndPoint { get { return _SpriteReachedEndPoint; } internal set { _SpriteReachedEndPoint = value; } }
        bool _SpriteReachedEndPoint = true;

        /// <summary>
        /// The visible Height as seen in the PictureBox.  It may be stretched, or shrunk from the actual
        /// image size.
        /// </summary>
        public int VisibleHeight { get { return MySpriteController.ReturnPictureBoxAdjustedHeight(Height); } }
        /// <summary>
        /// The visible width as seen in the PictureBox.  The Sprite may be stretched or shrunk from the
        /// actual image size.
        /// </summary>
        public int VisibleWidth { get { return MySpriteController.ReturnPictureBoxAdjustedWidth(Width); } }

        /// <summary>
        /// A Sprite can hold a payload.  Use this to store extra information about the various Sprites.  Health, Armor,
        /// Shoot time, etc.  But, to store information in the payload, you need to make a new class of SpritePayload.  The syntax
        /// for doing so is: 
        /// <code Lang="C#">
        /// public class TankPayload : SpritePayload {  public int Armor; public int Speed; }
        /// </code>
        /// You can access the payload and retrieve the various values.  
        /// </summary>
        public SpritePayload payload = null; //The user can put anything they want here.
        //We changed the payload from being an object.  The Object was too vague.  By making it a defined type,
        //It helps with some level of type protection.
        //public object payload = null; //The user can put anything they want here.

        private List<Sprite> CollisionSprites = new List<Sprite>(); //The list of sprites that are colliding with this one

        //*********************************
        //****   Add event stubs **********
        /// <summary>
        /// A delegate that has a SpriteEventArgs instead of EventArgs.  Used for most
        /// of the Sprite events.  This allows us to pass more information from sprite events than
        /// a basic EventArgs allows for
        /// </summary>
        /// <param name="sender">The Sprite that triggers the event</param>
        /// <param name="e">A SpriteEventArgs class which contains Sprite Event values</param>
        public delegate void SpriteEventHandler(object sender, SpriteEventArgs e);
        /// <summary>
        /// This event happens right after the sprite is created.  Use this to immediately set a 
        /// sprite to animate once or something like that.
        /// </summary>
        public event SpriteEventHandler SpriteInitializes = delegate { };
        /// <summary>
        /// This happens when the sprite hits the border of the picture-box.  
        /// Useful for when you want to have shots explode when they hit the side.
        /// </summary>
        public event SpriteEventHandler SpriteHitsPictureBox = delegate { };
        /// <summary>
        /// This happens when the sprite has exited the picture box.  Useful when you want to 
        /// keep sprites from traveling on forever after exiting.
        /// </summary>
        public event SpriteEventHandler SpriteExitsPictureBox = delegate { };
        /// <summary>
        /// Only used when you tell an animation to animate once.  At the end of the animation, 
        /// this function fires off.
        /// </summary>
        public event SpriteEventHandler SpriteAnimationComplete = delegate { };
        /// <summary>
        /// This happens when two sprites hit each-other.  The SpriteEventArgs that is returned 
        /// contains the sprite that this sprite hits.
        /// </summary>
        public event SpriteEventHandler SpriteHitsSprite = delegate { };
        /// <summary>
        /// This event fires off before a sprite is drawn. Use it if you have constraints.  You 
        /// can change the location or cancel the move entirely.
        /// </summary>
        public event SpriteEventHandler CheckBeforeMove = delegate { };
        /// <summary>
        /// This event happens when someone clicks on the sprite (on the rectangle in which the sprite is).
        /// If you want the event to fire off only when someone clicks on the visible part of the sprite,
        /// use ClickTransparent instead.
        /// </summary>
        public event SpriteEventHandler Click = delegate { };
        /// <summary>
        /// This event happens when someone clicks on the sprite (on the sprite image itself).
        /// If the sprite is sometimes hidden, but you want the click to work even if it is not
        /// visible at that instant, use Click instead.
        /// </summary>
        public event SpriteEventHandler ClickTransparent = delegate { };
        /// <summary>
        /// This event happens when the mouse moves over the sprite, and then pauses.  We use the hover timing from the
        /// parent form.
        /// </summary>
        public event SpriteEventHandler MouseHover = delegate { };
        /// <summary>
        /// When the mouse moves over the sprite.  Use this for a menu, when you want the menu item to glow when the
        /// mouse is over the menu item sprite.
        /// </summary>
        public event SpriteEventHandler MouseEnter = delegate { };
        /// <summary>
        /// When the mouse moves off the sprite.  Use this for a menu, when you want the menu item to stop glowing when
        /// the mouse moves away from the menu item sprite.
        /// </summary>
        public event SpriteEventHandler MouseLeave = delegate { };
        /// <summary>
        /// This event happens when the mouse moves over a non-transparent portion of the sprite, and then pauses.  
        /// We use the hover timing from the parent form.
        /// </summary>
        public event SpriteEventHandler MouseHoverTransparent = delegate { };
        /// <summary>
        /// When the mouse moves over a non-transparent portoin of the sprite.  Use this for a menu, when you want the 
        /// menu item to glow when the mouse is over the menu item sprite.
        /// </summary>
        public event SpriteEventHandler MouseEnterTransparent = delegate { };
        /// <summary>
        /// When the mouse moves off the non-transparent portion of the sprite.  Use this for a menu, when you want the 
        /// menu item to stop glowing when
        /// the mouse moves away from the menu item sprite.
        /// </summary>
        public event SpriteEventHandler MouseLeaveTransparent = delegate { };
        /// <summary>
        /// When the frame of an animation changes.  If you want to have something happen every time
        /// the foot of your monster comes down, when the swing of your sword is at certain points, etc.
        /// Check to see that the Animaton and FrameIndex are what you expect them to be.
        /// </summary>
        public event SpriteEventHandler SpriteChangesAnimationFrames = delegate { };
        /// <summary>
        /// An event for when you tell a Sprite to MoveTo(Point) a specific point, or, when you 
        /// tell the Sprite to MoveTo(list of points).  When the Sprite has reached the final destination,
        /// the Sprite fires off this event.
        /// </summary>
        public event SpriteEventHandler SpriteArrivedAtEndPoint = delegate { };
        /// <summary>
        /// When you tell a sprite to MoveTo(list of points), this fires off every time it gets to
        /// one of the points.  When it gets to the final point, only the SpriteAtEndPoint event fires off.
        /// </summary>
        public event SpriteEventHandler SpriteArrivedAtWaypoint = delegate { };

        /// <summary>
        /// The Sprite has just been told to be destroyed.  You might want to do some cleanup.
        /// If you need to destroy some payload data, or tell something to cleanup after the sprite
        /// this is where to do that.
        /// </summary>
        public event SpriteEventHandler SpriteBeingDestroyed = delegate { };


        // **********************************************************
        //     *************  Start of Sprite Code  **********
        //          *************************************


        /// <summary>
        /// Generate a new sprite.  It takes the image and the width and height.  If there are multiple images of that width 
        /// and height in the image, an animation is created.
        /// </summary>
        /// <param name="Controller">The sprite controller that manages this sprite</param>
        /// <param name="SpriteImage">The image we pull the animation from</param>
        /// <param name="width">The width of one animation frame</param>
        /// <param name="height">The height of one animation frame</param>
        public Sprite(SpriteController Controller, Image SpriteImage, int width, int height)
        {
            MySpriteController = Controller;
            ID = MySpriteController.SpriteCount;
            Width = width;
            Height = height;
            MyImage = new SmartImage(MySpriteController, SpriteImage);
            MySpriteController.AddSprite(this);
        }

        /// <summary>
        /// Generate a new sprite.  It takes the image and the width and height.  If there are multiple images of that width 
        /// and height in the image, an animation is created.
        /// </summary>
        /// <param name="Controller">The sprite controller that manages this sprite</param>
        /// <param name="SpriteImage">The image we pull the animation from</param>
       /// <param name="SpriteSize">The size of the animation frame</param>
        public Sprite(SpriteController Controller, Image SpriteImage,Size SpriteSize)
        {
            MySpriteController = Controller;
            ID = MySpriteController.SpriteCount;
            Width = SpriteSize.Width;
            Height = SpriteSize.Height;
            MyImage = new SmartImage(MySpriteController, SpriteImage);
            MySpriteController.AddSprite(this);
        }

        /// <summary>
        /// Generate a new single-frame sprite from the specified image.
        /// </summary>
        /// <param name="Controller">The sprite controller that manages this sprite</param>
        /// <param name="SpriteImage">The image we pull the animation from</param>
        public Sprite(SpriteController Controller, Image SpriteImage)
        {
            MySpriteController = Controller;
            ID = MySpriteController.SpriteCount;
            Width = SpriteImage.Width;
            Height = SpriteImage.Height;
            MyImage = new SmartImage(MySpriteController, SpriteImage);
            MySpriteController.AddSprite(this);
        }
        /// <summary>
        /// Generate a new sprite.  It takes a width, height, and the duration in Milliseconds for each frame
        /// </summary>
        /// <param name="Controller">The sprite controller</param>
        /// <param name="SpriteImage">The image we pull the animations from</param>
        /// <param name="width">The width of one animation frame</param>
        /// <param name="height">the height of one animation frame</param>
        /// <param name="durationInMilliseconds">The number of milliseconds each frame is shown for as it animates.</param>
        public Sprite(SpriteController Controller, Image SpriteImage, int width, int height, int durationInMilliseconds)
        {
            MySpriteController = Controller;
            ID = MySpriteController.SpriteCount;
            Width = width;
            Height = height;
            MyImage = new SmartImage(MySpriteController, SpriteImage, width, height, durationInMilliseconds);
            MySpriteController.AddSprite(this);
        }
        /// <summary>
        /// Create a Sprite from an animation image, specifying the number of consecutive 
        /// frames to grab.
        /// </summary>
        /// <param name="Start">A point on the specified image where we begin grabbing frames</param>
        /// <param name="Controller">The Sprite controller we are associating the sprite with</param>
        /// <param name="SpriteImage">An image that we grab the frames from</param>
        /// <param name="width">The width of one frame</param>
        /// <param name="height">The height of one frame</param>
        /// <param name="duration">The number of milliseconds each frame is displayed for</param>
        /// <param name="Count">The number of frames to grab as a part of this animation</param>
        public Sprite(Point Start, SpriteController Controller, Image SpriteImage, int width, int height, int duration, int Count)
        {
            MySpriteController = Controller;
            ID = MySpriteController.SpriteCount;
            Width = width;
            Height = height;
            MyImage = new SmartImage(Start, MySpriteController, SpriteImage, width, height, duration, Count);
            MySpriteController.AddSprite(this);
        }

        /// <summary>
        /// Create a Sprite that is based off of the specified sprite.  Clone the Sprite except that
        /// we set SpriteName = "" and OrigSpriteName = the OldSprite.SpriteName.  That way we know that
        /// the sprite was duplicated from the original, and we can still distinguish the original from
        /// the duplicate.
        /// </summary>
        /// <param name="OldSprite">The Sprite to make a copy of</param>
        /// <param name="RetainName">If we want to set this sprite name to be that of the original.  This is a terrible idea.  Never do it.</param>
        public Sprite(Sprite OldSprite, bool RetainName = false)
        {
            MySpriteController = OldSprite.MySpriteController;
            ID = MySpriteController.SpriteCount;
            Width = OldSprite.Width;
            Height = OldSprite.Height;
            MyImage = OldSprite.MyImage;
            MovementSpeed = OldSprite.MovementSpeed;
            SpriteOriginName = OldSprite.SpriteName;

            //duplicate any eventhandlers we may have added to the one being cloned.
            SpriteHitsPictureBox += OldSprite.SpriteHitsPictureBox;
            SpriteExitsPictureBox += OldSprite.SpriteExitsPictureBox;
            SpriteHitsSprite += OldSprite.SpriteHitsSprite;
            SpriteAnimationComplete += OldSprite.SpriteAnimationComplete;
            SpriteInitializes += OldSprite.SpriteInitializes;
            CheckBeforeMove += OldSprite.CheckBeforeMove;
            Click += OldSprite.Click;
            ClickTransparent += OldSprite.ClickTransparent;
            SpriteChangesAnimationFrames += OldSprite.SpriteChangesAnimationFrames;
            SpriteArrivedAtEndPoint += OldSprite.SpriteArrivedAtEndPoint;
            SpriteArrivedAtWaypoint += OldSprite.SpriteArrivedAtWaypoint;
            SpriteBeingDestroyed += OldSprite.SpriteBeingDestroyed;
            MouseEnter += OldSprite.MouseEnter;
            MouseHover += OldSprite.MouseHover;
            MouseLeave += OldSprite.MouseLeave;

            if (RetainName)
                SpriteName = OldSprite.SpriteName;
            MySpriteController.AddSprite(this);
        }


        // *******************

        /// <summary>
        /// Give this sprite a name.  This way we can make a duplicate of it by specifying the name
        /// </summary>
        /// <param name="Name">A string that represents the new name of the sprite</param>
        public void SetName(string Name)
        {
            SpriteName = Name;
        }

        /// <summary>
        /// Add another animation to an existing Sprite.  After you add animations, you can use
        /// ChangeAnimation to select which animation you want the specified sprite to show.
        /// For example, you may want to have Animation 0 be a guy walking left, and animation 1 is
        /// that same guy walking right.  Because we do not specify the number of frames, it starts
        /// at the top-left corner and grabs as many frames as it can from the image.
        /// </summary>
        /// <param name="SpriteImage">The animation image to grab the frames from</param>
        /// <param name="width">The width of each frame</param>
        /// <param name="height">The height of each frame</param>
        public void AddAnimation(Image SpriteImage, int width, int height)
        {
            int duration = GetAnimationSpeed(0);
            MyImage.AddAnimation(SpriteImage, width, height, duration);
        }

        /// <summary>
        /// Add another animation to an existing Sprite.  After you add animations, you can use
        /// ChangeAnimation to select which animation you want the specified sprite to show.
        /// For example, you may want to have Animation 0 be a guy walking left, and animation 1 is
        /// that same guy walking right.  Because we do not specify the number of frames, it starts
        /// at the top-left corner and grabs as many frames as it can from the image.
        /// </summary>
        /// <param name="SpriteImage">The animation image to grab the frames from</param>
        /// <param name="SpriteSize">The size of each frame</param>
        public void AddAnimation(Image SpriteImage, Size SpriteSize)
        {
            int duration = GetAnimationSpeed(0);
            MyImage.AddAnimation(SpriteImage, SpriteSize.Width, SpriteSize.Height, duration);
        }

        /// <summary>
        /// Add another animation to an existing Sprite.  After you add animations, you can use
        /// ChangeAnimation to select which animation you want the specified sprite to show.
        /// For example, you may want to have Animation 0 be a guy walking left, and animation 1 is
        /// that same guy walking right.  Because we do not specify the number of frames, it starts
        /// at the top-left corner and grabs as many frames as it can from the image.
        /// </summary>
        /// <param name="SpriteImage">The animation image to grab the frames from</param>
        public void AddAnimation(Image SpriteImage)
        {
            int duration = GetAnimationSpeed(0);
            MyImage.AddAnimation(SpriteImage, SpriteImage.Width, SpriteImage.Height, duration);
        }

        /// <summary>
        /// Add another animation to an existing Sprite.  After you add animations, you can use
        /// ChangeAnimation to select which animation you want the specified sprite to show.
        /// For example, you may want to have Animation 0 be a guy walking left, and animation 1 is
        /// that same guy walking right.  Because we do not specify the number of frames, it starts
        /// at the top-left corner and grabs as many frames as it can from the image.
        /// </summary>
        /// <param name="SpriteImage">The animation image to grab the frames from</param>
        /// <param name="duration">The duration the single frame uses before refreshing.  1000 is a good number.</param>
        public void AddAnimation(Image SpriteImage, int duration)
        {
            MyImage.AddAnimation(SpriteImage, SpriteImage.Width, SpriteImage.Height, duration);
        }


        /// <summary>
        /// Add another animation to an existing Sprite.  After you add animations, you can use
        /// ChangeAnimation to select which animation you want the specified sprite to show.
        /// For example, you may want to have Animation 0 be a guy walking left, and animation 1 is
        /// that same guy walking right. Because we do not specify the number of frames, it starts
        /// at the top-left corner and grabs as many frames as it can from the image.
        /// </summary>
        /// <param name="SpriteImage">The animation image to grab the frames from</param>
        /// <param name="width">The width of each frame</param>
        /// <param name="height">The height of each frame</param>
        /// <param name="duration">The time in milliseconds we use for each frame</param>
        public void AddAnimation(Image SpriteImage, int width, int height, int duration)
        {
            MyImage.AddAnimation(SpriteImage, width, height, duration);
        }

        /// <summary>
        /// Add another animation to an existing Sprite.  After you add animations, you can use
        /// ChangeAnimation to select which animation you want the specified sprite to show.
        /// For example, you may want to have Animation 0 be a guy walking left, and animation 1 is
        /// that same guy walking right. Because we do not specify the number of frames, it starts
        /// at the top-left corner and grabs as many frames as it can from the image.
        /// </summary>
        /// <param name="SpriteImage">The animation image to grab the frames from</param>
        /// <param name="width">The width of each frame</param>
        /// <param name="height">The height of each frame</param>
        /// <param name="duration">The time in milliseconds we use for each frame</param>
        /// <param name="Count">The number of frames we grab from the image</param>
        /// <param name="Start">The starting position on the Image where we grab the first frame</param>
        public void AddAnimation(Point Start, Image SpriteImage, int width, int height, int duration, int Count)
        {
            MyImage.AddAnimation(Start, SpriteImage, width, height, duration, Count);
        }

        /// <summary>
        /// Duplicate an animation, except rotated by the specified number of degrees.  For example, if you have
        /// a single animation (0), and you want to rotate it by 90 degrees, it will create animation 1 with that
        /// rotation to it.  In the long haul, generating a few rotated animations is less memory intensive than
        /// rotating it on demand.
        /// </summary>
        /// <param name="AnimationToCopy">An integer value specifying the animation to duplicate</param>
        /// <param name="RotationDegrees">The amount of counter-clockwise rotation to add</param>
        public void AddAnimation(int AnimationToCopy, int RotationDegrees)
        {
            if (AnimationToCopy < 0) return;
            if (AnimationToCopy > MyImage.AnimationCount) return;
            MyImage.AddAnimation(AnimationToCopy, RotationDegrees);
        }
        /// <summary>
        /// Duplicate an animation, except rotated by the specified number of degrees.  For example, if you have
        /// a single animation (0), and you want to rotate it by 90 degrees, it will create animation 1 with that
        /// rotation to it.  In the long haul, generating a few rotated animations is less memory intensive than
        /// rotating it on demand using the <see cref="Sprite.MirrorHorizontally"/> or <see cref="Sprite.MirrorVertically"/> booleans.
        /// </summary>
        /// <param name="AnimationToCopy">An integer value specifying the animation to duplicate</param>
        /// <param name="MirrorHorizontal">A boolean, stating if we should mirror horizontally</param>
        /// <param name="MirrorVertical">A boolean, stating if we should mirror vertically</param>
        public void AddAnimation(int AnimationToCopy, bool MirrorHorizontal, bool MirrorVertical)
        {
            if (AnimationToCopy < 0) return;
            if (AnimationToCopy > MyImage.AnimationCount) return;
            MyImage.AddAnimation(AnimationToCopy, MirrorHorizontal, MirrorVertical);
        }

        /// <summary>
        /// Start a new animation, but do it just once.  You can use AnimateJustAFewTimes(1) to the same effect.
        /// Or, you can use AnimateJustAFewTimes with a different number.  The SpriteAnimationComplete event will
        /// fire off when the animation completes.  The variable, Sprite.AnimationDone will be true once the 
        /// animation finishes animating.
        /// </summary>
        /// <param name="AnimationFrameToEndOn">Once the animation has finished, display this animation frame.
        /// -1, or any number that is not an actual frame, will show the last frame of the animation.</param>
        /// <param name="WhichAnimation">The animation index you want to use</param>
        public void AnimateOnce(int WhichAnimation, int AnimationFrameToEndOn = -1)
        {
            AnimateJustAFewTimes(WhichAnimation, 1);
            _FinalFrameAfterAnimation = AnimationFrameToEndOn;
        }

        /// <summary>
        /// Start a new animation.  It will complete the animation the number of times you specify.
        /// For example, if your sprite is walking, and one animation is one step, specifying 4 here
        /// will result in your sprite taking 4 steps and then the animation stops.  You will want
        /// to make sure you are checking for when the animation stops, using the SpriteAnimationComplete event,
        /// checking the Sprite.AnimationDone flag.
        /// </summary>
        /// <param name="WhichAnimation">The animation index you want to use</param>
        /// <param name="HowManyAnimations">The number of animations to do before it stops</param>
        /// <param name="AnimationFrameToEndOn">Once the animation has finished, display this animation frame.
        /// -1, or any number that is not an actual frame, will show the last frame of the animation.</param>
        public void AnimateJustAFewTimes(int WhichAnimation, int HowManyAnimations, int AnimationFrameToEndOn = -1)
        {
            if (WhichAnimation > -1 && WhichAnimation < MyImage.AnimationCount)
            { //We have a valid animation.  Do it once
                SetToAnimateOnce = true;
                AnimationNumberCount = HowManyAnimations;
                //Console.WriteLine("Setting to animate: " + HowManyAnimations);
                AnimationDone = false;
                AnimationIndex = WhichAnimation;
                FrameIndex = 0;
                ForceRedraw = true;
                LastResetImage = DateTime.UtcNow;
                _FinalFrameAfterAnimation = AnimationFrameToEndOn;
            }
        }
        /// <summary>
        /// Start a new animation index from scratch
        /// </summary>
        /// <param name="WhichAnimation">The animation index you want to use</param>
        /// <param name="StartFrame">The first frame you want to start the animation at.</param>
        public void ChangeAnimation(int WhichAnimation, int StartFrame = 0)
        {
            if (WhichAnimation > -1 && WhichAnimation < MyImage.AnimationCount)
            { //We have a valid animation.  Do it once
                SetToAnimateOnce = false;
                AnimationDone = false;
                AnimationIndex = WhichAnimation;
                FrameIndex = 0;
                int NumFrames = MyImage.AnimationFrameCount(WhichAnimation);
                if (StartFrame >= 0 && StartFrame <= NumFrames)
                    FrameIndex = StartFrame;
                ForceRedraw = true;
                LastResetImage = DateTime.UtcNow; //start from this second.
            }
        }
        /// <summary>
        /// Change the animation speed of a particular animation.  This looks at the first frame
        /// and compares that frame to the speed specified.  It adjusts all the animations by the
        /// same percentage.
        /// </summary>
        /// <param name="WhichAnimation">The integer representing the animation to change</param>
        /// <param name="newSpeed">The speed in milliseconds for the new animation</param>
        public void ChangeAnimationSpeed(int WhichAnimation, int newSpeed)
        {
            if (WhichAnimation > -1 && WhichAnimation < MyImage.AnimationCount)
            { //We have a valid animation
                TimeSpan CurrentTS = MyImage.GetCurrentDuration(WhichAnimation, 0);
                double Current = CurrentTS.TotalMilliseconds;
                double New = 1; //This is 1/2 times slower.  1 is the actual speed...
                if ((int)Current != newSpeed)
                {
                    //We have a different speed
                    if (Current == 0) Current = 10000; //A duration of zero should not rotate
                    if (newSpeed == 0)
                        New = 1;
                    else
                    {
                        New = Current / newSpeed; //We have a ratio.
                    }
                }
                //Console.WriteLine("New SpeedAdjust: " + New.ToString());
                SpeedAdjust = New;
            }
        }

        /// <summary>
        /// Change the animation speed of a specific frame.  Beware.  This affects every sprite using this frame
        /// </summary>
        /// <param name="WhichAnimation">The index of the animation</param>
        /// <param name="WhichFrame">The index of the frame within the animation</param>
        /// <param name="newSpeed">The new frame duration in milliseconds</param>
        public void ChangeFrameAnimationSpeed(int WhichAnimation, int WhichFrame, int newSpeed)
        {
            if (WhichAnimation > -1 && WhichAnimation < MyImage.AnimationCount)
            {
                Animation tAnimation = MyImage.getAnimation(WhichAnimation);
                if (WhichFrame < 0 || WhichFrame >= tAnimation.Frames.Count) return;
                tAnimation.Frames[WhichFrame].Duration = TimeSpan.FromMilliseconds(newSpeed);
            }
        }

        /// <summary>
        /// Get the animation speed of a single frame.
        /// </summary>
        /// <param name="WhichAnimation">The animation we are looking at</param>
        /// <param name="WhichFrame">The index of the frame we wish to get the speed of</param>
        /// <returns>-1 if either index is out of range.  Otherwise, return the total milliseconds of the specified frame.</returns>
        public int GetFrameAnimationSpeed(int WhichAnimation, int WhichFrame)
        {
            if (WhichAnimation > -1 && WhichAnimation < MyImage.AnimationCount)
            {
                Animation tAnimation = MyImage.getAnimation(WhichAnimation);
                if (WhichFrame < 0 || WhichFrame >= tAnimation.Frames.Count) return -1;
                return (int)tAnimation.Frames[WhichFrame].Duration.TotalMilliseconds;
            }
            return -1;
        }

        /// <summary>
        /// Return the animation speed of this particualar animation of the sprite.
        /// </summary>
        /// <param name="WhichAnimation">The animation we are looking at</param>
        /// <returns>The speed which was set.  The speed is calculated in pixels per amount of time.  A higher number is faster than a lower number</returns>
        public int GetAnimationSpeed(int WhichAnimation)
        {
            if (WhichAnimation > -1 && WhichAnimation < MyImage.AnimationCount)
            {
                TimeSpan CurrentTS = MyImage.GetCurrentDuration(WhichAnimation, 0);
                return (int)(CurrentTS.TotalMilliseconds / SpeedAdjust);
            }
            return -1;
        }
        private void EraseMe(bool SkipInvalidate = false)
        {
            EraseMe(MyRectangle.Location, SkipInvalidate);
        }
        private void EraseMe(Point tLocation, bool SkipInvalidate = false)
        {
            Image ChangedImage = MySpriteController.BackgroundImage; //This is the image itself.  Changes to this affect what is displayed
            Image OriginalImage = MySpriteController.OriginalImage;
            System.Drawing.Rectangle oldPlace = new System.Drawing.Rectangle(tLocation.X, tLocation.Y, Width, Height);
            
            lock(ChangedImage) lock(OriginalImage)
            {
                using (Graphics gx = Graphics.FromImage(ChangedImage))
                {
                    gx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                    gx.DrawImage(OriginalImage, oldPlace, oldPlace, GraphicsUnit.Pixel);
                }
            }
            if (!SkipInvalidate)
                MySpriteController.Invalidate(oldPlace);
            //Tell any sprite we overlap with that it needs to redraw
            foreach (Sprite CollidesWith in CollisionSprites.ToList())
            {
                CollidesWith.RedrawMeAndAllICollideWith();
            }
        }

        private void RedrawMeAndAllICollideWith()
        {
            if (NeedsDrawingAtEndOfTick) return; //we are already doing this
            NeedsDrawingAtEndOfTick = true;
            //if (Opacity != 1)
                EraseMe(true);
            //foreach (Sprite CollidesWith in CollisionSprites)
            //{
            //    CollidesWith.RedrawMeAndAllICollideWith();
            //}
        }

        private void DrawMe(bool SkipInvalidate = false, bool ActuallyDraw = false)
        {
            DrawMe(MyRectangle.Location, SkipInvalidate, ActuallyDraw);
        }
        private void DrawMe(Point tLocation, bool SkipInvalidate = false, bool ActuallyDraw = false)
        {
            if (ActuallyDraw)
            {
                lock(MySpriteController.BackgroundImage)
                {
                    Image ChangedImage = MySpriteController.BackgroundImage; //This is the image itself.  Changes to this affect what is displayed
                    System.Drawing.Rectangle ThePlace = new System.Drawing.Rectangle(tLocation.X, tLocation.Y, MyRectangle.Width, MyRectangle.Height);

                    ColorMatrix matrix = new ColorMatrix();
                    matrix.Matrix33 = Opacity;
                    ImageAttributes attributes = new ImageAttributes();
                    attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                    Image MeImage = MyImage.GetImage(AnimationIndex, FrameIndex, GetVisibleSize);
                    if (MirrorHorizontally || MirrorVertically)
                    {
                        MeImage = (Bitmap)MeImage.Clone();
                        if (MirrorHorizontally) MeImage.RotateFlip(RotateFlipType.RotateNoneFlipX);
                        if (MirrorVertically) MeImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    }
                    GraphicsUnit tUnit = GraphicsUnit.Pixel;
                    if (Rotation != 0 && MeImage != null)
                    {
                        Image rotatedImage = new Bitmap(MeImage.Width, MeImage.Height);
                        using (Graphics g = Graphics.FromImage(rotatedImage))
                        {
                            g.TranslateTransform(MeImage.Width / 2, MeImage.Height / 2); //set the rotation point as the center into the matrix
                            g.RotateTransform(Rotation); //rotate
                            g.TranslateTransform(-MeImage.Width / 2, -MeImage.Height / 2); //restore rotation point into the matrix
                            g.DrawImage(MeImage, MeImage.GetBounds(ref tUnit), rotatedImage.GetBounds(ref tUnit), tUnit); //draw the image on the new bitmap

                        }
                        //GC.Collect();
                        MeImage = rotatedImage;
                    }
                    if (MeImage != null)
                    {
                        //g.DrawImage(MeImage, new Rectangle(0, 0, MeImage.Width, MeImage.Height), 0, 0, rotatedImage.Width, rotatedImage.Height, tUnit, attributes); //draw the image on the new bitmap
                        //Graphics.FromImage(ChangedImage).DrawImage(MeImage, ThePlace, MeImage.GetBounds(ref tUnit), tUnit);
                        Graphics.FromImage(ChangedImage).DrawImage(MeImage, ThePlace, 0, 0, MeImage.Width, MeImage.Height, tUnit, attributes); //draw the image on the new bitmap
                                                                                                                                               //Pen tmpPen = new Pen(Color.Black);
                                                                                                                                               //Graphics.FromImage(ChangedImage).DrawRectangle(tmpPen, MyRectangle);
                        MySpriteController.Invalidate(MyRectangle);
                    }
                    NeedsDrawingAtEndOfTick = false;
                }
            }
            else
            {
                NeedsDrawingAtEndOfTick = true;
            }
        }

        /// <summary>
        /// Actually draw the Sprite.  Never use this.  It is used by the SpriteController
        /// </summary>
        internal void ActuallyDraw()
        {
            if (NeedsDrawingAtEndOfTick)
                DrawMe(false, true);
        }

        /// <summary>
        /// Put the Sprite at a specified location, using the dimentions of the BackgroundImage.
        /// Unless you are using coordinates you have gotten from a mouse-click, this is how you want
        /// to place a Sprite somewhere.  It is the easiest way to track things.  But, if you are
        /// doing something using mouse-click coordinates, you want to use PutPictureBoxLocation
        /// </summary>
        /// <param name="NewLocationOnImage">The new point on the Image</param>
        public void PutBaseImageLocation(Point NewLocationOnImage)
        {
            Point PointOnPictureBox = MySpriteController.ReturnPictureBoxAdjustedPoint(NewLocationOnImage);
            if (MyRectangle.Location != NewLocationOnImage || !HasBeenDrawn)
            {
                if (HasBeenDrawn)
                    EraseMe();
                xPositionOnImage = NewLocationOnImage.X;
                yPositionOnImage = NewLocationOnImage.Y;
                xPositionOnPictureBox = PointOnPictureBox.X;
                yPositionOnPictureBox = PointOnPictureBox.Y;
                xOnVector = NewLocationOnImage.X;
                yOnVector = NewLocationOnImage.Y;
                DrawMe(NewLocationOnImage);
                HasBeenDrawn = true;
            }
        }
        /// <summary>
        /// Put the Sprite at a specified location, using the dimentions of the BackgroundImage.
        /// Unless you are using coordinates you have gotten from a mouse-click, this is how you want
        /// to place a Sprite somewhere.  It is the easiest way to track things.  But, if you are
        /// doing something using mouse-click coordinates, you want to use PutPictureBoxLocation
        /// </summary>
        /// <param name="X">The X location on the background image</param>
        /// <param name="Y">the Y location on the background image</param>
        public void PutBaseImageLocation(double X, double Y)
        {
            Point NewLocation = new Point((int)X, (int)Y);
            Point actualPoint = MySpriteController.ReturnPictureBoxAdjustedPoint(NewLocation);
            if (MyRectangle.Location != NewLocation || !HasBeenDrawn)
            {
                if (HasBeenDrawn)
                    EraseMe();
                xPositionOnImage = NewLocation.X;
                yPositionOnImage = NewLocation.Y;
                xPositionOnPictureBox = actualPoint.X;
                yPositionOnPictureBox = actualPoint.Y;
                xOnVector = X;
                yOnVector = Y;
                DrawMe();
                HasBeenDrawn = true;
            }
        }

        /// <summary>
        /// Put the Sprite at a specified location, using the dimentions of the PictureBox.
        /// You want to use this if you got your X/Y position from a mouse-click.  Otherwise,
        /// this is the harder way to track things, particularly if your window can resize.  Use
        /// PutBaseImageLocation instead.
        /// </summary>
        /// <param name="NewLocationOnPictureBox">A point on the PictureBox</param>
        public void PutPictureBoxLocation(Point NewLocationOnPictureBox)
        {
            //We adjust to the location
            Point actualPoint = MySpriteController.ReturnPointAdjustedForImage(NewLocationOnPictureBox);
            PutBaseImageLocation(actualPoint);
            xPositionOnPictureBox = NewLocationOnPictureBox.X;
            yPositionOnPictureBox = NewLocationOnPictureBox.Y;
        }

        /// <summary>
        /// Done when the box resizes.  We need to recompute the picturebox location.  The resize function
        /// automatically calls this.  You should never need to do so.
        /// </summary>
        public void RecalcPictureBoxLocation()
        {
            Point nPoint = MySpriteController.ReturnPictureBoxAdjustedPoint(new Point(xPositionOnImage, yPositionOnImage));
            xPositionOnPictureBox = nPoint.X;
            yPositionOnPictureBox = nPoint.Y;
        }

        private void SetupForDrawing()
        {
            //We make sure we have the correct index for the image
            TimeSpan duration = DateTime.UtcNow - LastResetImage;
            if (PausedAnimation)
            {
                TimeSpan newduration = DateTime.UtcNow - PausedAnimationTime;
                LastResetImage = LastResetImage + newduration;
                PausedAnimationTime = DateTime.UtcNow;
                duration = DateTime.UtcNow - LastResetImage;
            }
            double orig = duration.TotalMilliseconds;
            if (SpeedAdjust != 1)
            {
                double Adjust = duration.TotalMilliseconds * SpeedAdjust;
                //Console.WriteLine(SpriteName + " " + SpriteOriginName + " " + orig.ToString() + " " + Adjust.ToString());
                duration = TimeSpan.FromMilliseconds(Adjust);
            }
            if (MyImage.NeedsNewImage(AnimationIndex, FrameIndex, duration) || ForceRedraw)
            {
                EraseMe();
                bool AtEnd = false;
                int oldindex = FrameIndex;
                if (SetToAnimateOnce && AnimationNumberCount <= 1) AtEnd = true;
                //Console.Write("Changing Animation Frame: " + FrameIndex);
                TimeSpan difference = MyImage.ChangeIndex(AnimationIndex, ref _FrameIndex, duration, AtEnd);
                //Console.WriteLine("  To: " + FrameIndex);
                SpriteChangesAnimationFrames(this, new SpriteEventArgs());
                LastResetImage = DateTime.UtcNow - difference;
                if (SetToAnimateOnce)
                {
                    if ((FrameIndex == 0 && oldindex != FrameIndex) || MyImage.AnimationDone(AnimationIndex, FrameIndex, SetToAnimateOnce))
                    {
                        //Console.WriteLine("We are at the end frame:");
                        TimeSpan HowLong = MyImage.GetCurrentDuration(AnimationIndex, FrameIndex);
                        if (difference > HowLong || FrameIndex == 0)
                        {
                            AnimationNumberCount--;
                            //Console.WriteLine("One animation done.  Now we have: " + AnimationNumberCount);
                            if (AnimationNumberCount < 1)
                            {
                                AnimationDone = true;
                                if (_FinalFrameAfterAnimation >= 0 && _FinalFrameAfterAnimation < AnimationCount)
                                {
                                    AnimationIndex = _FinalFrameAfterAnimation;
                                    _FinalFrameAfterAnimation = -1;
                                }
                                if (!PausedEvents)
                                    SpriteAnimationComplete(this, new SpriteEventArgs());
                            }
                        }
                    }
                }

                DrawMe();
                ForceRedraw = false; //We have done a redraw.  No need to do it every time
            }
        }

        /// <summary>
        /// This is run from the sprite controller every 10 miliseconds.  You should never
        /// need to call this yourself.
        /// </summary>
        internal void Tick()
        {
            if (!SpriteHasInitialized)
            {
                SpriteHasInitialized = true;
                SpriteInitializes(this, new SpriteEventArgs());
            }
            if (HasBeenDrawn)
            {
                SetupForDrawing();
                TryToMove();
            }
        }

        /// <summary>
        /// Return the point that this sprite needs to be shooting for, for the center of this sprite to 
        /// hit the center of the destination sprite.
        /// </summary>
        /// <param name="destination">The sprite we are shooting for trying to hit</param>
        /// <returns>A point which allows the moving sprite to collide with the destination sprite.</returns>
        private Point GetMoveToSpritePoint(Sprite destination)
        {
            if (destination.Destroying) return new Point(-1, -1);
            Point DestCenter = destination.GetSpriteBaseImageCenter();
            Point targetPoint = new Point(DestCenter.X - Width / 2, DestCenter.Y - Height / 2);
            return targetPoint;
        }

        private void TryToMove()
        {
            if (AutomaticallyMoves && MovementSpeed > 1)
            {
                //Now, we move it.
                //Take 1 sec and divide it by the speed.  That is how many ms we need before we move

                double MS = 50 / MovementSpeed;
                if (MS < 2) MS = 2;
                TimeSpan Elapsed = DateTime.UtcNow - LastMovement;
                if (PausedMovement)
                {
                    TimeSpan newduration = DateTime.UtcNow - PausedMovementTime;
                    LastMovement = LastMovement + newduration;
                    PausedMovementTime = DateTime.UtcNow;
                    Elapsed = DateTime.UtcNow - LastMovement;
                }
                if (Elapsed.TotalMilliseconds > MS)
                {
                    if(MovingToSprite != null && !MovingToSprite.Destroying)
                    {
                        MovementDestinations.Clear();
                        Point TargetPoint = GetMoveToSpritePoint(MovingToSprite);
                        MovementDestinations.Add(TargetPoint);
                    }
                    else if(MovingToSprite != null && MovingToSprite.Destroying)
                    {
                        MovingToSprite = null; //We stop shooting for the location of the sprite.
                        //We are still shooting for where the sprite used to be.
                    }
                    if (MovingToPoint && MovementDestinations.Count > 0)
                        SetSpriteDirectionToPoint(MovementDestinations[0]); //recalculate to decrease error
                    double MovementDelta = Elapsed.TotalMilliseconds / MS;
                    double newX = xOnVector + (MovementDelta * SpriteVector.X);
                    double newY = yOnVector + (MovementDelta * SpriteVector.Y);
                    //if(double.IsNaN(newX) || newX > 1000 || newX < -1000)
                    //{
                    //    Console.WriteLine("Major issue. NAN:   xOnVecor:" + xOnVector.ToString() + " MovementDelta:" + MovementDelta.ToString() + " SpriteVec:" + SpriteVector.X.ToString());
                    //}
                    //if (double.IsNaN(newY) || newY > 1000 || newY < -1000)
                    //{
                    //    Console.WriteLine("Major issue. NAN:   yOnVecor:" + yOnVector.ToString() + " MovementDelta:" + MovementDelta.ToString() + " SpriteVec:" + SpriteVector.Y.ToString());
                    //}
                    if (CannotMoveOutsideBox)
                    {
                        double tNewx = newX;
                        double tNewy = newY;
                        Image tImage = MySpriteController.BackgroundImage;
                        if (newX < -1) newX = -1;
                        if (newY < -1) newY = -1;
                        if (newX > tImage.Width - Width) newX = (tImage.Width - Width) + 1;
                        if (newY > tImage.Height - Height) newY = (tImage.Height - Height) + 1;
                        if (tNewx != newX || tNewy != newY && MovingToPoint)
                        {
                            //We are not allowed to go outside the box, but our point is outside the box.  Cancel
                            CancelMoveTo();
                        }
                    }
                    SpriteEventArgs e = new SpriteEventArgs();
                    e.NewLocation = new Point((int)Math.Round(newX), (int)Math.Round(newY));
                    if (MovingToPoint && MovementDestinations.Count > 0)
                    {
                        //do not go past the destination point
                        if (SpriteVector.X < 0 && newX < MovementDestinations[0].X) newX = MovementDestinations[0].X;
                        if (SpriteVector.X > 0 && newX > MovementDestinations[0].X) newX = MovementDestinations[0].X;
                        if (SpriteVector.X == 0) newX = MovementDestinations[0].X;
                        if (SpriteVector.Y < 0 && newY < MovementDestinations[0].Y) newY = MovementDestinations[0].Y;
                        if (SpriteVector.Y > 0 && newY > MovementDestinations[0].Y) newY = MovementDestinations[0].Y;
                        if (SpriteVector.Y == 0) newY = MovementDestinations[0].Y;
                        //Check to see if we have hit the waypoint
                        //Console.WriteLine("Heading to: " + MovementDestinations[0].ToString() + " At: " + newX.ToString() + " " + newY.ToString());
                        if ((int)newX == MovementDestinations[0].X && (int)newY == MovementDestinations[0].Y)
                        {
                            //check to see if we have hit the endpoint
                            MovementDestinations.RemoveAt(0); //Yank the destination
                            if (MovementDestinations.Count == 0)
                            {
                                CancelMoveTo();
                                SpriteArrivedAtEndPoint(this, e);
                            }
                            else
                            {
                                SpriteArrivedAtWaypoint(this, e);
                                SetSpriteDirectionToPoint(MovementDestinations[0]);
                            }
                        }
                    }
                    else if (MovingToPoint) {
                        CancelMoveTo();
                    }
                    if (!PausedEvents)
                        CheckBeforeMove(this, e); //See if there is any code to let us go or not go
                    //if(e.Cancel)
                    //{
                    //    Console.WriteLine("canceled. " + newX.ToString() + "  " + newY.ToString() + " " + MovementDelta.ToString());
                    //}
                    if (!e.Cancel)
                    {
                        //This allows our 'check before move'function to adjust the destination.
                        PutBaseImageLocation(e.NewLocation);
                    }
                    LastMovement = DateTime.UtcNow;
                    CheckForEvents();
                }
            }
        }

        /// <summary>
        /// Resize the sprite using the base image coordinates.  The width and height specified
        /// are relative to the size of the background image, not the picturebox.
        /// </summary>
        /// <param name="NewSize">The size (width, height) to make the sprite</param>
        public void SetSize(Size NewSize)
        {
            if (NewSize.Width == MyRectangle.Width && NewSize.Height == MyRectangle.Height)
                return;  //No need to do anything if we are not making changes
            if (HasBeenDrawn)
            {
                EraseMe(); //Erase ourselves
            }
            Width = NewSize.Width;
            Height = NewSize.Height;
            if (HasBeenDrawn)
            {
                DrawMe();
            }
        }

        /// <summary>
        /// Tell the sprite to kill itself.  It will erase itself and then
        /// be removed from the spritelist.  Then it will be gone forever.
        /// </summary>
        public void Destroy()
        {
            //If we are not already destroying ourselves
            if (!_Destroying)
            {
                //Mark ourselves as being destroyed
                _Destroying = true;
                //Erase ourselves
                EraseMe();
                //Remove ourselves from the controller (and the tick process)
                SpriteBeingDestroyed(this, new SpriteEventArgs()); 
                MySpriteController.DestroySprite(this);
            }
        }

        /// <summary>
        /// Remove the sprite from the field.  This does not destroy the sprite.  It simply removes it from action.
        /// Use UnhideSprite to show it again.
        /// </summary>
        public void HideSprite()
        {
            EraseMe();
            HasBeenDrawn = false;
        }


        /// <summary>
        /// Make the sprite reappear.  If you have not positioned it yet, it will show up at the top corner.  It is best to only
        /// use this when you have hidden it using HideSprite
        /// </summary>
        public void UnhideSprite()
        {
            DrawMe();
            HasBeenDrawn = true;
        }
        /// <summary>
        /// Return true or false, asking if the specifiec sprite is at the point on the picturebox.
        /// You can use this with a mouse-click to see if you are clicking on a sprite.  Use the 
        /// SpriteCollisionMethod "transparent" to see if you have clicked on an actual pixel of the 
        /// sprite instead of just within the sprite rectangle.
        /// </summary>
        /// <param name="location">The x and y location in ImageBox coordinates.</param>
        /// <param name="method">The method of determining if the sprite is at that position</param>
        /// <returns>True if the sprite is at the specified location, false if it is not</returns>
        public bool SpriteAtPictureBoxPoint(Point location, SpriteCollisionMethod method = SpriteCollisionMethod.rectangle)
        {
            //Translate the position to a position on the drawing pane
            SpriteAdjustmentRatio PictureBoxRatio = MySpriteController.ReturnAdjustmentRatio();
            int x = (int)(location.X / PictureBoxRatio.width_ratio);
            int y = (int)(location.Y / PictureBoxRatio.height_ratio);

            //The x,y is now the pixel in the sprite.
            return SpriteAtImagePoint(new Point(x, y), method);
        }

        /// <summary>
        /// Because sprites are scaled (shrunk or stretched), this function finds the point
        /// within the sprite that is specified by the location.  this function is used by
        /// a number of internal processes, but may be useful to you.  But probably not.
        /// </summary>
        /// <param name="location">A point given in Image coordinates</param>
        /// <returns>A point within the pixel that can be used to find a particular pixel in a sprite.</returns>
        public Point SpriteAdjustedPoint(Point location)
        {
            Point internalPoint = new Point(location.X - MyRectangle.Location.X, location.Y - MyRectangle.Location.Y);
            SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
            Point AdjustedPoint = new Point((int)(internalPoint.X / Ratio.width_ratio), (int)(internalPoint.Y / Ratio.height_ratio));
            return AdjustedPoint;
        }

        /// <summary>
        /// Check to see if the sprite exists at the point specified.  The point given is
        /// in coordinates used by the image (not the PictureBox, use SpriteAtPictureBox for that)
        /// </summary>
        /// <param name="location">An imagebox location</param>
        /// <param name="method">the method to use to determine if the image is there</param>
        /// <returns>true if the sprite is at that position, false if it is not</returns>
        public bool SpriteAtImagePoint(Point location, SpriteCollisionMethod method = SpriteCollisionMethod.rectangle)
        {
            if (location.X < MyRectangle.Location.X) return false;
            if (location.X > MyRectangle.Location.X + MyRectangle.Width) return false;
            if (location.Y < MyRectangle.Location.Y) return false;
            if (location.Y > MyRectangle.Location.Y + MyRectangle.Height) return false;

            
            //We need to adjust to the sprite being stretched or shrunk
            Point internalPoint = new Point(location.X - MyRectangle.Location.X, location.Y - MyRectangle.Location.Y);
            SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
            Point AdjustedPoint = SpriteAdjustedPoint(location);
            
            if (method == SpriteCollisionMethod.transparency)
            {
                Bitmap tImage = (Bitmap)GetImage();
                //Check the point within the sprite
                if (AdjustedPoint.X < 0 || AdjustedPoint.X >= tImage.Width) return false;
                if (AdjustedPoint.Y < 0 || AdjustedPoint.Y >= tImage.Height) return false;
                Color OneSpace = tImage.GetPixel(AdjustedPoint.X, AdjustedPoint.Y);
                if (OneSpace.A == 0)
                    return false; //It is transparent.  No collision at this point.  255 is solid
                return true;
            }
            if (method == SpriteCollisionMethod.circle)
            {

                Point center = new Point(
                  MyRectangle.Width / 2,
                  MyRectangle.Height / 2);

                double _xRadius = MyRectangle.Width / 2;
                double _yRadius = MyRectangle.Height / 2;


                if (_xRadius <= 0.0 || _yRadius <= 0.0)
                    return false;
                /* This is a more general form of the circle equation
                 *
                 * X^2/a^2 + Y^2/b^2 <= 1
                 */

                Point normalized = new Point(location.X - center.X,
                                             location.Y - center.Y);

                return ((double)(normalized.X * normalized.X)
                         / (_xRadius * _xRadius)) + ((double)(normalized.Y * normalized.Y) / (_yRadius * _yRadius))
                    <= 1.0;
            }

            return true;
        }


        /// <summary>
        /// return the current image frame.  Warning:  If you write to this image, it will
        /// affect all sprites using this frame.
        /// </summary>
        /// <returns>An image that is the current sprite frame for the current animation</returns>
        public Image GetImage()
        {
            if (AnimationIndex < 0) AnimationIndex = 0;
            if (FrameIndex < 0) FrameIndex = 0;
            return MyImage.GetImage(AnimationIndex, FrameIndex, GetVisibleSize);
        }

        /// <summary>
        /// return the frame for the given index.  Warning:  If you write to this image, it will
        /// affect all sprites using this frame.
        /// </summary>
        /// <param name="Animation_Index">The Animation index we are trying to find</param>
        /// <param name="Frame_Index">The Frame index we are trying to find</param>
        /// <returns>An image that is the current sprite frame for the current animation</returns>
        public Image GetImage(int Animation_Index, int Frame_Index)
        {
            if (Animation_Index < 0) Animation_Index = 0;
            if (Animation_Index > MyImage.AnimationCount) return null;
            if (Frame_Index < 0) Frame_Index = 0;
            if (Frame_Index > MyImage.AnimationFrameCount(Animation_Index)) return null;
            return MyImage.GetImage(Animation_Index, Frame_Index, GetVisibleSize);
        }


        /// <summary>
        /// Replace a sprite image.  It will replace the current frame unless you specify both an animation
        /// and the frame within the animation you wish to replace.  Warning:  This replaces the image_frame 
        /// for every sprite that uses that is based off the same image.
        /// </summary>
        /// <param name="newimage">The new image to use</param>
        /// <param name="animation">The animation you want to change</param>
        /// <param name="frame">The frame within the animation you want to change</param>
        public void ReplaceImage(Image newimage, int animation = -1, int frame = -1)
        {
            if (newimage == null) return; //do not replace it with nothing
            if (AnimationIndex < 0) AnimationIndex = 0;
            if (FrameIndex < 0) FrameIndex = 0;
            if (animation == -1) animation = AnimationIndex;
            if (frame == -1) frame = FrameIndex;
            MyImage.ReplaceImage(newimage, animation, frame);
            RedrawMeAndAllICollideWith();
        }

        /// <summary>
        /// Taking into consideration how the sprite is stretched or shrunk, it
        /// returns a SpriteAdjustmentRatio that can be used to work with the sprite
        /// itself.
        /// </summary>
        /// <returns>The current SpriteAdjustmentRatio used to display this sprite</returns>
        public SpriteAdjustmentRatio ReturnAdjustmentRatio()
        {
            SpriteAdjustmentRatio Ratio = new SpriteAdjustmentRatio();

            Image tImage = GetImage();
            //if(tImage == null) Console.WriteLine(this.ID.ToString());
            Ratio.width_ratio = (double)MyRectangle.Width / (double)tImage.Width;
            Ratio.height_ratio = (double)MyRectangle.Height / (double)tImage.Height;
            return Ratio;
        }

        /// <summary>
        /// Return true if the sprite can go to this point and still be on the drawing-board.
        /// </summary>
        /// <param name="newpoint">The point, given in pixels and corresponding to pixels on the picturebox</param>
        /// <returns>true or false</returns>
        public bool SpriteCanMoveOnPictureBox(Point newpoint)
        {
            return SpriteCanMoveOnImage(MySpriteController.ReturnPointAdjustedForImage(newpoint));
        }

        /// <summary>
        /// Return true if the sprite can go to this point and still be on the drawing-board.
        /// </summary>
        /// <param name="newpoint">The point, given in pixels and corresponding to pixels on the background image</param>
        /// <returns>true or false</returns>
        public bool SpriteCanMoveOnImage(Point newpoint)
        {
            Image tImage = MySpriteController.BackgroundImage;
            if (newpoint.X < 0) return false;
            if (newpoint.X + Width > tImage.Width) return false;
            if (newpoint.Y < 0) return false;
            if (newpoint.Y + Height > tImage.Height) return false;
            return true;
        }

        /// <summary>
        /// Move to where the destination sprite currently is at.  This is a dumb move.  It does not take into
        /// consideration the movement direction of the destination sprite.  So the moving sprite does need to be
        /// moving a bit faster than the sprite you are trying to hit for it to do so.
        /// </summary>
        /// <param name="Destination">The sprite we are trying to hit</param>
        public void MoveTo(Sprite Destination)
        {
            MovingToSprite = Destination;
            LastMovement = DateTime.UtcNow;
            MovementDestinations.Clear();
            Point TargetPoint = GetMoveToSpritePoint(Destination);
            MovementDestinations.Add(TargetPoint);
            MovingToPoint = true;
            SpriteReachedEndPoint = false;
            SetSpriteDirectionToPoint(TargetPoint);
        }

        /// <summary>
        /// Tell the Sprite to move towards a destination.  You need to give the sprite a MovementSpeed
        /// and tell the sprite that it can automatically move.  But the sprite will begin a journey towards
        /// that point at the MovementSpeed you have set.  When it gets to the point, the SpriteArrivedAtEndPoint event
        /// will fire off.  Also, the SpriteReachedEnd bool will be true.
        /// </summary>
        /// <param name="Destination">An image-point that the sprite will move to.</param>
        public void MoveTo(Point Destination)
        {
            List<Point> tList = new List<Point>();
            tList.Add(Destination);
            MoveTo(tList); //This way we only have one function to make.
        }

        /// <summary>
        /// Tell the sprite to move towards each point in turn.  The sprite will move in a straight line until the first point.
        /// From there it moves to the next point, until it has reached the last point.  Every time it reaches a point, the
        /// SpriteArrivedAtWaypoint event is triggered.  When it reaches the final point in the list, the SpriteArrivedAtEndPoint
        /// event is triggered.  While the sprite is moving, the SpriteReachedEndPoint attribute is set to false.  When it has
        /// arrived, it is set to true.
        /// </summary>
        /// <param name="DestinationList">A list of Image-Points that the sprite will follow, one after the other</param>
        public void MoveTo(List<Point> DestinationList)
        {
            MovingToSprite = null; //If we were trying to hit something, we are no longer trying to hit it.
            LastMovement = DateTime.UtcNow;
            if (DestinationList.Count == 0) CancelMoveTo(); //If we tell it to move nowhere, cancel it
            MovementDestinations.Clear();
            foreach(Point one in DestinationList)
                MovementDestinations.Add(one);
            MovingToPoint = true;
            SpriteReachedEndPoint = false;
            SetSpriteDirectionToPoint(DestinationList[0]);
        }

        /// <summary>
        /// Sets the Sprite Moving towards a given point.  You are responsible to do something with it once it gets there.
        /// If you want it to automatically stop upon reaching it, use MoveTo instead.  Actually, the MoveTo function works
        /// a lot better than this one.  Because of integer rounding and a few other things, this function is a little
        /// bit imprecise.  If you send it towards a point, it will go in that general direction.  The MoveTo function
        /// will perpetually recalculate its way to the destination point and actually reach that point.  SetSpriteDirectionToPoint
        /// will sort-of head in the direction of the point.  But MoveTo will go to that point.
        /// </summary>
        /// <param name="ImagePointDestination">The destination, based off a point on the background image, that we send the sprite towards.</param>
        public void SetSpriteDirectionToPoint(Point ImagePointDestination)
        {
            double x = ImagePointDestination.X - xPositionOnImage;
            double y = ImagePointDestination.Y - yPositionOnImage;
            double distance = Math.Sqrt(x *x + y * y);
            if (distance == 0) return; //No need to go anywhere.
            System.Windows.Vector newVec = new System.Windows.Vector(x / distance, y / distance);
            //if(double.IsNaN(newVec.X) || double.IsNaN(newVec.Y))
            //{
            //    Console.WriteLine("SetSpriteDirectionToPoint: Creating invalid vector " + distance);
            //}
            SetSpriteDirection(newVec);
            //Console.WriteLine("SetDirectionToPoint " + ImagePointDestination.ToString());
        }

        /// <summary>
        /// Cancel a MoveTo command.  The sprite will stop moving, and all the waypoints will be removed.
        /// </summary>
        public void CancelMoveTo()
        {
            SpriteReachedEndPoint = true;
            MovementDestinations.Clear();
            MovingToSprite = null; //If we were heading towards a sprite.  Stop doing so.
            if (!MovingToPoint) return; //We do not do anything if we are not moving.
            MovementSpeed = 0;
            //AutomaticallyMoves = false;
            SetSpriteDirectionDegrees(0);//Basically reset it to nothing
            MovingToPoint = false;
        }

        /// <summary>
        /// Given a "degree" (from 0 to 360, set the direction
        /// that the sprite moves automatically.  0 is right, 90 is up, 180 is left
        /// and 270 is down.
        /// </summary>
        /// <param name="AngleInDegrees">the degrees to use</param>
        public void SetSpriteDirectionDegrees(double AngleInDegrees)
        {
            //convert to Radians and set it with that
            double Radians = ConvertDegreesToRadians(AngleInDegrees);
            SetSpriteDirectionRadians(Radians);
        }

        /// <summary>
        /// Set the sprite direction using Radians.  Most people do not want to use this.
        /// Use SetSpriteDirectionDegrees instead unless you like math and know what you
        /// are doing with Radians.
        /// </summary>
        /// <param name="AngleInRadians">The angle in radians</param>
        public void SetSpriteDirectionRadians(double AngleInRadians)
        {
            //Turn it into a vector
            System.Windows.Vector newVector = new System.Windows.Vector((float)Math.Cos(AngleInRadians),
                                                                        -(float)Math.Sin(AngleInRadians));
            SetSpriteDirection(newVector);
        }

        /// <summary>
        /// Set the sprite direction using a vector.  The vector may contain
        /// a speed as well as the movement delta (amount of x shift, and amount
        /// of y shift.)  If so, this function may also affect the movement speed
        /// Most people prefer to use SetSpriteDirectionDegrees instead of using
        /// vectors.
        /// </summary>
        /// <param name="newVector">A vector</param>
        public void SetSpriteDirection(System.Windows.Vector newVector)
        {
            System.Windows.Vector oldVector = newVector;
            //use the specified vector
            if (Math.Round(newVector.Length) != 1)
            {
                double NewSpeed = Math.Round(newVector.Length);
                MovementSpeed = (int)NewSpeed;
            }
            newVector.Normalize();
            if (double.IsNaN(newVector.X) || double.IsNaN(newVector.Y))
            {
                //Console.WriteLine("SetSpriteDirection: Error setting direction.  " + oldVector.ToString());
                newVector = oldVector;
            }
            SpriteVector = newVector;
        }

        /// <summary>
        /// Convert a number from degrees to radians.
        /// </summary>
        /// <param name="Degrees">The number from 0 to 360 in degrees</param>
        /// <returns>The corresponding number converted to radians</returns>
        public double ConvertDegreesToRadians(double Degrees)
        {
            return (Math.PI / 180.0) * Degrees;
        }

        /// <summary>
        /// Convert a number from radians to degrees.
        /// </summary>
        /// <param name="Radians">The number of radians</param>
        /// <returns>The corresponding number in degrees</returns>
        public double ConvertRadiansToDegrees(double Radians)
        {
            double degrees = (180.0 / Math.PI) * Radians;
            if (Radians < 0) degrees += 360;
            return degrees;
        }

        /// <summary>
        /// Return the current vector that the sprite is moving along
        /// </summary>
        /// <returns>The current sprite vector</returns>
        public System.Windows.Vector GetSpriteVector()
        {
            return SpriteVector;
        }

        /// <summary>
        /// Returns the direction the sprite is currently traveling, using Radians.
        /// </summary>
        /// <returns>The direction in radians that the sprite is traveling in</returns>
        public double GetSpriteRadans()
        {
            //double radians = Math.Atan2((double)SpriteVector.Y, (double)SpriteVector.X);
            double radians;
            if(SpriteVector.Y > 0 && SpriteVector.X > 0)
            {
                //calculate it in the other quadrant and then adjust.
                radians = Math.Atan2((double)SpriteVector.Y, (double)SpriteVector.X);
                radians = (2 * Math.PI) - radians; 
            }
            else
                radians = Math.Atan2(-(double)SpriteVector.Y, (double)SpriteVector.X);
            return radians;
        }

        /// <summary>
        /// Get the direction that the sprite is traveling in in degrees.  You may want to
        /// use Math.Round on the results.  The value returned is usually just a tiny bit off
        /// from what you set it with.  For example, if you set the sprite movement direction
        /// to be 270 degrees (down), this function may return it as 269.999992.  Rounding the
        /// number will give it back to you at probably the same direction you set it as.
        /// </summary>
        /// <returns>A double (it has a decimal place) that represents the direction in degrees</returns>
        public double GetSpriteDegrees()
        {
            double radians = GetSpriteRadans();
            double degrees = ConvertRadiansToDegrees(radians);
            if (degrees < 0) degrees = 360 + degrees;
            return degrees;
        }

        /// <summary>
        /// Return the centerpoint of the sprite, as found on the background image
        /// </summary>
        /// <returns>a point with the x and y based off the background image location</returns>
        public Point GetSpriteBaseImageCenter()
        {
            Point corner = BaseImageLocation;
            return new Point(corner.X + Width / 2, corner.Y + Height / 2);
        }

        /// <summary>
        /// Return the centerpoint of the sprite, as found on the picturebox
        /// </summary>
        /// <returns>A point with the x and y found on the picturebox</returns>
        public Point GetSpritePictureboxCenter()
        {
            Point corner = PictureBoxLocation;
            return new Point(corner.X + VisibleWidth / 2, corner.Y + VisibleHeight / 2);
        }

        // ***************** Events ***********
        private bool CheckForHittingEdgeOfImage()
        {
            Image tImage = MySpriteController.BackgroundImage;
            bool outOfBounds = false;
            if (xPositionOnImage < 0) outOfBounds = true;
            if (xPositionOnImage + Width > tImage.Width) outOfBounds = true;
            if (yPositionOnImage < 0) outOfBounds = true;
            if (yPositionOnImage + Height > tImage.Height) outOfBounds = true;
            if (outOfBounds)
            {
                if (!PausedEvents)
                    SpriteHitsPictureBox(this, new SpriteEventArgs());
            }
            return outOfBounds;
        }
        private bool CheckForExitingImage()
        {
            Image tImage = MySpriteController.BackgroundImage;
            bool outOfBounds = false;
            if (xPositionOnImage + Width < 0) outOfBounds = true;
            if (xPositionOnImage > tImage.Width) outOfBounds = true;
            if (yPositionOnImage + Width < 0) outOfBounds = true;
            if (yPositionOnImage > tImage.Height) outOfBounds = true;
            if (outOfBounds)
            {
                if (!PausedEvents)
                    SpriteExitsPictureBox(this, new SpriteEventArgs());
            }
            return outOfBounds;
        }

        private bool CheckToSeeIfSpriteHitsSprite(Sprite target, SpriteCollisionMethod how)
        {
            if (target == this) return false; //We do not collide with ourselves.
            if (target.xPositionOnImage + target.Width < xPositionOnImage) return false;
            if (target.xPositionOnImage > xPositionOnImage + Width) return false;
            if (target.yPositionOnImage + target.Height < yPositionOnImage) return false;
            if (target.yPositionOnImage > yPositionOnImage + Height) return false;
            //If we get here, we have two rectangles ovelapping.
            if (how == SpriteCollisionMethod.circle)
            {

            }
            if (how == SpriteCollisionMethod.transparency)
            {

            }
            return true;
        }

        /// <summary>
        /// Check to see if the specified rectangle overlaps with the sprite.
        /// </summary>
        /// <param name="target">The rectangle we are looking to see if we hit</param>
        /// <returns>True if the rectangle overlaps the sprite rectabgle</returns>
        public bool SpriteIntersectsRectangle(Rectangle target)
        {
            if (target.X + target.Width < xPositionOnImage) return false;
            if (target.X > xPositionOnImage + Width) return false;
            if (target.Y + target.Height < yPositionOnImage) return false;
            if (target.Y > yPositionOnImage + Height) return false;
            //If we get here, we have two rectangles ovelapping.
            return true;
        }

        /// <summary>
        /// Check to see if two sprites hit each-other.  The sprite collision methods are
        /// not all programmed in.
        /// </summary>
        /// <param name="target">The Sprite we are checking to see if we hit</param>
        /// <param name="how">The method we use to determine if they hit</param>
        public void CheckSpriteHitsSprite(Sprite target, SpriteCollisionMethod how)
        {
            if (target == this) return;
            if (CheckToSeeIfSpriteHitsSprite(target, how))
            {
                target.NoteSpriteHitsSprite(this, how);
                NoteSpriteHitsSprite(target, how);
                CollisionSprites.Add(target);
            }
        }

        /// <summary>
        /// This is used when two sprites hit each-other. 
        /// </summary>
        /// <param name="target">The sprite it hits</param>
        /// <param name="how">the method for checking</param>
        internal void NoteSpriteHitsSprite(Sprite target, SpriteCollisionMethod how)
        {
            if (target == this) return;
            SpriteEventArgs newArgs = new SpriteEventArgs();
            newArgs.TargetSprite = target;
            newArgs.CollisionMethod = how;
            if (SpriteHitsSprite != null)
            {
                if (!PausedEvents)
                    SpriteHitsSprite(this, newArgs);
            }
        }

        internal void CheckForEvents()
        {
            if (!CheckForExitingImage())
            {
                CheckForHittingEdgeOfImage();
            }
        }

        internal void ClearCollisionList()
        {
            CollisionSprites.Clear();
        }

        /// <summary>
        /// Make the sprite show up in front of all other sprites.
        /// </summary>
        public void SendToFront()
        {
            MySpriteController.SpriteToFront(this);
        }

        /// <summary>
        /// Make the sprite go behind all other sprites
        /// </summary>
        public void SendToBack()
        {
            MySpriteController.SpriteToBack(this);
        }

        /// <summary>
        /// Pause the sprite.  We can pause just the animation (and still let it move), pause movement (and let it animate), or pause everything.
        /// </summary>
        /// <param name="What">Which aspects of the sprite you want to pause.</param>
        public void Pause(SpritePauseType What = SpritePauseType.PauseAll)
        {
            if(!PausedAnimation  && (What == SpritePauseType.PauseAnimation || What == SpritePauseType.PauseAll))
            {
                PausedAnimationTime = DateTime.UtcNow;
                PausedAnimation = true;
            }
            if (!PausedMovement && (  What == SpritePauseType.PauseMovement || What == SpritePauseType.PauseAll))
            {
                PausedMovementTime = DateTime.UtcNow;
                PausedMovement = true;
            }
            if (What == SpritePauseType.PauseEvents || What == SpritePauseType.PauseAll)
            {
                PausedEvents = true;
            }
        }
        /// <summary>
        /// unpause the sprite.
        /// </summary>
        /// <param name="What">Which aspects of the sprite you want to unpause.</param>
        public void UnPause(SpritePauseType What = SpritePauseType.PauseAll)
        {
            TimeSpan duration;
            if (PausedAnimation && What == SpritePauseType.PauseAnimation || What == SpritePauseType.PauseAll)
            {
                duration = DateTime.UtcNow - PausedAnimationTime;
                LastResetImage = LastResetImage + duration;
                PausedAnimation = false;
            }
            if (PausedMovement && What == SpritePauseType.PauseMovement || What == SpritePauseType.PauseAll)
            {
                duration = DateTime.UtcNow - PausedMovementTime;
                LastMovement = LastResetImage + duration;
                PausedMovement = false;
            }
            if (PausedEvents && What == SpritePauseType.PauseEvents || What == SpritePauseType.PauseAll)
            {
                PausedEvents = false;
            }
        }
        /// <summary>
        /// Ask if the sprite is paused using the specified sprite type (default is PauseAll)
        /// </summary>
        /// <param name="What">The spritePauseType to see if the sprite is paused with</param>
        /// <returns>True if the sprite is set to pause the specified item, false if not</returns>
        public bool IsPaused(SpritePauseType What = SpritePauseType.PauseAll)
        {
            if (What == SpritePauseType.PauseAnimation && PausedAnimation) return true;
            if (What == SpritePauseType.PauseMovement && PausedMovement) return true;
            if (What == SpritePauseType.PauseEvents && PausedMovement) return true;
            if (What == SpritePauseType.PauseAll && PausedAnimation && PausedMovement && PausedEvents) return true;
            return false;
        }

        internal void ClickedOn(SpriteCollisionMethod how)
        {
            if (how == SpriteCollisionMethod.rectangle)
                Click(this, new SpriteEventArgs());
            if (how == SpriteCollisionMethod.transparency)
                ClickTransparent(this, new SpriteEventArgs());
        }

        internal void HoverOver()
        {
            MouseHover(this, new SpriteEventArgs());
        }
        internal void Enter()
        {
            MouseEnter(this, new SpriteEventArgs());
        }
        internal void Leave()
        {
            MouseLeave(this, new SpriteEventArgs());
        }

        internal void HoverOverTransparent()
        {
            MouseHoverTransparent(this, new SpriteEventArgs());
        }
        internal void EnterTransparent()
        {
            MouseEnterTransparent(this, new SpriteEventArgs());
        }
        internal void LeaveTransparent()
        {
            MouseLeaveTransparent(this, new SpriteEventArgs());
        }
    }
}
