//BSD License
//DXGfx® - http://www.eteractions.com
//Copyright (c) 2005
//by Guillaume Randon
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software
//and associated documentation files (the "Software"), to deal in the Software without restriction,
//including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
//and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
//subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all copies or substantial
//portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
//AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
//DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.IO;
using System.Drawing;
using System.Diagnostics;
using System.Reflection;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.Samples.DirectX.UtilityToolkit;
using System.Xml;
using System.Windows.Forms;

namespace DXGfxLib
{
    /// <summary>
    /// This class is a recent addition to the library. It has been added when I have started to use effect file. This
    /// was a good central place to place a default effect group. Also this class is used from the editor.
    /// </summary>
    public class DXGfxManager
    {
        /// <summary>
        /// Height to use for RayFromScreenPos code and more generally to detect where we have clicked.
        /// This is useful as in the editor the dimension of the window might be different from the resolution of
        /// the framework viewport so we need to get this information from the editor.
        /// In fact the editor will push the current values in these static member variables.
        /// </summary>
        public int height = 640;
        /// <summary>
        /// Height to use for RayFromScreenPos code and more generally to detect where we have clicked.
        /// This is useful as in the editor the dimension of the window might be different from the resolution of
        /// the framework viewport so we need to get this information from the editor.
        /// In fact the editor will push the current values in these static member variables.
        /// </summary>
        public int width = 480;

        /// <summary>
        /// We keep a reference on the Sample Framework instance used in our D3D application.
        /// </summary>
        public Framework frameworkInUse;

        /// <summary>
        /// We also keep a reference to the active D3D device.
        /// </summary>
        public Device d3dDevice;

        public SurfaceDescription backBufferDescription;

        /// <summary>
        /// The default effect group that is going to be used to render a geometry is not stated otherwise.
        /// </summary>
        public EffectGroup defaultEffectGroup = null;

        /// <summary>
        /// At the moment our default effect group is stored in that file.
        /// </summary>
        public string defaultEffectGroupBaseFile = "base.fx";

        /// <summary>
        /// The default for newly created nodes. This will be used to decide if the newly created node should have
        /// useFrustrumCulling setted to true or false. As we are using a hierarchy of nodes, sometime when we are near the
        /// leaves it can be more interesting to avoid making the math to decide to render or not the geometry and just render it.
        /// As when we are nearing the leaves the probability for the geometry to be in the frustrum is raising..
        /// </summary>
        public bool cullNodes = true;

        /// <summary>
        /// We can associate scripts to our scene nodes. To add that functionnality we are using a class called ScriptManager,
        /// we want to have a unique instance of that class per AppDomain and we want to keep a reference to that instance here.
        /// </summary>
        public ScriptManager scriptManager = null;

        /// <summary>
        /// We want to keep a ref on the serializationManager we are going to use to serialize and deserialize scene and scene objects.
        /// </summary>
        public DXGfxLib.Serialization.Manager serializationManager = null;

        /// <summary>
        /// The currently active scene has a name.
        /// </summary>
        public string currentSceneName = "Default Scene";

        /// <summary>
        /// We also want to keep a reference to the currently active OutdoorScene. At the moment the only scene manager
        /// par of this library that is really interesting is the Outdoorscene manager and thus the type of this variable
        /// of course this might change on the future. It is better to relly only on the fact that we have a scene here and
        /// not an OutDoorScene. I recommend that but I don't really do it in my own code so maybe I should not say anything...
        /// Still this might change...
        /// </summary>
        private OutDoorScene outdoorScene = null;

        /// <summary>
        /// Let's keep information somewhere about the file used to store the scene.
        /// </summary>
        public string sceneFile;

        /// <summary>
        /// Let's keep the path to the media folder!
        /// </summary>
        public string mediaFolderPath;

        /// <summary>
        /// We have a SKy from a file.
        /// </summary>
        private string skyFile;

