using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using System.IO;

namespace Slayter
{
    public partial class Map : Background, IDrawable, IClickable
    {

        readonly int minXforChange;
        readonly int maxXforChange;
        readonly int minYforChange;
        readonly int maxYforChange;



        public int[,] map;
        int rows;
        int cols;

        MapCalculator calc;

        private int topX;
        public int TopX
        {
            get
            {
                return topX;
            }
            set
            {
                if (value > Picture.Width - 640)
                    topX = Picture.Width - 640;
                else if (value < 0)
                    topX = 0;
                else
                    topX = value;
            }
        }
        private int topY;

        public int TopY
        {
            get
            {
                return topY;
            }
            set
            {
                if (value > Picture.Height - 480)
                    topY = Picture.Height - 480;
                else if (value < 0)
                    topY = 0;
                else
                    topY = value;
            }
        }


        public Hero hero;
        public GameScreen parent;
        public List<MapObject> drawables;
        List<IMoveable> objectsOnMap;
        public bool hasPath;

        public int Rows { get { return rows; } }
        public int Cols { get { return cols; } }

        public Map(Texture2D t, Rectangle r, string csvfile,GameScreen parent)
            : base(t, r)
        {
            hasPath = false;
            this.parent = parent;
            calc = new MapCalculator(t, csvfile);
            this.map = calc.map;
            rows = calc.rows;
            cols = calc.cols;
            minXforChange = 320;
            maxXforChange = t.Width - 320;
            minYforChange = 240;
            maxYforChange = t.Height - 240;

            drawables = new List<MapObject>();
            objectsOnMap = new List<IMoveable>();

            LoadDrawables(parent.parent);
        }

        public void setHero(Game1 game,Hero h)
        {
            hero = h;
        }


        public void addHeroOnMap(Hero h)
        {
            objectsOnMap.Add(h);
        }

        public void removeHeroFromMap(Hero h)
        {
            if (objectsOnMap.Contains(h))
            {
                objectsOnMap.Remove(h);
            }
        }

        public void addForbidden(int x)
        {
            calc.forbidden.Add(x);
        }

        public bool getPosition(ref Rectangle screenPos, ref Rectangle picturePart)
        {
            screenPos.X -= TopX;
            screenPos.Y -= TopY;
            if (Rect.Intersects(screenPos))
            {
                Rectangle r = Rectangle.Intersect(screenPos, Rect);
                if (r.Y + r.Height == 480)
                {
                    picturePart.Height = r.Height;
                    screenPos.Height = r.Height;
                }
                return true;
            }
            return false;
        }

        public void LoadDrawables(Game1 game)
        {
            int[] place4 = new int[2] { 3, 4 };
            SpecialObjectsMap q = new SpecialObjectsMap(parent.parent.Content.Load<Texture2D>("chest"), this, place4, delegate(GameScreen screen, MapObject obj2)
            {
                RemoveFromDrawablesAndObjectOnMap(obj2);
                hero.player.gold += 2000; parent.UpdateText();
                MessageScreen m = new MessageScreen(this.parent,"Gold","Congrats! You found 2000 gold");
            });

            AddToDrawablesAndObjectsOnMap(q);
            
            int[] place5 = new int[2] { 2, 2 };
            SpecialObjectsMap z = new SpecialObjectsMap(parent.parent.Content.Load<Texture2D>("chest"), this, place5, delegate(GameScreen screen, MapObject obj2)
            {
                hero.PrintMonsters();
            });

            AddToDrawablesAndObjectsOnMap(z);
            
        }

        public void AddToDrawablesAndObjectsOnMap(SpecialObjectsMap q)
        {
            drawables.Add(q);
            objectsOnMap.Add(q);
        }

        public void RemoveFromDrawablesAndObjectOnMap(MapObject obj2)
        {
            SpecialObjectsMap obj = (SpecialObjectsMap)obj2;
            drawables.Remove(obj); objectsOnMap.Remove(obj);
        }

        public void drawDrawables(SpriteBatch spriteBatch)
        {
            foreach (IDrawable drawable in drawables)
            {
                drawable.draw(spriteBatch);
            }
        }

        public Boolean isClicked(MouseState state)
        {
            return Rect.X <= state.X && (Rect.X + Rect.Width) >= state.X &&
                        Rect.Y <= state.Y && (Rect.Y + Rect.Height) >= state.Y;
        }

