using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Mix.Tool.ModelEditor
{
    public partial class PreviewForm : Mix.Tool.Docking.DockContent
    {
        #region Private Enum

        /// <summary>
        /// コントロールモード
        /// </summary>
        private enum ControlMode
        {
            /// <summary>
            /// 無し
            /// </summary>
            None,

            /// <summary>
            /// ライト
            /// </summary>
            Light,

            /// <summary>
            /// カメラ
            /// </summary>
            Camera,

            /// <summary>
            /// ダイナミクス
            /// </summary>
            Dynamics,
        }

        #endregion

        #region Public Event

        /// <summary>
        /// メッシュ選択データクラス
        /// </summary>
        public class MeshSelectEventArgs : EventArgs
        {
            private uint key;

            internal MeshSelectEventArgs(uint _key)
            {
                this.key = _key;
            }

            /// <summary>
            /// 選択キーの取得
            /// </summary>
            public uint Key
            {
                get { return this.key; }
            }
        }
        /// <summary>
        /// メッシュステートイベントデータクラス
        /// </summary>
        public class MeshStateEventArgs : EventArgs
        {
            private bool visible;

            internal MeshStateEventArgs(bool _visible)
            {
                this.visible = _visible;
            }

            /// <summary>
            /// 表示の取得
            /// </summary>
            public bool Visible
            {
                get { return this.visible; }
            }
        }

        /// <summary>
        /// メッシュ選択イベントハンドラ
        /// </summary>
        /// <param name="sender">送信元オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        public delegate void MeshSelectEventHandler( object sender, MeshSelectEventArgs e );
        /// <summary>
        /// メッシュステートイベントハンドラ
        /// </summary>
        /// <param name="sender">送信元オブジェクト</param>
        /// <param name="e">イベントデータ</param>
        public delegate void MeshStateEventHandler(object sender, MeshStateEventArgs e);

        /// <summary>
        /// メッシュ選択イベント
        /// </summary>
        public event MeshSelectEventHandler MeshSelected = null;
        /// <summary>
        /// メッシュステート変更イベント
        /// </summary>
        public event MeshStateEventHandler MeshStateChanged = null;

        #endregion

        #region Private Member

        private Mix.Tool.Graphics.Scene scene = null;
        private Mix.Tool.Graphics.Camera camera = null;
        private Mix.Tool.Graphics.Model model = null;
        private Mix.Tool.Dynamics.World dynamicsWorld = null;
        private bool useDynamicsPicker = false;
        private Project.Preview preview = null;
        private Point preMouseLocation = new Point();
        private ControlMode ctrlMode = ControlMode.None;

        #endregion

        #region PreviewForm Method

        public PreviewForm( Mix.Tool.Graphics.Scene _scene,
                            Mix.Tool.Graphics.Model _model,
                            Mix.Tool.Dynamics.World _dynamicsWorld,
                            Project.Preview _preview)
        {
            InitializeComponent();

            ////////////////////////////////////////////////////////////////////////////////////////////////////
            // 初期化
            ////////////////////////////////////////////////////////////////////////////////////////////////////

            Mix.Tool.Graphics.Camera.DrawTypes dispFlags;

            this.scene = _scene;
            this.model = _model;
            this.dynamicsWorld = _dynamicsWorld;
            this.preview = _preview;

            this.camera = new Mix.Tool.Graphics.Camera(this.panel);
            this.scene.Cameras.Add(this.camera);
            this.preview.Camera = this.camera;

            this.useDynamicsPicker = this.model is Mix.Tool.Dynamics.Design.IBasicDocument;

            this.SetFillMode(this.preview.FillMode);

            dispFlags = this.preview.Display;
            this.tsbtDispGrid.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.Grid) == Mix.Tool.Graphics.Camera.DrawTypes.Grid;
            this.tsbtDispLight.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.Light) == Mix.Tool.Graphics.Camera.DrawTypes.Light;
            this.tsbtDispModel.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.Body) == Mix.Tool.Graphics.Camera.DrawTypes.Body;
            this.tsbtDispVV.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.ViewVolume) == Mix.Tool.Graphics.Camera.DrawTypes.ViewVolume;
            this.tsbtDispBone.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.Bone) == Mix.Tool.Graphics.Camera.DrawTypes.Bone;
            this.tsbtDispCollision.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.Collision) == Mix.Tool.Graphics.Camera.DrawTypes.Collision;
            this.tsbtDispJoint.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.Joint) == Mix.Tool.Graphics.Camera.DrawTypes.Joint;
            this.tsbtDispFPS.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.FramesPerSec) == Mix.Tool.Graphics.Camera.DrawTypes.FramesPerSec;
            this.tsbtDispPrimCount.Checked = (dispFlags & Mix.Tool.Graphics.Camera.DrawTypes.PrimitiveCount) == Mix.Tool.Graphics.Camera.DrawTypes.PrimitiveCount;

            this.tsbtInvisibleSelection.Checked = camera.InvisibleSelection;

            if (this.model is Mix.Tool.Graphics.ObjectModel)
            {
                Mix.Tool.Graphics.ObjectModel objModel = this.model as Mix.Tool.Graphics.ObjectModel;
                Mix.Tool.Graphics.RootTransformFlags rtFlags = objModel.RootTransform.Active;

                this.tsbtWorld_Stop.Enabled = true;
                this.tsbtWorld_Stand.Enabled = true;
                this.tsbtWorld_Ragdoll.Enabled = true;
                this.SetWorldMode(this.preview.WorldMode);

                this.tsbtResetPose.Enabled = true;
                this.tsbtJump.Enabled = true;

                this.tsbtRTRotation.Enabled = true;
                this.tsbtRTRotation.Checked = (rtFlags & Mix.Tool.Graphics.RootTransformFlags.Rotation) == Mix.Tool.Graphics.RootTransformFlags.Rotation;

                this.tsbtRTTranslation.Enabled = true;
                this.tsbtRTTranslation.Checked = (rtFlags & Mix.Tool.Graphics.RootTransformFlags.Translation) == Mix.Tool.Graphics.RootTransformFlags.Translation;

                this.tsbtDispBone.Enabled = true;
                this.tsbtDispJoint.Enabled = true;
            }
            else if (this.model is Mix.Tool.Graphics.MapModel)
            {
                this.tsbtWorld_Stop.Enabled = false;
                this.tsbtWorld_Stand.Enabled = false;
                this.tsbtWorld_Ragdoll.Enabled = false;

                this.tsbtResetPose.Enabled = false;
                this.tsbtJump.Enabled = false;

                this.tsbtRTRotation.Enabled = false;
                this.tsbtRTTranslation.Enabled = false;

                this.tsbtDispBone.Enabled = false;
                this.tsbtDispJoint.Enabled = false;
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////
            // イベントの設定
            ////////////////////////////////////////////////////////////////////////////////////////////////////

            //マウスホイール
            this.MouseWheel += new MouseEventHandler(this.PreviewForm_MouseWheel);
        }

        private void PreviewForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.camera != null)
            {
                this.preview.Flush();
                this.preview.Camera = null;

                this.scene.Cameras.Remove(this.camera);

                this.camera.Dispose();
                this.camera = null;
            }

            this.scene = null;
        }

        private void PreviewForm_MouseWheel(object sender, MouseEventArgs e)
        {
            if (this.ctrlMode == ControlMode.Camera)
            {
                this.camera.Distation((e.Delta < 0) ? 1 : -1);
            }
        }

        #endregion

        #region Panel Method

        private void panel_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
