/// <summary>
        /// Create a new group or snapshot
        /// </summary>
        /// <param name="container">Container element</param>
        /// <param name="x">Definition element</param>
        /// <returns>Returns a new group or snapshot</returns>
        private Group CreateItem(Group container, XElement x)
        {
            Group result = null;

            switch (x.Name.LocalName)
            {
            case "Snapshot":
                result = new Snapshot {
                    StoryboardName  = (string)x.Attribute("Storyboard"),
                    Frames          = (int?)x.Attribute("Frames"),
                    Filmstrip       = (bool?)x.Attribute("Filmstrip") ?? false,
                    Dpi             = (double?)x.Attribute("Dpi"),
                    Quality         = (int?)x.Attribute("Quality"),
                    Filename        = (string)x.Attribute("Filename") ?? (string)x.Attribute("File") ?? (string)x.Attribute("Image"),
                    CulturesString  = (string)x.Attribute("Cultures") ?? (string)x.Attribute("Culture"),
                    Page            = (string)x.Attribute("Page"),
                    FitToPage       = (bool?)x.Attribute("FitToPage") ?? false,
                    Loop            = (int?)x.Attribute("Loop") ?? 1,
                    Pause           = (double?)x.Attribute("Pause") ?? 0,
                    Type            = (string)x.Attribute("Type"),
                    Hash            = (int?)x.Attribute("Hash"),
                    Layer           = (int?)x.Attribute("Layer"),
                    Scale           = (double?)x.Attribute("Scale") ?? 1,
                    Title           = (string)x.Attribute("Title"),
                    Profile         = (string)x.Attribute("Profile"),
                    Info            = (string)x.Attribute("Info"),
                    RegistryName    = (string)x.Attribute("RegistryName"),
                    OutputCondition = (string)x.Attribute("OutputCondition"),
                    Author          = (string)x.Attribute("Author"),
                    Subject         = (string)x.Attribute("Subject"),
                    Keywords        = (string)x.Attribute("Keywords"),
                    Source          = (string)x.Attribute("Source"),
                    TypeName        = (string)x.Attribute("Type")
                };
                ValidAttributes(x, container, "Element", "Storyboard", "Frames", "Filmstrip", "Dpi", "Quality", "Filename", "Left", "Top", "Right", "Bottom", "Width", "Height", "Cultures", "Page", "FitToPage",
                                "File", "Loop", "Pause", "Skin", "Theme", "TextMode", "Type", "Image", "Culture", "Hash", "Layer", "Scale", "Parallel", "Ghost", "RenderMode", "Verbose", "Title", "Profile", "Info", "RegistryName", "OutputCondition",
                                "Author", "Subject", "Keywords", "Type", "Source");

                var xaml = x.Elements(ns + "Xaml").SingleOrDefault();
                xaml = x.Elements(ns + "Source").SingleOrDefault() ?? xaml;
                if (x.Attribute("Source") != null || x.Attribute("Type") != null)
                {
                    xaml = x;
                }

                result.XamlElement = xaml;
                result.IsScene     = !string.IsNullOrEmpty(result.Source) || !string.IsNullOrEmpty(result.TypeName) || xaml != null;

                break;

            case "ImageMap":
            case "Map":
                var map = new ImageMap {
                    Image    = (string)x.Attribute("Image"),
                    Source   = (string)x.Attribute("Source"),
                    Scale    = (double?)x.Attribute("Scale"),
                    XScale   = (double?)x.Attribute("XScale"),
                    YScale   = (double?)x.Attribute("YScale"),
                    XOffset  = (double?)x.Attribute("YOffset"),
                    YOffset  = (double?)x.Attribute("XOffset"),
                    Angle    = (double?)x.Attribute("Angle"),
                    Filename = (string)x.Attribute("Filename") ?? (string)x.Attribute("File"),
                    Flatness = (double?)x.Attribute("Flatness") ?? 0.5,
                    Dpi      = (double?)x.Attribute("Dpi") ?? 96.0
                };
                map.Type     = x.Name.LocalName == "Map" ? ImageMap.Types.Html : ImageMap.Types.AspNet;
                map.FileType = null;
                map.Ident    = null;

                /* switch (Path.GetExtension(map.Filename)) {
                 *      case ".ascx": map.FileType = ImageMap.FileTypes.UserControl; break;
                 *      case ".aspx": map.FileType = ImageMap.FileTypes.Insert; break;
                 *      default: map.FileType = ImageMap.FileTypes.Insert; break;
                 * } */

                var fileType = (string)x.Attribute("FileType");
                if (fileType != null)
                {
                    map.FileType = (ImageMap.FileTypes)Enum.Parse(typeof(ImageMap.FileTypes), fileType);
                }
                var type = (string)x.Attribute("Type");
                if (type != null)
                {
                    map.Type = (ImageMap.Types)Enum.Parse(typeof(ImageMap.Types), type);
                }
                var ident = (string)x.Attribute("Ident");
                if (ident != null)
                {
                    map.Ident = (ImageMap.IdentChars)Enum.Parse(typeof(ImageMap.IdentChars), ident);
                }

                var predefined = new string[] { "Image", "Scale", "XScale", "YScale", "XOffset", "YOffset", "Angle", "Filename", "File", "Type", "Flatness", "FileType", "Dpi", "Ident", "Source" };
                foreach (var attribute in x.Attributes().Where(a => predefined.All(p => p != a.Name)))
                {
                    map.Attributes.Add(attribute);
                }

                map.Areas.AddRange(x.Elements());
                result = map;

                xaml = x.Elements(ns + "Xaml").SingleOrDefault();
                xaml = x.Elements(ns + "Source").SingleOrDefault() ?? xaml;
                if (x.Attribute("Source") != null)
                {
                    xaml = x;
                }

                result.XamlElement = xaml;
                result.IsScene     = !string.IsNullOrEmpty(result.Source) || xaml != null;

                break;

            case "Set":
                result = new Parameters(x);
                break;

            case "Undo":
                result = new Undo();
                ValidAttributes(x, container);
                break;

            case "Reset":
                result = new Reset();
                ValidAttributes(x, container);
                break;

            case "Group":
                result = new Group {
                    OutputPath = (string)x.Attribute("OutputPath"), TypeName = (string)x.Attribute("Type"), Source = (string)x.Attribute("Source")
                };
                ValidAttributes(x, container, "Element", "OutputPath", "Left", "Top", "Right", "Bottom", "Width", "Height", "Skin", "Theme", "TextMode", "RenderMode", "Parallel", "Ghost", "Verbose", "Type", "Source");
                break;

            default:
                container.Errors.Error("Invalid element " + x.Name.LocalName, "20", x);
                result = new Group();
                break;
            }
            result.Compiler    = Compiler;
            result.ElementName = (string)x.Attribute("Element");
            result.XElement    = x;

            return(result);
        }
        /// <summary>
        /// Returns a collection of <see cref="Snapshot"/>s from configuration elements
        /// </summary>
        /// <param name="snapshots">A collection of snapshot configuration elements</param>
        /// <returns>Returns a list of <see cref="Snapshot"/>s</returns>
        public Group ParseScene(Group Root, DateTime Version, XElement x)
        {
            var scene = new Group()
            {
                Compiler = Compiler, XElement = x, IsScene = true
            };

            Root.Children.Add(scene);

            var xaml = x.Elements(ns + "Xaml").SingleOrDefault();

            xaml = x.Elements(ns + "Source").SingleOrDefault() ?? xaml;
            if (x.Attribute("Source") != null || x.Attribute("File") != null || x.Attribute("Type") != null)
            {
                xaml = x;
            }
            var srcAttr = xaml.Attribute("Source") ?? xaml.Attribute("File");

            if (srcAttr != null)
            {
                scene.Source = srcAttr.Value;
            }
            var src = scene.Source;

            if (xaml == null)
            {
                throw new CompilerException("Scene must contain source file specification.", 10, x, scene, null);
            }
            scene.XamlElement = xaml;

            var width  = (double?)xaml.Attribute("Width") ?? double.PositiveInfinity;
            var height = (double?)xaml.Attribute("Height") ?? double.PositiveInfinity;

            scene.Dependencies   = (string)x.Attribute("DependsOn");
            scene.CulturesString = (string)x.Attribute("Cultures");
            scene.OutputPath     = (string)x.Attribute("OutputPath");
            scene.PreferredSize  = new Size(width, height);

            ParseStyle(x, scene);

            DateTime XamlVersion = new DateTime();
            FileInfo info;

            if (src != null)
            {
                if (!(src.StartsWith("http://") || src.StartsWith("https://")))
                {
                    info = new FileInfo(Compiler.MapPath(src));
                    if (!info.Exists)
                    {
                        throw new CompilerException("Source file " + info.FullName + " not found.", 11, xaml, scene, null);
                    }

                    XamlVersion = info.LastWriteTimeUtc;
                }
                if (XamlVersion > Version)
                {
                    Version = XamlVersion;
                }
            }
            else
            {
                string assemblyName = (string)xaml.Attribute("Assembly");
                string typename     = (string)xaml.Attribute("Type");

                scene.AssemblyName = assemblyName;
                scene.TypeName     = typename;

                if (typename == null)
                {
                    scene.InnerXaml = xaml.Elements().SingleOrDefault();
                    if (scene.InnerXaml == null)
                    {
                        throw new CompilerException("Scene must contain a single XAML root element", 16, xaml, scene, null);
                    }
                }
            }

            if (xaml.Attribute("Dynamic") != null && xaml.Attribute("Dynamic").Value == "true")
            {
                Version = DateTime.Now.ToUniversalTime();
            }


            // parse dependencies
            foreach (var dependency in x.Elements().Where(child => child.Name == ns + "Depends"))
            {
                var d = new Dependency(dependency)
                {
                    Compiler = Compiler
                };
                if (d.Version > Version)
                {
                    Version = d.Version;
                }
            }

            scene.Version = Version;

            if (Compiler.Parameters.Count > 0)
            {
                var p = new Parameters(Compiler.Parameters);
                p.Compiler    = Compiler;
                p.ElementName = string.Empty;
                p.XElement    = null;
                scene.Children.Add(p);
            }

            // parse ordinary elements
            var names = new XName[] { ns + "Xaml", ns + "Depends" };

            foreach (var child in x.Elements().Where(child => !names.Contains(child.Name)))
            {
                Parse(child, scene);
            }

            foreach (var node in x.Nodes().Where(node => !(node is XElement || node is XComment ||
                                                           (node is XText && (string.IsNullOrWhiteSpace(((XText)node).Value) || node.NodeType == System.Xml.XmlNodeType.Whitespace || node.NodeType == System.Xml.XmlNodeType.SignificantWhitespace)))))
            {
                Root.Errors.Error(string.Format("Invalid content {0}", node.ToString(SaveOptions.DisableFormatting | SaveOptions.OmitDuplicateNamespaces)), "23", node);
            }

            return(scene);
        }