// TO DO: MAKE AN INOBJECTREGION METHOD THAT WILL DETECT WHETHER MOUSE IS IN OBJECT
 internal bool inObjectRegion(GameObject obj, Vector3d mouseCoord, bool enable3D)
 {
     Rectangle r = new Rectangle((int)obj.location.X - 50, (int)obj.location.Y - 50, 100, 100);
     if (!enable3D)
     {
         if (r.Contains((int)mouseCoord.X, (int)mouseCoord.Y))
         {
             Console.WriteLine("You are inside an object");
             return true;
         }
         else return false;
     }
     return false;
 }
        // DVector3 AA_2, DVector3 BB_2)
        private bool Add(GameObject BSSO, Node N)
        {
            //Достигнут минимальный уровень
            if (N.NestingLevel < 1)
            {
                N.Parent.ListBSSO.Add(BSSO);
                return true;
            }

            int rez = TestTwoAABB(N.AA, N.BB, BSSO.AABBMax, BSSO.AABBMin);
            //Не поподает
            if (rez == 0) return false;
            //Поподает частично
            if (rez == 1)
            {
                N.Parent.ListBSSO.Add(BSSO);
                return true;
            }

            double X = N.AA.X - N.BB.X;
            double Y = N.AA.Y - N.BB.Y;
            double Z = N.AA.Z - N.BB.Z;

            if (X + Y + Z < NodeMinSize)
            {
                N.ListBSSO.Add(BSSO);
                return true;
            }

            //Поподает полностью
            if (N.Children.Count < 1)
            {
                int Level = N.NestingLevel - 1;

                if (X > Math.Max(Y, Z))
                {
                    N.Children.Add(new Node(N, N.AA, new DVector3(N.AA.X - X / 2f, N.BB.Y, N.BB.Z), Level));
                    N.Children.Add(new Node(N, new DVector3(N.AA.X - X / 2f, N.AA.Y, N.AA.Z),  N.BB, Level));
                    if (BSSO.Position.X > N.AA.X - X / 2f)
                    {
                        if (Add(BSSO, N.Children[0])) return true;
                        if (Add(BSSO, N.Children[1])) return true;
                    }
                    else
                    {
                        if (Add(BSSO, N.Children[1])) return true;
                        if (Add(BSSO, N.Children[0])) return true;
                    }
                }
                else
                {
                    if (Y > Math.Max(X, Z))
                    {
                        N.Children.Add(new Node(N, N.AA, new DVector3(N.BB.X, N.AA.Y - Y / 2f, N.BB.Z), Level));
                        N.Children.Add(new Node(N, new DVector3(N.AA.X, N.AA.Y - Y / 2f, N.AA.Z), N.BB, Level));
                        if (BSSO.Position.Y > N.AA.Y - Y / 2f)
                        {
                            if (Add(BSSO, N.Children[0])) return true;
                            if (Add(BSSO, N.Children[1])) return true;
                        }
                        else
                        {
                            if (Add(BSSO, N.Children[1])) return true;
                            if (Add(BSSO, N.Children[0])) return true;
                        }
                    }
                    else
                    {
                        N.Children.Add(new Node(N, N.AA, new DVector3(N.BB.X, N.BB.Y, N.AA.Z - Z / 2f), Level));
                        N.Children.Add(new Node(N, new DVector3(N.AA.X, N.AA.Y, N.AA.Z - Z / 2f), N.BB, Level));
                        if (BSSO.Position.Z > N.AA.Z - Z / 2f)
                        {
                            if (Add(BSSO, N.Children[0])) return true;
                            if (Add(BSSO, N.Children[1])) return true;
                        }
                        else
                        {
                            if (Add(BSSO, N.Children[1])) return true;
                            if (Add(BSSO, N.Children[0])) return true;
                        }
                    }
                }
            }

            if (Add(BSSO, N.Children[0])) return true;
            if (Add(BSSO, N.Children[1])) return true;

            return false;
        }
        private void HandleMouseInput()
        {
            if (!eng.ThisMouse.LeftPressed())
            {
                clickdown = false;
            }
            // ADDING OBJECTS TO THE LIST
            if (eng.ThisMouse.LeftPressed() && !clickdown && !enable3d)
            {
                clickdown = true;
                // Pull the projection and model view matrix from the camera.   
                Matrix4d project = this.camera.GetProjectionMatrix();
                Matrix4d model = this.camera.GetModelViewMatrix();
                Vector3d mousecoord = new Vector3d((double)this.eng.Mouse.X, (double)(this.eng.Height - this.eng.Mouse.Y), 1.0);
                // Unproject the coordinates to convert from mouse to world coordinates
                Vector3d mouseWorld = GameMouse.UnProject(mousecoord, model, project, this.camera.getViewport());

                foreach (GameObject obj in objList)
                {
                    if (obj is Obstacle || obj is Enemy)
                    {
                        if (eng.ThisMouse.inObjectRegion(obj, mouseWorld, enable3d))
                        {
                            SelectedObject = obj;
                            Console.WriteLine("Selected Object");
                            return;
                        }
                    }
                }

                Vector3 loc = new Vector3((float)mouseWorld.X, (float)mouseWorld.Y, 50.0f);

                // Handle adding enemies
                if (listKey == 1)
                {
                    Enemy e = parseEnemy(ObjectList[listKey][objectIter], loc, player);
                    objList.Add(e);
                    physList.Add(e);
                    renderList.Add(e);
                    clickdown = false;
                    // Add to obstacle list
                    if (_xml_enemy_list.ContainsKey(objectIter))
                    {
                        _xml_enemy_list[objectIter].Add(e.location);
                    }
                    else
                    {
                        List<Vector3> locList = new List<Vector3>();
                        locList.Add(e.location);
                        _xml_enemy_list.Add(objectIter, locList);
                    }
                }


                else
                {
                    Obstacle o = ParseObstacle(ObjectList[listKey][objectIter], loc);
                    if (o == null)
                    {
                        Decoration dec = ParseDecoration(ObjectList[listKey][objectIter], loc);
                        objList.Add(dec);
                        renderList.Add(dec);

                        // Add decoration to decoration list
                        _xml_dec_list.Add(dec.location, objectIter);

                        /** TODO !!!! ***/
                        // Need to parse Enemies, Sound files, boss regions, backgrounds

                        /// PSEUDO-CODE
                        // if ( boss region )
                        //      _xml_boss_region.Add(Vector3, index)

                        // if ( boss bounds )
                        //      _xml_boss_bounds.Add(Vector3, index)

                        // if ( boss center )
                        //      _xml_boss_center.Add(Vector3, index)

                        // if ( sound file )
                        //      _xml_sound.Add(object, index)

                        // if ( end region )
                        //      _xml_end_region.Add(Vector3)

                        // if ( enemy )
                        //      _xml_enemy.Add(object, index)

                        // if ( background )
                        //      _xml_bg.Add(BackGroundData, index)  /// BackGroundData is a struct to hold the multiple data items needed to create a BG
                    }
                    else
                    {
                        objList.Add(o);
                        physList.Add(o);
                        renderList.Add(o);
                        clickdown = false;

                        // Add to obstacle list
                        if (_xml_obstacle_list.ContainsKey(objectIter))
                        {
                            _xml_obstacle_list[objectIter].Add(o.location);
                        }
                        else
                        {
                            List<Vector3> locList = new List<Vector3>();
                            locList.Add(o.location);
                            _xml_obstacle_list.Add(objectIter, locList);
                        }

                    }
                }
            }
            else if (eng.ThisMouse.LeftPressed() && !clickdown && enable3d)
            {
                // TO DO: ALLOW SELECTION AND OF OBJECTS IN 3D
                clickdown = true;
                // Pull the projection and model view matrix from the camera.   
                Matrix4d project = this.camera.GetProjectionMatrix();
                Matrix4d model = this.camera.GetModelViewMatrix();
                float[] t = new float[1];
                GL.ReadPixels(this.eng.Mouse.X, this.eng.Height - this.eng.Mouse.Y, 1, 1, PixelFormat.DepthComponent, PixelType.Float, t);
                Vector3d mousecoord = new Vector3d((double)this.eng.Mouse.X, (double)(this.eng.Height - this.eng.Mouse.Y), 1.0);
                // Unproject the coordinates to convert from mouse to world coordinates
                mousecoord.Z = 0.0;
                Vector3d near = GameMouse.UnProject(mousecoord, model, project, this.camera.getViewport());
                mousecoord.Z = 1.0;
                Vector3d far = GameMouse.UnProject(mousecoord, model, project, this.camera.getViewport());

                //Interpolate to find coordinates just in front of player
                double tA = (player.location.X + (100.0f * t[0]) - near.X) / (far.X - near.X);
                Vector3d mouseWorld = new Vector3d(player.location.X + (100.0 * (1 - t[0])), near.Y + (far.Y - near.Y) * tA, near.Z + (far.Z - near.Z) * tA);
                Console.WriteLine("{0} \t {1} \t {2}", mouseWorld.X, mouseWorld.Y, mouseWorld.Z);
                // Console.WriteLine(t[0]);
                clickdown = false;
            }
            else if (eng.ThisMouse.RightPressed())
            {
                // Pull the projection and model view matrix from the camera.   
                Matrix4d project = this.camera.GetProjectionMatrix();
                Matrix4d model = this.camera.GetModelViewMatrix();
                Vector3d mousecoord = new Vector3d((double)this.eng.Mouse.X, (double)(this.eng.Height - this.eng.Mouse.Y), 1.0);
                // Unproject the coordinates to convert from mouse to world coordinates
                Vector3d mouseWorld = GameMouse.UnProject(mousecoord, model, project, this.camera.getViewport());
                GameObject objToRemove = null;
                foreach (GameObject obj in objList)
                {
                    if (obj is Obstacle)
                    {
                        if (eng.ThisMouse.inObjectRegion(obj, mouseWorld, enable3d))
                        {
                            objToRemove = (Obstacle)obj;
                            foreach (int key in _xml_obstacle_list.Keys)
                            {
                                if (_xml_obstacle_list[key].Contains(objToRemove.location))
                                {
                                    _xml_obstacle_list[key].Remove(objToRemove.location);
                                }
                            }
                        }
                    }

                    // Remove object if it is an enemy
                    if (obj is Enemy)
                    {
                        if (eng.ThisMouse.inObjectRegion(obj, mouseWorld, enable3d))
                        {
                            objToRemove = obj;
                            foreach (int key in _xml_enemy_list.Keys)
                            {
                                if (_xml_enemy_list[key].Contains(objToRemove.location))
                                {
                                    _xml_enemy_list[key].Remove(objToRemove.location);
                                }
                            }
                        }
                    }
                    //else if (obj is Enemy)
                    //{
                    //    _xml_enemy_list.Remove(obj.location);
                    //    break;
                    //}
                    //else if (obj is Background)
                    //{
                    //    // Set temp BGD properties to the currently selected Background object and then search for a match in the Dictionary
                    //    Background b = (Background)obj;
                    //    BackGroundData bgd;
                    //    bgd._location = obj.location;
                    //    bgd._scale = b.scale;
                    //    bgd._speed = b.Speed;
                    //    bgd._sprite_file = b.Path;

                    //    // ?? Not sure this works, hard to test at the moment so be aware this may be a broken hack...sorry coding blind on this one ...
                    //    foreach (KeyValuePair<BackGroundData, int> pair in _xml_bg_list)
                    //    {
                    //        BackGroundData _b = pair.Key;
                    //        if (_b._location == bgd._location && _b._scale == bgd._scale && _b._speed == bgd._speed && _b._sprite_file.CompareTo(bgd._sprite_file) == 0)
                    //        {
                    //            _xml_bg_list.Remove(_b);
                    //            break;
                    //        }
                    //    }
                    //    break;
                    //}

                }
                if (objToRemove != null)
                {
                    objList.Remove(objToRemove);
                    physList.Remove((PhysicsObject)objToRemove);
                    renderList.Remove((RenderObject)objToRemove);
                }

            }

        }
        private void MoveObjects(GameObject gameObj, Vector3 newLoc)
        {
            if (gameObj == null) return;

            if (gameObj is Obstacle)
            {
                foreach (var key in _xml_obstacle_list.Keys)
                {
                    int xmlIndex;
                    if ((xmlIndex = _xml_obstacle_list[key].FindIndex(q => q == gameObj.location)) != -1)
                    {

                        _xml_obstacle_list[key][xmlIndex] += newLoc;
                    }
                }
                int index = objList.FindIndex(p => p.location == gameObj.location);
                if (index == -1) return;
                objList[index].location += newLoc;
                // Alter the dictionary location when we move objects
            }
            if (gameObj is Enemy)
            {
                foreach (var key in _xml_enemy_list.Keys)
                {
                    int xmlIndex;
                    if ((xmlIndex = _xml_enemy_list[key].FindIndex(q => q == gameObj.location)) != -1)
                    {

                        _xml_enemy_list[key][xmlIndex] += newLoc;
                    }
                }
                int index = objList.FindIndex(p => p.location == gameObj.location);
                if (index == -1) return;
                objList[index].location += newLoc;
                // Alter the dictionary location when we move objects
            }

        }
        public void LoadContent(Device device)
        {
            Light = new EELightShadow(new DVector3(10, 40, 40), new Vector3(2.4f, 2.2f, 2.0f));
            Camera = new EEDCamera(Global.Settings.Width, Global.Settings.Height, 45, 1, 10000);

            //Camera = new EEDCamera(Global.Settings.Width, Global.Settings.Height, 90, 1, 1000);
            Light = new EELightShadow(new DVector3(10, 40, 40), new Vector3(2.4f, 2.2f, 2.0f));
            SkyBox = new EESkyBox();
            SkyBox.Initialize();
            //TestCube_UV2
            //"Content\\Models\\Argon_1_export.material"
            AllObjects.Add(new GameObject("Content\\Models\\Argon_1_export.material"));
            AllObjects.Add(new GameObject("Content\\Models\\Argon_1_export.material"));
            AllObjects.Add(new GameObject("Content\\Models\\TestCube_UV2.material"));

            AllObjects[1].TempSetPos(new DVector3(0, 50, -200));
            AllObjects[2].TempSetPos(new DVector3(-100, -1000, 1000));

            Random R = new Random(1);
            for (int y = 0; y < 10; y++)
            {
                GameObject GO = new GameObject("Content\\Models\\Argon_1_export.material");
                GO.TempSetPos(new DVector3(R.NextDouble(-300, 300), R.NextDouble(-500, 500), R.NextDouble(-500, 500)));
                AllObjects.Add(GO);
            }

            float yawn = (float)Math.PI/ 2f;
            float pitch = 0f;

            Vector3 t_vec = new Vector3(0, 0, 350);
            Quaternion quat = Quaternion.RotationYawPitchRoll((float)yawn, (float)pitch, 0);
            Camera.position = Conversion.ToDoubleVector(Vector3.Transform(t_vec, quat));// +target;
            Camera.quaternion = quat;

            /*
            TS = new List<GSSprite> { };

            R = new Random(2);
            for (int i = 0; i < 1; i++)
            {
                DVector3 t = new DVector3(R.NextDouble(-500, 500), R.NextDouble(-500, 500), R.NextDouble(-500, 500));
                TS.Add(new GSSprite(device, t));
            }*/
            TC1 = ContentManager.LoadTexture2D("Content/Textures/Particl");
            TC2 = ContentManager.LoadTexture2D("Content/Textures/Particl2");
        }