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;
using VisimBox;
using VisimBox.Renderer;
using VisimBox.Scene;
using VisiMath;
using VisiMath.Geometry;

namespace VisimBuilder
{
    public partial class MainBuilderForm : Form
    {
        #region properties

        public class MainSettings
        {
            /// <summary>
            /// Perform collision check when moving rigid body?
            /// </summary>
            public bool RigidBodyColCheck { get; set; }
            /// <summary>
            /// Actualize Static collision on each change? (if false, user has to use Recalculate static collision command)
            /// </summary>
            public bool StaticColUpdate { get; set; }

            public MainSettings()
            {
                RigidBodyColCheck = true;
                StaticColUpdate = true;
            }
        }

        protected MainSettings _settings = new MainSettings();

        /// <summary>
        /// Main settings of the editor
        /// </summary>
        public MainSettings Settings
        {
            get
            {
                return _settings;
            }
        }

        MaterialEditor matedit = null;
        SceneBrowserDialog SceneBrowserDLG = null;

        /// <summary>
        /// was scene changed by user manipulation?
        /// </summary>
        public bool SceneChanged
        {
            get;
            set;
        }


        protected bool _StaticCollisionInvalid = false;

        /// <summary>
        /// If set to true, static collisions are invalid and need to be recalculated
        /// </summary>
        public bool StaticCollisionInvalid
        {
            get { return _StaticCollisionInvalid; }
            set 
            {
                _StaticCollisionInvalid = value;
                recalculateStaticCollisionsToolStripMenuItem.Enabled = value;
            }
        }
        
        VisimBox.Renderer.IRenderWindow RenWin;
        Gizmo CurrentGizmo;
        MoveGizmo MoveG;
        RotateGizmo RotateG;
        ScaleGizmo ScaleG;
        Gizmos.EditingGrid EditGrid;

        int mousex, mousey;
        float movementspeed = 0.5f;

        Ray PickingRay = new Ray();

        protected Node _selectedNode;

        public Node SelectedNode
        {
            get
            {
                return _selectedNode;
            }

            set
            {
                if (_selectedNode == value)
                    return;

                if (value != null)
                {
                    VisimBox.Console.WriteLine("Selecting node " + value.Name);
                    toolStripDropDownButtonDelete.Enabled = true;
                    toolStripDropDownButtonLink.Enabled = true;
                    toolStripDropDownButtonCopy.Enabled = true;
                }
                else
                {
                    VisimBox.Console.WriteLine("Deselecting node.");
                    toolStripDropDownButtonDelete.Enabled = false;
                    toolStripDropDownButtonLink.Enabled = false;
                    toolStripDropDownButtonCopy.Enabled = false;
                }

                RenderableNode rennode = _selectedNode as RenderableNode;
                if (rennode != null)
                {
                    rennode.RenderBoundObject = false;
                }                
                objectProperties.ChangeNode(value);

                _selectedNode = value;

                rennode = _selectedNode as RenderableNode;
                if (rennode != null)
                {
                    rennode.RenderBoundObject = true;
                }

                if (value == null)
                    CurrentGizmo = null;

                if (SelectedNodeChanged != null)
                    SelectedNodeChanged();
            }
        }

        protected string _SelectedMaterial;
        public string SelectedMaterial
        {
            get
            {
                return _SelectedMaterial;
            }

            set
            {
                if (_SelectedMaterial == value)
                    return;
                VisimBox.Console.WriteLine("Selecting material " + value);
                _SelectedMaterial = value;

                if (SelectedMaterialChanged != null)
                    SelectedMaterialChanged();
                if (_SelectedMaterial != null)
                    propertyGridMaterial.SelectedObject = VisimEngine.Instance.Renderer.MaterialMan[_SelectedMaterial];
                else
                    propertyGridMaterial.SelectedObject = null;
            }
        }

        public delegate void MaterialChangedCallback();
        public delegate void NodeChangedCallback();

        public event MaterialChangedCallback SelectedMaterialChanged;
        public event NodeChangedCallback SelectedNodeChanged;

        


        public SceneRoot Scene
        {
            get
            {
                return VisimEngine.Instance.MainScene;
            }
        }

        #endregion

        /// <summary>
        /// Selects new node and switches tool page to properties of the node
        /// </summary>
        /// <param name="newnode">New node</param>
        /// <param name="switchtoproperties">If true, toolbox wil switch to object properties</param>
        public void SelectNode(Node newnode, bool switchtoproperties)
        {
            SelectedNode = newnode;
            if (switchtoproperties)
                this.tabTools.SelectedTab = ObjectPropsPage;
        }

        /// <summary>
        /// Scene was changed, update browsers
        /// </summary>
        public void UpdateSceneChange()
        {
            sceneBrowser.UpdateScene();
            RefreshCameraList();
        }

        public MainBuilderForm()
        {
            InitializeComponent();
        }

        int ConsoleCharLimit = 4096;

        public void WriteConsoleLine(string line)
        {
            StringBuilder sb = new StringBuilder();
                       
            string ln = string.Format("{0}{1}\n",ConsoleWindow.Text, line);
            if (ln.Length > ConsoleCharLimit)
            {
                ln = ln.Substring(500);
            }
            this.ConsoleWindow.Text = ln;
            this.ConsoleWindow.SelectionStart = ConsoleWindow.Text.Length;
            this.ConsoleWindow.ScrollToCaret();
            this.ConsoleWindow.Refresh();
            
        }

        void Instance_OnWriteDebugLine(string line)
        {
            WriteConsoleLine(line); //todo, change color here?
        }

