using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.IO;
using SFML.Graphics;
using SFML.Window;

namespace YourBeatingHeart.Main.Graphics
{
    //put that into the player constructor 
    //sprite = new AnimatedSprite(playState.Game.LoadTexture("test.jpg"), "Default", new Animation(2, 0, 300, 300, 600));

    public class AnimatedSprite : Drawable
    {
        public Dictionary<string, Animation> animations;
        public Sprite Sprite { get; private set; }

        public string ActiveAnimation { get; private set; }

        public Vector2f Origin;
        public Vector2f Scale { get { return Sprite.Scale; } set { Sprite.Scale = value; } }
        public Color Color { get { return Sprite.Color; } set { Sprite.Color = value; } }
        public Vector2f Position;
        public bool IsPlaying { get { if (animations.ContainsKey(ActiveAnimation)) return animations[ActiveAnimation].IsAnimating; else return false; } }

        public struct FrameInfo
        {
            public string Name;
            public IntRect FrameRect;
            public Vector2f Offset;
            static readonly Regex nameMatch = new Regex("(?<=n=\")(.*)(?=\" x)");
            static readonly Regex xMatch = new Regex("(?<=x=\")(.*)(?=\" y)");
            static readonly Regex yMatch = new Regex("(?<=y=\")(.*)(?=\" w)");
            static readonly Regex widthMatch = new Regex("(?<=w=\")(.*)(?=\" h)");
            static readonly Regex heightMatch = new Regex("(?<=h=\")(.*)(?=\" oX)");
            static readonly Regex heightUntrimmedMatch = new Regex("(?<=h=\")(.*)(?=\"/>)");
            static readonly Regex xOffsetMatch = new Regex("(?<=oX=\")(.*)(?=\" oY)");
            static readonly Regex yOffsetMatch = new Regex("(?<=oY=\")(.*)(?=\" oW)");

            public static FrameInfo FromXMLLine(string _line)
            {
                FrameInfo retInfo = new FrameInfo();
                retInfo.Name = nameMatch.Match(_line).ToString();
                int x, y, w, h, oX = 0, oY = 0;
                x = int.Parse(xMatch.Match(_line).ToString());
                y = int.Parse(yMatch.Match(_line).ToString());
                w = int.Parse(widthMatch.Match(_line).ToString());
                if (int.TryParse(heightMatch.Match(_line).ToString(), out h))
                {
                    int.TryParse(xOffsetMatch.Match(_line).ToString(), out oX);
                    int.TryParse(xOffsetMatch.Match(_line).ToString(), out oY);
                }
                else
                    h = int.Parse(heightUntrimmedMatch.Match(_line).ToString());

                retInfo.FrameRect = new IntRect(x, y, w, h);
                retInfo.Offset = new Vector2f(oX, oY);
                return retInfo;
            }

            public class NameComparer : Comparer<FrameInfo>
            {
                public override int Compare(FrameInfo x, FrameInfo y)
                {
                    return x.Name.CompareTo(y.Name);
                }
            }
        }
        
        public AnimatedSprite(string _xmlFile, Game _game)
            : this(_xmlFile, _game, Constants.ANIMATION_FPS)
        {
        }

        public AnimatedSprite(string _xmlFile, Game _game, int fps)
        {
            string[] xmlContent = File.ReadAllLines(Path.Combine("data\\images", _xmlFile));

            int line = 0;
            while (!xmlContent[line].StartsWith("<TextureAtlas"))
                line++;

            Regex pathRegEx = new Regex("(?<=imagePath=\")(.*)(?=\" width)");

            int endIndex = xmlContent[line].IndexOf("\"", 26);
            string texPath = pathRegEx.Match(xmlContent[line]).ToString();
            texPath = Path.Combine(Path.GetDirectoryName(_xmlFile), texPath);
            Sprite = new Sprite(_game.LoadTexture(texPath));

            Dictionary<string, List<FrameInfo>> frameInfos = new Dictionary<string, List<FrameInfo>>();

            line++;
            Regex animNameMatch = new Regex("(?<=_)([a-z]*)");
            while (xmlContent[line] != "</TextureAtlas>")
            {
                
                FrameInfo newInfo = FrameInfo.FromXMLLine(xmlContent[line]);
                string name = newInfo.Name.Substring(0, newInfo.Name.Length - 4);
                if (string.IsNullOrEmpty(name))
                    name = "idle";

                if (!frameInfos.ContainsKey(name))
                    frameInfos[name] = new List<FrameInfo>();
                frameInfos[name].Add(FrameInfo.FromXMLLine(xmlContent[line]));
                line++;
            }

            animations = new Dictionary<string, Animation>();
            foreach (var anim in frameInfos)
            {
                anim.Value.Sort(new FrameInfo.NameComparer());
                animations[anim.Key] = new Animation(anim.Value, fps);
            }

            ActiveAnimation = "";
        }

        public void Pause()
        {
            if (animations.ContainsKey(ActiveAnimation))
                animations[ActiveAnimation].Pause();
        }

        public void SetFrame(int _index)
        {
            if (animations.ContainsKey(ActiveAnimation))
                animations[ActiveAnimation].SetFrame(_index);
        }

        public int GetFrame()
        {
            if (animations.ContainsKey(ActiveAnimation))
                return animations[ActiveAnimation].GetFrame();
            else
                return 0;
        }

        public void Play(string _animName)
        {
            if (_animName == ActiveAnimation)
                return;

            if (animations.ContainsKey(ActiveAnimation))
                animations[ActiveAnimation].Reset();

            if (animations.ContainsKey(_animName))
            {
                ActiveAnimation = _animName;
                Sprite.Position = Position + animations[ActiveAnimation].CurrentOffset;
                Sprite.TextureRect = animations[ActiveAnimation].CurrentFrameRect;
                animations[ActiveAnimation].Play();
            }
        }

        public void Resume()
        {
            if (animations.ContainsKey(ActiveAnimation))
                animations[ActiveAnimation].Play();
        }

        public void Stop()
        {
            if (animations.ContainsKey(ActiveAnimation))
            {
                animations[ActiveAnimation].Reset();
                Sprite.TextureRect = animations[ActiveAnimation].CurrentFrameRect;
            }

            ActiveAnimation = "";
        }

        public void Update(float _elapsedTime)
        {
            if (animations.ContainsKey(ActiveAnimation))
            {
                animations[ActiveAnimation].Update(_elapsedTime);
                Sprite.TextureRect = animations[ActiveAnimation].CurrentFrameRect;
                Sprite.Position = Position + animations[ActiveAnimation].CurrentOffset;
                Sprite.Origin = Origin;
            }
        }

        public void Draw(RenderTarget target, RenderStates states)
        {
            Sprite.Position = Position;
            if(animations.ContainsKey(ActiveAnimation))
                Sprite.Position += animations[ActiveAnimation].CurrentOffset;
            Sprite.Draw(target, states);
        }
    }
}
