using Microsoft.Xna.Framework;
using MonoGame.FourEngine;
using System;

namespace Rotor.Win32.Scenes
{
    public class RotatableScene : Scene
    {
        private const int TranslateSpeed = 2;
        private const float RotationSpeed = 0.015f;
        private const float ScalingSpeed = 0.005f;
        private const int Offset = 200;

        public float Rotation { get; private set; }
        public Point Translation { get; private set; }
        public float Scaling { get; private set; }

        private bool _mouseOver;
        private bool _isUpscaling;
        private Direction _dir;

        private Rectangle _rect;

        public override void OnAttach(DrawingSurfaceBase surface)
        {
            base.OnAttach(surface);
            EnableManipulation();
            DrawingSurface.Transformations.Add(Transform);
            _rect = new Rectangle(0, 0, surface.Width, surface.Height);
            Reset();
        }

        public override void OnUpdate(UpdateEventArgs args)
        {
            base.OnUpdate(args);
            var rect = _rect;
            _mouseOver = rect.Contains(args.Pointer.Position);
            Rotate();
            Translate();
            Scale();
        }

        public override void OnClear(ClearEventArgs args)
        {
            args.Color = _mouseOver
                ? Color.Red
                : Color.Green;
        }

        public override void OnPrimaryClick(ClickedEventArgs point)
        {
            base.OnPrimaryClick(point);
            Reset();
        }

        private void Rotate()
        {
            Rotation += RotationSpeed;
            Rotation = Rotation % (2 * (float)Math.PI);
        }

        private void Translate()
        {
            switch (_dir)
            {
                case Direction.Right:
                    Translation += new Point(TranslateSpeed, 0);
                    if (Translation.X >= Configuration.Size.X - _rect.Width - Offset)
                        _dir = Direction.Down;
                    break;
                case Direction.Down:
                    Translation += new Point(0, TranslateSpeed);
                    if (Translation.Y >= Configuration.Size.Y - _rect.Height - Offset)
                        _dir = Direction.Left;
                    break;
                case Direction.Left:
                    Translation += new Point(-TranslateSpeed, 0);
                    if (Translation.X <= Offset)
                        _dir = Direction.Up;
                    break;
                case Direction.Up:
                    Translation += new Point(0, -TranslateSpeed);
                    if (Translation.Y <= Offset)
                        _dir = Direction.Right;
                    break;
            }
        }

        private void Scale()
        {
            Scaling += _isUpscaling
                ? ScalingSpeed
                : -ScalingSpeed;
            if (Scaling >= 2 || Scaling <= 0.5)
                _isUpscaling = !_isUpscaling;
        }

        private void Transform(SpriteDrawEventArgs args)
        {
            args.Rotate(Rotation, new Vector2(0.5f));
            args.Translate(Translation);
            args.Scale(Scaling);
        }

        private void Reset()
        {
            Translation = new Point(Offset);
            Rotation = 0;
            Scaling = 1;
            _isUpscaling = true;
            _dir = Direction.Right;
        }

        enum Direction
        {
            Right, Down, Left, Up
        }
    }
}