// Game Name: Flatlands
// Author: John Hurst (sircrowbar@gmail.com) - Crowbar / Johannhat - http://www.badenoughdude.com/
// Started: 4/20/2012
// Last Updated: 4/22/2012
// For Ludum Dare 23!
// Holy crap I forgot to comment the shit out of everything. The good news is that I plan on expanding this game
// further so maybe there will be time for that afterwards! Happy Ludum Day! - JH

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

using Flatlands.Tiles;
using Microsoft.Xna.Framework.Content;

namespace Flatlands
{
    public struct WorldInfo{
        public int Population;
        public int Nature;
        public int Culture;
    };

    class Grid
    {
        const int DEFAULT_COLUMNS = 3;
        const int DEFAULT_TILES = 9;


        List<Tile> tiles = new List<Tile>();
        List<Warning> warnings = new List<Warning>();
        List<int> selectedColumns = new List<int>();

        List<Rectangle> hitBoxes = new List<Rectangle>();

        Vector2 pos = new Vector2(200, 75);
        public Rectangle hitBox;
        Rectangle gridHitBox;

        int numColumns = DEFAULT_COLUMNS;
        int numTiles = DEFAULT_TILES;

        int tileToMoveIndex = 0;
        Tile tileToMove = null;

        private Texture2D tex;

        public Grid()
        {

        }

        public void load(ContentManager content)
        {
            tex = content.Load<Texture2D>(@"Tiles\biggrid");

            hitBox.X = (int)pos.X;
            hitBox.Y = (int)pos.Y;
            hitBox.Width = tex.Width;
            hitBox.Height = tex.Height;
            
            gridHitBox.Width = tex.Width / numColumns;
            gridHitBox.Height = tex.Height / numColumns;
            
            for (int i = 0; i < numColumns; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    hitBoxes.Add(new Rectangle((int)pos.X + (gridHitBox.Width * j), (int)pos.Y + (gridHitBox.Height * i), gridHitBox.Width, gridHitBox.Height));
                }
                Warning warn = new Warning(new Vector2((int)pos.X + (gridHitBox.Width * i), (pos.Y - 100)));
                warn.load(content);
                warnings.Add(warn);
            }


        }

        public void draw(SpriteBatch batch)
        {
            batch.Draw(tex, pos, null, Color.Pink, 0.0f, new Vector2(0), 1.0f, SpriteEffects.None, 0.0f);

            foreach (Warning warn in warnings)
            {
                warn.draw(batch);
            }

            
            foreach (Tile tile in tiles)
            {
                tile.draw(batch);
            }

        }

        public void update(GameTime gameTime)
        {

            for (int i = 0; i < tiles.Count; i++)
            {
                tiles[i].update(gameTime);
                if (!hitBox.Intersects(tiles[i].hitBox)){
                    tiles[i].dead = true;
                }

                if (tiles[i].dead && tiles[i].scale <= 0.0f)
                {
                    tiles.RemoveAt(i);
                    i--;
                }
            }


        }

        public bool addTile(Tile tile, Vector2 mousePos, ContentManager content)
        {
            bool added = false;
            Vector2 oldPos = tile.Position;
            if (tiles.Count > numTiles)
            {
                tile.Position = oldPos;
                return added;
            }
            int add = -1;
            tile.load(content);

            tile.Position = calcGridPos(new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1));

            foreach (Tile temp in tiles)
            {
                if (tile.hitBox.Intersects(temp.hitBox))
                {
                    tile.Position = oldPos;
                    return added;
                } 
            }

            if (tiles.Count == 0) add = 0;
            else if (tiles.Count < numTiles) add = tiles.Count - 1;
            else
            {
                for (int i = 0; i < tiles.Count; i++)
                {
                    if (tiles[i] == null)
                    {


                        add = i;
                    }

                }
            }

            if (add >= 0)
            {
                tiles.Insert(add, tile);
                added = true;
            }

            if (!added) tile.Position = oldPos;

