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

namespace Slayter
{
    public class Player:IDrawable
    {
        Game1 parent;
        public Hero currentHero;
        List<Hero> heroes;
        public int gold;
        int heroInd;
        bool[,] covered;
        public Time time;
        int rows;
        int cols;
        Texture2D coveredTex;
        List<Castle> castles;

        public Player(Game1 game)
        {
            parent = game;
            castles = new List<Castle>();
            int[] place = new int[2] { 0, 1 };
            Castle o = new Castle(parent.Content.Load<Texture2D>("castle"), parent.GameScreen.Bground, place,this);
            parent.GameScreen.Bground.AddToDrawablesAndObjectsOnMap(o);
            castles.Add(o);

            coveredTex = game.Content.Load<Texture2D>("covered");
            rows=game.GameScreen.Bground.Rows;
            cols=game.GameScreen.Bground.Cols;
            covered=new bool[rows,cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    covered[i, j] = true;
                }
            }
                gold = 10000;
            time = new Time();
            Hero hero1= new Hero(parent.Content.Load<Texture2D>("arab"), parent, 0, 0,this);
            parent.GameScreen.addHeroToMap(hero1);
            Hero hero2= new Hero(parent.Content.Load<Texture2D>("warrior"), parent, 3,0, this);
            parent.GameScreen.addHeroToMap(hero2);
            currentHero = hero1;
            heroes = new List<Hero>();
            heroInd = 0;
            heroes.Add(currentHero);
            heroes.Add(hero2);
        }

        public bool checkIfUncovered(int x, int y)
        {
            return covered[x, y];
        }

        class BlockElement{
            public int X;
            public int Y;
            public int depth;
            public int[] Value { get { return new int[] { X, Y }; } }
            public BlockElement(int x,int y,int depth)
            {
                this.X = x;
                this.Y = y;
                this.depth = depth;
            }

                public override bool  Equals(object obj)
                {
                    BlockElement o = (BlockElement)obj;
 	                if (Object.ReferenceEquals(this, o)) return true;
                        if (Object.ReferenceEquals(this, null) || Object.ReferenceEquals(o, null))
                            return false;
                        bool result = true;
                        if (this.Value.Length != o.Value.Length)
                            return false;
                        for (int i = 0; i < this.Value.Length; i++)
                        {
                            if (this.Value[i] != o.Value[i])
                            {
                                result = false;
                                break;
                            }
                        }
                        return result;
               } 

            public override int GetHashCode()
            {
                if (Object.ReferenceEquals(this, null)) return 0;


                return this.GetHashCode() ^ this.GetHashCode();
            }
        }

        public void Uncover(int x,int y,int depth)
        {
            List<BlockElement> opened=new List<BlockElement>();
            List<BlockElement> closed = new List<BlockElement>();
            opened.Add(new BlockElement( x, y , depth));
            while (opened.Count != 0)
            {
                BlockElement temp;
                BlockElement element=opened[0];
                opened.Remove(element);
                closed.Add(element);
                covered[element.X,element.Y] = false;
                if (element.depth != -1)
                {
                    temp = new BlockElement(element.X - 1, element.Y, element.depth - 1);
                    if (element.X > 0 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                    temp = new BlockElement(element.X - 1, element.Y-1, element.depth - 1);
                    if (element.X > 0 && element.Y > 0 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp); 
                    }
                    temp = new BlockElement(element.X + 1, element.Y, element.depth - 1);
                    if (element.X < rows - 1 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                    temp = new BlockElement(element.X + 1, element.Y+1, element.depth - 1);
                    if (element.X < rows - 1 && element.Y < cols - 1 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                    temp = new BlockElement(element.X, element.Y - 1, element.depth - 1);
                    if (element.Y > 0 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                    temp = new BlockElement(element.X+1, element.Y - 1, element.depth - 1);
                    if (element.Y > 0 && element.X < rows - 1 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                    temp = new BlockElement(element.X, element.Y+1, element.depth - 1);
                    if (element.Y < cols - 1 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                    temp = new BlockElement(element.X-1, element.Y+1, element.depth - 1);
                    if (element.Y < cols - 1 && element.X > 0 && !closed.Contains(temp) && !opened.Contains(temp))
                    {
                        opened.Add(temp);
                    }
                }
            }
            
        }

        public void NewDay()
        {
            time.NewDay(this);
            foreach (Hero cool in heroes)
            {
                cool.refreshMoves();
            }
        }

        public void RemoveCastle(Castle castle){
            if (castles.Contains(castle))
            {
                castles.Remove(castle);
            }
            else
            {
                Console.Out.WriteLine("Error");
            }
            CheckCastles();
        }

        private void CheckCastles()
        {
            if (castles.Count == 0)
            {
                parent.EndGame();
            }
        }

        public void draw(SpriteBatch springBatch)
        {
            foreach (Hero element in heroes)
            {
                if(element!=currentHero)
                    element.draw(springBatch);
            };
            currentHero.draw(springBatch);
            currentHero.path.draw(springBatch);
            //drawMap(springBatch);
        }

        private void drawMap(SpriteBatch springBatch)
        {
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    if (covered[i, j])
                    {
                        Rectangle temp = new Rectangle(j * 40, i * 40, 40, 40);
                        Rectangle temp2 = new Rectangle(0, 0, 40, 40);
                        if (parent.GameScreen.Bground.getPosition(ref temp, ref temp2))
                        {
                            springBatch.Draw(coveredTex, temp, temp2, Color.White);
                        }
                    }
                }
            }
        }

        internal void ChangeHero()
        {
            Console.Out.WriteLine("herehere");
            heroInd++;
            if (heroInd>=heroes.Count)
            {
                heroInd=0;
            }
            currentHero = heroes[heroInd];
            parent.GameScreen.changeHero();
        }

        public void RemoveHero(Hero h)
        {
            if (heroes.Contains(h))
            {
                heroes.Remove(h);
                parent.GameScreen.RemoveHeroFromMap(h);
                ChangeHero();
            }
        }
    }
}