        public override void draw(SpriteBatch springBatch)
        {
            Rectangle r = new Rectangle(TopX, TopY, 640, 480);
            springBatch.Draw(picture, rect, r, Color.White);
            drawDrawables(springBatch);
        }

        public void Move(Game1 game, Microsoft.Xna.Framework.Input.KeyboardState keyboard)
        {
            if (keyboard.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.W))
            {
                TopY -= 4;
            }
            if (keyboard.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.S))
            {
                TopY += 4;
            }
            if (keyboard.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.A))
            {
                TopX -= 4;
            }
            if (keyboard.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D))
            {
                TopX += 4;
            }
            if (keyboard.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Space))
            {
                UpdateCurrent();
            }
        }

        internal void UpdateCurrent()
        {
            if (hero.CurrentX < minXforChange)
            {
                TopX = 0;
            }
            else if (hero.CurrentX > maxXforChange)
            {
                TopX = Picture.Width - 640;
            }
            else
                TopX = hero.CurrentX - 320;

            if (hero.CurrentY < minYforChange)
            {
                TopY = 0;
            }
            else if (hero.CurrentY > maxYforChange)
            {
                TopY = Picture.Width - 480;
            }
            else
                TopY = hero.CurrentY - 240;
        }
        public bool FirstClick;
        public void Click(MouseState state)
        {
            bool removed=false;
            Comparator r=new Comparator();
            IMoveable tempMoveable=null;
            int[] temp = new int[2];
            temp[0] = (state.X + TopX) / 40;
            temp[1] = (state.Y + TopY) / 40;
            int[] validity = new int[] { temp[1], temp[0] };
            foreach (IMoveable element in objectsOnMap)
            {
                if (r.Equals(element.Coordinates,validity))
                {
                    removed = true;
                    tempMoveable = element;
                    objectsOnMap.Remove(element);
                    break;
                }
            }
            if (!calc.forbidden.Contains<int>(map[temp[1], temp[0]]) && !parent.parent.currentPlayer.checkIfUncovered(temp[1],temp[0]))
            {
                List<int[]> obstacles = new List<int[]>();
                foreach (IMoveable element in objectsOnMap)
                {
                    obstacles.Add(element.Coordinates);
                }
                    if (hero.position[0] == temp[0] && hero.position[1] == temp[1] && !(hero.last[1] == temp[1] && hero.last[0] == temp[0]) && FirstClick)
                    {
                            FirstClick = false;
                            hero.path.WalkingPath = new List<int[]>(hero.path.DrawingPath);
                            hero.heroIsMoving = true;
                            hero.AbleToMove(map[hero.path.WalkingPath[0][1], hero.path.WalkingPath[0][0]]);
                    }
                    else
                    {
                        List<int[]> path = new List<int[]>();
                        if (hero.last[1] == temp[1] && hero.last[0] == temp[0])
                            path.Clear();
                        else
                            path = calc.DeterminePath(hero.last[1], hero.last[0], temp[1], temp[0], obstacles,parent.parent.currentPlayer);
                        if (path != null)
                        {
                            if (removed)
                                hero.path.movesToObject = true;
                            else
                                hero.path.movesToObject = false;
                            hero.path.DrawingPath = new List<int[]>(path);
                        }
                        else
                        {
                            hero.path.DrawingPath = new List<int[]>();
                            if (hero.path.WalkingPath.Count != 0)
                            {
                                {
                                    hero.path.WalkingPath.Clear();
                                    hero.path.WalkingPath.Add(hero.last);
                                    hero.path.DrawingPath.Add(hero.last);
                                }
                            }
                            hasPath = false;
                            if (removed)
                            {
                                objectsOnMap.Add(tempMoveable);
                            }
                            return;
                        }
                        hero.position[0] = temp[0];
                        hero.position[1] = temp[1];
                        hasPath = true;
                        FirstClick = true;
                        hero.heroIsMoving = false;
                        if (hero.path.DrawingPath.Count != 0)
                            hero.getHeroDir(hero.path.DrawingPath[0]);
                        if (hero.path.WalkingPath.Count != 0)
                        {
                            {
                                hero.path.WalkingPath.Clear();
                                hero.path.WalkingPath.Add(hero.last);
                            }
                        }
                    }
            }
            if (removed)
            {
                objectsOnMap.Add(tempMoveable);
            }
        }

        internal void checkTile(Hero h,int[] last)
        {
            foreach (IMoveable element in objectsOnMap)
            {
                if (element.isMovedOn(h,last))
                {
                    element.Act(parent);
                    break;
                }
            }
        }
    }
}