            return added;
        }

        public bool addTile(Vector2 mousePos, ContentManager content)
        {
            bool added = false;

            if (tiles.Count > numTiles) return added;

            int add = -1;
            Tile tile = new Tile();
            tile.load(content);

            tile.Position = calcGridPos(new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1));

            foreach (Tile temp in tiles)
            {
                if (tile.hitBox.Intersects(temp.hitBox)) return added;
            }

            if (tiles.Count == 0) add = 0;
            else if (tiles.Count < numTiles) add = tiles.Count - 1;
            else
            {
                for (int i = 0; i < tiles.Count; i++)
                {
                    if (tiles[i] == null)
                    {


                        add = i;
                    }

                }
            }

            if (add >= 0)
            {
                tiles.Insert(add, tile);
                added = true;
            }

            return added;
        }

        public bool destroyTile(Vector2 mousePos)
        {
            bool added = false;
            Rectangle mouseRect = new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1);
            
            foreach (Tile temp in tiles)
            {
                if (temp.hitBox.Intersects(mouseRect))
                {
                    tiles.Remove(temp);
                    added = true;
                    break;
                } 
            }

            return added;
        }

        public bool upgradeTile(Vector2 mousePos, ContentManager content)
        {
            bool added = false;
            Rectangle mouseRect = new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1);


            foreach (Tile temp in tiles)
            {
                if (temp.hitBox.Intersects(mouseRect))
                {
                    if (temp.upgradeable)
                    {
                        temp.upgrade(content);
                        added = true;
                    }
                    break;
                }
            }

            return added;
        }

        public bool selectTileToMove(Vector2 mousePos)
        {
            bool added = false;
            Rectangle mouseRect = new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1);

            for (int i = 0; i < tiles.Count; i++)
            {
                if (tiles[i].hitBox.Intersects(mouseRect))
                {
                    tileToMove = tiles[i];
                    tileToMoveIndex = i;
                    added = true;
                    break;

                }
            }
            return added;
        }

        public bool moveTile(Vector2 mousePos, ContentManager content)
        {
            bool added = false;
            Rectangle mouseRect = new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1);

            Vector2 newPos = calcGridPos(new Rectangle((int)mousePos.X, (int)mousePos.Y, 1, 1));
            Rectangle newRect = new Rectangle((int)newPos.X, (int)newPos.Y, tiles[tileToMoveIndex].hitBox.Width, tiles[tileToMoveIndex].hitBox.Height);


            if (hitBox.Intersects(mouseRect) && checkValid(tiles[tileToMoveIndex].hitBox, newRect))
            {
 
                for (int i = 0; i < tiles.Count; i++)
                {
                    if (tiles[i].hitBox.Intersects(mouseRect) && i != tileToMoveIndex)
                    {
                        if (tiles[tileToMoveIndex].upgradeable)
                        {
                            Tile newTile = new Tile(tileToMove.tile);
                            newTile.load(content);
                            newTile.Position = tiles[i].Position;

                            tiles[i] = newTile;
                            tiles[i].downgrade(content);
                            bool downgrade = tiles[tileToMoveIndex].downgrade(content);

                            if (!downgrade)
                            {
                                tiles.RemoveAt(tileToMoveIndex);
                                added = true;
                                break;
                            }
                        }
                        else
                        {
                            tiles[tileToMoveIndex].Position = tiles[i].Position;
                            tiles.RemoveAt(i);
                            i--;
                            added = true;
                            break;
                        }
 
                    }
               }

                if (!added)
                {
                    if (tiles[tileToMoveIndex].upgradeable)
                    {

                        Tile newTile = new Tile(tileToMove.tile);
                        newTile.load(content);
                        newTile.Position = newPos;
                        newTile.downgrade(content);

                        bool downgrade = tiles[tileToMoveIndex].downgrade(content);
                        if (downgrade)
                        {
                            tiles.Add(newTile);
                        }
                        else
                        {
                            tiles[tileToMoveIndex].Position = newPos;
                        }
                            added = true;
                    }
                    else
                    {
                        tiles[tileToMoveIndex].Position = newPos;
                        added = true;
                    }
                }

            }


            return added;
        }

        public bool checkValid(Rectangle rect, Rectangle mouseRect)
        {
            bool valid = false;

            Rectangle north = new Rectangle(rect.X, rect.Y-rect.Height, rect.Width, rect.Height);
            Rectangle south = new Rectangle(rect.X, rect.Y+rect.Height, rect.Width, rect.Height);
            Rectangle east = new Rectangle(rect.X-rect.Width, rect.Y, rect.Width, rect.Height);
            Rectangle west = new Rectangle(rect.X+rect.Width, rect.Y, rect.Width, rect.Height);

                if (north.Intersects(mouseRect) ||
                    south.Intersects(mouseRect) ||
                    east.Intersects(mouseRect) ||
                    west.Intersects(mouseRect))
                {
                    valid = true;
                }

            return valid;
        }

        public void moveColumn(int col)
        {
            //Get column data
            Rectangle colRect = hitBoxes[col];
            List<Tile> toMove = tiles.FindAll(delegate(Tile temp) { return temp.hitBox.X == colRect.X; });

            foreach (Tile tile in toMove)
            {
                tile.move = true;
            }
        }

        public void SelectRandomCols()
        {
            selectedColumns.Clear();
            foreach (Warning warn in warnings)
            {
                warn.clear();
            }

            Random rnd = new Random();
            int numCols = rnd.Next(0, 11);

            if (numCols > 5 && numCols <= 9)
                numCols = 2;
            else if (numCols == 10)
                numCols = 3;
            else
                numCols = 1;

            int temp = 0;

            for (int i = 0; i < numCols; i++)
            {
                temp = rnd.Next(0, 3);
                while (selectedColumns.Contains(temp)) temp = rnd.Next(0, 3);
                selectedColumns.Add(temp);
                warnings[temp].toggle();
            }

        }

        public void MoveRandomCols()
        {
            foreach (int temp in selectedColumns)
            {
                moveColumn(temp);
            }
            SelectRandomCols();
        }

        public Vector2 calcGridPos(Rectangle hit)
        {
            //Old Vector Code!
            //pos.X -= (pos.X % gridHitBox.Width);
            //pos.Y -= (pos.Y % gridHitBox.Height);

            //Doing some quick snapping for the ludum dare.
            Vector2 loc = Vector2.Zero;

            foreach (Rectangle temp in hitBoxes)
            {
                Rectangle tempTotal;
                tempTotal = Rectangle.Intersect(temp, hit);
                if (tempTotal.Width == 1 && tempTotal.Height == 1)
                {
                    loc.X = temp.X;
                    loc.Y = temp.Y;
                    break;
                }
            }

            return loc;
        }

        public WorldInfo getInfo()
        {
            WorldInfo info = new WorldInfo();
            info.Population = 0;
            info.Nature = 0;
            info.Culture = 0;

            foreach (Tile temp in tiles)
            {
                if (temp.dead) continue;

                info.Population += temp.Population;
                info.Nature += temp.Nature;
                info.Culture += temp.Culture;
            }

            return info;
        }

        public void reset()
        {
            tiles.Clear();

        }

    }
}
