/// <summary>
        /// Draws the specified tile layer to the screen.
        /// </summary>
        /// <param name="spriteBatch">A spritebatch object for drawing.</param>
        /// <param name="tileLayer">The TileLayer object to be drawn.</param>
        /// <param name="location">The location to draw the layer.</param>
        /// <param name="startIndex">The i and j indices of the first tile to draw.</param>
        public void DrawLayer(SpriteBatch spriteBatch, TileLayer tileLayer, Rectangle location, Vector2 startIndex)
        {
            int width       = location.Width / TileWidth;   //The number of tiles in the i direction that fit on the screen
            int height      = location.Height / TileHeight; //The number of tiles in the j direction that fit on the screen
            int iStartIndex = (int)startIndex.X;            //The i index of the first tile to draw
            int jStartIndex = (int)startIndex.Y;            //The j index of the first tile to draw

            if (RenderOrder == RenderOrder.RightDown)
            {
                for (int j = 0; j < height; j++)
                {
                    for (int i = 0; i < width; i++)
                    {
                        Draw(spriteBatch, i, j, iStartIndex, jStartIndex, tileLayer);
                    }
                }
            }
            else if (RenderOrder == RenderOrder.RightUp)
            {
                for (int j = height; 0 <= j; j--)
                {
                    for (int i = 0; i < width; i++)
                    {
                        Draw(spriteBatch, i, j, iStartIndex, jStartIndex, tileLayer);
                    }
                }
            }
            else if (RenderOrder == RenderOrder.LeftDown)
            {
                for (int j = 0; j < height; j++)
                {
                    for (int i = 0; i < width; i++)
                    {
                        Draw(spriteBatch, i, j, iStartIndex, jStartIndex, tileLayer);
                    }
                }
            }
            else if (RenderOrder == RenderOrder.LeftUp)
            {
                for (int j = height; 0 <= j; j--)
                {
                    for (int i = width; 0 <= i; i--)
                    {
                        Draw(spriteBatch, i, j, iStartIndex, jStartIndex, tileLayer);
                    }
                }
            }
        }
        /// <summary>
        /// Performs the actual drawing. Above Draw method tells it what render order to use.
        /// </summary>
        /// <param name="spriteBatch">A spritebatch object for drawing.</param>
        /// <param name="i">The i index for drawwing in the i direction.</param>
        /// <param name="j">The j index for drawwing in the i direction.</param>
        /// <param name="iStartIndex">The i index of the first tile to draw.</param>
        /// <param name="jStartIndex">The j index of the first tile to draw.</param>
        /// <param name="layer">The layer to be drawn.</param>
        private void Draw(SpriteBatch spriteBatch, int i, int j, int iStartIndex, int jStartIndex, TileLayer layer)
        {
            int   tileOffsetX = 0;
            int   tileOffsetY = 0;
            float opacity     = 1.0f;

            if (layer.Opacity != 1.0f)
            {
                opacity = layer.Opacity;
            }

            //This if statement keeps the code from throwing an out of range exception depending on where the start indices are.
            //There is an explanation along with comments on how to prevent this from happening in the documentation.
            if (iStartIndex + i < layer.Data.TileData.GetUpperBound(0) && jStartIndex + j < layer.Data.TileData.GetUpperBound(1) &&
                iStartIndex >= 0 && jStartIndex >= 0)
            {
                int gid = layer.Data.GetTileData(iStartIndex + i, jStartIndex + j); //The global id of the tile in the layer at this point

                //If a gid of 0 occurs, it means that for this layer there is no tile placed in that location
                if (gid != 0)
                {
                    Tileset tileset = GetTileset(gid); //Find the tileset with the tile that we want to draw

                    //If the tileset has drawing offsets applied
                    if (tileset.TileOffset != null)
                    {
                        if (tileset.TileOffset.X != 0)
                        {
                            tileOffsetX = tileset.TileOffset.X;
                        }
                        else
                        {
                            tileOffsetX = 0;
                        }

                        if (tileset.TileOffset.Y != 0)
                        {
                            tileOffsetY = tileset.TileOffset.Y;
                        }
                        else
                        {
                            tileOffsetY = 0;
                        }
                    }

                    Tile tile = tileset.GetTile(gid); //Find the tile in that tileset

                    spriteBatch.Draw(tileset.Image.Texture, new Rectangle((i * TileWidth) + tileOffsetX, (j * TileHeight) + tileOffsetY, TileWidth, TileHeight),
                                     tile.Location, Color.White * opacity);
                }
            }
        }
        /// <summary>
        /// Returns the global id of the tile at the specified postion on the screen.
        /// </summary>
        /// <remarks>
        /// This is a powerful method that can be used in combination with your game logic to determine collisions, doors, etc.
        /// </remarks>
        /// <param name="tileOnScreen">The i and j indices of the tile on the screen.</param>
        /// <param name="startIndex">The i and j indices of the upper left most tile in the actual layer data.</param>
        /// <param name="tileLayer">The specific TileLayer to search.</param>
        /// <returns>The global id of the tile at the given location.</returns>
        /// <see cref="MapImporter.Tile"/>
        public int GetTile(Vector2 tileOnScreen, Vector2 startIndex, TileLayer tileLayer)
        {
            Vector2 temp = TranslateScreenToMap(tileOnScreen, startIndex);

            return(tileLayer.Data.GetTileData((int)temp.X, (int)temp.Y));
        }
        /// <summary>
        /// Parses the given text from a JSON file and turns it into a Map object.
        /// </summary>
        /// <param name="fileText">The text of the JSON file.</param>
        /// <returns>A new Map object.</returns>
        private static Map ReadMapAsJson(string fileText)
        {
            JObject mapJSON = JObject.Parse(fileText);
            Map     m       = new Map();

            if (mapJSON != null)
            {
                m.Version = mapJSON["version"].ToString();

                if (mapJSON["orientation"].ToString() == "orthogonal")
                {
                    m.Orientation = Orientation.Orthogonal;
                }
                else
                {
                    throw new Exception("The Orientation of a given Map file is not 'Orthogonal'. " +
                                        "This version of the Importer library does not support any other types.");
                }

                /*else if (mapJSON["orientation"].ToString() == "isometric")
                 * {
                 *  m.Orientation = Orientation.Isometric;
                 * }
                 * else if (mapJSON["orientation"].ToString() == "staggered")
                 * {
                 *  m.Orientation = Orientation.Staggered;
                 * }*/

                m.Width      = (int)mapJSON["width"];
                m.Height     = (int)mapJSON["height"];
                m.TileWidth  = (int)mapJSON["tilewidth"];
                m.TileHeight = (int)mapJSON["tileheight"];

                if (mapJSON["backgroundcolor"] != null)
                {
                    m.BackgroundColor = ToColor(mapJSON["backgroundcolor"].ToString());
                }

                if (mapJSON["renderorder"].ToString() == "right-down")
                {
                    m.RenderOrder = RenderOrder.RightDown;
                }
                else if (mapJSON["renderorder"].ToString() == "right-up")
                {
                    m.RenderOrder = RenderOrder.RightUp;
                }
                else if (mapJSON["renderorder"].ToString() == "left-down")
                {
                    m.RenderOrder = RenderOrder.LeftDown;
                }
                else if (mapJSON["renderorder"].ToString() == "left-up")
                {
                    m.RenderOrder = RenderOrder.LeftUp;
                }

                if (mapJSON["properties"] != null)
                {
                    m.Props.PropertiesList = JsonConvert.DeserializeObject <Dictionary <string, string> >(mapJSON["properties"].ToString());
                }

                if (mapJSON["nextobjectid"] != null)
                {
                    int num;
                    int.TryParse(mapJSON["nextobjectid"].ToString(), out num);
                    m.NextObjectId = num;
                }

                // Create and add the tilesets
                int    gid         = 1; //Keeps track of the global ids for all tiles
                JArray tilesetJson = (JArray)mapJSON["tilesets"];
                if (tilesetJson != null)
                {
                    foreach (JObject tilesets in tilesetJson)
                    {
                        Tileset tileset = new Tileset((int)tilesets["firstgid"], tilesets["name"].ToString(), (int)tilesets["tilewidth"], (int)tilesets["tileheight"],
                                                      (int)tilesets["spacing"], (int)tilesets["margin"]);

                        if (tilesets["tileoffset"] != null)
                        {
                            JObject offset = (JObject)tilesets["tileoffset"];
                            tileset.TileOffset = new TileOffset();
                            if (offset["x"] != null)
                            {
                                tileset.TileOffset.X = (int)offset["x"];
                            }
                            else
                            {
                                tileset.TileOffset.X = 0;
                            }

                            if (offset["y"] != null)
                            {
                                tileset.TileOffset.Y = (int)offset["x"];
                            }
                            else
                            {
                                tileset.TileOffset.Y = 0;
                            }
                        }

                        if (tilesets["image"] != null)
                        {
                            tileset.Image.Source = tilesets["image"].ToString();
                            tileset.Image.Format = Path.GetExtension(tileset.Image.Source);
                            if (tilesets["trans"] != null)
                            {
                                tileset.Image.Trans = ToColor(tilesets["trans"].ToString());
                            }
                            if (tilesets["imagewidth"] != null)
                            {
                                tileset.Image.Width = (int)tilesets["imagewidth"];
                            }
                            if (tilesets["imageheight"] != null)
                            {
                                tileset.Image.Height = (int)tilesets["imageheight"];
                            }
                            tileset.Source = tileset.Image.Source;
                        }

                        if (tilesets["properties"] != null)
                        {
                            tileset.Props.PropertiesList = JsonConvert.DeserializeObject <Dictionary <string, string> >(tilesets["properties"].ToString());
                        }

                        if (tilesets["terraintypes"] != null)
                        {
                            // add terraintypes
                        }

                        int id = 0; //Keeps track of the local id for the tiles
                        for (int y = (tileset.Margin / tileset.TileHeight); y < ((tileset.Image.Height - tileset.Margin) / tileset.TileHeight); y++)
                        {
                            for (int x = (tileset.Margin / tileset.TileWidth); x < ((tileset.Image.Width - tileset.Margin) / tileset.TileWidth); x++)
                            {
                                Tile tile = new Tile(id, gid, new Rectangle((x * tileset.TileWidth) + tileset.Spacing, (y * tileset.TileHeight) + tileset.Spacing,
                                                                            tileset.TileWidth, tileset.TileHeight));
                                tileset.Tiles.Add(tile);
                                id++;
                                gid++;
                            }
                        }

                        if (tilesets["tileproperties"] != null)
                        {
                            int    index = 0;
                            string str   = tilesets["tileproperties"].ToString();
                            if (str.Contains(","))
                            {
                                string[] elements = str.Split(',');
                                foreach (string s in elements)
                                {
                                    string[] i = s.Split('\"');

                                    //Property for a tile that does not currently have any
                                    if (i.Length > 5)
                                    {
                                        try
                                        {
                                            int.TryParse(i[1], out index);
                                        }
                                        catch (OverflowException)
                                        {
                                            Console.Write("ERROR: Class=Importer --- Int32 conversion failed --- Value=" + i[1] + "\n");
                                        }

                                        tileset.Tiles[index].Props = new Properties();
                                        tileset.Tiles[index].Props.PropertiesList.Add(i[3].ToString(), i[5].ToString());
                                    }
                                    else
                                    {
                                        tileset.Tiles[index].Props.PropertiesList.Add(i[1].ToString(), i[3].ToString());
                                    }
                                }
                            }
                        }
                        m.Tilesets.Add(tileset);
                    }
                }

                // Add the layers
                int indexInLayerList   = 0;
                int indexInTileLayer   = 0;
                int indexInObjectGroup = 0;
                int indexInImageLayer  = 0;
                foreach (JObject layerJson in mapJSON["layers"])
                {
                    if (layerJson["type"].ToString() == "tilelayer")
                    {
                        LayerData ld = new LayerData(indexInLayerList, indexInTileLayer, LayerType.TileLayer);
                        m.LayerDataList.Add(ld);
                        indexInTileLayer++;

                        TileLayer l = new TileLayer(layerJson["name"].ToString(), (int)layerJson["x"], (int)layerJson["y"], (int)layerJson["width"],
                                                    (int)layerJson["height"], (float)layerJson["opacity"]);

                        //Put the data from the layer into the Data object
                        JArray dataJson = (JArray)layerJson["data"];
                        l.Data = new Data(l.Width, l.Height);
                        List <int> nums = new List <int>();

                        try
                        {
                            foreach (int num in dataJson)
                            {
                                nums.Add(num);
                            }
                        }
                        catch
                        {
                            throw new OverflowException("ERROR: Class=Importer --- Int32 conversion failed ---" + "\n");
                        }

                        int k = 0;
                        for (int j = 0; j < l.Height; j++)
                        {
                            for (int i = 0; i < l.Width; i++)
                            {
                                try
                                {
                                    l.Data.TileData[i, j] = nums[k];
                                    k++;
                                }
                                catch
                                {
                                    throw new IndexOutOfRangeException("ERROR: Class=Importer --- Problem with indices in TileData --- Value="
                                                                       + l.Data.TileData[i, j] + "\n");
                                }
                            }
                        }

                        string s = layerJson["visible"].ToString();
                        if (s.Equals("true") || s.Equals("True"))
                        {
                            l.Visible = true;
                        }
                        else
                        {
                            l.Visible = false;
                        }

                        if (layerJson["properties"] != null)
                        {
                            l.Props = new Properties();
                            l.Props.PropertiesList = JsonConvert.DeserializeObject <Dictionary <string, string> >(layerJson["properties"].ToString());
                        }

                        m.TileLayers.Add(l); // Add the new layer to the list of Layers
                    }
                    else if (layerJson["type"].ToString() == "objectgroup")
                    {
                        LayerData ld = new LayerData(indexInLayerList, indexInObjectGroup, LayerType.ObjectGroup);
                        m.LayerDataList.Add(ld);
                        indexInObjectGroup++;

                        ObjectGroup objGroup = new ObjectGroup(layerJson["name"].ToString(), (int)layerJson["x"], (int)layerJson["y"],
                                                               (int)layerJson["width"], (int)layerJson["height"], (float)layerJson["opacity"]);

                        if (layerJson["color"] != null)
                        {
                            objGroup.Color = ToColor(layerJson["color"].ToString());
                        }

                        string str = layerJson["draworder"].ToString();
                        if (str.Equals("topdown"))
                        {
                            objGroup.DrawOrder = DrawOrder.TopDown;
                        }
                        else
                        {
                            objGroup.DrawOrder = DrawOrder.TopDown;
                        }

                        string s = layerJson["visible"].ToString();
                        if (s.Equals("true") || s.Equals("True"))
                        {
                            objGroup.Visible = true;
                        }
                        else
                        {
                            objGroup.Visible = false;
                        }

                        JArray objectJson = (JArray)layerJson["objects"];
                        foreach (JObject o in objectJson)
                        {
                            Object obj = new Object(o["name"].ToString(), (int)o["id"], (double)o["width"], (double)o["height"],
                                                    (double)o["x"], (double)o["y"], o["type"].ToString(), (double)o["rotation"]);

                            string st = o["visible"].ToString();
                            if (st.Equals("true") || s.Equals("True"))
                            {
                                obj.Visible = true;
                            }
                            else
                            {
                                obj.Visible = false;
                            }

                            if (o["properties"] != null)
                            {
                                obj.Props.PropertiesList = JsonConvert.DeserializeObject <Dictionary <string, string> >(o["properties"].ToString());
                            }

                            if (o["gid"] != null)
                            {
                                obj.Gid = (int)o["gid"];
                            }

                            // If the property Ellipse exists, then the object is an Ellipse
                            if (o["ellipse"] != null)
                            {
                                obj.ObjType = ObjectType.Ellipse;
                            }
                            else if (o["polygon"] != null)
                            {
                                obj.ObjType = ObjectType.Polygon;
                                JArray         polygonJson = (JArray)o["polygon"];
                                List <Vector2> points      = new List <Vector2>();
                                foreach (JObject point in polygonJson)
                                {
                                    points.Add(new Vector2((int)point["x"], (int)point["y"]));
                                }
                                obj.Polygon = new Polygon(points);
                            }
                            else if (o["polyline"] != null)
                            {
                                obj.ObjType = ObjectType.Polyline;
                                JArray polylineJson = (JArray)o["polyline"];
                                foreach (JObject polyline in polylineJson)
                                {
                                }
                            }
                            else
                            {
                                obj.ObjType = ObjectType.Rectangle;
                            }

                            objGroup.Objects.Add(obj);
                        }

                        m.ObjectGroups.Add(objGroup);
                    }
                    else if (layerJson["type"].ToString() == "imagelayer")
                    {
                        LayerData ld = new LayerData(indexInLayerList, indexInImageLayer, LayerType.ImageLayer);
                        m.LayerDataList.Add(ld);
                        indexInImageLayer++;
                    }
                    indexInLayerList++;
                }
            }
            return(m);
        }