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

namespace FredriksdalAssault2
{
    /// <summary>
    /// This class represent the Hills map, the second map for this game.
    /// </summary>
    public class Hills : IMap
    {
        #region Instance variables

        // Lists of resources
        List<CubePrimitive> cubeBarackList;
        List<CubePrimitive> cubeBaseHouseList;
        List<CubePrimitive> cubeCrossWallList;

        // Stone texture
        Texture2D stoneTexture;

        #endregion

        #region Constructors

        /// <summary>
        /// Create a new Hills map.
        /// </summary>
        /// <param name="content"></param>
        /// <param name="graphicsDevice"></param>
        public Hills(ContentManager content, GraphicsDevice graphicsDevice)
            : base (content, graphicsDevice, Vector3.Zero)
        {

            // Set the number of barrels
            this.numberOfBarrels = 4;

            // Create new lists (arrays)
            this.buildings = new List<Building>(100);
            this.numberOfBuildings = 8;
            this.items = new Item[numberOfBarrels];
            this.grass = new List<Vegetation>(400);

            // Load content
            LoadContent();

        }

        /// <summary>
        /// A helper method to load the graphical content for this map.
        /// </summary>
        private void LoadContent()
        {
            // Load models.
            this.mapModel = content.Load<Model>("Maps/Hills/hillsHeightMap");
            this.sky = content.Load<Sky>("Maps/CommonResources/sky");
            this.water = new Water(content, this.graphicsDevice, new Vector3(0,-3190,0));
            this.barrelModel = content.Load<Model>("Models/Barrels/Barrel");
            this.treeModel = content.Load<Model>("Models/Trees/Oak_Bald_05");
            this.grassModel = content.Load<Model>("Models/Grass/grass_v1");

            // The terrain processor attached a HeightMapInfo to the terrain model's Tag. 
            this.heightMapInfo = mapModel.Tag as HeightMapInfo;

            if (this.heightMapInfo == null)
            {
                string message = "The terrain model did not have a HeightMapInfo " +
                    "object attached. Are you sure you are using the " +
                    "TerrainProcessor?";
                throw new InvalidOperationException(message);
            }

            // Create the vegetation map.
            this.vegetationMap = content.Load<Texture2D>("Maps/Hills/hillsVegetationMap");

            // Load the height data array with data.
            this.LoadVegetationHeights();

            // Load HLSL effect files.
            this.graphicEffect = content.Load<Effect>("Effects/TerrainEffect");

            // Load textures.
            this.roadTexture = content.Load<Texture2D>("Textures/dirtRoad");
            this.sandTexture = content.Load<Texture2D>("Textures/sandRefraction");
            this.grassTexture = content.Load<Texture2D>("Textures/rock");
            this.rockTexture = content.Load<Texture2D>("Textures/rock-yellow");
            this.floorTexture = content.Load<Texture2D>("Models/House/cementFloor");
            this.wallTexture = content.Load<Texture2D>("Models/House/wall");
            this.roofTexture = content.Load<Texture2D>("Models/House/roof");
            this.stoneTexture = content.Load<Texture2D>("Textures/stone-wall");

            // Load the minimap
            this.minimap = content.Load<Texture2D>("Maps/Hills/hillsMinimap");

            // Add some baracks.
            buildings.Add(new Barack(new Vector3(-600, -1890, 2000), new Vector3(0, 0, 0), 1f));
            buildings.Add(new Barack(new Vector3(-2900, -1780, 3000), new Vector3(0, 0, 0), 1f));
            buildings.Add(new Barack(new Vector3(2500, -1820, 3000), new Vector3(0, 0, 0), 1f));

            // Add a base house
            buildings.Add(new BaseHouse(new Vector3(0, -1780, 4700), new Vector3(0, 0, 0), 1f));

            // Add some walls
            float height = 0;
            this.heightMapInfo.GetHeight(new Vector3(-3400, 0, -900), out height);
            buildings.Add(new CrossWalls(new Vector3(-3400, height - 5, -900), new Vector3(0, 0, 0), 1f));
            this.heightMapInfo.GetHeight(new Vector3(-3100, 0, 600), out height);
            buildings.Add(new CrossWalls(new Vector3(-3100, height - 5, 600), new Vector3(0, 0, 0), 1f));
            this.heightMapInfo.GetHeight(new Vector3(3400, 0, -1300), out height);
            buildings.Add(new CrossWalls(new Vector3(3400, height - 5, -1300), new Vector3(0, 0, 0), 1f));
            this.heightMapInfo.GetHeight(new Vector3(2900, 0, 200), out height);
            buildings.Add(new CrossWalls(new Vector3(2900, height - 5, 200), new Vector3(0, 0, 0), 1f));
 
            // Add vegetation
            this.AddVegetation();

            // Add four barrels if the game mode is Assault.
            if (Program.gameMode == 0)
            {
                items[0] = new Barrel(new Vector3(-600, -1890, 2000), new Vector3(0, 0, 0), 35f);
                items[1] = new Barrel(new Vector3(-2900, -1780, 3000), new Vector3(0, 0, 0), 35f);
                items[2] = new Barrel(new Vector3(2500, -1820, 3000), new Vector3(0, 0, 0), 35f);
                items[3] = new Barrel(new Vector3(0, -1780, 4700), new Vector3(0, 0, 0), 35f);
            }

            // Load the cubeBarackList with cubes for a barack.
            this.cubeBarackList = Barack.CreateCubes(this.graphicsDevice);

            // Load the baseHouseList with cubes for a base house.
            this.cubeBaseHouseList = BaseHouse.CreateCubes(this.graphicsDevice);

            // Load cross walls
            this.cubeCrossWallList = CrossWalls.CreateCubes(this.graphicsDevice);

        } // End of the LoadContent method.

