/// <summary>
        /// Actually parses an array, and is used in both short-hand and separate
        /// element formats of array specification.
        /// </summary>
        public static Array ParseArray(string elementTypeName, XmlElement[] childElements, XmlProcessingContext context)
        {
            context.EnterRunningLocation(string.Format("Array({0})", elementTypeName ?? "object"));

            var elementType = typeof(object);

            if (elementTypeName != null)
            {
                elementType = SimpleTypeParserUtil.ParseType(elementTypeName, context);
                if (elementType == null)
                {
                    context.ReportError(string.Format("Type '{0}' could not be loaded.", elementTypeName));
                    return(null);
                }
            }

            var arrayElements = GetCollectionElements(childElements, elementType, context);

            var result = Array.CreateInstance(elementType, arrayElements.Count);

            for (var i = 0; i < result.Length; i++)
            {
                result.SetValue(arrayElements[i], i);
            }

            context.LeaveRunningLocation();

            return(result);
        }
        /// <summary>
        /// Actually parses the contents of lists from composition XMLs, and is
        /// used in both short-hand form and complete form of list specification.
        /// </summary>
        public static IList ParseList(string elementTypeName, XmlElement[] childElements, XmlProcessingContext context)
        {
            context.EnterRunningLocation(string.Format("List({0})", elementTypeName ?? "object"));

            var elementType = typeof(object);

            if (elementTypeName != null)
            {
                elementType = SimpleTypeParserUtil.ParseType(elementTypeName, context);
                if (elementType == null)
                {
                    context.ReportError(string.Format("Type '{0}' could not be loaded.", elementTypeName));
                    context.LeaveRunningLocation();
                    return(null);
                }
            }

            var listElements = GetCollectionElements(childElements, elementType, context);

            var listType = Type.GetType(string.Format("System.Collections.Generic.List`1[[{0}]]",
                                                      elementType.AssemblyQualifiedName));

            var result = (IList)Activator.CreateInstance(listType);

            foreach (var o in listElements)
            {
                result.Add(o);
            }

            context.LeaveRunningLocation();

            return(result);
        }
        /// <summary>
        /// Actually parses the object and returns the result. Used both in short-hand
        /// form and in direct Object element parsing.
        /// </summary>
        public static object ParseObject(string typeName, bool initializePlugs, XmlElement[] childElements,
                                         XmlProcessingContext context)
        {
            context.EnterRunningLocation(string.Format("Object({0})", typeName));

            // Look for constructor arguments.
            // Set default to null, so that Activator calls default constructor
            // in case the the "ConstructorArgs" element is not specified.

            object[] constructorArguments = null;

            foreach (var childElement in childElements)
            {
                if (childElement.Name != "ConstructorArgs")
                {
                    continue;
                }
                // Check if this is the second "ConstructorArgs" element.
                // If so, report an error and return.

                if (constructorArguments != null)
                {
                    context.ReportError("The 'ConstructorArgs' element can be specified maximum once in an 'Object' element.");
                    context.LeaveRunningLocation();
                    return(null);
                }

                constructorArguments = ParseConstructorArgs(childElement, context);
                context.ThrowIfErrors();
            }

            // Resolve the "Type" for the object to be instantiated

            var objectType = SimpleTypeParserUtil.ParseType(typeName, context);

            if (objectType == null)
            {
                context.ReportError(string.Format("Type '{0}' could not be loaded.", typeName));
                context.LeaveRunningLocation();
                return(null);
            }

            // Use Activator class to instantiate the object

            var result = Activator.CreateInstance(objectType, constructorArguments);

            if (initializePlugs)
            {
                context.ComponentContext.InitializePlugs(result, objectType);
            }

            foreach (var childElement in childElements)
            {
                switch (childElement.Name)
                {
                case "ConstructorArgs":
                    break;

                case "Property":
                    ParseObjectProperty(result, childElement, context);
                    break;

                case "Field":
                    ParseObjectField(result, childElement, context);
                    break;

                default:                                // Also: case "ConstructorArgs"
                    context.ReportError(
                        string.Format("Xml element '{0}' is not allowed in 'Object' element - type: {1}", childElement.Name,
                                      typeName));
                    context.LeaveRunningLocation();
                    return(null);
                }
            }

            context.LeaveRunningLocation();
            return(result);
        }
        /// <summary>
        /// Actually parses the contents of dictionaries in composition XMLs, and is
        /// used for both short-hand and seperate element formats of dictionary specification.
        /// </summary>
        public static IDictionary ParseDictionary(string keyTypeName, string valueTypeName, XmlElement[] xmlElements,
                                                  XmlProcessingContext context)
        {
            context.EnterRunningLocation(
                string.Format("Parse Dictionary({0}, {1})", keyTypeName ?? "object", valueTypeName ?? "object"));

            var keyType   = typeof(object);
            var valueType = typeof(object);

            if (keyTypeName != null)
            {
                keyType = SimpleTypeParserUtil.ParseType(keyTypeName, context);
                if (keyType == null)
                {
                    context.ReportError(string.Format("Type '{0}' could not be loaded.", keyTypeName));
                    context.LeaveRunningLocation();
                    return(null);
                }
            }

            if (valueTypeName != null)
            {
                valueType = SimpleTypeParserUtil.ParseType(valueTypeName, context);
                if (valueType == null)
                {
                    context.ReportError(string.Format("Type '{0}' could not be loaded.", valueTypeName));
                    context.LeaveRunningLocation();
                    return(null);
                }
            }

            var dictionaryType = Type.GetType(string.Format("System.Collections.Generic.Dictionary`2[[{0}],[{1}]]",
                                                            keyType.AssemblyQualifiedName,
                                                            valueType.AssemblyQualifiedName));

            var result = (IDictionary)Activator.CreateInstance(dictionaryType);

            for (var i = 0; i < xmlElements.Length; i++)
            {
                var childElement = xmlElements[i];

                if (childElement.Name == "Item")
                {
                    context.EnterRunningLocation(string.Format("Item({0})", i));
                    ParseDictionaryItem(result, childElement, context);
                    context.LeaveRunningLocation();                     // For Item
                }
                else
                {
                    context.ReportError(
                        string.Format("Xml element '{0}' is not allowed in 'Dictionary' element - type: Dictionary<{1}, {2}>",
                                      childElement.Name,
                                      keyType.FullName, valueType.FullName));
                    context.LeaveRunningLocation();
                    return(null);
                }
            }

            context.LeaveRunningLocation();
            return(result);
        }
        public static object ParseValue(XmlElement[] elements, XmlAttribute[] attributes,
                                        XmlProcessingContext xmlProcessingContext)
        {
            // Check if there is any attributes. If there's not,
            // go straight into the nested elements.

            if ((attributes == null) || (attributes.Length == 0))
            {
                // There should be only one element for values that do not
                // specify anythin by the attributes. Otherwise, throw.

                if ((elements == null) || (elements.Length != 1))
                {
                    xmlProcessingContext.ReportError("Exactly one nested element should specify the value.");
                    return(null);
                }

                // If the element is okay, just pass it to the element parser.

                var element = elements[0];

                switch (element.Name)
                {
                case "Object":
                    return(ObjectParserUtil.ParseObject(element, xmlProcessingContext));

                case "Dictionary":
                    return(CollectionParserUtil.ParseDictionary(element, xmlProcessingContext));

                case "Array":
                    return(CollectionParserUtil.ParseArray(element, xmlProcessingContext));

                case "List":
                    return(CollectionParserUtil.ParseList(element, xmlProcessingContext));
                }

                return(SimpleTypeParserUtil.ParseSimpleType(element, xmlProcessingContext));
            }

            // There are attributes. So, based on the name of the attributes,
            // decide who should take responsibility for parsing.

            var attributeNames = new List <string>(
                Array.ConvertAll(attributes, attribute => attribute.Name));

            if (attributeNames.Contains("objectType"))
            {
                return(ObjectParserUtil.ParseObject(attributes, elements, xmlProcessingContext));
            }

            if ((attributeNames.Contains("dictionaryKeyType")) || (attributeNames.Contains("dictionaryValueType")))
            {
                return(CollectionParserUtil.ParseDictionary(attributes, elements, xmlProcessingContext));
            }

            if (attributeNames.Contains("arrayElementType"))
            {
                return(CollectionParserUtil.ParseArray(attributes, elements, xmlProcessingContext));
            }

            return(attributeNames.Contains("listElementType")
                                ? CollectionParserUtil.ParseList(attributes, elements, xmlProcessingContext)
                                : SimpleTypeParserUtil.ParseSimpleType(attributes, xmlProcessingContext));
        }