/// <summary>
        /// Writes an EntitiesFile object to a file
        /// </summary>
        /// <param name="entitiesFile">EntitiesFile object</param>
        /// <param name="path">destination path</param>
        public static void WriteEntitiesFile(EntitiesFile entitiesFile, string path)
        {
            using (var streamWriter = new StreamWriter(path, false))
            {
                streamWriter.NewLine = "";
                streamWriter.WriteLine(GetEntitiesFileHeaderString(entitiesFile));

                if (entitiesFile.Properties != null && entitiesFile.Properties.Count != 0)
                {
                    streamWriter.WriteLine(GetPropertiesSectionString(entitiesFile.Properties));
                }

                for (int i = 0; i < entitiesFile.Entities.Count; i++)
                {
                    streamWriter.WriteLine(GetEntityString(entitiesFile.Entities[i]));

                    if (i != entitiesFile.Entities.Count - 1)
                    {
                        streamWriter.WriteLine("\n");
                    }
                }

                streamWriter.Close();
            }
        }
        /// <summary>
        /// Builds the header string of the entities file
        /// </summary>
        /// <param name="entitiesFile">EntitiesFile object</param>
        /// <returns>the header string of the entities file</returns>
        internal static string GetEntitiesFileHeaderString(EntitiesFile entitiesFile)
        {
            StringBuilder header = new StringBuilder();

            if (!string.IsNullOrEmpty(entitiesFile.Version))
            {
                header.Append("Version ").Append(entitiesFile.Version).Append("\n");
            }

            if (!string.IsNullOrEmpty(entitiesFile.HierarchyVersion))
            {
                header.Append("HierarchyVersion ").Append(entitiesFile.HierarchyVersion).Append("\n");
            }

            return(header.ToString());
        }
        /// <summary>
        /// Parses the given entities file into an EntitiesFile object
        /// </summary>
        /// <param name="entitiesFilePath">path to the entities file</param>
        /// <returns>an EntitiesFile object with the parsed data from the entities file</returns>
        public EntitiesFileParseResult Parse(string entitiesFilePath)
        {
            if (!File.Exists(entitiesFilePath))
            {
                throw new FileNotFoundException(string.Format("Entities file not found in path: {0}", entitiesFilePath));
            }

            Warnings = new List <string>();
            Errors   = new List <string>();

            EntitiesFile entitiesFile = new EntitiesFile()
            {
                Version          = string.Empty,
                HierarchyVersion = string.Empty
            };

            int currentLineNumber = 0;

            using (FileStream fs = File.Open(entitiesFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (BufferedStream bs = new BufferedStream(fs))
                {
                    using (StreamReader sr = new StreamReader(bs))
                    {
                        string        line                = string.Empty;
                        bool          nextEntityError     = false;
                        int           openingBracketCount = 0;
                        int           closingBracketCount = 0;
                        List <Entity> entities            = new List <Entity>();
                        StringBuilder currentEntity       = new StringBuilder();

                        // Get whole entity blocks to pass them to the entity parser
                        while ((line = sr.ReadLine()) != null)
                        {
                            // Remove comments from lines
                            line = RemoveComments(line, "//");

                            currentLineNumber++;
                            line = line.Trim();

                            if (string.IsNullOrEmpty(line))
                            {
                                continue;
                            }

                            // Try to parse the version headers first if we don't have them yet and
                            // if we haven't found any entity block yet
                            if (entitiesFile.Version == string.Empty || entitiesFile.HierarchyVersion == string.Empty && openingBracketCount == 0)
                            {
                                string[] versionHeaderPart = line.Split(' ');

                                if (versionHeaderPart.Length == 2 && versionHeaderPart[0].Equals("Version"))
                                {
                                    entitiesFile.Version = versionHeaderPart[1];
                                    continue;
                                }
                                else if (versionHeaderPart.Length == 2 && versionHeaderPart[0].Equals("HierarchyVersion"))
                                {
                                    entitiesFile.HierarchyVersion = versionHeaderPart[1];
                                    continue;
                                }
                            }

                            // Look for the properties section
                            if (openingBracketCount == 0 && entitiesFile.Properties == null &&
                                (line.Equals("properties {") || line.Equals("properties{")))
                            {
                                // Parse the properties
                                entitiesFile.Properties = new List <EntityProperty>();

                                while ((line = sr.ReadLine()) != null && !line.Trim().Equals("}"))
                                {
                                    try
                                    {
                                        currentLineNumber++;
                                        entitiesFile.Properties.Add(ParseEntityProperty(line, ref currentLineNumber, true));
                                    }
                                    catch (FormatException)
                                    {
                                        throw;
                                    }
                                }

                                // Closing bracket
                                currentLineNumber++;

                                // Read the next line after the closing bracket
                                if ((line = sr.ReadLine()) == null)
                                {
                                    break;
                                }

                                // Next line
                                currentLineNumber++;
                            }

                            // Look for entities
                            if (openingBracketCount == 0)
                            {
                                if (!line.Equals("entity {") && !line.Equals("entity{"))
                                {
                                    if (line.Equals("entity"))
                                    {
                                        Errors.Add(string.Format("Line {0}: missing '{{'", currentLineNumber));
                                    }
                                    else
                                    {
                                        Errors.Add(string.Format("Line {0}: unexpected '{1}", currentLineNumber, line));
                                    }

                                    continue;
                                }

                                // Found an entity here, add the first line and look for the lines in its block
                                currentEntity.Append(line).Append("\n");
                                openingBracketCount++;
                                closingBracketCount = 0;
                                continue;
                            }

                            // We are in an entity block here, get everything until we find the closing bracket
                            if (line[line.Length - 1] == '{')
                            {
                                openingBracketCount++;
                            }

                            if (line[line.Length - 1] == '}')
                            {
                                closingBracketCount++;
                            }

                            // If we find another entity block, check for the closing bracket of our current entity
                            // and opening bracket for the next entity, then continue with it
                            // If not, just continue adding current entity block lines until we hit another entity
                            if (!line.Equals("entity {") && !line.Equals("entity{"))
                            {
                                if (line.Equals("entity"))
                                {
                                    Errors.Add(string.Format("Line {0}: missing '{{'", currentLineNumber));
                                    nextEntityError = true;
                                }
                                else
                                {
                                    if (openingBracketCount != closingBracketCount)
                                    {
                                        currentEntity.Append(line).Append("\n");
                                        continue;
                                    }
                                    else
                                    {
                                        currentEntity.Append(line);

                                        // All OK, push current entity to the entity parser
                                        // and continue searching for more
                                        try
                                        {
                                            Entity parsedEntity = ParseEntity(currentEntity.ToString(), ref currentLineNumber);

                                            if (parsedEntity != null && parsedEntity.EntityDef != null)
                                            {
                                                entities.Add(parsedEntity);
                                            }
                                        }
                                        catch (FormatException)
                                        {
                                            throw;
                                        }

                                        openingBracketCount = 0;
                                        closingBracketCount = 0;
                                        currentEntity.Clear();
                                        continue;
                                    }
                                }
                            }

                            // We hit another entity at this point
                            // Check for the closing bracket of this current entity
                            // Substract 1 from the opening brackets count to not take
                            // the next entity opening bracket into account
                            if ((openingBracketCount - 1 != closingBracketCount) ||
                                (nextEntityError && (openingBracketCount != closingBracketCount)))
                            {
                                Errors.Add(string.Format("Line {0}: missing '}}'", currentLineNumber));
                                nextEntityError = false;
                            }

                            // All OK, push current entity to the entity parser
                            // and continue with the next one
                            try
                            {
                                // Don't take into account the next entity line
                                currentLineNumber--;

                                // Remove last new line character
                                currentEntity.Remove(currentEntity.Length - 1, 1);

                                Entity parsedEntity = ParseEntity(currentEntity.ToString(), ref currentLineNumber);

                                if (parsedEntity != null && parsedEntity.EntityDef != null)
                                {
                                    entities.Add(parsedEntity);
                                }
                            }
                            catch (FormatException)
                            {
                                throw;
                            }

                            currentLineNumber++;
                            openingBracketCount = 1;
                            closingBracketCount = 0;
                            currentEntity.Clear();
                            currentEntity.Append(line).Append("\n");
                        }

                        entitiesFile.Entities = entities;
                    }
                }
            }

            return(new EntitiesFileParseResult()
            {
                Errors = Errors.ToArray(),
                Warnings = Warnings.ToArray(),
                EntitiesFile = entitiesFile
            });
        }