/*            switch (e.KeyCode)
            {
                case Keys.D:
                    this.ToggleFillMode();
                    break;

                case Keys.G:
                    this.tsbtDispGrid.Checked = !this.tsbtDispGrid.Checked;
                    break;
                case Keys.L:
                    this.tsbtDispLight.Checked = !this.tsbtDispLight.Checked;
                    break;
                case Keys.V:
                    this.tsbtDispVV.Checked = !this.tsbtDispVV.Checked;
                    break;
                case Keys.B:
                    this.tsbtDispBone.Checked = !this.tsbtDispBone.Checked;
                    break;

                case Keys.H:
                    this.ResetModelPose();
                    break;
                case Keys.R:
                    this.tsbtRTRotation.Checked = !this.tsbtRTRotation.Checked;
                    break;
                case Keys.T:
                    this.tsbtRTTranslation.Checked = !this.tsbtRTTranslation.Checked;
                    break;

                case Keys.E:
                    this.ToggleEditMode();
                    break;

                case Keys.M:
                    this.NotifyMeshStateChanged(false);
                    break;
            }
*/        }

        private void panel_MouseDown(object sender, MouseEventArgs e)
        {
            this.preMouseLocation.X = e.X;
            this.preMouseLocation.Y = e.Y;

            this.ctrlMode = ControlMode.None;

            if (e.Button == MouseButtons.Left)
            {
                if (Control.ModifierKeys == Keys.Control)
                {
                    //ライトの操作を開始
                    this.ctrlMode = ControlMode.Light;
                }
                else if (Control.ModifierKeys == Keys.None)
                {
                    if (this.useDynamicsPicker == true)
                    {
                        //ダイナミクスの操作を開始
                        Mix.Tool.Math.Vector fromWorldPos = this.camera.Unproject(new Mix.Tool.Math.Vector(e.X, e.Y, 0.0f));
                        Mix.Tool.Math.Vector toWorldPos = this.camera.Unproject(new Mix.Tool.Math.Vector(e.X, e.Y, 1.0f));

                        this.dynamicsWorld.Picker.Catch(this.camera.Position, fromWorldPos, toWorldPos);
                        this.ctrlMode = ControlMode.Dynamics;
                    }
                }
            }
            else if (e.Button == MouseButtons.Middle)
            {
                //カメラの操作を開始
                this.ctrlMode = ControlMode.Camera;
            }
            else if (e.Button == MouseButtons.Right)
            {
                if (this.MeshSelected != null)
                {
                    //メッシュの選択
                    uint selectKey = this.camera.SelectDrawObjectMesh(this.preMouseLocation);
                    this.MeshSelected(this, new MeshSelectEventArgs(selectKey));
                }
            }
        }

        private void panel_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.ctrlMode == ControlMode.Dynamics)
                {
                    if (this.useDynamicsPicker == true)
                    {
                        this.dynamicsWorld.Picker.Release();
                    }
                }
            }
        }

        private void panel_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.ctrlMode == ControlMode.Light)
                {
                    //ライトの回転
                    int h = e.X - this.preMouseLocation.X;
                    int v = e.Y - this.preMouseLocation.Y;

                    this.camera.RotationLight(h, v);
                }
                else if (this.ctrlMode == ControlMode.Dynamics)
                {
                    if (this.useDynamicsPicker == true)
                    {
                        //ダイナミクスワールドのピック処理
                        Mix.Tool.Math.Vector toWorldPos = this.camera.Unproject(new Mix.Tool.Math.Vector(e.X, e.Y, 1.0f));

                        this.dynamicsWorld.Picker.Update(this.camera.Position, toWorldPos);
                    }
                }
            }
            else if (e.Button == MouseButtons.Middle)
            {
                if (this.ctrlMode == ControlMode.Camera)
                {
                    int h = e.X - this.preMouseLocation.X;
                    int v = e.Y - this.preMouseLocation.Y;

                    switch (Control.ModifierKeys)
                    {
                        case Keys.Control:
                            this.camera.Distation(v);
                            break;
                        case Keys.Shift:
                            this.camera.Translation(h, v);
                            break;
                        default:
                            this.camera.Rotation(h, v);
                            break;
                    }
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                //無し
            }

            this.preMouseLocation.X = e.X;
            this.preMouseLocation.Y = e.Y;
        }

        #endregion

        #region ToolStrip Method

        private void tsbtResetPose_Click(object sender, EventArgs e)
        {
            this.ResetPose();
        }

        private void tsbtWorld_Stop_Click(object sender, EventArgs e)
        {
            this.SetWorldMode(Project.Preview.WorldModes.Stop);
        }

        private void tsbtWorld_Stand_Click(object sender, EventArgs e)
        {
            this.SetWorldMode(Project.Preview.WorldModes.Stand);
        }

        private void tsbtWorld_Ragdoll_Click(object sender, EventArgs e)
        {
            this.SetWorldMode(Project.Preview.WorldModes.Ragdoll);
        }

        private void tsbtJump_Click(object sender, EventArgs e)
        {
            this.Jump();
        }

        private void tsbtRTRotation_CheckedChanged(object sender, EventArgs e)
        {
            this.SetRootTransformFlags();
        }

        private void tsbtRTTranslation_CheckedChanged(object sender, EventArgs e)
        {
            this.SetRootTransformFlags();
        }

        private void tsbtDispGrid_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.Grid, this.tsbtDispGrid.Checked);
        }

        private void tsbtDispLight_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.Light, this.tsbtDispLight.Checked);
        }

        private void tsbtDispModel_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.Body, this.tsbtDispModel.Checked);
        }

        private void tsbtDispVV_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.ViewVolume, this.tsbtDispVV.Checked);
        }

        private void tsbtDispBone_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.Bone, this.tsbtDispBone.Checked);
        }

        private void tsbtDispCollision_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.Collision, this.tsbtDispCollision.Checked);
        }

        private void tsbtDispJoint_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.Joint, this.tsbtDispJoint.Checked);
        }

        private void tsbtDispFPS_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.FramesPerSec, this.tsbtDispFPS.Checked);
        }

        private void tsbtDispPrimCount_CheckedChanged(object sender, EventArgs e)
        {
            this.SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes.PrimitiveCount, this.tsbtDispPrimCount.Checked);
        }

        private void tsbtInvisibleSelection_CheckedChanged(object sender, EventArgs e)
        {
            ToolStripButton tsbt = sender as ToolStripButton;

            this.camera.InvisibleSelection = tsbt.Checked;
        }

        private void tsbtSolid_Click(object sender, EventArgs e)
        {
            this.SetFillMode(Mix.Tool.Graphics.Camera.FillModes.Solid);
        }

        private void tsbtWireframe_Click(object sender, EventArgs e)
        {
            this.SetFillMode(Mix.Tool.Graphics.Camera.FillModes.Wireframe);
        }

        private void tsmiCamResetR_Click(object sender, EventArgs e)
        {
            this.camera.ResetRotation();
        }

        private void tsmiCamResetT_Click(object sender, EventArgs e)
        {
            this.camera.ResetTranslation();
        }

        private void tsmiCamResetD_Click(object sender, EventArgs e)
        {
            this.camera.ResetDistation();
        }

        #endregion

        #region Misc Method

        private void NotifyMeshStateChanged(bool visible)
        {
            if (this.MeshStateChanged != null)
            {
                this.MeshStateChanged(this, new MeshStateEventArgs(visible));
            }
        }

        private void SetFillMode(Mix.Tool.Graphics.Camera.FillModes mode)
        {
            switch (mode)
            {
                case Mix.Tool.Graphics.Camera.FillModes.Solid:
                    this.tsbtSolid.Checked = true;
                    this.tsbtWireframe.Checked = false;
                    break;
                case Mix.Tool.Graphics.Camera.FillModes.Wireframe:
                    this.tsbtSolid.Checked = false;
                    this.tsbtWireframe.Checked = true;
                    break;
            }

            this.camera.FillMode = mode;
        }

        private void ToggleFillMode()
        {
            switch (this.camera.FillMode)
            {
                case Mix.Tool.Graphics.Camera.FillModes.Solid:
                    this.SetFillMode(Mix.Tool.Graphics.Camera.FillModes.Wireframe);
                    break;
                case Mix.Tool.Graphics.Camera.FillModes.Wireframe:
                    this.SetFillMode(Mix.Tool.Graphics.Camera.FillModes.Solid);
                    break;
            }
        }

        private void SetDisplayEnabled(Mix.Tool.Graphics.Camera.DrawTypes type, bool enabled)
        {
            Mix.Tool.Graphics.Camera.DrawTypes types = this.camera.DrawType;

            if (enabled == true)
            {
                if ((types & type) != type)
                {
                    types |= type;
                }
            }
            else
            {
                if ((types & type) == type)
                {
                    types ^= type;
                }
            }

            this.camera.DrawType = types;
        }

        private void SetWorldMode(Project.Preview.WorldModes mode)
        {
            switch (mode)
            {
                case Project.Preview.WorldModes.Stop:
                    this.tsbtWorld_Stop.Checked = true;
                    this.tsbtWorld_Stand.Checked = false;
                    this.tsbtWorld_Ragdoll.Checked = false;
                    break;
                case Project.Preview.WorldModes.Stand:
                    this.tsbtWorld_Stop.Checked = false;
                    this.tsbtWorld_Stand.Checked = true;
                    this.tsbtWorld_Ragdoll.Checked = false;
                    break;
                case Project.Preview.WorldModes.Ragdoll:
                    this.tsbtWorld_Stop.Checked = false;
                    this.tsbtWorld_Stand.Checked = false;
                    this.tsbtWorld_Ragdoll.Checked = true;
                    break;
            }

            if (this.model is Mix.Tool.Dynamics.Design.IBasicDocument)
            {
                Mix.Tool.Dynamics.Design.IBasicDocument dynDoc = this.model as Mix.Tool.Dynamics.Design.IBasicDocument;
                Mix.Tool.Dynamics.Design.Actor dynActor = dynDoc.DynamicsDesigner as Mix.Tool.Dynamics.Design.Actor;

                switch (mode)
                {
                    case Project.Preview.WorldModes.Stop:
                        dynActor.SimulationMode = Mix.Tool.Dynamics.Design.SimulationMode.Stop;
                        break;
                    case Project.Preview.WorldModes.Stand:
                        dynActor.SimulationMode = Mix.Tool.Dynamics.Design.SimulationMode.Stand;
                        break;
                    case Project.Preview.WorldModes.Ragdoll:
                        dynActor.SimulationMode = Mix.Tool.Dynamics.Design.SimulationMode.Ragdoll;
                        break;
                }
            }
            else if (this.model is Mix.Tool.Dynamics.Design.ITerrainDocument)
            {
                Mix.Tool.Dynamics.Design.ITerrainDocument dynDoc = this.model as Mix.Tool.Dynamics.Design.ITerrainDocument;

                switch (mode)
                {
                    case Project.Preview.WorldModes.Stop:
                        break;
                    case Project.Preview.WorldModes.Stand:
                    case Project.Preview.WorldModes.Ragdoll:
                        break;
                }
            }

            this.preview.WorldMode = mode;
        }

        private void ResetPose()
        {
            if ((this.model != null) &&
                (this.model is Mix.Tool.Graphics.ObjectModel))
            {
                Mix.Tool.Graphics.ObjectModel objModel = this.model as Mix.Tool.Graphics.ObjectModel;

                objModel.ResetPose();
            }
        }

        private void Jump()
        {
            if ((this.model != null) &&
                (this.model is Mix.Tool.Graphics.ObjectModel))
            {
                Mix.Tool.Graphics.ObjectModel objModel = this.model as Mix.Tool.Graphics.ObjectModel;

                objModel.Jump();
            }
        }

        private void SetRootTransformFlags()
        {
            if (this.model is Mix.Tool.Graphics.ObjectModel)
            {
                Mix.Tool.Graphics.ObjectModel objModel = this.model as Mix.Tool.Graphics.ObjectModel;
                Mix.Tool.Graphics.RootTransformFlags flags = Mix.Tool.Graphics.RootTransformFlags.Init;

                if (this.tsbtRTRotation.Checked == true)
                {
                    flags |= Mix.Tool.Graphics.RootTransformFlags.Rotation;
                    this.tsbtRTRotation.Image = Properties.Resources.Model_RTRotation;
                }
                else
                {
                    this.tsbtRTRotation.Image = Properties.Resources.Model_RTRotation_Invalid;
                }

                if (this.tsbtRTTranslation.Checked == true)
                {
                    flags |= Mix.Tool.Graphics.RootTransformFlags.Translation;
                    this.tsbtRTTranslation.Image = Properties.Resources.Model_RTTranslation;
                }
                else
                {
                    this.tsbtRTTranslation.Image = Properties.Resources.Model_RTTranslation_Invalid;
                }

                objModel.RootTransform.Active = flags;
            }
        }

        #endregion
    }
}