        /// <summary>
        /// We have some water from a bitmap file.
        /// </summary>
        private string waterFile;

        /// <summary>
        /// We also have texture used as a heigth file for our terrain.
        /// </summary>
        private string heigthMapFile;

        //private ShaderFlags shaderFlags = ShaderFlags.Debug | ShaderFlags.SkipOptimization;
        private ShaderFlags shaderFlags = ShaderFlags.NoPreShader;

        public Avatar CurrentAvatar
        {
            get
            {
                if (outdoorScene == null)
                    return null;
                return outdoorScene.CurrentAvatar;
            }
            set
            {
                if (outdoorScene == null)
                    return;
                outdoorScene.CurrentAvatar = value;
            }
        }

        public ThirdPersonCamera CurrentCamera
        {
            get 
            {
                if (outdoorScene == null)
                    return null;
                return outdoorScene.CurrentCamera; 
            }
            set
            {
                if (outdoorScene == null)
                    return;
                outdoorScene.CurrentCamera = value; 
            }
        }

        public Matrix MatView
        {
            get
            {
                if (outdoorScene == null)
                    return Matrix.Identity;
                return outdoorScene.matView;
            }
            set
            {
                if (outdoorScene == null)
                    return;
                outdoorScene.matView = value;
            }
        }

        public Matrix MatProj
        {
            get
            {
                if (outdoorScene == null)
                    return Matrix.Identity;
                return outdoorScene.matProj;
            }
            set
            {
                if (outdoorScene == null)
                    return;
                outdoorScene.matProj = value;
            }
        }

        public IInputHandler CurrentInputHandler
        {
            get
            {
                if (outdoorScene == null)
                    return null;
                return outdoorScene.CurrentInputHandler;
            }
            set
            {
                if (outdoorScene == null)
                    return;
                outdoorScene.CurrentInputHandler = value;
            }
        }

        private static DXGfxManager globalInstance = null;

        /// <summary>
        /// The default constructor for this class. Does not perform much. In fact the true initialisation of this class
        /// happen when the Init(Framework) method is called.
        /// </summary>
        public DXGfxManager()
        {
            if (globalInstance == null)
            {
                globalInstance = this;
            }
            else
            {
                throw new Exception("This is inapropriate! Only one instance of DXGfxManager should exist per process! Use GetGlobalInstance() instead!");
            }
        }

        /// <summary>
        /// This static method will return a ref to the DXGfxManager instance for this process!
        /// </summary>
        /// <returns></returns>
        public static DXGfxManager GetGlobalInstance()
        {
            if (globalInstance == null)
            {
                globalInstance = new DXGfxManager();
            }

            return globalInstance;
        }

        /// <summary>
        /// Called by Init(Framework) for all initialization that are not related to the Framework object.
        /// </summary>
        public void Init()
        {
            scriptManager = new ScriptManager();

            //currentInputHandler = new PointAndClickHandler();

            //currentCamera = new ThirdPersonCamera(); // A model viewing camera
            //// Setup the camera's view parameters
            //currentCamera.SetViewParameters(new Vector3(0.0f, 0.0f, -5.0f), Vector3.Empty);

            serializationManager = new DXGfxLib.Serialization.Manager();
        }

        /// <summary>
        /// This method will clean the scriptManager the input handler and the serializationManager.
        /// This is really the pendant of the Init method.
        /// </summary>
        public void Reset()
        {
            if (scriptManager != null)
            {
                scriptManager.Dispose();
                scriptManager = null;
            }
            if (serializationManager != null)
            {
                serializationManager.Dispose();
                serializationManager = null;
            }
        }

