using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace AdvancedXNAGamesWP
{
	/// <summary>
	/// This is the main type for your game
	/// </summary>
	public class Game1 : Microsoft.Xna.Framework.Game
	{
		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;
		private Camera _camera;
		private Model _model;
		private Matrix _world = Matrix.Identity;
		private float _scale;
		private Vector3 _rotation;
		private Texture2D _background;

		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);

			graphics.PreferredBackBufferWidth = 480;
			graphics.PreferredBackBufferHeight = 800;

			Content.RootDirectory = "Content";

			// Frame rate is 30 fps by default for Windows Phone.
			TargetElapsedTime = TimeSpan.FromTicks(333333);

			// Extend battery life under lock.
			InactiveSleepTime = TimeSpan.FromSeconds(1);

			graphics.SupportedOrientations = DisplayOrientation.Portrait;
			graphics.IsFullScreen = true;
		}

		/// <summary>
		/// Allows the game to perform any initialization it needs to before starting to run.
		/// This is where it can query for any required services and load any non-graphic
		/// related content.  Calling base.Initialize will enumerate through any components
		/// and initialize them as well.
		/// </summary>
		protected override void Initialize()
		{
			_camera = new Camera(MathHelper.PiOver4, (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height, 1, 1000);
			_camera.ViewPosition = new Vector3(0, 0, 500);
			_camera.LookAt = Vector3.Zero;

			base.Initialize();
		}

		/// <summary>
		/// LoadContent will be called once per game and is the place to load
		/// all of your content.
		/// </summary>
		protected override void LoadContent()
		{
			// Create a new SpriteBatch, which can be used to draw textures.
			spriteBatch = new SpriteBatch(GraphicsDevice);

			_model = Content.Load<Model>("alienship");
			_background = Content.Load<Texture2D>("vegasbg");
			AudioManager.Load(Content);

			AudioManager.StartTheme();
		}

		/// <summary>
		/// UnloadContent will be called once per game and is the place to unload
		/// all content.
		/// </summary>
		protected override void UnloadContent()
		{
			// TODO: Unload any non ContentManager content here
		}

		/// <summary>
		/// Allows the game to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Update(GameTime gameTime)
		{
			// Allows the game to exit
			if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
				this.Exit();

			InputManager.Update();

			_world = Matrix.CreateFromYawPitchRoll(_rotation.X, _rotation.Y, _rotation.Z) * Matrix.CreateScale(_scale);
			_scale = 1.0f;

			if(InputManager.ControlState.Left)
				_rotation.X += 0.1f;
			if(InputManager.ControlState.Right)
				_rotation.X -= 0.1f;

			if(InputManager.ControlState.Up)
				_rotation.Y += 0.1f;
			if(InputManager.ControlState.Down)
				_rotation.Y -= 0.1f;

			base.Update(gameTime);
		}

		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Draw(GameTime gameTime)
		{
			// Uncomment to mess around with cull mode/fill mode
			//RasterizerState state = new RasterizerState();
			//state.CullMode = CullMode.CullCounterClockwiseFace;
			//state.FillMode = FillMode.WireFrame;
			//GraphicsDevice.RasterizerState = state;

			GraphicsDevice.Clear(Color.CornflowerBlue);

			// Uncomment to mess around with 2D + 3D and render states
			//spriteBatch.Begin();
			//spriteBatch.Draw(_background, Vector2.Zero, Color.White);
			//spriteBatch.End();

			//GraphicsDevice.BlendState = BlendState.Opaque;
			//GraphicsDevice.DepthStencilState = DepthStencilState.Default;

			Matrix[] transforms = new Matrix[_model.Bones.Count];
			_model.CopyAbsoluteBoneTransformsTo(transforms);

			foreach(ModelMesh mesh in _model.Meshes)
			{
				foreach(BasicEffect effect in mesh.Effects)
				{
					effect.EnableDefaultLighting();

					// Uncomment to mess around with lighting effects provided by BasicEffect
					//effect.LightingEnabled = true;
					//effect.DirectionalLight0.DiffuseColor = new Vector3(1, 0, 0);
					//effect.DirectionalLight0.Direction = new Vector3(1, 0, 0);
					//effect.DirectionalLight0.SpecularColor = new Vector3(0, 1, 0);
					//effect.DirectionalLight0.Enabled = true;
					//effect.EmissiveColor = new Vector3(1, 0, 0);
					
					effect.World = _world * transforms[mesh.ParentBone.Index];
					effect.View = _camera.View;
					effect.Projection = _camera.Projection;
				}

				mesh.Draw();
			}

			base.Draw(gameTime);
		}
	}
}