        void Instance_OnWriteLine(string line)
        {
            WriteConsoleLine(line);
        }

        private void StealObjects(TreeNode treenode, ToolStripMenuItem menuitem)
        {
            CreateNewItem newit = treenode as CreateNewItem;
            if (newit != null)
            {
                ToolStripMenuItem newitem = new CreateNewItemToolStrip(newit.Name, newit);
                menuitem.DropDownItems.Add(newitem);
                menuitem = newitem;
            }

            if ((treenode == null) || (treenode.Nodes == null))
                return;

            foreach (TreeNode tn in treenode.Nodes)
            {
                StealObjects(tn, menuitem);
            }
        }

        private void Startup(object sender, EventArgs e)
        {
            if (DesignMode)
                return;



            MoveG = new MoveGizmo(this);
            RotateG = new RotateGizmo(this);
            ScaleG = new ScaleGizmo(this);
            CurrentGizmo = null;
            RenWin = (VisimBox.Renderer.IRenderWindow)this.RenderWindow;

            VisimBox.Console.Instance.OnWriteLine += new VisimBox.Console.ConsoleCallback(Instance_OnWriteLine);
            VisimBox.Console.Instance.OnWriteDebugLine += new VisimBox.Console.ConsoleCallback(Instance_OnWriteDebugLine);            
            
            VisimEngine.Instance.Initialize(new VisimBox.Renderer.RenderContextSettings(this.RenderWindow));
            //VisimEngine.Instance.Initialize(new VisimBox.Renderer.RenderContextSettings());
            VisimEngine.Instance.NewScene();
            
            VisimEngine.Instance.Running = true;
            

            VisimEngine.Instance.Renderer.MainContext.ShowFPS = true;

            createObjectBrowser1.Init(this);

            foreach (TreeNode tn in createObjectBrowser1.ObjectTree.Nodes)
            {
                StealObjects(tn, newObjectToolStripMenuItem);
            }
            
            //steal data from object browser to menuitem


            sceneBrowser.Init(this);
            objectProperties.Init(this);


            //Node mm = VisimBoxDemos.RobotArm.RobotArmConstructor.CreateArm();
            //Scene.AddNode(mm, "RobotArm");

            //Node mm = new VisimBoxDemos.MarsRover.MarsTerrain();
            //Node mm = new VisimBoxDemos.EarthAttack.EarthAttack();

            //Node mm = VisimBoxDemos.MarsRover.TerrainConstructor.ConstructTerrain();

            //Scene.AddNode(mm, "Demo");

            /*
            NodeFactory.Settings.ImportMaterials = true;
            Transformation trans = new Transformation();
            trans.UniformScale = 0.01f;
            trans.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitX, -MathTools.HalfPi);
            NodeFactory.Settings.DefaultTrans = trans;
            var node = NodeFactory.ImportNodes("models/MarsRover.obj");
            if (node != null)
            {
                if (node.Trans == null)
                    node.Trans = new QTransformation();
                Scene.AddNode(node, "rover");
            }
            */

            /*

            var light = VisimEngine.Instance.Renderer.LightMan.AddDirectional("light", new Vector3(0, 0, 1), new ColorByte(50, 50, 50), ColorByte.White);


            var lnode = new LightNode(light);
            lnode.Trans = new QTransformation();
            lnode.Trans.Move(new Vector3(0, 0, 10));
            lnode.Trans.Pitch(1.57f);
            lnode.UpdateLight(0);

            Scene.AddNode(lnode, "lightnode");

            StandardColorValues svals = new StandardColorValues(ColorByte.Green);
            var mat = VisimBox.VisimEngine.Instance.Renderer.MaterialMan.Add("testmat", ref svals);


            AABox box;

            //Sphere sph;
            //var spheremesh = GeoFactory.CreateSphere(new Vector3(), 0.6f, out sph, 0.3f);

            //IndexedMesh boxmesh = GeoFactory.CreateBox(new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0.5f, 0.5f, 0.5f), out box);

            box = new AABox(1, 1, 1);

            //var mesh = VisimBox.VisimEngine.Instance.Renderer.MeshMan.Add(boxmesh);
            //var mesh = VisimBox.VisimEngine.Instance.Renderer.MeshMan.Add(spheremesh);

            VisimBox.Physics.RigidBody rb = new VisimBox.Physics.RigidBody(null as Node);
            //rb.PhysicalBody = new ConvexHull(box.GetCorners());
            rb.PhysicalBody =  box;
            rb.BoundingObject = box;
            rb.Mass = 100;
            rb.InertiaTensor = Matrix3.CreateInertiaCuboid(1, 1, 1, 100);
            rb.Material = new VisimBox.Physics.PhysMaterial();

            GeometryNode gn = new GeometryNode(box, typeof(NormalVertex), mat);
            rb.AddNode(gn, "renderobject");

            //NodeMesh meshnode = new NodeMesh(mesh, mat);
            //rb.AddNode(meshnode, "renderobject");
            
            rb.Trans.Move(new Vector3(5, 0, 1.5f));
            Scene.AddNode(rb, "RigidBody1");
            //Scene.PhysScene.RegisterBody(rb);   //todo - should be done autoamtically

            //boxmesh = GeoFactory.CreateBox(new Vector3(-1, -1, -1), new Vector3(1, 1, 1), out box);
            //mesh = VisimBox.VisimEngine.Instance.Renderer.MeshMan.Add(spheremesh);
            //mesh = VisimBox.VisimEngine.Instance.Renderer.MeshMan.Add(boxmesh);

            box = new AABox(2, 2, 2);

            rb = new VisimBox.Physics.RigidBody(null as Node);
            rb.PhysicalBody = box;
            rb.BoundingObject = box;
            //rb.Mass = 100;
            rb.InvertedMass = 0;
            //rb.InertiaTensor = Matrix3.CreateInertiaCuboid(2, 2, 2, float.PositiveInfinity);
            rb.InvertedInertia = new Matrix3(0);
            rb.Material = new VisimBox.Physics.PhysMaterial();

            gn = new GeometryNode(box, typeof(NormalVertex), mat);
            //meshnode = new NodeMesh(mesh, mat);

            rb.AddNode(gn, "renderobject");
            //rb.AddNode(meshnode, "renderobject");
            rb.Trans.Move(new Vector3(5, 0, 0.0f));
            //rb.Trans.Roll(MathTools.HalfPi);
            Scene.AddNode(rb, "RigidBody2");
            rb.HasStandardGravity = false;
            rb.Sleeping = true;
            //Scene.PhysScene.RegisterBody(rb);   //todo - should be done autoamtically
            */

            
            if (RenWin.RenderContext.MainCamera == null)
                RenWin.RenderContext.MainCamera = RenWin.RenderContext.CreateDefaultCamera();
            
            /*
            CameraNode camnode = new CameraNode(RenWin.RenderContext.MainCamera);
            Scene.AddNode(camnode, "camera");
            camnode.Trans.Move(new Vector3(0, 0, 0));
            //camnode.Trans.Pitch(1.57f);

            camnode = new CameraNode(new VisimBox.Renderer.StandardCamera());
            camnode.Trans.Move(new Vector3(0, 0, 0));
            //camnode.Trans.Pitch(1.57f);
            Scene.AddNode(camnode, "cameraQ");

            //camnode = new CameraNode(new VisimBox.Renderer.StandardCamera(100, 100));
            //camnode.Trans.Move(new Vector3(0, 5, 10));
            //Scene.AddNode(camnode, "cameraQ2");
            
            */

            UpdateSceneChange();

            System.Windows.Forms.Application.Idle += new EventHandler(Application_Idle);

            textBoxSpeed.Text = movementspeed.ToString();
            VisimEngine.Instance.Running = true;

            BackgGroundTimer = new Timer();
            BackgGroundTimer.Interval = 1000;
            BackgGroundTimer.Tick += new EventHandler(BackgGroundTimer_Tick);
            BackgGroundTimer.Start();


            EditGrid = new Gizmos.EditingGrid();
            EditGrid.Init(this);

            this.gridControl1 = new VisimBuilder.ObjectCreation.GridControl();
            this.gridControl1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.gridControl1.Location = new System.Drawing.Point(3, 3);
            this.gridControl1.Name = "gridControl1";
            this.gridControl1.Size = new System.Drawing.Size(407, 380);
            this.gridControl1.TabIndex = 0;

            gridControl1.Init(this, EditGrid);

            this.tabPageGrid.Controls.Add(this.gridControl1);


            this.lightsBrowser1 = new VisimBuilder.LightsBrowser();
            this.lightsBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.lightsBrowser1.Location = new System.Drawing.Point(3, 3);
            this.lightsBrowser1.Name = "lightsBrowser1";
            this.lightsBrowser1.Size = new System.Drawing.Size(407, 380);
            this.lightsBrowser1.TabIndex = 0;
            this.tabPageLights.Controls.Add(this.lightsBrowser1);
            lightsBrowser1.Init(this);

            RefreshMaterialList();

            VisimBox.Console.WriteLine("Simulation builder initialized.");
        }