        #endregion

        #region Methods

        /// <summary>
        /// Update the Hills map.
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            // Update the water.
            this.water.Update(gameTime);

        } // End of the update method

        /// <summary>
        /// Draw the Hills map.
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="view"></param>
        /// <param name="projection"></param>
        /// <param name="viewProj"></param>
        /// <param name="cameraPosition"></param>
        public override void Draw(GameTime gameTime, Matrix view, Matrix projection, Matrix viewProj, Vector3 cameraPosition)
        {
            
            // Draw the terrain first, then the sky.
            this.DrawTerrain(view, projection);

            // Draw buildings.
            this.DrawBuildings(view, projection);

            // Draw water (Must draw this last)
            this.water.Draw(gameTime, cameraPosition, viewProj);

            // Draw the sky last
            this.sky.Draw(view, projection);

            // Draw barrels if the game mode is Assault.
            if (Program.gameMode == 0)
                this.DrawItems(view, projection);


        } // End of the Draw method

        /// <summary>
        /// Helper to draw primitive boxes for a house.
        /// </summary>
        /// <param name="view"></param>
        /// <param name="projection"></param>
        private void DrawBuildings(Matrix view, Matrix projection)
        {

            // Loop through each cube in the cubeBarackList.
            for (int i = 0; i < cubeBarackList.Count; i++)
            {

                if (i == 0)
                    cubeBarackList[i].DrawTextureVerts(buildings, "Barack", 4, view, projection, this.floorTexture);
                else
                    cubeBarackList[i].DrawTextureVerts(buildings, "Barack", 4, view, projection, this.wallTexture);

            }

            // Loop through each cube in the cubeBaseHouseList.
            for (int i = 0; i < cubeBaseHouseList.Count; i++)
            {

                if (i < 6)
                    cubeBaseHouseList[i].DrawTextureVerts(buildings, "BaseHouse", 4, view, projection, this.floorTexture);
                else if (i == 6)
                    cubeBaseHouseList[i].DrawTextureVerts(buildings, "BaseHouse", 4,  view, projection, this.roofTexture);
                else
                    cubeBaseHouseList[i].DrawTextureVerts(buildings, "BaseHouse", 4, view, projection, this.wallTexture);

            }

            // Draw cross walls
            for (int i = 0; i < cubeCrossWallList.Count; i++)
            {
                cubeCrossWallList[i].DrawTextureVerts(buildings, "CrossWalls", 8, view, projection, this.stoneTexture);
            }

        } // End of the DrawBuildings method

        #endregion

    } // End of class

} // End of namespace
