using System.Windows.Forms;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.Samples.DirectX.UtilityToolkit;

namespace DXGfxLib
{
    /// <summary>
    /// This class knows how to handle user inputs in a point and click scenario.
    /// 
    /// Click indicates to the avatar where to go.
    /// Click on objects will:
    /// Call the click on the object.
    /// Instruct the avatar to go near the object (up to the point where they collide!).
    /// Instruct the avatar to interact with the object !
    /// </summary>
    public class PointAndClickHandler : IInputHandler
    {
        private Avatar currentAvatar = null;

        private bool ready = false;

        public Avatar CurrentAvatar
        {
            get { return currentAvatar; }
            set { currentAvatar = value; ready = true; }
        }

        public PointAndClickHandler()
        {
        }

        public void Dispose()
        {
        }

        public virtual void OnKeyPress(KeyEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnKeyDown(KeyEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnKeyUp(KeyEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnMouseMove(MouseEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnMouseDown(MouseEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnMouseUp(MouseEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnMouseWheel(MouseEventArgs e)
        {
            if (!ready)
                return;
        }

        public virtual void OnMouseClick(MouseEventArgs e)
        {
            if (!ready)
                return;

            Vector2 point = new Vector2(e.X, e.Y);

            Vector3 rayO; Vector3 rayD;
            MathUtil.RayFromScreenPos(DXGfxManager.GetGlobalInstance().frameworkInUse.Device.Viewport, DXGfxManager.GetGlobalInstance().CurrentCamera.ProjectionMatrix, Matrix.Multiply(DXGfxManager.GetGlobalInstance().CurrentCamera.WorldMatrix, DXGfxManager.GetGlobalInstance().CurrentCamera.ViewMatrix), point, out rayO, out rayD);
            List<SceneObject> theList = new List<SceneObject>();

            if (DXGfxManager.GetGlobalInstance().GetScene().Intersect(rayO, rayD, ref theList))
            {
                foreach (SceneObject obj in theList)
                {
                    obj.HasBeenClicked = true;
                }
            }
            
            if (currentAvatar != null)
            {
                Vector3 dest = DXGfxManager.GetGlobalInstance().GetScene().PickEnvironmentPosition(DXGfxManager.GetGlobalInstance().frameworkInUse.Device.Viewport, DXGfxManager.GetGlobalInstance().CurrentCamera.ProjectionMatrix, Matrix.Multiply(DXGfxManager.GetGlobalInstance().CurrentCamera.WorldMatrix, DXGfxManager.GetGlobalInstance().CurrentCamera.ViewMatrix), point);
                currentAvatar.MoveTo(dest);
            }
        }

        public virtual void OnMouseDoubleClick(MouseEventArgs e)
        {
            if (!ready)
                return;

            Vector2 point = new Vector2(e.X, e.Y);

            Viewport viewport = DXGfxManager.GetGlobalInstance().frameworkInUse.Device.Viewport;
            viewport.Width = DXGfxManager.GetGlobalInstance().width;
            viewport.Height = DXGfxManager.GetGlobalInstance().height;

            Vector3 rayO; Vector3 rayD;
            MathUtil.RayFromScreenPos(viewport, DXGfxManager.GetGlobalInstance().CurrentCamera.ProjectionMatrix, DXGfxManager.GetGlobalInstance().CurrentCamera.ViewMatrix, point, out rayO, out rayD);
            List<SceneObject> theList = new List<SceneObject>();

            if (DXGfxManager.GetGlobalInstance().GetScene().Intersect(rayO, rayD, ref theList))
            {
                foreach (SceneObject obj in theList)
                {
                    obj.HasBeenClicked = true;
                }
            }

            if (currentAvatar != null)
            {
                Vector3 dest = DXGfxManager.GetGlobalInstance().GetScene().PickEnvironmentPosition(viewport, DXGfxManager.GetGlobalInstance().CurrentCamera.ProjectionMatrix, DXGfxManager.GetGlobalInstance().CurrentCamera.ViewMatrix, point);
                currentAvatar.MoveTo(dest);
            }
        }

        public virtual void WndProc(ref Message m)
        {
            if (!ready)
                return;
        }

        public bool HandleMessages(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            DXGfxManager.GetGlobalInstance().CurrentCamera.HandleMessages(hWnd, msg, wParam, lParam);
            return true;
        }

        public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            DXGfxManager.GetGlobalInstance().CurrentCamera.HandleMessages(hWnd, msg, wParam, lParam);
            return IntPtr.Zero;
        }

        public void FrameMove(float elapsedTime)
        {
            // Update the camera's position based on user input 
            if (DXGfxManager.GetGlobalInstance().CurrentAvatar != null)
            {
                DXGfxManager.GetGlobalInstance().CurrentAvatar.FrameMove(elapsedTime);
                DXGfxManager.GetGlobalInstance().CurrentCamera.FrameMove(elapsedTime);
            }
        }
    }
}