        /// <summary>
        /// Don't forget to call that one.
        /// The library might evolve to be usable both with the sample framework and without it but at the moment at least it
        /// is more usable from it. The below method really need to be called for all functionalities to work correctly.
        /// </summary>
        /// <param name="framework"></param>
        public void Init(Framework framework)
        {
            frameworkInUse = framework;

            // Add handlers for specific device events.
            // If Init method is called directly it is the outside code responsability
            // to call the appropriate DXGfxManager methods on specific device events.
            framework.Disposing += new EventHandler(OnDestroyDevice);
            framework.DeviceLost += new EventHandler(OnLostDevice);
            framework.DeviceCreated += new DeviceEventHandler(OnCreateDevice);
            framework.DeviceReset += new DeviceEventHandler(OnDeviceReset);

            Init();
        }

        /// <summary>
        /// This event will be fired immediately after the Direct3D device has been 
        /// reset, which will happen after a lost device scenario. This is the best location to 
        /// create Pool.Default resources since these resources need to be reloaded whenever 
        /// the device is lost. Resources created here should be released in the OnLostDevice 
        /// event. 
        /// </summary>
        public void OnDeviceReset(object sender, DeviceEventArgs e)
        {
            if (outdoorScene != null)
            {
                if (outdoorScene.CurrentCamera != null)
                {
                    // Setup the camera's view parameters
                    outdoorScene.CurrentCamera.SetViewParameters(new Vector3(0.0f, 0.0f, -5.0f), Vector3.Empty);
                    // Setup the camera's projection parameters
                    float aspectRatio = (float)e.BackBufferDescription.Width / (float)e.BackBufferDescription.Height;
                    outdoorScene.CurrentCamera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, 0.1f, 1000.0f);
                    outdoorScene.CurrentCamera.SetViewParameters(new Vector3(0.0f, 5.0f, -30.0f), new Vector3(0.0f, 0.0f, 0.0f));
                    outdoorScene.CurrentCamera.IsPositionMovementEnabled = true;
                }
            }

            d3dDevice = e.Device;
            backBufferDescription = e.BackBufferDescription;
        }

