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

namespace Snake
{
    public class Level
    {
        Map map;
        TileLayer walls;
        int maxBonus;
        List<Bonus> bonuses = new List<Bonus>();
        List<Wormhole> wormholes = new List<Wormhole>();
        Random random = new Random();
        Point start;
        Direction direction;
        string title;
        string description;
        int goal;
        int bonusCD;
        int time;
        ScreenManager screenManager;

        public Point Start
        {
            get { return start; }
        }

        public Direction Direction
        {
            get { return direction; }
        }

        public int Goal
        {
            get { return goal; }
        }

        public string Title
        {
            get { return title; }
        }

        public string Description
        {
            get { return description; }
        }

        public Level(Map map, ScreenManager screenManager)
        {
            this.screenManager = screenManager;
            this.map = map;
            walls = map.GetLayer("walls") as TileLayer;
            if (walls == null)
                throw new ArgumentException("No walls layer");
            maxBonus = int.Parse(map.Properties["MaxBonus"].RawValue);
            direction = (Direction)Enum.Parse(Direction.GetType(), map.Properties["Direction"].RawValue);
            goal = int.Parse(map.Properties["Goal"].RawValue);
            title = map.Properties["Title"].RawValue;
            bonusCD = int.Parse(map.Properties["BonusCD"].RawValue);
            description = map.Properties["Desc"].RawValue;
            MapObjectFinder of = delegate(MapObjectLayer layer, MapObject obj)
            {
                if (layer.Name.Equals("triggers"))
                {
                    return obj.Name.Equals("start");
                }
                return false;
            };
            MapObjectFinder wormholeFinder = delegate(MapObjectLayer layer, MapObject obj)
            {
                if (layer.Name.Equals("triggers"))
                {
                    return obj.Type.Equals("wormhole");
                }
                return false;
            };
            MapObject start = map.FindObject(of);
            if (start == null)
                throw new ArgumentException("No start position");
            this.start = new Point((int)(start.Bounds.Center.X / Game1.CELL_SIZE), (int)(start.Bounds.Center.Y / Game1.CELL_SIZE));
            foreach (MapObject obj in map.FindObjects(wormholeFinder))
            {
                Point coord = new Point((int)(obj.Bounds.Center.X / Game1.CELL_SIZE), (int)(obj.Bounds.Center.Y / Game1.CELL_SIZE));
                Wormhole wormhole = new Wormhole(Game1.CELL_SIZE, obj.Name, coord);
                wormholes.Add(wormhole);
            }
        }

        // Жутко некрасиво но делать крутую систему сообщений для звуков лень
        public void Update(GameTime gameTime)
        {
            foreach (Wormhole it in wormholes)
            {
                it.Update(gameTime);
            }
            foreach (Bonus it in bonuses)
            {
                it.Update(gameTime);
            }
            time += gameTime.ElapsedGameTime.Milliseconds;
            if (bonuses.Count == 0)
                time = 0;
            if (time >= bonusCD * 1000)
            {
                int n = random.Next(bonuses.Count);
                bonuses[n].Transform();
                time = 0;
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            map.Draw(spriteBatch);
            foreach (Bonus it in bonuses)
            {
                it.Draw(spriteBatch);
            }
            foreach (Wormhole it in wormholes)
            {
                it.Draw(spriteBatch);
            }
        }

        void SpawnBonus()
        {
            Point coord = Point.Zero;
            do
            {
                coord = new Point(random.Next(Game1.WIDTH), random.Next(Game1.HEIGHT));
            } while (!CellEmpty(coord));
            Bonus bonus = new Bonus(Game1.CELL_SIZE);
            bonus.Spawn(coord);
            bonuses.Add(bonus);
        }

        bool CellEmpty(Point coord)
        {
            Tile tile = walls.Tiles[coord.X, coord.Y];
            if (tile != null)
                return false;
            foreach (Bonus it in bonuses)
            {
                if (it.Coord == coord)
                    return false;
            }
            foreach (Wormhole it in wormholes)
            {
                if (it.Coord == coord)
                    return false;
            }
            return true;
        }

        public bool CanMove(Point coord)
        {
            Tile tile = walls.Tiles[coord.X, coord.Y];
            return tile == null;
        }

        public void Update(GameTime gameTime, Snake snake)
        {
            foreach (Bonus it in bonuses)
            {
                if (it.Coord == snake.Head)
                {
                    it.Eat(snake);
                    screenManager.PlaySound("collect");
                }
            }
            for (int i = 0; i < bonuses.Count; ++i)
            {
                Bonus it = bonuses[i];
                if (!it.Alive)
                    bonuses.Remove(it);
            }
            bool teleported = false;
            foreach (Wormhole it in wormholes)
            {
                if (snake.Head == it.Coord)
                {
                    foreach (Wormhole jt in wormholes)
                    {
                        if (jt != it && it.Color == jt.Color)
                        {
                            snake.Head = jt.Coord;
                            teleported = true;
                            screenManager.PlaySound("teleport");
                            break;
                        }
                    }
                }
                if (teleported)
                    break;
            }
            while (bonuses.Count < maxBonus)
            {
                SpawnBonus();
            }
        }
    }
}