        private ObjectCreation.GridControl gridControl1;
        private LightsBrowser lightsBrowser1;


        /// <summary>
        /// just occasionally render tick once per secondif not focused
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void BackgGroundTimer_Tick(object sender, EventArgs e)
        {
            if (Focused)
                return;
            RenderMainWindow();
            //Invalidate();
        }

        Timer BackgGroundTimer;


        void GizmoTimeTick()
        {
            EditGrid.TimeTick();
            
            ICamera cam = RenWin.RenderContext.MainCamera;

            if (cam == null)
                return;

            if (!cam.GetPickingRay(mousex, mousey, PickingRay))
                return;

            //todo - info for grid editor?

            if (CurrentGizmo == null)
                return;
            if (SelectedNode == null)
                return;

            CurrentGizmo.MouseHover(PickingRay);
        }

        int GrabbedFrames = 0;
        bool videograbbing = false;
        string GrabbingPath = null;

        bool IddleCheck()
        {
            if (!ContainsFocus)
                return false;
            return VisimEngine.Instance.Renderer.IsIdle();
        }



        void Application_Idle(object sender, EventArgs e)
        {
            var irc = VisimEngine.Instance.Renderer.MainContext;

            GizmoTimeTick();

            while (IddleCheck())
            {
                
                if (SimState != SimulationStateEnum.Stopped)
                {
                    float timeval = 0.05f;
                    switch (SimState)
                    {
                        case SimulationStateEnum.Running:
                            timeval = 0.05f;//change this to REALTIME!
                            break;
                        case SimulationStateEnum.SingleStep:
                            timeval = StepSize;
                            SimState = SimulationStateEnum.Stopped;
                            break;
                    }
                    VisimEngine.Instance.TimeTick(timeval);

                    physControl1.SimulationTime += timeval;
                }            


                RenderMainWindow();               

                Vector3 move = new Vector3();
                //float val = movementspeed / irc.CurrentFPS;
                float val = movementspeed;
                bool moved = false;
                if (keyW)
                {
                    move.Add(val, 0, 0);
                    moved = true;
                }
                if (keyS)
                {
                    move.Add(-val, 0, 0);
                    moved = true;
                }
                if (keyA)
                {
                    move.Add(0, -val, 0);
                    moved = true;
                }
                if (keyD)
                {
                    move.Add(0, val, 0);
                    moved = true;
                }
                if (keyR)
                {
                    move.Add(0, 0, val);
                    moved = true;
                }
                if (keyF)
                {
                    move.Add(0, 0, -val);
                    moved = true;
                }
                if (keyQ)
                {
                    RenWin.RenderContext.MainCamera.Roll(-0.1f*val);
                    UpdateCameraGui();
                }
                if (keyE)
                {
                    RenWin.RenderContext.MainCamera.Roll(0.1f * val);
                    UpdateCameraGui();
                }

                if (moved)
                    MoveMainCamera(move);
            }
        }

