/// <summary>
        /// Builds the string for an array object value
        /// </summary>
        /// <param name="arrayObjectValue">EntityPropertyObjectValue object of the value of the array</param>
        /// <param name="arrayItemIndex">index of this item in the array</param>
        /// <param name="indentationLevel">current indentation level</param>
        /// <returns>the string for the array object value></returns>
        internal static string GetArrayObjectValueString(EntityPropertyObjectValue arrayObjectValue, int arrayItemIndex, uint indentationLevel)
        {
            StringBuilder objectString = new StringBuilder();

            objectString.Append(IndentText("item[", indentationLevel)).Append(arrayItemIndex).Append("] = {").Append("\n");
            indentationLevel++;

            foreach (var value in arrayObjectValue.Value)
            {
                if (value == null)
                {
                    continue;
                }

                if (value.Value.GetType() == typeof(EntityPropertyArrayValue))
                {
                    objectString.Append(GetArrayString(value, ref indentationLevel)).Append("\n");
                }
                else if (value.Value.GetType() == typeof(EntityPropertyObjectValue))
                {
                    objectString.Append(GetObjectString(value, ref indentationLevel)).Append("\n");
                }
                else
                {
                    objectString.Append(GetPropertyString(value, indentationLevel)).Append("\n");
                }
            }

            indentationLevel--;
            objectString.Append(IndentText("}", indentationLevel));

            return(objectString.ToString());
        }
        /// <summary>
        /// Parses any kind of property from an entityDef into an EntityProperty object
        /// </summary>
        /// <param name="propertyText">text containing the property</param>
        /// <param name="currentLineNumber">current line number reference in the file</param>
        /// <param name="isFromPropertiesSection">indicates wether or not this property comes from the properties section</param>
        /// <returns>an EntityProperty object containing the parsed data from the property</returns>
        internal EntityProperty ParseEntityProperty(string propertyText, ref int currentLineNumber, bool isFromPropertiesSection = false)
        {
            // Split the property definition into lines (if it has any)
            EntityProperty entityProperty = new EntityProperty();

            string[] propertyLines = propertyText.Split('\n');
            currentLineNumber -= propertyLines.Length - 1;

            for (int i = 0; i < propertyLines.Length; i++)
            {
                propertyLines[i] = propertyLines[i].Trim();

                if (i > 0)
                {
                    currentLineNumber++;
                }

                // Skip closing brackets
                if (propertyLines[i].Equals("}"))
                {
                    continue;
                }

                // Again, first we need to determine which kind of property this is to properly parse it
                string[] propertyParts = propertyLines[i].Split('=');

                if (propertyParts.Length != 2 || string.IsNullOrEmpty(propertyParts[1].Trim()))
                {
                    Errors.Add(string.Format("Line {0}: bad property declaration '{1}'", currentLineNumber, propertyLines[i].Trim()));
                    continue;
                }

                propertyParts[0] = propertyParts[0].TrimEnd();
                propertyParts[1] = propertyParts[1].Trim();

                // This is a "single-line" property
                if (propertyParts[1][propertyParts[1].Length - 1] != '{')
                {
                    propertyParts[0] = propertyParts[0].Trim();
                    propertyParts[1] = propertyParts[1].Trim();

                    // Check if the property name is quoted
                    if (propertyParts[0].StartsWith("\"") && propertyParts[0].EndsWith("\""))
                    {
                        entityProperty.IsQuoted = true;
                        propertyParts[0]        = propertyParts[0].Remove(0, 1);
                        propertyParts[0]        = propertyParts[0].Remove(propertyParts[0].Length - 1, 1);
                    }

                    if (!IsValidPropertyName(propertyParts[0]))
                    {
                        Errors.Add(string.Format("Line {0}: invalid property name '{1}'", currentLineNumber, propertyParts[0]));
                        continue;
                    }

                    entityProperty.Name = propertyParts[0];

                    try
                    {
                        // Check for and remove semicolon at the end for the value parser
                        if (propertyParts[1][propertyParts[1].Length - 1] != ';' && !isFromPropertiesSection)
                        {
                            Errors.Add(string.Format("Line {0}: missing ';'", currentLineNumber));
                        }
                        else if (!isFromPropertiesSection)
                        {
                            propertyParts[1] = propertyParts[1].Remove(propertyParts[1].Length - 1, 1);
                        }

                        entityProperty.Value = ParseEntityPropertyValue(propertyParts[1].Trim(), ref currentLineNumber);

                        if (entityProperty.Value == null)
                        {
                            continue;
                        }
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                }
                else
                {
                    // Check if the "Important" flag is present
                    if (propertyParts[1].Length > 1 && propertyParts[1][0] == '!')
                    {
                        entityProperty.Important = true;
                    }

                    // We will loop through all the properties in this object/array
                    // and do recursion to get the values
                    List <EntityProperty> properties       = new List <EntityProperty>();
                    EntityProperty        arrayNumProperty = null;
                    bool isArray = false;
                    int  arrayNumPropertyLineNumber = 0;
                    int  openingBracketCount        = 1;
                    int  closingBracketCount        = 0;

                    currentLineNumber++;

                    // Get everything until the block is closed
                    for (int j = i + 1; j < propertyLines.Length - 1; j++, currentLineNumber++, i = j)
                    {
                        if (string.IsNullOrEmpty(propertyLines[j]))
                        {
                            continue;
                        }

                        if (propertyLines[j][propertyLines[j].Length - 1] == '{')
                        {
                            openingBracketCount++;
                        }

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

                        if (openingBracketCount == closingBracketCount)
                        {
                            currentLineNumber++;
                            break;
                        }

                        // Check if this is a single property or an object
                        // Everything inside the entityDef must be a property of some kind
                        // We will get all the text of the property and pass it to the property parser
                        EntityProperty nestedEntityProperty = new EntityProperty();
                        string[]       currentPropertyText  = propertyLines[j].Split('=');

                        if (currentPropertyText.Length != 2)
                        {
                            if (propertyLines[j].Equals("{") || propertyLines[j].Equals("}"))
                            {
                                continue;
                            }
                            else
                            {
                                Errors.Add(string.Format("Line {0}: unexpected '{1}'", currentLineNumber, propertyLines[j]));
                                continue;
                            }
                        }

                        currentPropertyText[0] = currentPropertyText[0].TrimEnd();
                        currentPropertyText[1] = currentPropertyText[1].Trim();

                        if (string.IsNullOrEmpty(currentPropertyText[1]))
                        {
                            Errors.Add(string.Format("Line {0}: missing property value", currentLineNumber));
                            continue;
                        }

                        // Determine what kind of property this is to get all it's text
                        // This is probably a "single-line" property, so we can just pass the whole line to the property parser
                        if (currentPropertyText[1][currentPropertyText[1].Length - 1] != '{')
                        {
                            // Check if this is an array or an object
                            string trimmedPropertyName = currentPropertyText[0].TrimStart();

                            // Get the number of items in the array
                            // We will use it to check that the number matches with the actual
                            // amount of items
                            if (!isArray & trimmedPropertyName.Equals("num"))
                            {
                                arrayNumPropertyLineNumber = currentLineNumber;
                                arrayNumProperty           = ParseEntityProperty(propertyLines[j], ref currentLineNumber);

                                if (arrayNumProperty != null && arrayNumProperty.Value != null &&
                                    arrayNumProperty.Value.GetType() != typeof(EntityPropertyLongValue))
                                {
                                    Errors.Add(string.Format("Line {0}: 'num' property value must be a number", currentLineNumber));
                                }

                                isArray = true;
                            }

                            try
                            {
                                nestedEntityProperty = ParseEntityProperty(propertyLines[j], ref currentLineNumber);
                            }
                            catch (FormatException)
                            {
                                throw;
                            }
                        }
                        else
                        {
                            // Check if the "Important" flag is present
                            if (currentPropertyText[1].Length > 1 && currentPropertyText[1][0] == '!')
                            {
                                nestedEntityProperty.Important = true;
                            }

                            // This is either an object or an array, so we'll just get the whole block
                            // to pass it to the property parser
                            StringBuilder currentNestedPropertyText = new StringBuilder();
                            int           nestedOpeningBracketCount = 1;
                            int           nestedClosingBracketCount = 0;

                            currentNestedPropertyText.Append(propertyLines[j]).Append("\n");

                            // Get everything until the block is closed
                            for (int k = j + 1; j < propertyLines.Length; k++, currentLineNumber++, j = k)
                            {
                                if (string.IsNullOrEmpty(propertyLines[k]))
                                {
                                    continue;
                                }

                                if (propertyLines[k][propertyLines[k].Length - 1] == '{')
                                {
                                    nestedOpeningBracketCount++;
                                    currentNestedPropertyText.Append(propertyLines[k]).Append("\n");
                                    continue;
                                }

                                if (propertyLines[k][propertyLines[k].Length - 1] == '}')
                                {
                                    nestedClosingBracketCount++;
                                }

                                if (nestedOpeningBracketCount == nestedClosingBracketCount)
                                {
                                    currentNestedPropertyText.Append(propertyLines[k]);
                                    currentLineNumber++;
                                    break;
                                }

                                currentNestedPropertyText.Append(propertyLines[k]).Append("\n");
                            }

                            nestedEntityProperty = ParseEntityProperty(currentNestedPropertyText.ToString(), ref currentLineNumber);
                            currentNestedPropertyText.Clear();
                        }

                        if (nestedEntityProperty != null)
                        {
                            properties.Add(nestedEntityProperty);
                        }
                    }

                    if (!isArray)
                    {
                        EntityPropertyObjectValue objectValue = new EntityPropertyObjectValue();
                        objectValue.Value = properties;

                        entityProperty.Value = objectValue;
                    }
                    else
                    {
                        // If this is an array we only need the values
                        uint elementCount = 0;
                        EntityPropertyArrayValue arrayValue = new EntityPropertyArrayValue();
                        arrayValue.Values = new List <EntityPropertyValue>();

                        foreach (var property in properties)
                        {
                            if (property.Value == null || property.Name == null || property.Name.Equals("num"))
                            {
                                continue;
                            }

                            arrayValue.Values.Add(property.Value);
                            elementCount++;
                        }

                        // Print a warning if the 'num' value doesn't match the array's actual element count
                        if (arrayNumProperty != null && arrayNumProperty.Value != null &&
                            arrayNumProperty.Value.GetType() == typeof(EntityPropertyLongValue) &&
                            ((EntityPropertyLongValue)arrayNumProperty.Value).Value != elementCount)
                        {
                            Warnings.Add(string.Format("Line {0}: 'num' property value '{1}' doesn't match the array's actual element count '{2}'",
                                                       arrayNumPropertyLineNumber, ((EntityPropertyLongValue)arrayNumProperty.Value).Value, elementCount));
                        }

                        entityProperty.Value = arrayValue;
                    }

                    // Check if the property name is quoted
                    if (propertyParts[0].StartsWith("\"") && propertyParts[0].EndsWith("\""))
                    {
                        entityProperty.IsQuoted = true;
                        propertyParts[0]        = propertyParts[0].Remove(0, 1);
                        propertyParts[0]        = propertyParts[0].Remove(propertyParts[0].Length - 1, 1);
                    }

                    if (!IsValidPropertyName(propertyParts[0].Trim()))
                    {
                        Errors.Add(string.Format("Line {0}: invalid property name '{1}'", currentLineNumber, propertyParts[0].Trim()));
                        return(null);
                    }

                    entityProperty.Name = propertyParts[0].Trim();
                }
            }

            return(entityProperty);
        }