        /// <summary>
        /// This event function will be called fired after the Direct3D device has 
        /// entered a lost state and before Device.Reset() is called. Resources created
        /// in the OnResetDevice callback should be released here, which generally includes all 
        /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
        /// information about lost devices.
        /// </summary>
        public void OnLostDevice(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// This callback function will be called immediately after the Direct3D device has 
        /// been destroyed, which generally happens as a result of application termination or 
        /// windowed/full screen toggles. Resources created in the OnCreateDevice callback 
        /// should be released here, which generally includes all Pool.Managed resources. 
        /// </summary>
        public void OnDestroyDevice(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// This event will be fired immediately after the Direct3D device has been 
        /// created, which will happen during application initialization and windowed/full screen 
        /// toggles. This is the best location to create Pool.Managed resources since these 
        /// resources need to be reloaded whenever the device is destroyed. Resources created  
        /// here should be released in the Disposing event. 
        /// </summary>
        public void OnCreateDevice(object sender, DeviceEventArgs e)
        {
            d3dDevice = e.Device;
            backBufferDescription = e.BackBufferDescription;

            defaultEffectGroup = new EffectGroup();
            defaultEffectGroup.Set(d3dDevice, defaultEffectGroupBaseFile);
        }

        public void UpdateOutdoorScene(float elapsedTime, double appTime)
        {
            if (outdoorScene == null)
            {
                return;
            }

            outdoorScene.Update(d3dDevice, appTime, elapsedTime);
        }

        public void DrawOutdoorScene()
        {
            //bool beginSceneCalled = false;
            
            if (outdoorScene == null)
            {
                return;
            }

            //try
            //{
                // Clear the render target and the zbuffer 
                d3dDevice.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x00424B79, 1.0f, 0);

                //d3dDevice.BeginScene();
                //beginSceneCalled = true;

                outdoorScene.RenderScene(d3dDevice, outdoorScene.currentFrustrum);
            //}
            //finally
            //{
            //    if (beginSceneCalled)
            //        d3dDevice.EndScene();
            //}
        }

        /// <summary>
        /// If we want we can ask DXGfxManager to load a FrameworkMesh for us.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public FrameworkMesh FrameworkMeshFromFile(string fileName)
        {
            if (d3dDevice == null)
            {
                throw new Exception("d3dDevice is null, loading of a FrameworkMesh is impossible without a valid device!");
            }
            return new FrameworkMesh(d3dDevice, fileName);
        }

        /// <summary>
        /// We can ask DXGfxManager to create a new fresh scene for us.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="size"></param>
        /// <param name="quadtreeLevels"></param>
        /// <returns></returns>
        public OutDoorScene NewScene(string name, float size, int quadtreeLevels)
        {
            AABBox desiredBBox = new AABBox(new BBox(new Vector3(0.0f, 0.0f, 0.0f), size));
            outdoorScene = new OutDoorScene(desiredBBox, quadtreeLevels);

            outdoorScene.sceneContent.Remove(currentSceneName);
            outdoorScene.sceneContent.Add(name, outdoorScene);
            currentSceneName = name;

            outdoorScene.name = StringUtil.GetName(name);

            return outdoorScene;
        }

        public void SetScene(OutDoorScene outdoor)
        {
            this.outdoorScene = outdoor;
        }

        public void CloseScene()
        {
            if (outdoorScene != null)
            {
                outdoorScene.Dispose();
                outdoorScene = null;
            }

            // Let's do this, it is safer !!
            Reset();
            Init();
        }

        /// <summary>
        /// Use this method if you want to get access to the content of the scene.
        /// </summary>
        /// <returns></returns>
        public Hashtable GetSceneContent()
        {
            return outdoorScene.sceneContent;
        }

        /// <summary>
        /// By calling this method we will instruct our OutdoorScene to load a heightmap to create an associated terrain.
        /// </summary>
        /// <param name="fileName"></param>
        public void SetHeightMap(string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            outdoorScene.LoadTerrain(fileName);

            heigthMapFile = fileName;
        }

        /// <summary>
        /// Guess what, with this method we are going to create some water at height 0, with extend 1000, 10 segments and
        /// the texture referenced by fileName.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public Water2 SetWater(string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            Water2 theWater = new Water2(1000);
            outdoorScene.SceneWater = theWater;
            theWater.name = "Water";
            theWater.fileName = fileName;

            waterFile = fileName;

            outdoorScene.sceneContent.Add(fileName, theWater);

            return theWater;
        }

        /// <summary>
        /// By calling this method we will load the X file passed in argument and we will use that geometry as a SkyBox, I mean
        /// it will move with the camera.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public SkyDome SetSky(string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            SkyDome theSky = new SkyDome();
            theSky.LoadFromFile(this.d3dDevice, fileName);
            outdoorScene.SceneSky = theSky;
            theSky.name = "theSky";
            theSky.fileName = fileName;

            skyFile = fileName;

            outdoorScene.sceneContent.Add(fileName, theSky);

