/// <summary>
        /// Creates a fully populated <see cref="ResourceStore" /> which contains all resources defined in a <see cref="TemplateCollection" />.
        /// This is for backward compatibility during processing of a <see cref="TemplateCollection" />.
        /// </summary>
        /// <param name="templateCollection">The template collection.</param>
        /// <param name="templatePackage">The template package.</param>
        /// <returns>
        /// A fully populated <see cref="ResourceStore" />
        /// </returns>
        internal static ResourceStore Create(TemplateCollection templateCollection, ExcelTemplatePackage templatePackage)
        {
            if (templateCollection == null || string.IsNullOrEmpty(templateCollection.XamlString))
            {
                return(null);
            }

            ResourceStore resourceStore = new ResourceStore();
            var           document      = XDocument.Parse(templateCollection.XamlString);

            // Add in the defined Styles
            foreach (var resource in templateCollection.StyleResources)
            {
                resourceStore.Add(resource.Key, ResourceTypeNames.StyleBase, resource, null);
            }

            // Add in CellStyleSelectors
            foreach (var resource in templateCollection.CellStyleSelectors)
            {
                resourceStore.Add(resource.Key, ResourceTypeNames.CellStyleSelector, resource, null);
            }

            // Loop over each all elements, adding any that are defined in the Maps collection or identified as being Template resources
            foreach (var element in document.Root.Elements())
            {
                if (element.NodeType != XmlNodeType.Element || element.Name == null)
                {
                    continue;
                }

                if (element.Name.LocalName.CompareTo("TemplateCollection.Maps") == 0)
                {
                    foreach (var mapElement in element.Elements())
                    {
                        AddElementToStore(templateCollection, resourceStore, mapElement);
                    }
                }
                else if (element.Name.LocalName.CompareTo("Template") == 0)
                {
                    var id = element.Attribute("TemplateId").Value;
                    resourceStore.Add(id, element.Name.LocalName, element.ToString(), templateCollection.TemplateFileName, null);
                }
            }

            // Add the TemplateFile as a designer file, which can be used by maps as a resource
            if (!string.IsNullOrEmpty(templateCollection.TemplateFileName))
            {
                var data = templatePackage.TemplateResourceStore.templateDocumentDictionary[templateCollection.TemplateFileName].Data;
                resourceStore.AddDesignerFileData(templateCollection.TemplateFileName, data);
            }

            // Populate chart and shape models from the supplied resource designer files and defined templates,
            // such as ChartTemplate and ShapeTempaltes.
            resourceStore.PopulateModels();

            return(resourceStore);
        }
        /// <summary>
        /// Builds and returns a list of indexes (into the resource store) of elements to add be added.
        /// </summary>
        /// <param name="uri">The URI.</param>
        /// <param name="resourceStore">The resource store.</param>
        /// <param name="rd">The rd.</param>
        /// <returns></returns>
        private static List <int> ExtractCellStyleSelectors(string uri, ResourceStore resourceStore, IResourceContainer rd)
        {
            var indecesOfElementsToAdd = new List <int>();

            int index = 0;

            foreach (var resource in rd.Resources)
            {
                // CellStyleSelectors allow us to 'look up' cell styles depending on the underlying data
                // For this reason, they are isolated and added using the ResourceTypeName of CellStyleSelector
                if (resource is CellStyleSelector)
                {
                    resourceStore.Add(resource.Key, ResourceTypeNames.CellStyleSelector, resource, uri);
                }
                //else if (resource is StyleBase)
                //{
                //    resourceStore.Add(resource.Key, ResourceTypeNames.StyleBase, resource, uri);
                //}
                else
                {
                    indecesOfElementsToAdd.Add(index);
                }
                index++;
            }
            return(indecesOfElementsToAdd);
        }
        /// <summary>
        /// Adds the element to store.
        /// </summary>
        /// <param name="templateCollection">The template collection.</param>
        /// <param name="resourceStore">The resource store.</param>
        /// <param name="element">The element.</param>
        private static void AddElementToStore(TemplateCollection templateCollection, ResourceStore resourceStore, XElement element)
        {
            var keyAttrib = element.Attribute("Key");

            if (keyAttrib != null && !string.IsNullOrEmpty(keyAttrib.Value))
            {
                resourceStore.Add(keyAttrib.Value, element.Name.LocalName, element.ToString(), templateCollection.TemplateFileName, null);
            }
        }
        /// <summary>
        /// Parses the specified resource string and creates a resource store from it
        /// </summary>
        /// <param name="resourceString">The resource string.</param>
        /// <param name="uri">The URI.</param>
        /// <returns></returns>
        /// <exception cref="MetadataException"></exception>
        internal static ResourceStore Parse(string resourceString, string uri)
        {
            ResourceStore resourceStore = new ResourceStore();

            // Deserialise the template xaml
            IResourceContainer rd = null;

            using (var sr = new StringReader(resourceString))
            {
                using (var xr = new XmlTextReader(sr))
                {
                    rd = (IResourceContainer)XamlReader.Load(xr);
                }
            }

            if (rd == null)
            {
                return(resourceStore);
            }

            List <int> elementsForResourceStore = new List <int>();

            int index = 0;

            foreach (var resource in rd.Resources)
            {
                if (resource is CellStyleSelector)
                {
                    resourceStore.Add(resource.Key, ResourceTypeNames.CellStyleSelector, resource, uri);
                }
                //else if (resource is StyleBase)
                //{
                //    resourceStore.Add(resource.Key, ResourceTypeNames.StyleBase, resource, uri);
                //}
                else
                {
                    elementsForResourceStore.Add(index);
                }
                index++;
            }

            index = 0;

            var document = XDocument.Parse(resourceString);

            XElement rootElement = null;

            if (rd is ResourceMetadata)
            {
                rootElement = document.Root;
            }
            else if (rd is ExcelDocumentMetadata)
            {
                // initially check for a ResourceCollection node
                // there will be one of these if there is a MergeResources going on
                rootElement = (from d in document.Descendants()
                               where d.Name.LocalName.CompareTo("ResourceCollection") == 0
                               select d).FirstOrDefault();

                if (rootElement == null)
                {
                    // if no merge resources then look for a ExcelDocumentMetadata.Resources node
                    // all style etc will be located directly beneath this
                    rootElement = (from d in document.Descendants()
                                   where d.Name.LocalName.CompareTo("ExcelDocumentMetadata.Resources") == 0
                                   select d).FirstOrDefault();
                }
            }
            else
            {
                throw new MetadataException(string.Format("Unexpected type in ResourceStore.Parse <{0}>", rd.GetType().ToString()));
            }

            if (rootElement != null)
            {
                foreach (var element in rootElement.Elements())
                {
                    // only store those elements that we havent stored an instance of above
                    // basically everything other that Styles and CellStyleSelectors
                    if (elementsForResourceStore.Contains(index))
                    {
                        var keyAttrib = element.Attribute("Key");
                        if (keyAttrib != null && !string.IsNullOrEmpty(keyAttrib.Value))
                        {
                            resourceStore.Add(keyAttrib.Value, element.Name.LocalName, element.ToString(), rd.DesignerFileName, uri);
                        }
                    }
                    index++;
                }
            }

            return(resourceStore);
        }
        /// <summary>
        /// Parses the specified resource string and creates a resource store from it
        /// </summary>
        /// <param name="resourceString">The resource string.</param>
        /// <param name="uri">The URI.</param>
        /// <returns></returns>
        /// <exception cref="MetadataException"></exception>
        internal static ResourceStore Parse(string resourceString, string uri)
        {
            ResourceStore resourceStore = new ResourceStore();

            // Deserialise the template xaml
            IResourceContainer resourceContainer = null;

            using (var sr = new StringReader(resourceString))
            {
                using (var xr = new XmlTextReader(sr))
                {
                    resourceContainer = (IResourceContainer)XamlReader.Load(xr);
                }
            }

            if (resourceContainer == null)
            {
                return(resourceStore);
            }

            var indecesOfElementsToAdd = ExtractCellStyleSelectors(uri, resourceStore, resourceContainer);

            int idx      = 0;
            var document = XDocument.Parse(resourceString);

            XElement rootElement = null;

            if (resourceContainer is ResourceMetadata)
            {
                rootElement = document.Root;
            }
            else if (resourceContainer is ExcelDocumentMetadata)
            {
                // initially check for a ResourceCollection node
                // there will be one of these if there is a MergeResources going on
                rootElement = (from d in document.Descendants()
                               where d.Name.LocalName.CompareTo("ResourceCollection") == 0
                               select d).FirstOrDefault();

                if (rootElement == null)
                {
                    // if no merge resources then look for a ExcelDocumentMetadata.Resources node
                    // all style etc will be located directly beneath this
                    rootElement = (from d in document.Descendants()
                                   where d.Name.LocalName.CompareTo("ExcelDocumentMetadata.Resources") == 0
                                   select d).FirstOrDefault();
                }
            }
            else
            {
                throw new MetadataException(string.Format("Unexpected type in ResourceStore.Parse <{0}>", resourceContainer.GetType().ToString()));
            }

            if (rootElement != null)
            {
                foreach (var element in rootElement.Elements())
                {
                    // only store those elements that we havent stored an instance of above
                    // basically everything other that Styles and CellStyleSelectors
                    if (indecesOfElementsToAdd.Contains(idx))
                    {
                        var keyAttrib = element.Attribute("Key");
                        if (keyAttrib != null && !string.IsNullOrEmpty(keyAttrib.Value))
                        {
                            // TODO: Optimisation - DesignerFileName could reference an entry in a string dictionary
                            resourceStore.Add(keyAttrib.Value, element.Name.LocalName, element.ToString(), resourceContainer.DesignerFileName, uri);
                        }
                    }
                    idx++;
                }
            }

            return(resourceStore);
        }