using System;
using System.Collections.Generic;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Drawing;
using System.Windows.Forms;

namespace Bil_LD
{
    public class GameEngine
    {
        public List<IRenderable> _RenderableItems = new List<IRenderable>();
        public GameObject SelectedObject = null;

        public Ground ground;

        private Form _Screen;
        private Device _Device;

        private int _LastTickCount = 1;
        private int _Frames = 0;
        private float _LastFrameRate = 0;

        public GameObject CurrentObject = null;

        public Vector3 Camera_Position = new Vector3(0, 30, 0);

        public Device gameDevice
        {
            get { return _Device; }
        }

        public GameEngine()
        {
            Settings.Reset();
            Console.WriteLine("Path: " + Settings.GetSingleton().MediaPath);
        }

        public void Run()
        {
            _Screen = new FormLD(this);
            _Screen.Load += new EventHandler(Load);
            _Screen.FormClosing += new FormClosingEventHandler(Shutdown);

            Application.Run(_Screen);
        }



        private bool InitializeGraphics()
        {
            PresentParameters pp = new PresentParameters();
            pp.SwapEffect = SwapEffect.Discard;
            pp.Windowed = true;

            pp.EnableAutoDepthStencil = true;
            pp.AutoDepthStencilFormat = DepthFormat.D16;

            try
            {
                _Device = new Device(0, DeviceType.Hardware, ((FormLD)_Screen).TopView.Handle, CreateFlags.SoftwareVertexProcessing, pp);
            }
            catch (DirectXException)
            {
                return false;
            }

            #region Quality setup
            // Try to set up a texture minify filter, pick anisotropic first
            if (_Device.DeviceCaps.TextureFilterCaps.SupportsMinifyAnisotropic)
            {
                _Device.SamplerState[0].MinFilter = TextureFilter.Anisotropic;
            }
            else if (_Device.DeviceCaps.TextureFilterCaps.SupportsMinifyLinear)
            {
                _Device.SamplerState[0].MinFilter = TextureFilter.Linear;
            }
            // Do the same thing for magnify filter
            if (_Device.DeviceCaps.TextureFilterCaps.SupportsMagnifyAnisotropic)
            {
                _Device.SamplerState[0].MagFilter = TextureFilter.Anisotropic;
            }
            else if (_Device.DeviceCaps.TextureFilterCaps.SupportsMagnifyLinear)
            {
                _Device.SamplerState[0].MagFilter = TextureFilter.Linear;
            }
            #endregion


            return true;
        }

        public void Load(object sender, EventArgs e)
        {
            if (InitializeGraphics())
            {
                _Device.DeviceLost += new EventHandler(OnDeviceLost);
            }

            ground = new Ground(_Device);

        }

        public void Setup()
        {
            _Device.Transform.World = Matrix.Identity;

            Vector3 cam_target = new Vector3(Camera_Position.X, 0, Camera_Position.Z);

            _Device.Transform.View = Matrix.LookAtLH(
                Camera_Position,
                cam_target,
                new Vector3(0, 0, 1));            

            //_Device.Transform.Projection = Matrix.OrthoRH(400f, 400f, 0.0f, 1000.0f);
            _Device.Transform.Projection = Matrix.PerspectiveFovLH((float)(Math.PI / 4.0f),
                1.0f, 0.0f, 1000.0f);

            _Device.RenderState.CullMode = Cull.None;
            _Device.RenderState.ZBufferEnable = true;
            _Device.RenderState.ZBufferWriteEnable = true;

            #region Lightning
            _Device.RenderState.Lighting = true;
            _Device.RenderState.Ambient = Color.Gray;

            _Device.Lights[0].Type = LightType.Directional;
            _Device.Lights[0].Direction = new Vector3(10, 10, 0);
            _Device.Lights[0].Diffuse = Color.White;
            _Device.Lights[0].Enabled = true;
            #endregion
        }

        public void Render(ViewControl.ViewTypes viewtype)
        {
            Setup();

            _Device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.LightBlue, 1.0f, 0);
            _Device.BeginScene();

            ground.Render();

            foreach (IRenderable item in _RenderableItems)
            {
                item.Render(_Device);
            }

            UpdateFramerate();

            _Device.EndScene();
            _Device.Present();
        }

        private void UpdateFramerate()
        {
            _Frames++;
            if (Math.Abs(Environment.TickCount - _LastTickCount) > 1000)
            {
                _LastFrameRate = (float)_Frames * 1000 / Math.Abs(Environment.TickCount - _LastTickCount);
                _LastTickCount = Environment.TickCount;
                _Frames = 0;
            }
            _Screen.Text = "Level Designer - " + string.Format("Framerate : {0:0.00} fps", _LastFrameRate);
        }

        public void OnDeviceLost(object obj, EventArgs e)
        {
            Settings.SaveSettings();
        }

        public void Shutdown(object sender, FormClosingEventArgs e)
        {
            _Device.Dispose();
        }
    }
}
