using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using GE.Visualisation;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using GFXEditor.Level;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace GFXEditor
{
    public partial class wndLevel : Form
    {
        enum eUserMode
        {
            eAddSprite,
            eMoveSprite,
            eMovePlayer,
            eNone,
            eAddPlatform,
            eSelectedPlatform,
            eResizePlatformTop,
            eResizePlatformBottom,
            eResizePlatformLeft,
            eResizePlatformRight,
            eAddLadder,
            eSelectedLadder,
            eResizeLadderTop,
            eResizeLadderBottom,
            eResizeLadderLeft,
            eResizeLadderRight,
            eAddSpike,
            eSelectedSpike,
            eResizeSpikeTop,
            eResizeSpikeLeft,
            eResizeSpikeRight,
            eResizeSpikeBottom,
            eAddEntity,
            eSelectedEntity,
            eMoveEntity,
            eModeCount
        }

        enum eSelectionMode
        {
            eSelectSprite,
            eSelectPlatform,
            eSelectLadder,
            eSelectSpike,
            eSelectEntity,
            eSelectNone,
            eSelectCount
        }
        #region Variable

        /// <summary>
        /// The selection mode currently used by the user
        /// </summary>
        eSelectionMode _selectionMode;

        /// <summary>
        /// Reference to a new entity created
        /// </summary>
        object _newEntity;

        /// <summary>
        /// Flag set when the first point of a new rectangle is setted
        /// </summary>
        bool _bFirstPointAdded;

        /// <summary>
        /// The temp rectangle used when a new rectangle is created
        /// </summary>
        Rectangle _newRectangle;

        /// <summary>
        /// Level width
        /// </summary>
        const int LEVEL_WIDTH = 10000;

        /// <summary>
        /// Level Height
        /// </summary>
        const int LEVEL_HEIGHT = 10000;

        /// <summary>
        /// The zoom level used
        /// </summary>
        int _iZoom;

        string _filename;
        Vector2[] _v2PlayerRectangle;
        Vector2[] _v2PlayerRectangleScreen;
        Entity _addedEntity;
        eUserMode _userMode;
        Vector2 _v2CameraPosition;

        /// <summary>
        /// Level object
        /// </summary>
        Level.Level _level;

        /// <summary>
        /// Timer used to refresh the screen
        /// </summary>
        Timer _refreshScreenTimer;

        /// <summary>
        /// Visualisation component for the level
        /// </summary>
        Visu _visuLevel;

        /// <summary>
        /// Presentation parameters for the level
        /// </summary>
        PresentationParameters _param;

        /// <summary>
        /// Level's graphic device
        /// </summary>
        GraphicsDevice _device;

        /// <summary>
        /// List of loaded sprites
        /// </summary>
        List<comboBoxItem> _spriteListComboBoxItem;

        int _iIdTextureSelectedSprite;
        int _iIdSpriteSelectedSprite;

        /// <summary>
        /// Id of the selected element in the level
        /// </summary>
        int _iIdSelectedElementInLevel;

        /// <summary>
        /// List of panel to diaply entity info
        /// </summary>
        Dictionary<string, panelEntity> _listPanelEntity;

        /// <summary>
        /// List of all the editor version of the entities types
        /// </summary>
        Dictionary<string, Type> _listEditorEntityType;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor. Create a new level
        /// </summary>
        public wndLevel()
        {
            InitializeComponent();

            //initialise data
            _iZoom = 1;
            _filename = "";
            VScrollBarLevel.Maximum = LEVEL_HEIGHT - panelLevel.Height;
            HScrollBarLevel.Maximum = LEVEL_WIDTH - panelLevel.Width;
            _iIdSelectedElementInLevel = -1;
            _addedEntity = null;
            _userMode = eUserMode.eNone;
            _spriteListComboBoxItem = new List<comboBoxItem>();
            _iIdTextureSelectedSprite = -1;
            _iIdSpriteSelectedSprite = -1;
            _v2CameraPosition = new Vector2(0);
            gbEntity.Visible = false;
            _listPanelEntity = new Dictionary<string, panelEntity>();
            _listEditorEntityType = new Dictionary<string, Type>();
            _selectionMode = eSelectionMode.eSelectSprite;

            //fill the selection mode combo box
            tscbSelection.Items.Add("Sprite");
            tscbSelection.Items.Add("Platform");
            tscbSelection.Items.Add("Ladder");
            tscbSelection.Items.Add("Spike");
            tscbSelection.Items.Add("Entity");
            tscbSelection.SelectedIndex = 0;

            //create the visualisation component
            _param = new PresentationParameters();
            _param.DeviceWindowHandle = panelLevel.Handle;
            _param.IsFullScreen = false;
            _device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.HiDef, _param);
            //_spriteBatchLevel = new SpriteBatch(_device);
            _visuLevel = new Visu();
            _visuLevel.init(_device);
            _level = new Level.Level(_visuLevel);

            //create the visualisation for the sprites
            //_paramSprite = new PresentationParameters();
            //_paramSprite.DeviceWindowHandle = panelSprite.Handle;
            //_paramSprite.IsFullScreen = false;
            //_deviceSprite = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.HiDef, _paramSprite);
            //_deviceSprite.Reset(
            //_spriteBatchSprite = new SpriteBatch(_deviceSprite);
            //_visuSprite = new Visu();
            //_visuSprite.init(_deviceSprite);

            //create the timer
            _refreshScreenTimer = new Timer();
            _refreshScreenTimer.Interval = 1000 / 60;
            _refreshScreenTimer.Tick += new System.EventHandler(_refreshScreenTimer_Tick);
            _refreshScreenTimer.Start();

            //create the player rectangle
            _v2PlayerRectangle = new Vector2[4];
            _v2PlayerRectangle[0] = new Vector2(0);
            _v2PlayerRectangle[1] = new Vector2(30, 0);
            _v2PlayerRectangle[2] = new Vector2(30, 30);
            _v2PlayerRectangle[3] = new Vector2(0, 30);
            _v2PlayerRectangleScreen = new Vector2[4];

            createEditorEntity();
        }

        /// <summary>
        /// Constructor. Load a level
        /// </summary>
        /// <param name="filename">Level to load</param>
        public wndLevel(string filename) : this()
        {
            
            load(filename);
            Text = "Level " + filename;
            tstbLevelName.Text = _level._name;

            
        }

        private void createEditorEntity()
        {
            //create assembly
            AssemblyName aname = new AssemblyName("EditorEntities.dll");
            AppDomain currentDomain = AppDomain.CurrentDomain; // Thread.GetDomain();
            AssemblyBuilder asmBuilder = currentDomain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.Run);

            //create the module
            ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("GameEntities");

            //create a list of entities
            string strEntitiesFolder = Program.m_Options.SrcRoot;
            string[] sourceFiles = Directory.GetFiles(strEntitiesFolder, "*.cs", SearchOption.AllDirectories);

            //create a c# compiler
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters compilerParams = new CompilerParameters();
            compilerParams.CompilerOptions = "/target:library";
            compilerParams.GenerateExecutable = false;
            compilerParams.GenerateInMemory = true;
            compilerParams.IncludeDebugInformation = false;
            compilerParams.ReferencedAssemblies.Add("System.dll");
            compilerParams.ReferencedAssemblies.Add("System.Core.dll");
            compilerParams.ReferencedAssemblies.Add("System.Xml.dll");
            compilerParams.ReferencedAssemblies.Add("Microsoft.Xna.Framework.dll");
            compilerParams.ReferencedAssemblies.Add("Microsoft.Xna.Framework.GamerServices.dll");
            compilerParams.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Graphics.dll");
            compilerParams.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Game.dll");

            //compile
            CompilerResults res = provider.CompileAssemblyFromFile(compilerParams, sourceFiles);

            //display the first error
            if (res.Errors.HasErrors)
            {
                MessageBox.Show(res.Errors[0].ErrorText);
                return;
            }

            TypeBuilder typeBuilder = null;

            //go throught each type
            System.Type[] t = res.CompiledAssembly.GetTypes();
            foreach (System.Type currentType in t)
            {
                //parse only the entities
                if (currentType.Namespace == "GE.World.Entities" && currentType.IsClass)
                {

                    panelEntity newPanelEntity = new panelEntity(currentType.Name);

                    //create a class
                    typeBuilder = modBuilder.DefineType("Editor" + currentType.Name, TypeAttributes.Public);

                    string strEditorTileset = "";
                    string strEditorSprite = "";
                    object e = null;
                    if (currentType.IsAbstract)
                        continue;

                    try
                    {
                        e = Activator.CreateInstance(currentType);
                    }
                    catch (Exception ex)
                    {
                        //MessageBox.Show(ex.Message);
                        continue;    
                    }
                    

                    cbEntityType.Items.Add(currentType.Name);
                    _listPanelEntity.Add(currentType.Name, newPanelEntity);

                    //go through each properties to add controls
                    PropertyInfo[] properties = currentType.GetProperties();
                    foreach (PropertyInfo p in properties)
                    {
                        if (p.Name == "EDITOR_TILESET")
                            strEditorTileset = (string)p.GetValue(e, null);
                        else if (p.Name == "EDITOR_SPRITE")
                            strEditorSprite = (string)p.GetValue(e, null);

                        if (!p.CanWrite) continue;

                        //handle the enumeration types
                        if (p.PropertyType.IsEnum)
                        {
                            ComboBox newComboBoxEnum = new ComboBox();
                            newComboBoxEnum.Tag = p.Name;
                            newPanelEntity.addControl(p.Name, newComboBoxEnum);
                            Type ty = p.PropertyType.GetEnumUnderlyingType();
                            newComboBoxEnum.Items.AddRange( p.PropertyType.GetEnumNames());
                            newComboBoxEnum.SelectedIndexChanged += new EventHandler(newComboBoxEnum_SelectedIndexChanged);
                           // continue;
                        }

                        switch (p.PropertyType.Name)
                        {
                            case "Rectangle":
                                TextBox newTextBoxRecX = new TextBox();
                                newTextBoxRecX.Tag = p.Name + " X";
                                newPanelEntity.addControl(p.Name + " X : ", newTextBoxRecX);
                                newTextBoxRecX.TextChanged += new EventHandler(newTextBoxRecX_TextChanged);

                                TextBox newTextBoxRecY = new TextBox();
                                newTextBoxRecY.Tag = p.Name + " Y";
                                newPanelEntity.addControl(p.Name + " Y : ", newTextBoxRecY);
                                newTextBoxRecY.TextChanged += new EventHandler(newTextBoxRecY_TextChanged);

                                TextBox newTextBoxRecWidth = new TextBox();
                                newTextBoxRecWidth.Tag = p.Name + " Width";
                                newPanelEntity.addControl(p.Name + " Width : ", newTextBoxRecWidth);
                                newTextBoxRecWidth.TextChanged += new EventHandler(newTextBoxRecWidth_TextChanged);

                                TextBox newTextBoxRecHeight = new TextBox();
                                newTextBoxRecHeight.Tag = p.Name + " Height";
                                newPanelEntity.addControl(p.Name + " Height : ", newTextBoxRecHeight);
                                newTextBoxRecHeight.TextChanged += new EventHandler(newTextBoxRecHeight_TextChanged);
                                break;

                            case "Vector2":
                                TextBox newTextBoxX = new TextBox();
                                newTextBoxX.Tag = p.Name+" X";
                                newPanelEntity.addControl(p.Name + " X : ", newTextBoxX);
                                newTextBoxX.TextChanged += new EventHandler(newTextBoxX_TextChanged);
                                TextBox newTextBoxY = new TextBox();
                                newTextBoxY.Tag = p.Name+" Y";
                                newPanelEntity.addControl(p.Name + " Y : ", newTextBoxY);
                                newTextBoxY.TextChanged += new EventHandler(newTextBoxY_TextChanged);
                                break;

                            case "Boolean":
                                CheckBox newCheckBox = new CheckBox();
                                newCheckBox.Text = "";
                                newCheckBox.Tag = p.Name;
                                newPanelEntity.addControl(p.Name, newCheckBox);
                                newCheckBox.CheckedChanged += new EventHandler(newCheckBox_CheckedChanged);
                                break;

                            case "Int32":
                                TextBox newTextBoxInt32 = new TextBox();
                                newTextBoxInt32.Tag = p.Name;
                                newPanelEntity.addControl(p.Name, newTextBoxInt32);
                                newTextBoxInt32.TextChanged += new EventHandler(newTextBoxInt32_TextChanged);
                                break;

                            case "Single":
                                TextBox newTextBoxSingle = new TextBox();
                                newTextBoxSingle.Tag = p.Name;
                                newPanelEntity.addControl(p.Name, newTextBoxSingle);
                                newTextBoxSingle.TextChanged += new EventHandler(newTextBoxSingle_TextChanged);
                                break;
                        }

                        //create the field
                        typeBuilder.DefineField(p.Name, p.PropertyType, FieldAttributes.Public);
                    }

                    //add graphic variables
                    typeBuilder.DefineField("EDITOR_TILESET", typeof(int), FieldAttributes.Public | FieldAttributes.Static);
                    typeBuilder.DefineField("EDITOR_SPRITE", typeof(int), FieldAttributes.Public | FieldAttributes.Static);

                    //store the type
                    _listEditorEntityType.Add("Editor" + currentType.Name, typeBuilder.CreateType());

                    //load and set graphics variables
                    int iTileset = 0;
                    int iSprite = 0;
                    if (strEditorTileset != "")
                    {
                        string AbsoluteTilesetPath = Path.Combine(Program.m_Options.DataRoot, strEditorTileset);
                        iTileset = _visuLevel.loadTileset(AbsoluteTilesetPath);
                        iSprite = _visuLevel.getSpriteId(iTileset, strEditorSprite);
                    }
                    Type myType = _listEditorEntityType["Editor" + currentType.Name];
                    myType.GetField("EDITOR_TILESET").SetValue(null, iTileset);
                    myType.GetField("EDITOR_SPRITE").SetValue(null, iSprite);

                    newPanelEntity._layout.Size = newPanelEntity._layout.PreferredSize;

                }
            }
        }

        /// <summary>
        /// Change the enumeration value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newComboBoxEnum_SelectedIndexChanged(object sender, EventArgs e)
        {
            //get the combo box and the field name
            ComboBox cb = (ComboBox)sender;
            string tag = (string)cb.Tag;

            //get the selected entity
            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            //get the field
            FieldInfo field = entity.GetType().GetField(tag);
            if (field == null) return;

            //set the value
            field.SetValue(entity, Enum.Parse(field.FieldType, (string)cb.SelectedItem)); 

        }

        /// <summary>
        /// Change the height of a rectangle
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxRecHeight_TextChanged(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            tag = tag.Substring(0, tag.Length - 7);

            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Rectangle currentValue = (Rectangle)f.GetValue(entity);
                    float newValue = 0;
                    bool res = float.TryParse(tb.Text, out newValue);
                    if (!res) return;
                    currentValue.Height = (int)newValue;
                    f.SetValue(entity, currentValue);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the width of a rectangle
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxRecWidth_TextChanged(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            tag = tag.Substring(0, tag.Length - 6);

            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Rectangle currentValue = (Rectangle)f.GetValue(entity);
                    float newValue = 0;
                    bool res = float.TryParse(tb.Text, out newValue);
                    if (!res) return;
                    currentValue.Width = (int)newValue;
                    f.SetValue(entity, currentValue);
                    return;
                }
            }
        }

        /// <summary>
        /// change the y coordinate of a rectangle
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxRecY_TextChanged(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            tag = tag.Substring(0, tag.Length - 2);

            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Rectangle currentValue = (Rectangle)f.GetValue(entity);
                    float newValue = 0;
                    bool res = float.TryParse(tb.Text, out newValue);
                    if (!res) return;
                    currentValue.Y = (int)newValue;
                    f.SetValue(entity, currentValue);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the x value for a rectangle
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxRecX_TextChanged(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            tag = tag.Substring(0, tag.Length - 2);

            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Rectangle currentValue = (Rectangle)f.GetValue(entity);
                    float newX = 0;
                    bool res = float.TryParse(tb.Text, out newX);
                    if (!res) return;
                    currentValue.X = (int)newX;
                    f.SetValue(entity, currentValue);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the value for a single field
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxSingle_TextChanged(object sender, EventArgs e)
        {
            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;

            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Single newSingle = 0;
                    bool res = Single.TryParse(tb.Text, out newSingle);
                    if (!res) return;
                    f.SetValue(entity, newSingle);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the value of a integer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxInt32_TextChanged(object sender, EventArgs e)
        {
            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;

            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    int newInt = 0;
                    bool res = int.TryParse(tb.Text, out newInt);
                    if(!res) return;
                    f.SetValue(entity, newInt);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the value of a check box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;

            CheckBox tb = (CheckBox)sender;
            string tag = (string)tb.Tag;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    f.SetValue(entity, tb.Checked);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the value for the vector2 y component
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxY_TextChanged(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            tag = tag.Substring(0, tag.Length - 2);

            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Vector2 currentValue = (Vector2)f.GetValue(entity);
                    float newY = 0;
                    bool res = float.TryParse(tb.Text, out newY);
                    if (!res) return;
                    currentValue.Y = newY;
                    f.SetValue(entity, currentValue);
                    return;
                }
            }
        }

        /// <summary>
        /// Change the value for a Vector2 x component
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void newTextBoxX_TextChanged(object sender, EventArgs e)
        {
            TextBox tb = (TextBox)sender;
            string tag = (string)tb.Tag;
            tag = tag.Substring(0, tag.Length - 2);

            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;
            object entity = _level._listEntity[_iIdSelectedElementInLevel];

            FieldInfo[] fields = entity.GetType().GetFields();
            foreach (FieldInfo f in fields)
            {
                if (f.Name == tag)
                {
                    Vector2 currentValue = (Vector2)f.GetValue(entity);
                    float newX = 0;
                    bool res = float.TryParse(tb.Text, out newX);
                    if(!res) return;
                    currentValue.X = newX;
                    f.SetValue(entity, currentValue);
                    return;
                }
            }
        }

        #endregion

        #region Tools

        /// <summary>
        /// Compute the max value of the horizontal scroll bar
        /// </summary>
        private void computeHScrollMax()
        {
            HScrollBarLevel.Maximum = (LEVEL_WIDTH * _iZoom - panelLevel.Width);
        }

        /// <summary>
        /// Compute the maximum value if the vertical scroll bar
        /// </summary>
        private void computeVScrollMax()
        {
            VScrollBarLevel.Maximum = (LEVEL_HEIGHT * _iZoom - panelLevel.Height);
        }

        /// <summary>
        /// Compute a new scroll bar position when the zoom changed
        /// </summary>
        /// <param name="oldZoom"></param>
        /// <param name="newZoom"></param>
        private void computeScrollPosition(int oldZoom, int newZoom, int oldHValue, int oldVValue)
        {
            int scroll = oldHValue / oldZoom;
            scroll = scroll * newZoom;
            if (scroll > HScrollBarLevel.Maximum)
                HScrollBarLevel.Value = HScrollBarLevel.Maximum;
            else
                HScrollBarLevel.Value = scroll;

            scroll = oldVValue / oldZoom;
            scroll = scroll * newZoom;
            if (scroll > VScrollBarLevel.Maximum)
                VScrollBarLevel.Value = VScrollBarLevel.Maximum;
            else
                VScrollBarLevel.Value = scroll;
        }

        #endregion

        #region Slots

        /// <summary>
        /// Increase the zoom
        /// </summary>
        private void zoomIn()
        {
            if (_iZoom >= 8) return;

            int oldZoom = _iZoom;
            _iZoom *= 2;
            int oldHValue = HScrollBarLevel.Value;
            int oldVValue = VScrollBarLevel.Value;

            computeHScrollMax();
            computeVScrollMax();

            computeScrollPosition(oldZoom, _iZoom, oldHValue, oldVValue);
        }


        /// <summary>
        /// Decrease the zoom
        /// </summary>
        private void zoomOut()
        {
            if (_iZoom <= 1) return;

            int oldZoom = _iZoom;
            _iZoom = (int)(_iZoom * 0.5f);
            int oldHValue = HScrollBarLevel.Value;
            int oldVValue = VScrollBarLevel.Value;

            computeHScrollMax();
            computeVScrollMax();

            computeScrollPosition(oldZoom, _iZoom, oldHValue, oldVValue);
        }

        #endregion
        /// <summary>
        /// Refresh the screen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _refreshScreenTimer_Tick(object sender, System.EventArgs e)
        {
            renderLevel();
            renderSprite();
        }

        /// <summary>
        /// Render the level
        /// </summary>
        private void renderLevel()
        {
           
            _visuLevel.preRender( false);
            if (_visuLevel.Error) return;

            Vector2 Camera = _v2CameraPosition;

            //dra a new entity
            if (_userMode == eUserMode.eAddEntity)
            {

                Vector2 worldPos = (Vector2)_newEntity.GetType().GetField("Position").GetValue(_newEntity);
                Vector2 position = (worldPos * _iZoom) - Camera;

                int idTexture = (int)_newEntity.GetType().GetField("EDITOR_TILESET").GetValue(null);
                int idSprite = (int)_newEntity.GetType().GetField("EDITOR_SPRITE").GetValue(null);
                _visuLevel.displaySprite( idTexture, idSprite, position, SpriteEffects.None, new Vector2(_iZoom, _iZoom));
            }

            //draw a new sprite
            if (_userMode == eUserMode.eAddSprite)
            {
                Vector2 position = (_addedEntity._position * _iZoom) - Camera;
                _visuLevel.displaySprite( _addedEntity._idTexture, _addedEntity._idSprite, position, SpriteEffects.None, new Vector2(_iZoom, _iZoom));
            }

            //draw the level
            foreach (Entity e in _level._listSprite)
            {
                Vector2 position = (e._position * _iZoom) - Camera;
                //_visuLevel.displaySprite(e._idTexture, e._idSprite, e._position - Camera, SpriteEffects.None, new Vector2(_iZoom, _iZoom));
                _visuLevel.displaySprite( e._idTexture, e._idSprite, position, SpriteEffects.None, new Vector2(_iZoom, _iZoom));
            }

            //draw the player's start position
            //for (int i = 0; i < 4; i++)
            //{
            //    Vector2 position = (_v2PlayerRectangle[i] + _level._playerEntity._position - _v2CameraPosition) * _iZoom;
            //    //_v2PlayerRectangleScreen[i] = _v2PlayerRectangle[i] + _level._playerEntity._position - _v2CameraPosition;
            //    _v2PlayerRectangleScreen[i] = position;
            //}
            //_visuLevel.displayBlackPolygon( _v2PlayerRectangleScreen);

            //draw the currently created platform
            if (_userMode == eUserMode.eAddPlatform || _userMode == eUserMode.eAddLadder || _userMode == eUserMode.eAddSpike)
            {
                Rectangle rec = _newRectangle;
                rec.X *= _iZoom;
                rec.Y *= _iZoom;
                rec.X -= (int)_v2CameraPosition.X;
                rec.Y -= (int)_v2CameraPosition.Y;

                rec.Width *= _iZoom;
                rec.Height *= _iZoom;
                _visuLevel.displayBlackRectangle( rec);
            }

            //draw the platforms
            if(checkBoxDisplayPlatform.Checked)
            {
                for (int i = 0; i < _level._listPlatform.Count; i++)
                {
                    Rectangle rec = _level._listPlatform[i];
                    rec.X *= _iZoom;
                    rec.Y *= _iZoom;
                    rec.X -= (int)_v2CameraPosition.X;
                    rec.Y -= (int)_v2CameraPosition.Y;

                    rec.Width *= _iZoom;
                    rec.Height *= _iZoom;
                    _visuLevel.displayBlackRectangle( rec);
                }
            }

            //draw the ladders
            if (checkBoxLadder.Checked)
            {
                for (int i = 0; i < _level._listLadder.Count; i++)
                {
                    Rectangle rec = _level._listLadder[i];
                    rec.X *= _iZoom;
                    rec.Y *= _iZoom;
                    rec.X -= (int)_v2CameraPosition.X;
                    rec.Y -= (int)_v2CameraPosition.Y;

                    rec.Width *= _iZoom;
                    rec.Height *= _iZoom;
                    _visuLevel.displayBlackRectangle( rec);
                }
            }

            //draw the spikes
            if (checkBoxSpike.Checked)
            {
                for (int i = 0; i < _level._listSpike.Count; i++)
                {
                    Rectangle rec = _level._listSpike[i];
                    rec.X *= _iZoom;
                    rec.Y *= _iZoom;
                    rec.X -= (int)_v2CameraPosition.X;
                    rec.Y -= (int)_v2CameraPosition.Y;

                    rec.Width *= _iZoom;
                    rec.Height *= _iZoom;
                    _visuLevel.displayBlackRectangle( rec);
                }
            }

            //draw entities
            if (checkBoxEntity.Checked)
            {
                for (int i = 0; i < _level._listEntity.Count; i++)
                {
                    object entity = _level._listEntity[i];
                    Vector2 worldPos = (Vector2)entity.GetType().GetField("Position").GetValue(entity);
                    Vector2 position = (worldPos * _iZoom) - Camera;

                    int idTexture = (int)entity.GetType().GetField("EDITOR_TILESET").GetValue(null);
                    int idSprite = (int)entity.GetType().GetField("EDITOR_SPRITE").GetValue(null);
                    _visuLevel.displaySprite( idTexture, idSprite, position, SpriteEffects.None, new Vector2(_iZoom, _iZoom));

                    //cehck if there is a trigger
                    //PropertyInfo propertyTrigger = entity.GetType().GetProperty("Trigger");
                    FieldInfo fieldTrigger = entity.GetType().GetField("Trigger");
                    if (fieldTrigger != null)
                    {
                        Rectangle rec = (Rectangle)fieldTrigger.GetValue(entity);
                        rec.X *= _iZoom;
                        rec.Y *= _iZoom;
                        rec.X -= (int)_v2CameraPosition.X;
                        rec.Y -= (int)_v2CameraPosition.Y;

                        rec.Width *= _iZoom;
                        rec.Height *= _iZoom;
                        _visuLevel.displayBlackRectangle(rec);
                    }
                }
            }

            _visuLevel.postRender();
            _device.Present();
        }

        /// <summary>
        /// Render the selected psrite in the list of sprite
        /// </summary>
        private void renderSprite()
        {
            _visuLevel.preRender( false);
            if (_visuLevel.Error) return;

            if (_iIdSpriteSelectedSprite >= 0 && _iIdTextureSelectedSprite >= 0)
            {
                _visuLevel.displaySprite( _iIdTextureSelectedSprite, _iIdSpriteSelectedSprite, new Vector2(5));
            }
            _visuLevel.postRender();

            Rectangle src = new Rectangle(0, 0, panelSprite.Width, panelSprite.Height);
            if(!panelSprite.IsDisposed)
                _device.Present(src, null, panelSprite.Handle);
      
        }

        /// <summary>
        /// Resize the window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void wndLevel_Resize(object sender, System.EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized) return;

            //resize the level device
            if (panelLevel.Height != 0 && panelLevel.Width != 0)
            {
                _param.BackBufferHeight = panelLevel.Height;
                _param.BackBufferWidth = panelLevel.Width;
                _device.Reset(_param);
                computeVScrollMax();
            }

            ////resize the sprite device
            //if (panelSprite.Height != 0 && panelSprite.Width != 0)
            //{
            //    _paramSprite.BackBufferHeight = panelSprite.Height;
            //    _paramSprite.BackBufferWidth = panelSprite.Width;
            //    _deviceSprite.Reset(_paramSprite);
            //    computeHScrollMax();
            //}

            gbEntity.Left = 0;
            gbEntity.Width = gbOptions.ClientSize.Width;
            gbEntity.Height = gbOptions.ClientSize.Height - gbEntity.Top;

        }

        private void tsbOpenTileset_Click(object sender, System.EventArgs e)
        {
            openTileset();
        }

        private int openTileset(string filename)
        {
            //load the tileset
            //int ret = _visuSprite.loadTileset(filename);
            int ret = _visuLevel.loadTileset(filename);

            //go through the loaded tilesets
            cbListSprite.Items.Clear();
            _spriteListComboBoxItem.Clear();
            int idTexture = 0;
            //TextureEx tileset = _visuSprite.getTextureEx(idTexture);
            TextureEx tileset = _visuLevel.getTextureEx(idTexture);
            while (tileset != null)
            {
                //go through all the sprites
                for (int idSprite = 0; idSprite < tileset.SpriteCount; idSprite++)
                {
                    comboBoxItem newItem = new comboBoxItem(idTexture, idSprite, tileset.Filename + "." + tileset.getSpriteName(idSprite));
                    _spriteListComboBoxItem.Add(newItem);
                    cbListSprite.Items.Add(newItem._text);
                }

                idTexture++;
                //tileset = _visuSprite.getTextureEx(idTexture);
                tileset = _visuLevel.getTextureEx(idTexture);
            }

            return ret;
        }

        private int openTileset()
        {
            //open a dialog
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Open tileset";
            ofd.Filter = "Xml files (*.xml)|*.xml";
            DialogResult res = ofd.ShowDialog();

            if (res != System.Windows.Forms.DialogResult.OK) return -1;

            return openTileset(ofd.FileName);
        }

        private void addSprite()
        {
            if (_iIdSpriteSelectedSprite < 0 || _iIdTextureSelectedSprite < 0) return;

            _addedEntity = new Entity();
            _addedEntity._idTexture = _iIdTextureSelectedSprite;
            _addedEntity._idSprite = _iIdSpriteSelectedSprite;
            //_addedEntity._spriteName = _visuSprite.getTextureEx(_iIdTextureSelectedSprite).getSpriteName(_iIdSpriteSelectedSprite);
            //_addedEntity._tilesetName = _visuSprite.getTextureEx(_iIdTextureSelectedSprite).Filename;
            _addedEntity._spriteName = _visuLevel.getTextureEx(_iIdTextureSelectedSprite).getSpriteName(_iIdSpriteSelectedSprite);
            _addedEntity._tilesetName = _visuLevel.getTextureEx(_iIdTextureSelectedSprite).Filename;
            _addedEntity._position = new Vector2(0);
            _addedEntity._type = eEntityType.ePlatform;

            //dynamic platform
            //_addedEntity._waypoints = new List<Pose>();
            _addedEntity._bLoop = false;
            _addedEntity._bBackAndForth = false;

            _userMode = eUserMode.eAddSprite;
        }

        private void cbListSprite_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            _iIdTextureSelectedSprite = _spriteListComboBoxItem[cbListSprite.SelectedIndex]._idTexture;
            _iIdSpriteSelectedSprite = _spriteListComboBoxItem[cbListSprite.SelectedIndex]._idSprite;
        }

        private void tsbAddSprite_Click(object sender, System.EventArgs e)
        {
            addSprite();
        }

        private void panelLevel_MouseMove(object sender, MouseEventArgs e)
        {
            switch (_userMode)
            {
                case eUserMode.eMoveEntity:
                    panelLevelMouseMove_MoveEntity(e.X, e.Y);
                    break;
                case eUserMode.eAddEntity:
                    panelLevelMouseMove_AddEntity(e.X, e.Y);
                    break;
                case eUserMode.eAddLadder:
                    panelLevelMouseMove_AddLadder(e.X, e.Y);
                    break;
                case eUserMode.eAddSpike:
                    panelLevelMouseMove_AddSpike(e.X, e.Y);
                    break;
                case eUserMode.eAddSprite:
                    panelLevelMouseMove_AddSprite(e.X, e.Y);
                    break;
                case eUserMode.eMoveSprite:
                    panelLevelMouseMove_MoveSprite(e.X, e.Y);
                    break;
                case eUserMode.eMovePlayer:
                    panelLevelMouseMove_MovePlayer(e.X, e.Y);
                    break;
                case eUserMode.eAddPlatform:
                    panelLevelMouseMove_AddPlatform(e.X, e.Y);
                    break;
                case eUserMode.eSelectedPlatform:
                    panelLevelMouseMove_SelectedPlatform(e.X, e.Y);
                    break;
                case eUserMode.eSelectedLadder:
                    panelLevelMouseMove_SelectedLadder(e.X, e.Y);
                    break;

                case eUserMode.eSelectedSpike:
                    panelLevelMouseMove_SelectedSpike(e.X, e.Y);
                    break;

                //move the top bound of a platform
                case eUserMode.eResizePlatformTop:
                    panelLevelMouseMove_ResizeTop(e.X, e.Y);
                    break;

                //move the bottom bound of a platform
                case eUserMode.eResizePlatformBottom:
                    panelLevelMouseMove_ResizeBottom(e.X, e.Y);
                    break;

                //move the left bound of a platform
                case eUserMode.eResizePlatformLeft:
                    panelLevelMouseMove_ResizeLeft(e.X, e.Y);
                    break;

                //move the right bound of a platform
                case eUserMode.eResizePlatformRight:
                    panelLevelMouseMove_ResizeRight(e.X, e.Y);
                    break;

                //move the top bound of a ladder
                case eUserMode.eResizeLadderTop:
                    panelLevelMouseMove_ResizeLadderTop(e.X, e.Y);
                    break;

                //move the bottom bound of a ladder
                case eUserMode.eResizeLadderBottom:
                    panelLevelMouseMove_ResizeLadderBottom(e.X, e.Y);
                    break;

                //move the left bound of a ladder
                case eUserMode.eResizeLadderLeft:
                    panelLevelMouseMove_ResizeLadderLeft(e.X, e.Y);
                    break;

                //move the right bound of a ladder
                case eUserMode.eResizeLadderRight:
                    panelLevelMouseMove_ResizeLadderRight(e.X, e.Y);
                    break;

                case eUserMode.eResizeSpikeBottom:
                    panelLevelMouse_ResizeSpikeBottom(e.X, e.Y);
                    break;

                case eUserMode.eResizeSpikeLeft:
                    panelLevelMouse_ResizeSpikeLeft(e.X, e.Y);
                    break;

                case eUserMode.eResizeSpikeRight:
                    panelLevelMouse_ResizeSpikeRight(e.X, e.Y);
                    break;

                case eUserMode.eResizeSpikeTop:
                    panelLevelMouse_ResizeSpikeTop(e.X, e.Y);
                    break;
            }
        }

        private void panelLevelMouse_ResizeSpikeTop(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listSpike[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new top and height
            rec.Height = (int)(rec.Height - worldPos.Y + rec.Y);
            rec.Y = (int)worldPos.Y;


            _level._listSpike[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.HSplit;
        }

        private void panelLevelMouse_ResizeSpikeRight(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listSpike[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new height
            rec.Width = (int)(worldPos.X - rec.X);
            _level._listSpike[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.VSplit;
        }

        private void panelLevelMouse_ResizeSpikeLeft(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listSpike[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new left and width
            rec.Width = (int)(rec.Width - worldPos.X + rec.X);
            rec.X = (int)worldPos.X;
            
            _level._listSpike[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.VSplit;
        }

        private void panelLevelMouse_ResizeSpikeBottom(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listSpike[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new height
            rec.Height = (int)(worldPos.Y - rec.Y);
            _level._listSpike[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.HSplit;
        }

        private void panelLevelMouseMove_AddSpike(int x, int y)
        {
            if (!_bFirstPointAdded) return;
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));
            _newRectangle.Width = (int)worldPos.X - _newRectangle.X;
            _newRectangle.Height = (int)worldPos.Y - _newRectangle.Y;
        }
            
        public void panelLevelMouseMove_ResizeRight(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listPlatform[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new height
            rec.Width = (int)(worldPos.X - rec.X);
            _level._listPlatform[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.VSplit;
        }

        public void panelLevelMouseMove_ResizeLeft(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listPlatform[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new left and width
            rec.Width = (int)(rec.Width - worldPos.X + rec.Left);
            rec.X =  (int)worldPos.X;
            
            _level._listPlatform[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.VSplit;
        }

        public void panelLevelMouseMove_ResizeBottom(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listPlatform[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new height
            rec.Height = (int)(worldPos.Y - rec.Y);
            _level._listPlatform[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.HSplit;
        }

        public void panelLevelMouseMove_ResizeTop(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listPlatform[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new top and height
            rec.Height = (int)(rec.Height - worldPos.Y + rec.Y);
            rec.Y = (int)worldPos.Y;
            

            _level._listPlatform[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.HSplit;
        }

        public void panelLevelMouseMove_ResizeLadderRight(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listLadder[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new height
            rec.Width = (int)(worldPos.X - rec.X);
            _level._listLadder[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.VSplit;
        }

        public void panelLevelMouseMove_ResizeLadderLeft(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listLadder[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new left and width
            rec.Width = (int)(rec.Width - worldPos.X + rec.Left);
            rec.X = (int)worldPos.X;
            
            _level._listLadder[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.VSplit;
        }

        public void panelLevelMouseMove_ResizeLadderBottom(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listLadder[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new height
            rec.Height = (int)(worldPos.Y - rec.Y);
            _level._listLadder[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.HSplit;
        }

        public void panelLevelMouseMove_ResizeLadderTop(int x, int y)
        {
            //get the rectangle
            Rectangle rec = _level._listLadder[_iIdSelectedElementInLevel];
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));

            //calculate the new top and height
            rec.Height = (int)(rec.Height - worldPos.Y + rec.Y);
            rec.Y = (int)worldPos.Y;
            

            _level._listLadder[_iIdSelectedElementInLevel] = rec;
            Cursor = Cursors.HSplit;
        }

        /// <summary>
        /// When a spike is selected, change the cursor 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void panelLevelMouseMove_SelectedSpike(int x, int y)
        {
            //if a sprite is selected, change the cursor
            if (_iIdSelectedElementInLevel == -1) return;

            //check if the mouse is on a line of the spike
            Rectangle rec = _level._listSpike[_iIdSelectedElementInLevel];
            Vector2 vec2Mouse = getPanelPositionToTexturePosition(new Vector2(x, y));

            Cursor = Cursors.Default;

            //check top
            if (vec2Mouse.Y == rec.Y && vec2Mouse.X > rec.X && vec2Mouse.X < rec.X + rec.Width)
                Cursor = Cursors.HSplit;

            //check left
            if (vec2Mouse.X == rec.X && vec2Mouse.Y > rec.Y && vec2Mouse.Y < rec.Y + rec.Height)
                Cursor = Cursors.VSplit;

            //check right
            if (vec2Mouse.X == rec.X + rec.Width && vec2Mouse.Y > rec.Y && vec2Mouse.Y < rec.Y + rec.Height)
                Cursor = Cursors.VSplit;

            //check bottom
            if (vec2Mouse.Y == rec.Y + rec.Height && vec2Mouse.X > rec.X && vec2Mouse.X < rec.X + rec.Width)
                Cursor = Cursors.HSplit;
        }

        /// <summary>
        /// When a ladder is selected, change the cursor when the mouse is over an edge
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void panelLevelMouseMove_SelectedLadder(int x, int y)
        {
            //if a sprite is selected, change the cursor
            if (_iIdSelectedElementInLevel == -1) return;

            //check if the mouse is on a line of the sprite
            Rectangle rec = _level._listLadder[_iIdSelectedElementInLevel];
            Vector2 vec2Mouse = getPanelPositionToTexturePosition(new Vector2(x, y));

            Cursor = Cursors.Default;

            //check top
            if (vec2Mouse.Y == rec.Y && vec2Mouse.X > rec.X && vec2Mouse.X < rec.X + rec.Width)
                Cursor = Cursors.HSplit;

            //check left
            if (vec2Mouse.X == rec.X && vec2Mouse.Y > rec.Y && vec2Mouse.Y < rec.Y + rec.Height)
                Cursor = Cursors.VSplit;

            //check right
            if (vec2Mouse.X == rec.X + rec.Width && vec2Mouse.Y > rec.Y && vec2Mouse.Y < rec.Y + rec.Height)
                Cursor = Cursors.VSplit;

            //check bottom
            if (vec2Mouse.Y == rec.Y + rec.Height && vec2Mouse.X > rec.X && vec2Mouse.X < rec.X + rec.Width)
                Cursor = Cursors.HSplit;

        }

        /// <summary>
        /// When a platform is selected, change the icon when the mouse is over an edge
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void panelLevelMouseMove_SelectedPlatform(int x, int y)
        {
            //if a sprite is selected, change the cursor
            if (_iIdSelectedElementInLevel == -1) return;
            
            //check if the mouse is on a line of the sprite
            Rectangle rec = _level._listPlatform[_iIdSelectedElementInLevel];
            Vector2 vec2Mouse = getPanelPositionToTexturePosition(new Vector2(x, y));

            Cursor = Cursors.Default;

            //check top
            if (vec2Mouse.Y == rec.Y && vec2Mouse.X > rec.X && vec2Mouse.X < rec.X + rec.Width)
                Cursor = Cursors.HSplit;

            //check left
            if (vec2Mouse.X == rec.X && vec2Mouse.Y > rec.Y && vec2Mouse.Y < rec.Y + rec.Height)
                Cursor = Cursors.VSplit;

            //check right
            if (vec2Mouse.X == rec.X + rec.Width && vec2Mouse.Y > rec.Y && vec2Mouse.Y < rec.Y + rec.Height)
                Cursor = Cursors.VSplit;

            //check bottom
            if (vec2Mouse.Y == rec.Y + rec.Height && vec2Mouse.X > rec.X && vec2Mouse.X < rec.X + rec.Width)
                Cursor = Cursors.HSplit;
    
        }

        /// <summary>
        /// Move a selected entity
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void panelLevelMouseMove_MoveEntity(int x, int y)
        {
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));
            object e = _level._listEntity[_iIdSelectedElementInLevel];
            e.GetType().GetField("Position").SetValue(e, worldPos);
        }

        /// <summary>
        /// Move a new entity
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void panelLevelMouseMove_AddEntity(int x, int y)
        {
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));
            _newEntity.GetType().GetField("Position").SetValue(_newEntity, worldPos);
        }

        /// <summary>
        /// Handle the mouse movement when the user is creating a new ladder
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void panelLevelMouseMove_AddLadder(int x, int y)
        {
            if (!_bFirstPointAdded) return;
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));
            _newRectangle.Width = (int)worldPos.X - _newRectangle.X;
            _newRectangle.Height = (int)worldPos.Y - _newRectangle.Y;
        }

        /// <summary>
        /// Handle the mouse movement when the user is adding a platform
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void panelLevelMouseMove_AddPlatform(int x, int y)
        {
            if (!_bFirstPointAdded) return;
            Vector2 worldPos = getPanelPositionToTexturePosition(new Vector2(x, y));
            _newRectangle.Width = (int)worldPos.X - _newRectangle.X;
            _newRectangle.Height = (int)worldPos.Y - _newRectangle.Y;
        }

        private void panelLevelMouseMove_MovePlayer(int x, int y)
        {
            _level._playerEntity._position.X = (x + _v2CameraPosition.X)/_iZoom;
            _level._playerEntity._position.Y = (y + _v2CameraPosition.Y)/_iZoom;
        }

        private void panelLevelMouseMove_AddSprite(int x, int y)
        {
            //int spriteHalfWidth = _visuSprite.getSpriteWidth(_addedEntity._idTexture, _addedEntity._idSprite)/2 * _iZoom;
            //int spriteHalfHeight = _visuSprite.getSpriteHeight(_addedEntity._idTexture, _addedEntity._idSprite)/2 * _iZoom;
            int spriteHalfWidth = _visuLevel.getSpriteWidth(_addedEntity._idTexture, _addedEntity._idSprite) / 2 * _iZoom;
            int spriteHalfHeight = _visuLevel.getSpriteHeight(_addedEntity._idTexture, _addedEntity._idSprite) / 2 * _iZoom;

            _addedEntity._position = getPanelPositionToTexturePosition(new Vector2(x, y));
        }

        private void panelLevelMouseMove_MoveSprite(int x, int y)
        {
            Entity e = _level._listSprite[_iIdSelectedElementInLevel];
            //int spriteHalfWidth = _visuSprite.getSpriteWidth(e._idTexture, e._idSprite) / 2 * _iZoom;
            //int spriteHalfHeight = _visuSprite.getSpriteHeight(e._idTexture, e._idSprite) / 2 * _iZoom;
            int spriteHalfWidth = _visuLevel.getSpriteWidth(e._idTexture, e._idSprite) / 2 * _iZoom;
            int spriteHalfHeight = _visuLevel.getSpriteHeight(e._idTexture, e._idSprite) / 2 * _iZoom;

            e._position = getPanelPositionToTexturePosition(new Vector2(x, y));
        }

        private void panelLevel_MouseClick(object sender, MouseEventArgs e)
        {
            switch (_userMode)
            {
                case eUserMode.eAddSprite:
                    panelLevelMouseClick_AddSprite(e.X, e.Y);
                    break;
                case eUserMode.eNone:
                case eUserMode.eMoveSprite:
                case eUserMode.eSelectedPlatform:
                case eUserMode.eSelectedLadder:
                case eUserMode.eSelectedSpike:
                case eUserMode.eSelectedEntity:
                    panelLevelMouseClick_None(e.X, e.Y);
                    break;
                case eUserMode.eMovePlayer:
                    panelLevelMouseClick_MovePlayer();
                    break;
                case eUserMode.eAddEntity:
                    _iIdSelectedElementInLevel = _level._listEntity.Count;
                    _level._listEntity.Add(_newEntity);
                    _userMode = eUserMode.eSelectedEntity;
                    displayAndFillEntityPanel();
                    break;
            }
        }

        private void panelLevelMouseClick_MovePlayer()
        {
            _userMode = eUserMode.eNone;
        }

        private void panelLevelMouseClick_AddSprite(int x, int y)
        {
            _userMode = eUserMode.eNone;
            _level._listSprite.Add(_addedEntity);
        }

        /// <summary>
        /// Apply a click to select an entity
        /// </summary>
        /// <param name="x">Mouse position X in panel coordinates</param>
        /// <param name="y">Mouse position Y in panel coordinates</param>
        private void panelLevelMouseClick_None(int x, int y)
        {
            Vector2 s = Vector2.Zero;
            switch(_selectionMode)
            {
            //if (checkBoxDisplayPlatform.Checked)//select a platform
            //{
                case eSelectionMode.eSelectPlatform:
                    s = getPanelPositionToTexturePosition(new Vector2(x, y));
                    _iIdSelectedElementInLevel = _level.getSelectedPlatform(s);
                    if (_iIdSelectedElementInLevel == -1)
                    {
                        _userMode = eUserMode.eNone;
                        return;
                    }
                    _userMode = eUserMode.eSelectedPlatform;
                    break;


            //}
            //else if (checkBoxLadder.Checked)//select a ladder
            //{
                case eSelectionMode.eSelectLadder:
                    s = getPanelPositionToTexturePosition(new Vector2(x, y));
                    _iIdSelectedElementInLevel = _level.getSelectedLadder(s);
                    if (_iIdSelectedElementInLevel == -1)
                    {
                        _userMode = eUserMode.eNone;
                        return;
                    }
                    _userMode = eUserMode.eSelectedLadder;
                    break;
            //}
            //else if (checkBoxSpike.Checked)
            //{
                case eSelectionMode.eSelectSpike:
                    s = getPanelPositionToTexturePosition(new Vector2(x, y));
                    _iIdSelectedElementInLevel = _level.getSelectedSpike(s);
                    if (_iIdSelectedElementInLevel == -1)
                    {
                        _userMode = eUserMode.eNone;
                        return;
                    }
                    _userMode = eUserMode.eSelectedSpike;
                    break;
            //}
            //else if (checkBoxEntity.Checked)
            //{
                case eSelectionMode.eSelectEntity:
                    s = getPanelPositionToTexturePosition(new Vector2(x, y));
                    _iIdSelectedElementInLevel = _level.getSelectedEntity(s);
                    if (_iIdSelectedElementInLevel == -1)
                    {
                        _userMode = eUserMode.eNone;
                        return;
                    }
                    _userMode = eUserMode.eSelectedEntity;
                    displayAndFillEntityPanel();
                    break;
            //}
            //else
            //{
                case eSelectionMode.eSelectSprite:
                    //check if there is an entity where the user clicked
                    s = (new Vector2(x, y) + _v2CameraPosition) / _iZoom;
                    _iIdSelectedElementInLevel = _level.getSelectedSprite(s);
                    if (_iIdSelectedElementInLevel == -1) return;

                    //fill the fields
                    Entity e = _level._listSprite[_iIdSelectedElementInLevel];
                    tbPositionX.Text = e._position.X.ToString();
                    tbPositionY.Text = e._position.Y.ToString();
                    //cbEntityType.SelectedIndex = (int)e._type;
                    break;
            }
 
        }

        /// <summary>
        /// Fill the controls with the values of the selected entity
        /// </summary>
        private void displayAndFillEntityPanel()
        {
            //if the id is out of range
            if (_iIdSelectedElementInLevel == -1 || _iIdSelectedElementInLevel >= _level._listEntity.Count) return;

            object e = _level._listEntity[_iIdSelectedElementInLevel];
            string className = e.GetType().Name;
            className = className.Substring(6);
            cbEntityType.SelectedItem = className;
            panelEntity p = _listPanelEntity[className];
            gbEntity.Controls.Clear();
            gbEntity.Controls.Add(p._group);
            

            FieldInfo[] f = e.GetType().GetFields();

            for(int i = 0; i < f.Length; i++)
            {
                FieldInfo field = f[i];
                if (field.Name == "EDITOR_TILESET" || field.Name == "EDITOR_SPRITE") continue;

                //handle enumeration
                if (field.FieldType.IsEnum)
                {
                    ComboBox cbEnum = (ComboBox)p.getControl(field.Name);
                    object enumValue = field.GetValue(e);
                    cbEnum.SelectedIndex = (int)enumValue;
                }

                switch (field.FieldType.Name)
                {
                    case "Rectangle":
                        Rectangle recValue = (Rectangle)field.GetValue(e);
                        TextBox ctrl=(TextBox)p.getControl(field.Name + " X");
                        ctrl.Text = recValue.X.ToString();

                        ctrl=(TextBox)p.getControl(field.Name + " Y");
                        ctrl.Text = recValue.Y.ToString();

                        ctrl=(TextBox)p.getControl(field.Name + " Width");
                        ctrl.Text = recValue.Width.ToString();

                        ctrl=(TextBox)p.getControl(field.Name + " Height");
                        ctrl.Text = recValue.Height.ToString();
                        break;

                    case "Vector2":
                        Vector2 v2Value = (Vector2)field.GetValue(e);
                        ctrl = (TextBox)p.getControl(field.Name + " X");//(TextBox)p._listControl[idCtrl];
                        ctrl.Text = v2Value.X.ToString();
                        ctrl = (TextBox)p.getControl(field.Name + " Y");//(TextBox)p._listControl[idCtrl];
                        ctrl.Text = v2Value.Y.ToString();
                        break;
                    case "Boolean":
                        bool bValue = (bool)field.GetValue(e);
                        CheckBox cbCtrl = (CheckBox)p.getControl(field.Name);
                        cbCtrl.Checked = bValue;
                        break;
                    case "Int32":
                        int iValue = (int)field.GetValue(e);
                        TextBox iCtrl = (TextBox)p.getControl(field.Name);
                        iCtrl.Text = iValue.ToString();
                        break;
                    case "Single":
                        Single sValue = (Single)field.GetValue(e);
                        TextBox sCtrl = (TextBox)p.getControl(field.Name);
                        sCtrl.Text = sValue.ToString();
                        break;
                    case "Float":
                        float fValue = (float)field.GetValue(e);
                        TextBox fCtrl = (TextBox)p.getControl(field.Name);
                        fCtrl.Text = fValue.ToString();
                        break;
                }
            }
        }

        private void panelLevel_MouseDown(object sender, MouseEventArgs e)
        {

            Vector2 s = (new Vector2(e.X, e.Y) + _v2CameraPosition) / _iZoom;
            switch (_userMode)
            {
                case eUserMode.eNone:
                    if (!checkBoxDisplayPlatform.Checked)
                    {
                        _iIdSelectedElementInLevel = _level.getSelectedSprite(s);
                        if (_iIdSelectedElementInLevel == -1) return;
                        _userMode = eUserMode.eMoveSprite;
                    }
                break;

                case eUserMode.eAddPlatform:
                    _newRectangle = new Rectangle((int)s.X, (int)s.Y, 0, 0);
                    _bFirstPointAdded = true;
                break;

                case eUserMode.eSelectedPlatform:
                    panelLevelMouseDown_SelectedPlatform(s);
                break;

                case eUserMode.eAddLadder:
                    _newRectangle = new Rectangle((int)s.X, (int)s.Y, 0, 0);
                    _bFirstPointAdded = true;
                    break;
                
                case eUserMode.eAddSpike:
                    _newRectangle = new Rectangle((int)s.X, (int)s.Y, 0, 0);
                    _bFirstPointAdded = true;
                    break;

                case eUserMode.eSelectedLadder:
                    panelLevelMouseDown_SelectedLadder(s);
                    break;

                case eUserMode.eSelectedSpike:
                    panelLevelMouseDown_SelectedSpike(s);
                    break;

                case eUserMode.eSelectedEntity:
                    panelLevelMouseDown_SelectedEntity(s);
                    break;

            }
        }

        /// <summary>
        /// Check if the mouse is down on the selected element
        /// </summary>
        /// <param name="worldPos"></param>
        private void panelLevelMouseDown_SelectedEntity(Vector2 worldPos)
        {
            if (_iIdSelectedElementInLevel == -1) return;

            if (!_level.isEntitySelected(worldPos, _iIdSelectedElementInLevel)) return;

            _userMode = eUserMode.eMoveEntity;
        }

        private void panelLevelMouseDown_SelectedSpike(Vector2 worldPos)
        {
            //if a sprite is selected, change the cursor
            if (_iIdSelectedElementInLevel == -1) return;

            //check if the mouse is on a line of ladder
            Rectangle rec = _level._listSpike[_iIdSelectedElementInLevel];

            Cursor = Cursors.Default;

            //check top
            if (worldPos.Y == rec.Y && worldPos.X > rec.X && worldPos.X < rec.X + rec.Width)
            {
                _userMode = eUserMode.eResizeSpikeTop;
                Cursor = Cursors.HSplit;
            }

            //check left
            if (worldPos.X == rec.X && worldPos.Y > rec.Y && worldPos.Y < rec.Y + rec.Height)
            {
                _userMode = eUserMode.eResizeSpikeLeft;
                Cursor = Cursors.VSplit;
            }

            //check right
            if (worldPos.X == rec.X + rec.Width && worldPos.Y > rec.Y && worldPos.Y < rec.Y + rec.Height)
            {
                _userMode = eUserMode.eResizeSpikeRight;
                Cursor = Cursors.VSplit;
            }

            //check bottom
            if (worldPos.Y == rec.Y + rec.Height && worldPos.X > rec.X && worldPos.X < rec.X + rec.Width)
            {
                _userMode = eUserMode.eResizeSpikeBottom;
                Cursor = Cursors.HSplit;
            }
        }

        /// <summary>
        /// Select a single edge of a ladder
        /// </summary>
        /// <param name="worldPos"></param>
        private void panelLevelMouseDown_SelectedLadder(Vector2 worldPos)
        {
            //if a sprite is selected, change the cursor
            if (_iIdSelectedElementInLevel == -1) return;

            //check if the mouse is on a line of ladder
            Rectangle rec = _level._listLadder[_iIdSelectedElementInLevel];

            Cursor = Cursors.Default;

            //check top
            if (worldPos.Y == rec.Y && worldPos.X > rec.X && worldPos.X < rec.X + rec.Width)
            {
                _userMode = eUserMode.eResizeLadderTop;
                Cursor = Cursors.HSplit;
            }

            //check left
            if (worldPos.X == rec.X && worldPos.Y > rec.Y && worldPos.Y < rec.Y + rec.Height)
            {
                _userMode = eUserMode.eResizeLadderLeft;
                Cursor = Cursors.VSplit;
            }

            //check right
            if (worldPos.X == rec.X + rec.Width && worldPos.Y > rec.Y && worldPos.Y < rec.Y + rec.Height)
            {
                _userMode = eUserMode.eResizeLadderRight;
                Cursor = Cursors.VSplit;
            }

            //check bottom
            if (worldPos.Y == rec.Y + rec.Height && worldPos.X > rec.X && worldPos.X < rec.X + rec.Width)
            {
                _userMode = eUserMode.eResizeLadderBottom;
                Cursor = Cursors.HSplit;
            }
        }

        /// <summary>
        /// Select an edge of a platform
        /// </summary>
        /// <param name="worldPos"></param>
        private void panelLevelMouseDown_SelectedPlatform(Vector2 worldPos)
        {
            //if a sprite is selected, change the cursor
            if (_iIdSelectedElementInLevel == -1) return;

            //check if the mouse is on a line of the sprite
            Rectangle rec = _level._listPlatform[_iIdSelectedElementInLevel];

            Cursor = Cursors.Default;

            //check top
            if (worldPos.Y == rec.Y && worldPos.X > rec.X && worldPos.X < rec.X + rec.Width)
            {
                _userMode = eUserMode.eResizePlatformTop;
                Cursor = Cursors.HSplit;
            }

            //check left
            if (worldPos.X == rec.X && worldPos.Y > rec.Y && worldPos.Y < rec.Y + rec.Height)
            {
                _userMode = eUserMode.eResizePlatformLeft;
                Cursor = Cursors.VSplit;
            }

            //check right
            if (worldPos.X == rec.X + rec.Width && worldPos.Y > rec.Y && worldPos.Y < rec.Y + rec.Height)
            {
                _userMode = eUserMode.eResizePlatformRight;
                Cursor = Cursors.VSplit;
            }

            //check bottom
            if (worldPos.Y == rec.Y + rec.Height && worldPos.X > rec.X && worldPos.X < rec.X + rec.Width)
            {
                _userMode = eUserMode.eResizePlatformBottom;
                Cursor = Cursors.HSplit;
            }
        }

        private void panelLevel_MouseUp(object sender, MouseEventArgs e)
        {
            switch (_userMode)
            {
                case eUserMode.eMoveEntity:
                    _userMode = eUserMode.eSelectedEntity;
                    break;

                case eUserMode.eMoveSprite:
                    _userMode = eUserMode.eNone;
                    break;
                case eUserMode.eAddPlatform:
                    _level._listPlatform.Add(_newRectangle);
                    _userMode = eUserMode.eSelectedPlatform;
                    _bFirstPointAdded = false;
                    _iIdSelectedElementInLevel = _level._listPlatform.Count - 1;
                    break;

                case eUserMode.eAddLadder:
                    _level._listLadder.Add(_newRectangle);
                    _userMode = eUserMode.eSelectedLadder;
                    _bFirstPointAdded = false;
                    _iIdSelectedElementInLevel = _level._listLadder.Count - 1;
                    break;

                case eUserMode.eAddSpike:
                    _level._listSpike.Add(_newRectangle);
                    _userMode = eUserMode.eSelectedSpike;
                    _bFirstPointAdded = false;
                    _iIdSelectedElementInLevel = _level._listSpike.Count - 1;
                    break;

                case eUserMode.eResizePlatformBottom:
                case eUserMode.eResizePlatformLeft:
                case eUserMode.eResizePlatformRight:
                case eUserMode.eResizePlatformTop:
                    _userMode = eUserMode.eSelectedPlatform;
                    break;

                case eUserMode.eResizeLadderBottom:
                case eUserMode.eResizeLadderLeft:
                case eUserMode.eResizeLadderRight:
                case eUserMode.eResizeLadderTop:
                    _userMode = eUserMode.eSelectedLadder;
                    break;

                case eUserMode.eResizeSpikeBottom:
                case eUserMode.eResizeSpikeLeft:
                case eUserMode.eResizeSpikeRight:
                case eUserMode.eResizeSpikeTop:
                    _userMode = eUserMode.eSelectedSpike;
                    break;
            }
        }

        private void VScrollBarLevel_ValueChanged(object sender, System.EventArgs e)
        {
            _v2CameraPosition.Y = VScrollBarLevel.Value;
        }

        private void HScrollBarLevel_ValueChanged(object sender, System.EventArgs e)
        {
            _v2CameraPosition.X = HScrollBarLevel.Value;
        }

        private void tbPositionX_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (_iIdSelectedElementInLevel == -1) return;
                int newX = -1;
                bool res = int.TryParse(tbPositionX.Text, out newX);
                if(!res) return;
                _level._listSprite[_iIdSelectedElementInLevel]._position.X = newX;
            }
        }

        private void tbPositionY_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (_iIdSelectedElementInLevel == -1) return;
                int newY = -1;
                bool res = int.TryParse(tbPositionY.Text, out newY);
                if (!res) return;
                _level._listSprite[_iIdSelectedElementInLevel]._position.Y = newY;
            }
        }

        /// <summary>
        /// Select a new type of entity
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbEntityType_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            //clear the panel
            panelEntity.Controls.Clear();

            //display the new panel for the targeted entity
            string entityClassName = (string)cbEntityType.SelectedItem;
            panelEntity.Controls.Add(_listPanelEntity[entityClassName]._group);
            _listPanelEntity[entityClassName]._group.Dock = DockStyle.Fill;
            gbEntity.Visible = true;
        }

        private void tstbLevelName_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                _level._name = tstbLevelName.Text;
            }
        }

        private void tsbPlayerStart_Click(object sender, System.EventArgs e)
        {
            _userMode = eUserMode.eMovePlayer;
        }

        /// <summary>
        /// save the file using filename
        /// </summary>
        private void save()
        {
            
            XmlTextWriter writer;

            try
            {
                writer = new XmlTextWriter(_filename, null);
            }
            catch (XmlException e)
            {
                MessageBox.Show("erreur : " + e.Message);
                return;
            }
            
            writer.WriteStartDocument();

            //<Level name="">
            writer.WriteStartElement("Level");

            //Attribute name
            writer.WriteStartAttribute("name");
            writer.WriteString(_level._name);
            writer.WriteEndAttribute();

            //go throught every entity
            writer.WriteStartElement("SpriteElements");
            foreach (Entity e in _level._listSprite)
            {
                  savePlatform(writer, e);
            }
            writer.WriteEndElement();

            //go through every platform
            writer.WriteStartElement("StaticPhysicShapes");
            foreach (Rectangle r in _level._listPlatform)
            {
                savePlatform(writer, r);
            }
            writer.WriteEndElement();

            //go through every ladder
            writer.WriteStartElement("Ladders");
            foreach (Rectangle r in _level._listLadder)
                saveLadder(writer, r);
            writer.WriteEndElement();
           
            //go through every Spikes
            writer.WriteStartElement("Spikes");
            foreach (Rectangle r in _level._listSpike)
                saveSpike(writer, r);
            writer.WriteEndElement();

            //go through every entities
            writer.WriteStartElement("Entities");
            foreach (object o in _level._listEntity)
                saveEntity(writer, o);
            writer.WriteEndElement();

            //<Player>
            writer.WriteStartElement("Player");
            writer.WriteString(_level._playerEntity._position.X.ToString() + " " + _level._playerEntity._position.Y.ToString());
            writer.WriteEndElement();

            writer.WriteEndDocument();
            writer.Close();
            MessageBox.Show("Level saved");

        }

        private void saveWithDialog()
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Save level";
            sfd.Filter = "Xml file (*.xml)|*.xml";

            DialogResult res = sfd.ShowDialog();
            if (res != System.Windows.Forms.DialogResult.OK) return;

            _filename = sfd.FileName;
            Text = "Level " + _filename;
            save();
        }

        /// <summary>
        /// Save an entity
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="o"></param>
        private void saveEntity(XmlWriter writer, object o)
        {
            Type entityType = o.GetType();
            //<Entity>
            writer.WriteStartElement("Entity");

            //write the type of entity
            writer.WriteStartAttribute("type");
            writer.WriteString(entityType.Name.Substring(6));
            writer.WriteEndAttribute();

            //go throught each properties
            FieldInfo[] infos = entityType.GetFields();
            foreach (FieldInfo info in infos)
            {
                if (info.IsStatic) continue;

                writer.WriteStartElement("Property");

                //write the property's name
                writer.WriteStartAttribute("name");
                writer.WriteString(info.Name);
                writer.WriteEndAttribute();

                if (info.FieldType.IsEnum)
                {
                    object enumValue = info.GetValue(o);
                    writer.WriteString(enumValue.ToString());
                }

                //write the value
                switch(info.FieldType.Name)
                {
                    case "Vector2":
                        Vector2 v2Value = (Vector2)info.GetValue(o);
                        writer.WriteString(v2Value.X.ToString() + " " + v2Value.Y.ToString());
                        break;

                    case "Boolean":
                    case "Int32":
                    case "Single":
                        object oValue = info.GetValue(o);
                        writer.WriteString(oValue.ToString());
                        break;

                    case "Rectangle":
                        Rectangle recValue = (Rectangle)info.GetValue(o);
                        writer.WriteString(recValue.X.ToString() + " " + recValue.Y.ToString() + " " + recValue.Width.ToString() + " " + recValue.Height.ToString());
                        break;
                }

                //</Property>
                writer.WriteEndElement();
            }

            //</Entity>
            writer.WriteEndElement();
                
        }

        private void savePlatform(XmlWriter writer, Rectangle r)
        {
            writer.WriteStartElement("Shape");
            //return;
            writer.WriteString(r.X.ToString() + " " + r.Y.ToString() + " " + r.Width.ToString() + " " + r.Height.ToString());

            //</>
            writer.WriteEndElement();
        }

        private void saveSpike(XmlWriter writer, Rectangle r)
        {
            writer.WriteStartElement("Spike");

            writer.WriteString(r.X.ToString() + " " + r.Y.ToString() + " " + r.Width.ToString() + " " + r.Height.ToString());

            //</>
            writer.WriteEndElement();
        }

        private void saveLadder(XmlWriter writer, Rectangle r)
        {
            writer.WriteStartElement("Ladder");
          
            writer.WriteString(r.X.ToString() + " " + r.Y.ToString() + " " + r.Width.ToString() + " " + r.Height.ToString());

            //</>
            writer.WriteEndElement();
        }

        private void saveSprite(XmlWriter writer, Entity e)
        {
            writer.WriteStartElement("Sprite");
            //tilesetName
            writer.WriteStartAttribute("tilesetName");
            writer.WriteString(e._tilesetName + ".xml");
            writer.WriteEndAttribute();

            //spriteName
            writer.WriteStartAttribute("spriteName");
            writer.WriteString(e._spriteName);
            writer.WriteEndAttribute();

            //position
            writer.WriteString(e._position.X.ToString() + " " + e._position.Y.ToString());

            //</>
            writer.WriteEndElement();
        }

        /// <summary>
        /// Open a save file dialog to choose a file and then save the level
        /// </summary>
        //private void saveWithDialog()
        //{
        //    SaveFileDialog sfd = new SaveFileDialog();
        //    sfd.Title = "Save level";
        //    sfd.Filter = "Xml file (*.xml)|*.xml";

        //    DialogResult res = sfd.ShowDialog();
        //    if (res != System.Windows.Forms.DialogResult.OK) return;

        //    _filename = sfd.FileName;
        //    Text = "Level " + _filename;
        //    save();
        //}

        /// <summary>
        /// save the file using filename
        /// </summary>
        //private void save()
        //{
        //    XmlTextWriter writer = new XmlTextWriter(_filename, null);
        //    writer.WriteStartDocument();

        //    //<Level name="">
        //    writer.WriteStartElement("Level");

        //    //Attribute name
        //    writer.WriteStartAttribute("name");
        //    writer.WriteString(_level._name);
        //    writer.WriteEndAttribute();

        //    //go throught every entity
        //    foreach (Entity e in _level._listEntity)
        //    {
        //        switch (e._type)
        //        {
        //            case eEntityType.eHook:
        //                saveHook(writer, e);
        //                break;
        //            case eEntityType.ePlatform:
        //                savePlatform(writer, e);
        //                break;
        //            case eEntityType.eDynamicPlatform:
        //                saveDynamicPlatform(writer, e);
        //                break;
        //        }

        //    }

        //    //<Player>
        //    writer.WriteStartElement("Player");
        //    writer.WriteString(_level._playerEntity._position.X.ToString() + " " + _level._playerEntity._position.Y.ToString());
        //    writer.WriteEndElement();

        //    writer.WriteEndDocument();
        //    writer.Close();
        //    MessageBox.Show("Level saved");

        //}

        private void saveDynamicPlatform(XmlWriter writer, Entity e)
        {
            writer.WriteStartElement("DynamicPlatform");
            //tilesetName
            writer.WriteStartAttribute("tilesetName");
            writer.WriteString(e._tilesetName + ".xml");
            writer.WriteEndAttribute();

            //spriteName
            writer.WriteStartAttribute("spriteName");
            writer.WriteString(e._spriteName);
            writer.WriteEndAttribute();

            //Waypoints
            writer.WriteStartElement("Waypoints");

            //loop
            writer.WriteStartAttribute("loop");
            writer.WriteString(e._bLoop.ToString());
            writer.WriteEndAttribute();

            //back and forth
            writer.WriteStartAttribute("backAndForth");
            writer.WriteString(e._bBackAndForth.ToString());
            writer.WriteEndAttribute();

            //save the waypoints
            foreach (Pose p in e._waypoints)
            {
                //<Waypoint>
                writer.WriteStartElement("Waypoint");

                //time
                writer.WriteStartAttribute("time");
                writer.WriteString(p._time.ToString());
                writer.WriteEndAttribute();

                //Position
                writer.WriteString(p._position.X.ToString() + " " + p._position.Y.ToString());

                //</Waypoint>
                writer.WriteEndElement();
            }

            //</Waypoints>
            writer.WriteEndElement();

            //</DynamicPlatform>
            writer.WriteEndElement();
        }

        private void savePlatform(XmlWriter writer, Entity e)
        {
            writer.WriteStartElement("Platform");
            //tilesetName
            writer.WriteStartAttribute("tilesetName");
            writer.WriteString(e._tilesetName + ".xml");
            writer.WriteEndAttribute();

            //spriteName
            writer.WriteStartAttribute("spriteName");
            writer.WriteString(e._spriteName);
            writer.WriteEndAttribute();

            //position
            writer.WriteString(e._position.X.ToString() + " " + e._position.Y.ToString());

            //</>
            writer.WriteEndElement();
        }

        private void saveHook(XmlWriter writer, Entity e)
        {
            writer.WriteStartElement("Hook");
            //tilesetName
            writer.WriteStartAttribute("tilesetName");
            writer.WriteString(e._tilesetName + ".xml");
            writer.WriteEndAttribute();

            //spriteName
            writer.WriteStartAttribute("spriteName");
            writer.WriteString(e._spriteName);
            writer.WriteEndAttribute();

            //position
            writer.WriteString(e._position.X.ToString() + " " + e._position.Y.ToString());

            //</>
            writer.WriteEndElement();
        }

        private bool load(string filename)
        {
            //load the file
            XmlDocument xmlDocLevel = new XmlDocument();
            try
            {
                xmlDocLevel.Load(filename);
            }
            catch
            {
                MessageBox.Show("Can't load " + filename);
                return false;
            }

            //check if the file is a level file
            if (xmlDocLevel.DocumentElement.Name != "Level")
            {
                MessageBox.Show("The xml file is not a level file.");
                return false;
            }

            //get the path
            //string path = filename.Substring(0, filename.LastIndexOf('\\') + 1);

            //level name
            _level._name = xmlDocLevel.DocumentElement.Attributes["name"].InnerText;

            //go through every entity
            foreach (XmlNode n in xmlDocLevel.DocumentElement.ChildNodes)
            {
                if (n.Name == "Player")
                {
                    _level._playerEntity._position = GE.Tools.XmlHelper.getVector2FromNode(n);
                }
                else if (n.Name == "SpriteElements")
                {
                    foreach (XmlNode spriteElement in n.ChildNodes)
                        loadSprite(spriteElement, Program.m_Options.DataRoot);
                }
                else if (n.Name == "StaticPhysicShapes")
                {
                    foreach(XmlNode shape in n.ChildNodes)
                        loadPlatform(shape);
                }
                else if (n.Name == "Ladders")
                {
                    foreach (XmlNode l in n.ChildNodes)
                        loadLadder(l);
                }
                else if (n.Name == "Spikes")
                {
                    foreach (XmlNode s in n.ChildNodes)
                        loadSpike(s);
                }
                else if (n.Name == "Entities")
                {
                    foreach (XmlNode s in n.ChildNodes)
                        loadEntity(s);
                }
            }

            _filename = filename;

            return true;
        }

        /// <summary>
        /// Load an entity
        /// </summary>
        /// <param name="root"></param>
        private void loadEntity(XmlNode root)
        {
            //get the entity type
            string typeName = root.Attributes["type"].InnerText;
            typeName = "Editor" + typeName;
            Type newType = _listEditorEntityType[typeName];

            //create the entity
            object newEntity = Activator.CreateInstance(newType);

            //go through each property
            foreach (XmlNode nodeProperty in root.ChildNodes)
            {
                //get the field name
                string fieldName = nodeProperty.Attributes["name"].InnerText;

                try
                {
                    //get the field type
                    string fieldType = newType.GetField(fieldName).FieldType.Name;

                    //get the value 
                    object value = null;

                   
                    switch (fieldType)
                    {
                        case "Vector2":
                            value = GE.Tools.XmlHelper.getVector2FromNode(nodeProperty);
                            break;
                        case "Int32":
                            value = GE.Tools.XmlHelper.getIntFromNode(nodeProperty);
                            break;
                        case "Single":
                            value = GE.Tools.XmlHelper.getFloatFromNode(nodeProperty);
                            break;
                        case "Boolean":
                            if (nodeProperty.InnerText.ToUpper() == "TRUE")
                                value = true;
                            else
                                value = false;
                            break;
                        case "Rectangle":
                            string[] recValue = nodeProperty.InnerText.Split(' ');
                            Rectangle newRectangle = new Rectangle();
                            newRectangle.X = int.Parse(recValue[0]);
                            newRectangle.Y = int.Parse(recValue[1]);
                            newRectangle.Width = int.Parse(recValue[2]);
                            newRectangle.Height = int.Parse(recValue[3]);
                            value = newRectangle;
                            break;

                        default:
                            value = Enum.Parse(newType.GetField(fieldName).FieldType, nodeProperty.InnerText);
                            break;
                    }

                    //set the value
                    newType.GetField(fieldName).SetValue(newEntity, value);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            _level._listEntity.Add(newEntity);
        }

        public void loadSprite(XmlNode n, string path)
        {
            Entity e = new Entity();
            e._tilesetName = n.Attributes["tilesetName"].InnerText;
            e._spriteName = n.Attributes["spriteName"].InnerText;
            e._position = GE.Tools.XmlHelper.getVector2FromNode(n);
            e._type = eEntityType.ePlatform;

            //load the tileset
            e._idTexture = openTileset(Path.Combine(path, e._tilesetName));
            e._idSprite = _visuLevel.getSpriteId(e._idTexture, e._spriteName);
            e._tilesetName = e._tilesetName.Substring(0, e._tilesetName.Length - 4);
            _level._listSprite.Add(e);
        }

        /// <summary>
        /// Load a static platform
        /// </summary>
        /// <param name="n"></param>
        public void loadPlatform(XmlNode n)
        {
            Rectangle rec = new Rectangle();

            string innerText = n.InnerText;
            string[] values = innerText.Split(' ');
            rec.X = int.Parse(values[0]);
            rec.Y = int.Parse(values[1]);
            rec.Width = int.Parse(values[2]);
            rec.Height = int.Parse(values[3]);

            _level._listPlatform.Add(rec);
        }

        private void loadSpike(XmlNode n)
        {
            Rectangle rec = new Rectangle();

            string innerText = n.InnerText;
            string[] values = innerText.Split(' ');
            rec.X = int.Parse(values[0]);
            rec.Y = int.Parse(values[1]);
            rec.Width = int.Parse(values[2]);
            rec.Height = int.Parse(values[3]);

            _level._listSpike.Add(rec);
        
        }

        /// <summary>
        /// Load a ladder
        /// </summary>
        /// <param name="n"></param>
        public void loadLadder(XmlNode n)
        {
            Rectangle rec = new Rectangle();

            string innerText = n.InnerText;
            string[] values = innerText.Split(' ');
            rec.X = int.Parse(values[0]);
            rec.Y = int.Parse(values[1]);
            rec.Width = int.Parse(values[2]);
            rec.Height = int.Parse(values[3]);

            _level._listLadder.Add(rec);
        }
        /// <summary>
        /// Click on the save button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbSave_Click(object sender, System.EventArgs e)
        {
            if (_filename != "")
                save();
            else
                saveWithDialog();
        }

        /// <summary>
        /// click on the save as button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbSaveAs_Click(object sender, System.EventArgs e)
        {
            saveWithDialog();
        }

        private void wndLevel_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.A && e.Modifiers == Keys.Control)
            {
                if (_iIdSpriteSelectedSprite != -1)
                {
                    addSprite();
                    e.Handled = true;
                }
            }

            if (e.KeyCode == Keys.Delete)
            {
                if (_iIdSelectedElementInLevel != -1 && checkBoxDisplayPlatform.Checked) //delete a platform
                {
                    DialogResult res = MessageBox.Show("Do you really want to delete this platform?", "Delete", MessageBoxButtons.YesNo);
                    if (res == System.Windows.Forms.DialogResult.Yes)
                    {
                        _level._listPlatform.RemoveAt(_iIdSelectedElementInLevel);
                        _iIdSelectedElementInLevel = -1;
                        e.Handled = true;
                    }
                }
                else if (_iIdSelectedElementInLevel != -1 && checkBoxLadder.Checked)
                {
                    DialogResult res = MessageBox.Show("Do you really want to delete this ladder?", "Delete", MessageBoxButtons.YesNo);
                    if (res == System.Windows.Forms.DialogResult.Yes)
                    {
                        _level._listLadder.RemoveAt(_iIdSelectedElementInLevel);
                        _iIdSelectedElementInLevel = -1;
                        e.Handled = true;
                    }
                }
                else if (_iIdSelectedElementInLevel != -1 && checkBoxSpike.Checked)
                {
                    DialogResult res = MessageBox.Show("Do you really want to delete this spike?", "Delete", MessageBoxButtons.YesNo);
                    if (res == System.Windows.Forms.DialogResult.Yes)
                    {
                        _level._listSpike.RemoveAt(_iIdSelectedElementInLevel);
                        _iIdSelectedElementInLevel = -1;
                        e.Handled = true;
                    }
                }
                else if (_iIdSelectedElementInLevel != -1 && checkBoxEntity.Checked)
                {
                    DialogResult res = MessageBox.Show("Do you really want to delete this entity?", "Delete", MessageBoxButtons.YesNo);
                    if (res == System.Windows.Forms.DialogResult.Yes)
                    {
                        _level._listEntity.RemoveAt(_iIdSelectedElementInLevel);
                        _iIdSelectedElementInLevel = -1;
                        e.Handled = true;
                    }
                }
                else if (_iIdSelectedElementInLevel != -1)//delete a sprite
                {
                    DialogResult res = MessageBox.Show("Do you really want to delete this sprite?", "Delete", MessageBoxButtons.YesNo);
                    if (res == System.Windows.Forms.DialogResult.Yes)
                    {
                        _level._listSprite.RemoveAt(_iIdSelectedElementInLevel);
                        _iIdSelectedElementInLevel = -1;
                        e.Handled = true;
                    }
                }
            }
        }

        /// <summary>
        /// Set and display the group box waypoint using the selected sprite
        /// </summary>
        private void setAndDisplayGroupBoxWaypoint()
        {
            //nothing selected
            if (_iIdSelectedElementInLevel == -1) return;

            //display the group box
            gbEntity.Visible = true;

            //get the entity
            Entity e = _level._listSprite[_iIdSelectedElementInLevel];

           
        }


    
        private void tsbZoomIn_Click(object sender, System.EventArgs e)
        {
            zoomIn();
        }

        private void tsbZoomOut_Click(object sender, System.EventArgs e)
        {
            zoomOut();
        }

        /// <summary>
        /// Take a point in the panel coordinate and return it into texture coordinate.
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        private Vector2 getPanelPositionToTexturePosition(Vector2 v)
        {
            Vector2 res = v;
            res += _v2CameraPosition;
            res /= _iZoom;
            res.X = (int)res.X;
            res.Y = (int)res.Y;
            return res;
        }

        private void tsbAddPlatform_Click(object sender, System.EventArgs e)
        {
            if (!checkBoxDisplayPlatform.Checked)
                checkBoxDisplayPlatform.Checked = true;

            _userMode = eUserMode.eAddPlatform;
            _bFirstPointAdded = false;
        }

        private void checkBoxDisplayPlatform_CheckedChanged(object sender, System.EventArgs e)
        {
            if (checkBoxDisplayPlatform.Checked == false)
                _userMode = eUserMode.eNone;
        }

        private void toolStripButton1_Click(object sender, System.EventArgs e)
        {
            saveWithDialog();
        }

        private void tsbAddLadder_Click(object sender, System.EventArgs e)
        {
            if (!checkBoxLadder.Checked)
                checkBoxLadder.Checked = true;

            _bFirstPointAdded = false;

            _userMode = eUserMode.eAddLadder;
        }

        private void tsbAddSpike_Click(object sender, System.EventArgs e)
        {
            if (!checkBoxSpike.Checked)
                checkBoxSpike.Checked = true;

            _bFirstPointAdded = false;

            _userMode = eUserMode.eAddSpike;
        }

        /// <summary>
        /// Add an entity
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbAddEntity_Click(object sender, EventArgs e)
        {
            //no type of entity selected
            if (cbEntityType.SelectedIndex == -1) return;

            //change the user mode
            _userMode = eUserMode.eAddEntity;

            //create the entity
            Type typeOfEntity = _listEditorEntityType["Editor" + cbEntityType.SelectedItem];
            _newEntity = Activator.CreateInstance(typeOfEntity);

            //display all entities
            checkBoxEntity.Checked = true;
        }

        private void splitContainer_Panel2_Resize(object sender, EventArgs e)
        {
            gbEntity.Left = 0;
            gbEntity.Width = gbOptions.ClientSize.Width;
            gbEntity.Height = gbOptions.ClientSize.Height - gbEntity.Top;
        }

        /// <summary>
        /// Change the selection mode
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tscbSelection_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectionMode = (eSelectionMode)tscbSelection.SelectedIndex;
        }
    }

    public class comboBoxItem
    {
        public string _text;
        public int _idTexture;
        public int _idSprite;

        public comboBoxItem(int idTexture, int idSprite, string text)
        {
            _idTexture = idTexture;
            _idSprite = idSprite;
            _text = text;
        }
    }
}