        private void ShutDown(object sender, FormClosedEventArgs e)
        {
            if ((matedit != null) && (!matedit.IsDisposed))
            {
                matedit.Close();
                matedit.Dispose();
            }
            VisimEngine.Instance.Close();
        }

        protected VisimBox.Renderer.RendererEventArgs renargs = new RendererEventArgs(null, null, null);

        private void RenderMainWindow()
        {
            var irc = VisimEngine.Instance.Renderer.MainContext;
            irc.StartFrame();
            irc.RenderNodes(Scene);

            if (this._selectedNode != null)
            {
                if (CurrentGizmo != null)
                    CurrentGizmo.Render(irc);
            }

            renargs.RC = irc;
            renargs.Renderer = irc.Renderer;
            EditGrid.Render(renargs);

            irc.EndFrame();
            if (videograbbing)
            {
                irc.SaveScreenShot("video" + GrabbedFrames.ToString() + ".png");
                GrabbedFrames++;
            }
        }

        private void PaintWindow(object sender, PaintEventArgs e)
        {
            RenderMainWindow();
        }

        private void UpdateCameraGui()
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                Vector3 pos = RenWin.RenderContext.MainCamera.Position;
                Vector3 rot = RenWin.RenderContext.MainCamera.RPY;

                this.textBoxCameraPos.Text = string.Format("{0} : {1} : {2}",
                    pos.X.ToString("F"), pos.Y.ToString("F"), pos.Z.ToString("F"));

                rot.X = MathTools.RadToDeg(rot.X);
                rot.Y = MathTools.RadToDeg(rot.Y);
                rot.Z = MathTools.RadToDeg(rot.Z);