            return theSky;
        }

        /// <summary>
        /// This method can be used to Load a Mesh from an X file.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public SceneObject LoadObject(string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            MeshObject sceneObject = new MeshObject(d3dDevice, fileName);
            outdoorScene.Attach(sceneObject);

            if (outdoorScene.sceneContent.Contains(fileName))
            {
                // We already have one object with the same name so let's rename our object !!
                sceneObject.name += "I";
            }
            outdoorScene.sceneContent.Add(sceneObject.name, sceneObject);

            return sceneObject;
        }

        /// <summary>
        /// This method allow the creation of a SceneObject of a specific Type that will load its data from the specified file.
        /// Basically we will create an empty instance of that type and call its LoadFromFile method passing the fileName as
        /// an argument. If the LoadFromFile method is not implemented for that type unexpected things can happen, becarefull.
        /// </summary>
        /// <param name="desiredType"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public SceneObject LoadObject(Type desiredType, string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            ConstructorInfo ctor = desiredType.GetConstructor(new Type[] { });
            Object[] args = new Object[] { };
            Object obj = ctor.Invoke(args);

            if (obj == null)
            {
                throw new Exception("Non creatable type !!");
            }

            SceneObject sobj = obj as SceneObject;

            if (sobj == null)
            {
                throw new Exception("Type doesn't derive from SceneObject this is wrong!!");
            }

            if (File.Exists(fileName))
            {
                sobj.LoadFromFile(d3dDevice, fileName);
            }
            outdoorScene.Attach(sobj);

            if (outdoorScene.sceneContent.Contains(fileName))
            {
                // We already have one object with the same name so let's rename our object !!
                sobj.name += "I";
            }
            outdoorScene.sceneContent.Add(sobj.name, sobj);

            return sobj;
        }

        public void LoadEffect(Device device, string file, ref Effect effOut)
        {
            // Read the D3DX effect file
            if (!File.Exists(file))
            {
                OpenFileDialog ofdlg = new OpenFileDialog();
                ofdlg.Title = file + " not found. Select it!";

                if (ofdlg.ShowDialog() == DialogResult.OK)
                {
                    file = ofdlg.FileName;
                }
            }
            
            string effError;

            effOut = ResourceCache.GetGlobalInstance().CreateEffectFromFile(device,
            file, null, null, shaderFlags, null, out effError);

            if (!effError.Equals(""))
            {
                MessageBox.Show(effError);
            }
        }

        public Effect LoadEffect(Device device, string file)
        {
            Effect newEff = null;
            LoadEffect(device, file, ref newEff);

            return newEff;
        }
        /// <summary>
        /// You know the name of an object and you want to get a reference to it. THen you can use this method.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public Object GetObj(string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            return outdoorScene.sceneContent[fileName];
        }

        /// <summary>
        /// This should return a scene object if we have one with the matching fileName or name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public SceneObject GetSceneObject(string fileName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            SceneObject sceneObj = outdoorScene.sceneContent[fileName] as SceneObject;
            return sceneObj;
        }

        /// <summary>
        /// This method throws back a reference to the scene.
        /// </summary>
        /// <returns></returns>
        public Scene GetScene()
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            return outdoorScene;
        }

        /// <summary>
        /// This method will save scene information in the specified XML file. The scene is not serialized to that file as one
        /// might expect, instead this method contains the logic to query the appropriate member variables to get all the information
        /// needed on the scene in order to be able to built it again.
        /// Serialization is a very nice mechanism but it can be sometime a lot of work to use it nicely to support versionning
        /// without trouble. You have to use things like Serialization surrogates (very good articles from Jefrey Richter on that
        /// in MSDN) but for the moment it was quicker to implement save functionnality as I did below.
        /// </summary>
        /// <param name="dstFullPathName"></param>
        public void Save(string dstFullPathName)
        {
            if (outdoorScene == null)
            {
                throw new NullReferenceException("The is no outdoorScene at this stage so this method can not be called!");
            }

            //// We save heighmap, textures, water, skybox and then per entity file, positions orientation and script!
            //XmlWriter writer = XmlWriter.Create(dstFullPathName);

            //writer.WriteStartElement("Scene");
            //writer.WriteAttributeString("Name", "DefaultSceneName!");

            //writer.WriteElementString("HeigthMap", heigthMapFile);

            //IDictionaryEnumerator sceneEnumerator = outdoorScene.sceneContent.GetEnumerator();

            //writer.WriteStartElement("SceneContent");
            //while (sceneEnumerator.MoveNext())
            //{
            //    SceneObject sceneObj = sceneEnumerator.Value as SceneObject;

            //    if (sceneObj != null)
            //    {
            //        writer.WriteStartElement(StringUtil.GetName(sceneObj.name));
            //        writer.WriteAttributeString("Type", sceneObj.GetType().ToString());
            //        writer.WriteAttributeString("Name", sceneObj.name);
            //        writer.WriteAttributeString("FileName", sceneObj.fileName);
            //        writer.WriteAttributeString("X", sceneObj.X.ToString());
            //        writer.WriteAttributeString("Y", sceneObj.Y.ToString());
            //        writer.WriteAttributeString("Z", sceneObj.Z.ToString());
            //        writer.WriteAttributeString("Yaw", sceneObj.Yaw.ToString());
            //        writer.WriteAttributeString("Pitch", sceneObj.Pitch.ToString());
            //        writer.WriteAttributeString("Roll", sceneObj.Roll.ToString());
            //        string varSrc = "";
            //        string codeSrc = "";
            //        string onClickSrc = "";
            //        string onCollSrc = "";
            //        if (sceneObj.OurScript != null)
            //        {
            //            varSrc = sceneObj.OurScript.GetVarSrc();
            //            codeSrc = sceneObj.OurScript.GetCodeSrc();
            //            onClickSrc = sceneObj.OurScript.GetClickCodeSrc();
            //            onCollSrc = sceneObj.OurScript.GetCollisionCodeSrc();
            //        }
            //        writer.WriteAttributeString("VarSrc", varSrc);
            //        writer.WriteAttributeString("CodeSrc", codeSrc);
            //        writer.WriteAttributeString("OnClickSrc", onClickSrc);
            //        writer.WriteAttributeString("OnCollSrc", onCollSrc);
            //        writer.WriteEndElement();
            //    }
            //}
            //writer.WriteEndElement();
            //writer.WriteEndElement();
            //writer.Flush();
            //writer.Close();

            DXGfxLib.Serialization.Manager.GetGlobalInstance().SaveScene(outdoorScene, dstFullPathName);
        }

        /// <summary>
        /// This will load a scene from a previously saved scene. It will also extract the path to the media folder (a folder
        /// called Media in the xml file folder).
        /// </summary>
        /// <param name="fullPathName"></param>
        public void Load(string fullPathName)
        {
            string mediaFolder = StringUtil.GetPath(fullPathName);
            mediaFolder += "Media";

            Load(fullPathName, mediaFolder);
        }

        /// <summary>
        /// This will load a scene from a previously saved scene to an XML file. It will perform all the work neede to load all
        /// the ressources associated with the objects that are part of the scene. It should also load scripts associated with
        /// instances...
        /// </summary>
        /// <param name="fullPathName"></param>
        /// <param name="mediaFolder"></param>
        public void Load(string fullPathName, string mediaFolder)
        {
            //string currentFolder = Directory.GetCurrentDirectory();
            //Directory.SetCurrentDirectory(mediaFolder);

            //XmlReader reader = XmlReader.Create(fullPathName);

            //reader.ReadStartElement("Scene");

            //NewScene(reader.Name, 1000, 4);

            //heigthMapFile = reader.ReadElementString("HeigthMap");
            //if (File.Exists(heigthMapFile))
            //{
            //    SetHeightMap(heigthMapFile);
            //}

            //reader.ReadStartElement("SceneContent");

            //do
            //{
            //    if (reader.HasAttributes)
            //    {

            //        reader.MoveToAttribute("Type");
            //        Type type = Type.GetType(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("Name");
            //        string name = reader.Value;
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("FileName");
            //        string fileName = reader.Value;
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("X");
            //        float X = float.Parse(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("Y");
            //        float Y = float.Parse(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("Z");
            //        float Z = float.Parse(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("Yaw");
            //        float Yaw = float.Parse(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("Pitch");
            //        float Pitch = float.Parse(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("Roll");
            //        float Roll = float.Parse(reader.Value);
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("VarSrc");
            //        string VarSrc = reader.Value;
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("CodeSrc");
            //        string CodeSrc = reader.Value;
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("OnClickSrc");
            //        string onClickSrc = reader.Value;
            //        reader.MoveToElement();

            //        reader.MoveToAttribute("OnCollSrc");
            //        string onCollSrc = reader.Value;
            //        reader.MoveToElement();

            //        if (name == "theSky")
            //        {
            //            if (File.Exists(fileName))
            //            {
            //                SkyBox sky = SetSky(fileName);
            //                sky.Position = new Vector3(X, Y, Z);
            //                sky.Orientation = new Vector3(Yaw, Pitch, Roll);

            //                Script script = sky.GetScript();
            //                script.UpdateVarSrc(VarSrc);
            //                script.UpdateCodeSrc(CodeSrc);
            //                script.UpdateClickCodeSrc(onClickSrc);
            //                script.UpdateCollisionCodeSrc(onCollSrc);
            //            }
            //        }
            //        else if (name == "Water")
            //        {
            //            if (File.Exists(fileName))
            //            {
            //                Water water = SetWater(fileName);
            //                water.Position = new Vector3(X, Y, Z);
            //                water.Orientation = new Vector3(Yaw, Pitch, Roll);

            //                Script script = water.GetScript();
            //                script.UpdateVarSrc(VarSrc);
            //                script.UpdateCodeSrc(CodeSrc);
            //                script.UpdateClickCodeSrc(onClickSrc);
            //                script.UpdateCollisionCodeSrc(onCollSrc);
            //            }
            //        }
            //        else if (type != null)
            //        {
            //            if (File.Exists(fileName))
            //            {
            //                SceneObject sobj = LoadObject(type, fileName);

            //                sobj.Position = new Vector3(X, Y, Z);
            //                sobj.Orientation = new Vector3(Yaw, Pitch, Roll);

            //                Script script = sobj.GetScript();
            //                script.UpdateVarSrc(VarSrc);
            //                script.UpdateCodeSrc(CodeSrc);
            //                script.UpdateClickCodeSrc(onClickSrc);
            //                script.UpdateCollisionCodeSrc(onCollSrc);
            //            }
            //        }
            //    }
            //} while (reader.Read());
            //Directory.SetCurrentDirectory(currentFolder);

            sceneFile = fullPathName;
            mediaFolderPath = mediaFolder;

            outdoorScene = DXGfxLib.Serialization.Manager.GetGlobalInstance().LoadOutdoor(fullPathName);
            // We now have a fully functionnal outdoorscene. Let's really load the data.
            string currentFolder = Directory.GetCurrentDirectory();
            Directory.SetCurrentDirectory(mediaFolder);
            if (outdoorScene.SceneTerrain != null)
            {
                if (File.Exists(outdoorScene.SceneTerrain.heightmapFile))
                {
                    outdoorScene.SceneTerrain.LoadFromFile(DXGfxManager.GetGlobalInstance().d3dDevice, (OutDoorScene)DXGfxManager.GetGlobalInstance().GetScene(), outdoorScene.SceneTerrain.heightmapFile);
                }
            }
            // Let's ask the whole scene to get prepared !!
            outdoorScene.GetPrepared();

            Directory.SetCurrentDirectory(currentFolder);
        }

        /// <summary>
        /// This method will call the Evaluate method on all Scene objects in the scene and the scene itself.
        /// </summary>
        /// <param name="appTime"></param>
        /// <param name="elapsedTime"></param>
        public void CallEvaluation(double appTime, float elapsedTime)
        {
            IDictionaryEnumerator sceneEnum = outdoorScene.sceneContent.GetEnumerator();

            /// TODO : Rewrite this more cleanly when IScriptableObject interface has been added.
            while (sceneEnum.MoveNext())
            {
                SceneObject sceneObj = sceneEnum.Value as SceneObject;

                if (sceneObj != null)
                {
                    sceneObj.Evaluate(appTime, elapsedTime);
                    continue;
                }

                Scene scene = sceneEnum.Value as Scene;

                if (scene != null)
                {
                    scene.Evaluate(appTime, elapsedTime);
                    continue;
                }
            }
        }
    }
}