                this.textBoxCameraRot.Text = string.Format("{0} : {1} : {2}",
                    rot.X.ToString("F"), rot.Y.ToString("F"), rot.Z.ToString("F"));

            }
        }

        #region Camera Control

        void MoveMainCamera(Vector3 vec)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                RenWin.RenderContext.MainCamera.MoveLocal(ref vec);
                UpdateCameraGui();
            }
        }


        private void buttonCameraRollLeft_Click(object sender, EventArgs e)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                RenWin.RenderContext.MainCamera.Roll(VisiMath.MathTools.DegToRad(-1));
            }
            UpdateCameraGui();
        }

        private void buttonCameraRollRight_Click(object sender, EventArgs e)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                RenWin.RenderContext.MainCamera.Roll(VisiMath.MathTools.DegToRad(1));
            }
            UpdateCameraGui();
        }

        private void buttonCamLookLeft_Click(object sender, EventArgs e)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                RenWin.RenderContext.MainCamera.Pitch(VisiMath.MathTools.DegToRad(-1));
            }
            UpdateCameraGui();
        }

        private void buttonCamLookRight_Click(object sender, EventArgs e)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                RenWin.RenderContext.MainCamera.Pitch(VisiMath.MathTools.DegToRad(1));
            }
            UpdateCameraGui();
        }

        private void buttonCamLookUp_Click(object sender, EventArgs e)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                 RenWin.RenderContext.MainCamera.Yaw(VisiMath.MathTools.DegToRad(1));
            }
            UpdateCameraGui();
        }

        private void buttonCamLookDown_Click(object sender, EventArgs e)
        {
            if (RenWin.RenderContext.MainCamera != null)
            {
                RenWin.RenderContext.MainCamera.Yaw(VisiMath.MathTools.DegToRad(-1));
            }
            UpdateCameraGui();
        }


        private void buttonCamForward_Click(object sender, EventArgs e)
        {
            MoveMainCamera(new Vector3(1,0,0));
        }

        private void buttonCameraBackWard_Click(object sender, EventArgs e)
        {
            MoveMainCamera(new Vector3(-1, 0, 0));
        }

        private void buttonCamMoveRight_Click(object sender, EventArgs e)
        {
            MoveMainCamera(new Vector3(0, 1, 0));
        }

        private void buttonCamMoveLeft_Click(object sender, EventArgs e)
        {
            MoveMainCamera(new Vector3(0, -1, 0)); 
        }

        private void buttonCamMoveUp_Click(object sender, EventArgs e)
        {
            MoveMainCamera(new Vector3(0, 0, 1)); 
        }

        private void buttonCamMoveDown_Click(object sender, EventArgs e)
        {
            MoveMainCamera(new Vector3(0, 0, -1));
        }


        #endregion


        private bool UpdatePickingRay()
        {
            ICamera cam = RenWin.RenderContext.MainCamera;

            if (cam == null)
                return false;

            if (!cam.GetPickingRay(mousex, mousey, PickingRay))
                return false;
            return true;
        }

        private void MouseMoving(object sender, MouseEventArgs e)
        {
            int deltax = mousex - e.X;
            int deltay = mousey - e.Y;

            mousex = e.X;
            mousey = e.Y;

            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                if (RenWin.RenderContext.MainCamera != null)
                {
                    RenWin.RenderContext.MainCamera.Yaw(VisiMath.MathTools.DegToRad(deltay));
                    RenWin.RenderContext.MainCamera.Pitch(VisiMath.MathTools.DegToRad(-deltax));
                    UpdateCameraGui();
                }
            }

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if ((SelectedNode != null) && (CurrentGizmo != null))
                {
                    if (!UpdatePickingRay())
                        return;
                    CurrentGizmo.MouseMove(deltax, deltay, PickingRay);
                }
            }

        }

        private void MouseIsDown(object sender, MouseEventArgs e)
        {
            mousex = e.X;
            mousey = e.Y;

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {

                if (!UpdatePickingRay())
                    return;

                if ((SelectedNode == null) || (CurrentGizmo == null))
                    return;

                CurrentGizmo.MouseDown(PickingRay);
            }
        }

        private void MouseIsUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                //left click! try to select...

                if (!UpdatePickingRay())
                    return;

                if ((CurrentGizmo != null) && (CurrentGizmo.MouseUp(PickingRay)))
                    return;

                Node node = Scene.PickNode(PickingRay);
                SelectNode(node, false);
                //if (node != null)
                    //SelectNode(node, false);                               
            }
        }

        void MouseWheeling(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            MoveMainCamera(new Vector3((float)e.Delta/240.0f, 0, 0));
        }


        #region keyboard


        bool keyW = false;
        bool keyA = false;
        bool keyS = false;
        bool keyD = false;
        bool keyR = false;
        bool keyF = false;
        bool keyQ = false;
        bool keyE = false;


        private void UpdateKeyboard(KeyEventArgs e, bool down)
        {
            switch (e.KeyCode)
            {
                case Keys.A:
                    keyA = down;
                    break;
                case Keys.W:
                    keyW = down;
                    break;
                case Keys.S:
                    keyS = down;
                    break;
                case Keys.D:
                    keyD = down;
                    break;
                case Keys.F:
                    keyF = down;
                    break;
                case Keys.R:
                    keyR = down;
                    break;
                case Keys.Q:
                    keyQ = down;
                    break;
                case Keys.E:
                    keyE = down;
                    break;
            }
        }

        private void MainKeyDown(object sender, KeyEventArgs e)
        {
            UpdateKeyboard(e, true);
        }

        private void MainKeyUp(object sender, KeyEventArgs e)
        {
            UpdateKeyboard(e, false);

            if (e.KeyCode == Keys.Delete)
            {
                DeleteNode();
            }

        }

        #endregion

        void updatespeed()
        {
            try
            {
                float val = (float)Convert.ToDouble(textBoxSpeed.Text);
                movementspeed = val;
            }
            catch
            {
                VisimBox.Console.WriteLine("Movement speed changed to " + movementspeed.ToString());
                textBoxSpeed.Text = movementspeed.ToString();
            }
        }

        private void KeyMoveSpeed(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                updatespeed();
            }
        }

        private void MoveSpeedFocusLeave(object sender, EventArgs e)
        {
            updatespeed();
        }

        private void MouseHovering(object sender, EventArgs e)
        {
        }

        private void SwitchGizmoSelect()
        {
            CurrentGizmo = null;
            toolStripStatusLabel1.Text = "Selecting...";
            VisimBox.Console.WriteLine("Switching to select tool.");
        }

        private void SwitchGizmoMove()
        {
            CurrentGizmo = MoveG;
            toolStripStatusLabel1.Text = "Moving...";
            VisimBox.Console.WriteLine("Switching to move tool.");
        }

        private void SwitchGizmoRotate()
        {
            CurrentGizmo = RotateG;
            toolStripStatusLabel1.Text = "Rotating...";
            VisimBox.Console.WriteLine("Switching to rotate tool.");
        }

        private void SwitchGizmoScale()
        {
            CurrentGizmo = ScaleG;
            toolStripStatusLabel1.Text = "Scaling...";
            VisimBox.Console.WriteLine("Switching to scale tool.");
        }

        private void SelectClicked(object sender, EventArgs e)
        {
            SwitchGizmoSelect();
        }

        private void MoveClicked(object sender, EventArgs e)
        {
            SwitchGizmoMove();
        }

        private void RotateClicked(object sender, EventArgs e)
        {
            SwitchGizmoRotate();
        }

        private void ScaleClicked(object sender, EventArgs e)
        {
            SwitchGizmoScale();
        }

        private void SaveScreenshot(object sender, EventArgs e)
        {
            RenWin.RenderContext.SaveScreenShot();
        }

        private void buttonStartManEditor_Click(object sender, EventArgs e)
        {
            ShowMatEditor();
        }

        public void ShowMatEditor()
        {
            if ((matedit == null) || (matedit.IsDisposed))
            {
                matedit = new MaterialEditor(this);
            }
            else
                matedit.UpdateMaterials();
            matedit.Show();
            matedit.Focus();
        }

        public DialogResult ShowSceneBrowser()
        {
            if ((SceneBrowserDLG == null) || (SceneBrowserDLG.IsDisposed))
            {
                SceneBrowserDLG = new SceneBrowserDialog();
                SceneBrowserDLG.Init(this);
            }

            SceneBrowserDLG.UpdateScene();
            return SceneBrowserDLG.ShowDialog();            
        }

        private void GravityChanged(float stepsize)
        {
            if (VisimEngine.Instance.MainScene.PhysScene != null)
            {
                VisimEngine.Instance.MainScene.PhysScene.Gravity = new Vector3(0, 0, -stepsize);
                VisimBox.Console.WriteLine("Gravity changed to 0, 0, -" + stepsize.ToString() + ".");
            }
            else
            {
                VisimBox.Console.DebugLine("Can't change gravity, Scene has no physics");
            }
        }

        private enum SimulationStateEnum { Stopped, Running, SingleStep };
        private float StepSize = 0.05f; //read this from physcontrol or vice versa
        private SimulationStateEnum _SimState = SimulationStateEnum.Stopped;

        private SimulationStateEnum SimState
        {
            get
            {
                return _SimState;
            }

            set
            {
                if (_SimState == value)
                    return;

                _SimState = value;

                switch (_SimState)
                {
                    case SimulationStateEnum.Stopped:
                        physControl1.Running = false;
                        toolStripButtonSimStep.Enabled = true;
                        toolStripButtonStartScene.Enabled = true;
                        toolStripButtonStopScene.Enabled = false;
                        break;
                    case SimulationStateEnum.SingleStep:
                        physControl1.Running = false;
                        toolStripButtonSimStep.Enabled = true;
                        toolStripButtonStartScene.Enabled = true;
                        toolStripButtonStopScene.Enabled = false;
                        break;
                    case SimulationStateEnum.Running:
                        physControl1.Running = true;
                        toolStripButtonSimStep.Enabled = false;
                        toolStripButtonStartScene.Enabled = false;
                        toolStripButtonStopScene.Enabled = true;
                        break;
                }
            }
        }

        private void SimReset()
        {
            VisimBox.Console.WriteLine("Simulation reset.");
            FunctionNotDone();
        }

        private void SimStart()
        {
            VisimBox.Console.WriteLine("Simulation starting.");
            SimState = SimulationStateEnum.Running;
        }

        private void SimStep(float stepsize)
        {
            StepSize = stepsize;
            SimState = SimulationStateEnum.SingleStep;
        }

        private void SimStop()
        {
            SimState = SimulationStateEnum.Stopped;
            VisimBox.Console.WriteLine("Simulation stopped.");
        }

        private void MainKeyPress(object sender, KeyPressEventArgs e)
        {
            switch (e.KeyChar)
            {
                case '1':
                    SwitchGizmoSelect();
                    break;
                case '2':
                    SwitchGizmoMove();
                    break;
                case '3':
                    SwitchGizmoRotate();
                    break;
                case '4':
                    SwitchGizmoScale();
                    break;
                case ' ':
                    if (SimState == SimulationStateEnum.Running)
                    {
                        physControl1.Running = false;
                        SimStop();
                    }
                    else if (SimState == SimulationStateEnum.Stopped)
                    {
                        SimStart();
                        physControl1.Running = true;
                    }
                    break;
            }
        }

        private void viewSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.tabTools.SelectedTab = ViewSettabPage1;
        }

        private void materialEditorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowMatEditor();
        }

        private void physicalSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.tabTools.SelectedTab = tabPagePhysical;
        }

        private void saveSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ((VisimEngine.Instance.MainScene.FileName == null) || (VisimEngine.Instance.MainScene.FileName == ""))
                saveAsToolStripMenuItem_Click(sender, e);
            else 
            VisimEngine.Instance.SaveScene();
        }

        private void reloadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ((VisimEngine.Instance.MainScene.FileName != null) && (VisimEngine.Instance.MainScene.FileName != ""))
            {

                if (MessageBox.Show("Forget changes and reload scene?", "Reload scene", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                    return;
                //VisimEngine.Instance.MainScene.LoadScene("Visimbox.VSB");
                VisimEngine.Instance.MainScene.ReloadScene();
                UpdateSceneChange();
            }
            else MessageBox.Show("Scene wasn't saved, so it cannot be reloaded!");
        }

        private void newSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Forget any changes and create new empty scene?", "New scene", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                return;
            VisimEngine.Instance.NewScene();
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveFileDialogScene.FileName == "")
            {
                if ((VisimEngine.Instance.MainScene.FileName != null) && (VisimEngine.Instance.MainScene.FileName != ""))
                {
                    saveFileDialogScene.FileName = VisimEngine.Instance.MainScene.FileName;
                }
                else
                {
                    saveFileDialogScene.FileName = "VisimBoxScene.vsb";
                }
            }
            if (saveFileDialogScene.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                VisimEngine.Instance.SaveScene(saveFileDialogScene.FileName);
            }

        }

        private void loadSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //todo : check for changes!!!
            if (MessageBox.Show("Forget any changes and load new scene?", "Load new scene", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.No)
                return;
            
            if ((VisimEngine.Instance.MainScene.FileName != null) && (VisimEngine.Instance.MainScene.FileName != ""))
            {
                if (openFileDialogScene.FileName == "")
                    openFileDialogScene.FileName = VisimEngine.Instance.MainScene.FileName;
            }
            if (openFileDialogScene.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                VisimEngine.Instance.LoadScene(openFileDialogScene.FileName);
                UpdateSceneChange();
            }            
        }

        private void FunctionNotDone()
        {
            MessageBox.Show("This function is either not implemented, or is disabled");
        }

        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialogImport.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Node newnode = NodeFactory.ImportNodes(openFileDialogImport.FileName);
                if (newnode == null)
                {
                    MessageBox.Show("File import failed!");
                    return;
                }
                string name = System.IO.Path.GetFileNameWithoutExtension(openFileDialogImport.FileName);
                Scene.AddNode(newnode, name);
            }            
        }

        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FunctionNotDone();
        }

        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Quit Visimbuilder without saving?", "Quit?", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                this.Close();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("VisimBuilder 0.9a, editor for VisimBox 0.9a\n(c)2009-2011 Jiri Matyskiewicz", "VISIMBUILDER");
        }

        private void sceneSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SelectNode(Scene, true);
        }

        private void sceneInfoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FunctionNotDone();
        }

        private void recalculateStaticCollisionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Scene.PhysScene.RecalcStaticCollisions();
        }

        private void gridControlToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.tabTools.SelectedTab = tabPageGrid;
        }

        private void sceneBrowserToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.tabTools.SelectedTab = SceneBrowsetabPage;
        }

        private void saveScreenshotAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Bitmap bmp = VisimEngine.Instance.Renderer.MainContext.GetScreenShot();
            if (saveFileDialogScreenShot.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                bmp.Dispose();
                return;
            }

            string filename = saveFileDialogScreenShot.FileName;
            if ((filename == null) || (filename == ""))
            {
                MessageBox.Show("Can't save screenshot, invalid filename!");
                bmp.Dispose();
                return;
            }

            //get extension
            string extension = "jpg";

            int idx = filename.LastIndexOf('.');
            if ((idx >= 0) || (idx < (filename.Length - 1)))
            {
                extension = filename.Substring(idx+1);
            }

            System.Drawing.Imaging.ImageFormat form = System.Drawing.Imaging.ImageFormat.Jpeg;

            if (extension == "jpg")
            {
            }
            else if (extension =="png")
            {
                form = System.Drawing.Imaging.ImageFormat.Png;
            }
            else if (extension == "bmp")
            {
                form = System.Drawing.Imaging.ImageFormat.Bmp;
            }
            else
            {
                filename = filename + ".jpg";
            }

            bmp.Save(filename, form);
            bmp.Dispose();
        }

        public void LookAtSelectedObject()
        {
            if (SelectedNode == null)
                return;
            LookAtObject(SelectedNode);
        }

        public void LookAtObject(Node node)
        {
            if (node == null)
                return;
            Matrix4 worldmat = Matrix4.Identitity;
            Vector3 lookpos;
            if (!node.GetWorldTransformation(ref worldmat))
            {
                lookpos = new Vector3(0);
            }
            else
            {
                lookpos = worldmat.Translation;
            }

            VisimBox.VisimEngine.Instance.Renderer.MainContext.MainCamera.LookAt(lookpos);
        }

        public void TeleportToSelected()
        {
            if (SelectedNode == null)
                return;
            TeleportToObject(SelectedNode);
        }
        
        public void TeleportToObject(Node node)
        {
            if (node == null)
                return;

            Matrix4 worldmat = Matrix4.Identitity;
            Vector3 lookpos;
            if (!node.GetWorldTransformation(ref worldmat))
            {
                lookpos = new Vector3(0);
            }
            else
            {
                lookpos = worldmat.Translation;
            }

            VisimBox.VisimEngine.Instance.Renderer.MainContext.MainCamera.LookAt(lookpos);

            VisimBox.VisimEngine.Instance.Renderer.MainContext.MainCamera.Position = lookpos;
        }

        private void lookAtSelectedObjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LookAtSelectedObject();
        }

        private void toolStripButtonStartScene_Click(object sender, EventArgs e)
        {
            if (SimState != SimulationStateEnum.Running)
            {
                SimState = SimulationStateEnum.Running;
                physControl1.Running = true;
                VisimBox.Console.WriteLine("Simulation starting.");
            }
        }

        private void toolStripButtonStopScene_Click(object sender, EventArgs e)
        {
            if (SimState != SimulationStateEnum.Stopped)
            {
                SimState = SimulationStateEnum.Stopped;
                physControl1.Running = false;
                VisimBox.Console.WriteLine("Simulation stopped.");
            }
        }

        private void objectPropertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.tabTools.SelectedTab = ObjectPropsPage;
        }

        private void setVideoGrabbingDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialogVideoGrabb.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            GrabbingPath = folderBrowserDialogVideoGrabb.SelectedPath;
        }

        private void startSavingVideoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (GrabbingPath == null)
            {
                MessageBox.Show("Path for grabbed files not set! Set it now and then start grabbing again!");
                setVideoGrabbingDirectoryToolStripMenuItem_Click(sender, e);
                return;
            }

            stopSavingVideoToolStripMenuItem.Enabled = true;
            startSavingVideoToolStripMenuItem.Enabled = false;
            toolStripButtonStartRecord.Enabled = false;
            toolStripButtonStopRecord.Enabled = true;

            videograbbing = true;
            GrabbedFrames = 0;
        }

        private void stopSavingVideoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!videograbbing)
                return;

            videograbbing = false;
            MessageBox.Show(GrabbedFrames.ToString() + " frames grabbed and saved to folder " + GrabbingPath, "Video grabbing");
            stopSavingVideoToolStripMenuItem.Enabled = false;
            startSavingVideoToolStripMenuItem.Enabled = true;
            toolStripButtonStartRecord.Enabled = true;
            toolStripButtonStopRecord.Enabled = false;

        }

        private void CollisionCheckChange(object sender, EventArgs e)
        {
            Settings.RigidBodyColCheck = collisionCheckForBodiesToolStripMenuItem.Checked;
        }

        private void StaticUpdateChanged(object sender, EventArgs e)
        {
            Settings.StaticColUpdate = updateStaticCollisionToolStripMenuItem.Checked;
        }

        private void buttonRefreshMaterials_Click(object sender, EventArgs e)
        {
            RefreshMaterialList();
        }

        private void MaterialComboChanged(object sender, EventArgs e)
        {
            SelectedMaterial = (string)comboBoxMaterials.SelectedItem;
        }

        public void RefreshMaterialList()
        {
            var matman = VisimEngine.Instance.Renderer.MaterialMan;

            comboBoxMaterials.Items.Clear();
            foreach (var mat in matman)
            {
                comboBoxMaterials.Items.Add(mat.Key);
            }
            comboBoxMaterials.SelectedItem = SelectedMaterial;
        }

        private void buttonCameraRefresh_Click(object sender, EventArgs e)
        {
            RefreshCameraList();
        }

        public void RefreshCameraList()
        {
            comboBoxCameras.Items.Clear();
            AddCameraToList(Scene);
        }

        protected void AddCameraToList(Node node)
        {
            CameraNode camnode = node as CameraNode;
            if (camnode != null)
            {
                comboBoxCameras.Items.Add(node.FullName);
            }

            foreach (Node nod in node)
            {
                AddCameraToList(nod);
            }
        }

        private void CameraChanged(object sender, EventArgs e)
        {
            string cameraname = (string)comboBoxCameras.SelectedItem;

            Node node = Scene.GetChildByFullName(cameraname);

            CameraNode camnode = node as CameraNode;

            ICamera icam = camnode.Camera;
            if (icam != null)
                RenWin.RenderContext.MainCamera = icam;
        }

        private void DeleteNode()
        {
            if (SelectedNode == null)
                return;
            if (SelectedNode == Scene)
            {
                MessageBox.Show("Can't delete whole scene, use new scene function!");
                return;
            }
            if (MessageBox.Show("Delete node " + SelectedNode.FullName + "and all it's children?", "Node deleting", MessageBoxButtons.YesNo) != DialogResult.Yes)
                return;

            Node node = SelectedNode;
            SelectedNode = null;

            if (node.Parent != null)
                node.Parent.RemoveNode(node);
            node.Dispose();
            UpdateSceneChange();
            //todo - info for resource managers?
        }

        private void toolStripButtonSimStep_Click(object sender, EventArgs e)
        {
            SimState = SimulationStateEnum.SingleStep;
        }

        private void toolStripButtonStartRecord_Click(object sender, EventArgs e)
        {
            startSavingVideoToolStripMenuItem_Click(sender, e);
        }

        private void toolStripButtonStopRecord_Click(object sender, EventArgs e)
        {
            stopSavingVideoToolStripMenuItem_Click(sender, e);
        }

        private void toolStripDropDownButtonLink_Click(object sender, EventArgs e)
        {
            LinkNode(SelectedNode);
        }

        private void toolStripDropDownButtonDelete_Click(object sender, EventArgs e)
        {
            DeleteNode();
        }

        private void toolStripDropDownButtonCopy_Click(object sender, EventArgs e)
        {
            SelectedNode = CreateNodeCopy(SelectedNode);
        }


        /// <summary>
        /// Returns true if node belongs to parent tree
        /// </summary>
        /// <param name="node"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        bool CheckParent(Node node, Node parent)
        {
            if (node.Parent == null)
                return false;
            if (node.Parent == parent)
                return true;
            return CheckParent(node.Parent, parent);
        }

        public void LinkNode(Node source)
        {
            Node selnode = SelectedNode;


            if (source == null)
                return;

            if (ShowSceneBrowser() != System.Windows.Forms.DialogResult.OK)
                return;

            if (SelectedNode == null)
                return;

            //sanity check
            if (CheckParent(SelectedNode, source))
            {
                MessageBox.Show("Selected parent for node would result in cyclical graph, which is NOT allowed");
            }
            else
            {
                source.ChangeParent(SelectedNode, true, true);
            }

            SelectedNode = selnode;
            UpdateSceneChange();
        }

        public Node CreateNodeCopy(Node source)
        {
            if (source == null)
                return null;
            Node rval = source.CreateCopy();

            if (rval == null)
            {
                MessageBox.Show("Node copying failed!");
                return null;
            }

            Node parent = source.Parent;
            if (parent == null)
                parent = Scene;

            parent.AddNode(rval, rval.Name);
            return rval;
        }

        ImportModelSettings importsettings = new ImportModelSettings();

        private void importSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            importsettings.Settings = new NodeImportSettings(NodeFactory.Settings);
            if (importsettings.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                NodeFactory.Settings = importsettings.Settings;
            }
        }

        private void UniformScaleChecked(object sender, EventArgs e)
        {
            ScaleG.UniformScale = uniformScaleToolStripMenuItem1.Checked;
        }

        private void MoviGizmoLocalCheckChange(object sender, EventArgs e)
        {
            MoveG.InLocalCoords = MoveGizmoInLocal.Checked;
        }

        private void RotateLocalCoordsChecked(object sender, EventArgs e)
        {
            RotateG.InLocalCoords = rotateInLocalMenuItem.Checked;
        }

        private void teleportToSelectedObjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TeleportToSelected();
        }

        private void createCopyOfSelectedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SelectedNode = CreateNodeCopy(SelectedNode);
        }

    } // mainform


}
