internal static RenderableObjectList getRenderableFromLayerFile(string layerFile, World parentWorld, Cache cache, bool enableRefresh)
 {
     return getRenderableFromLayerFile(layerFile, parentWorld, cache, enableRefresh, null);
 }
        private static void addTiledWFSPlacenameSet(XPathNodeIterator iter, World parentWorld, RenderableObjectList parentRenderable, Cache cache)
        {
            if (iter.Count > 0)
            {
                while (iter.MoveNext())
                {
                    string name = getInnerTextFromFirstChild(iter.Current.Select("Name"));
                    double distanceAboveSurface = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("DistanceAboveSurface")));
                    double minimumDisplayAltitude = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("MinimumDisplayAltitude")));
                    double maximumDisplayAltitude = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("MaximumDisplayAltitude")));

                    string wfsBaseUrl = getInnerTextFromFirstChild(iter.Current.Select("WFSBaseURL"));
                    string typename = getInnerTextFromFirstChild(iter.Current.Select("TypeName"));
                    string labelfield = getInnerTextFromFirstChild(iter.Current.Select("LabelField"));
                    /*
                    if (!Path.IsPathRooted(wfsBaseUrl))
                    {
                         Path.Combine(
                              Path.GetDirectoryName(
                              System.Windows.Forms.Application.ExecutablePath),
                              wfsBaseUrl);
                    }
                    */
                    string iconFilePath = getInnerTextFromFirstChild(iter.Current.Select("IconFilePath"));

                    Microsoft.DirectX.Direct3D.FontDescription fd = getDisplayFont(iter.Current.Select("DisplayFont"));

                    System.Drawing.Color c = parseColorNode(iter.Current);

                    //TODO:Validate URL
                    //Construct WFS Base URL
                    wfsBaseUrl += "TypeName=" + typename + "&Request=GetFeature&Service=WFS";

                    TiledWFSPlacenameSet twps = new TiledWFSPlacenameSet(
                         name,
                         parentWorld,
                         distanceAboveSurface,
                         maximumDisplayAltitude,
                         minimumDisplayAltitude,
                         wfsBaseUrl,
                         typename,
                         labelfield,
                         fd,
                         c,
                         iconFilePath,
                 cache);

                    string description = getInnerTextFromFirstChild(iter.Current.Select("Description"));
                    if (description != null && description.Length > 0)
                        twps.Description = description;

                    addExtendedInformation(iter.Current.Select("ExtendedInformation"), twps);

                    string infoUri = iter.Current.GetAttribute("InfoUri", "");

                    if (infoUri != null && infoUri.Length > 0)
                    {
                        if (twps.MetaData.Contains("InfoUri"))
                        {
                            twps.MetaData["InfoUri"] = infoUri;
                        }
                        else
                        {
                            twps.MetaData.Add("InfoUri", infoUri);
                        }
                    }

                    twps.MetaData.Add("WFSBaseURL", wfsBaseUrl);
                    twps.MetaData.Add("XmlSource", (string)parentRenderable.MetaData["XmlSource"]);
                    twps.ParentList = parentRenderable;
                    twps.IsOn = ParseBool(iter.Current.GetAttribute("ShowAtStartup", ""));

                    parentRenderable.ChildObjects.Add(
                         twps
                         );

                    parentRenderable.RenderPriority = RenderPriority.Placenames;

                }
            }
        }
        public static RenderableObjectList getRenderableFromLayerFile(string layerFile, World parentWorld, Cache cache, bool enableRefresh, string layerSetSchema)
        {
            Log.Write(Log.Levels.Debug + 1, "CONF", "Loading renderable from " + layerFile);
            try
            {
                XPathDocument docNav = null;
                XPathNavigator nav = null;

                XmlReaderSettings readerSettings = new XmlReaderSettings();

                if (layerSetSchema != null && File.Exists(layerSetSchema))
                {
                    Log.Write(Log.Levels.Debug, "CONF", "validating " + layerFile + " against LayerSet.xsd");
                    readerSettings.ValidationType = ValidationType.Schema;
                    XmlSchemaSet schemas = new XmlSchemaSet();
                    schemas.Add(null, layerSetSchema);

                    readerSettings.Schemas = schemas;
                    readerSettings.ValidationEventHandler += new ValidationEventHandler(XMLValidationCallback);
                    readerSettings.ValidationFlags |= System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;
                }
                else
                {
                    Log.Write(Log.Levels.Debug, "CONF", "loading " + layerFile + " without validation");
                    readerSettings.ValidationType = ValidationType.None;
                }

                try
                {
                    if (layerFile.IndexOf(@"http://") < 0)
                    {
                        XmlReader docReader = XmlReader.Create(layerFile, readerSettings);
                        docNav = new XPathDocument(docReader);
                        docReader.Close();
                    }
                    else
                    {
                        Angle[] bbox = CameraBase.getViewBoundingBox();
                        string viewBBox = string.Format(CultureInfo.InvariantCulture,
                             "{0},{1},{2},{3}",
                             bbox[0].ToString().TrimEnd('°'), bbox[1].ToString().TrimEnd('°'), bbox[2].ToString().TrimEnd('°'), bbox[3].ToString().TrimEnd('°'));

                        //See if there is a ? already in the URL
                        int flag = layerFile.IndexOf("?");
                        if (flag == -1)
                            layerFile = layerFile + "?BBOX=" + viewBBox;
                        else
                            layerFile = layerFile + "&BBOX=" + viewBBox;

                        WorldWind.Net.WebDownload download = new WorldWind.Net.WebDownload(layerFile);
                        download.DownloadMemory();

                        XmlReader docReader = XmlReader.Create(download.ContentStream, readerSettings);
                        docNav = new XPathDocument(docReader);
                        docReader.Close();
                    }

                    nav = docNav.CreateNavigator();
                }
                catch (Exception ex)
                {
                    Log.Write(ex);
                    return null;
                }

                XPathNodeIterator iter = nav.Select("/LayerSet");

                if (iter.Count > 0)
                {
                    iter.MoveNext();
                    string redirect = iter.Current.GetAttribute("redirect", "");
                    redirect = redirect.Replace("${WORLDWINDVERSION}", System.Windows.Forms.Application.ProductVersion);
                    string redirectWithoutBBOX = redirect;
                    if (redirect != null && redirect.Length > 0)
                    {
                        FileInfo layerFileInfo = new FileInfo(layerFile);

                        try
                        {
                            Angle[] bbox = CameraBase.getViewBoundingBox();
                            string viewBBox = string.Format(CultureInfo.InvariantCulture,
                                 "{0},{1},{2},{3}",
                                 bbox[0].ToString().TrimEnd('°'), bbox[1].ToString().TrimEnd('°'), bbox[2].ToString().TrimEnd('°'), bbox[3].ToString().TrimEnd('°'));

                            //See if there is a ? already in the URL
                            int flag = redirect.IndexOf("?");
                            if (flag == -1)
                                redirect = redirect + "?BBOX=" + viewBBox;
                            else
                                redirect = redirect + "&BBOX=" + viewBBox;

                            WorldWind.Net.WebDownload download = new WorldWind.Net.WebDownload(redirect);

                            string username = iter.Current.GetAttribute("username", "");

                            if (username != null)
                            {
                                ////	download.UserName = username;
                                ////	download.Password = password;
                            }

                            FileInfo tempDownloadFile = new FileInfo(layerFile.Replace(layerFileInfo.Extension, "_.tmp"));

                            download.DownloadFile(tempDownloadFile.FullName, WorldWind.Net.DownloadType.Unspecified);

                            tempDownloadFile.Refresh();
                            if (tempDownloadFile.Exists && tempDownloadFile.Length > 0)
                            {
                                FileInfo tempStoreFile = new FileInfo(tempDownloadFile.FullName.Replace("_.tmp", ".tmp"));
                                if (tempStoreFile.Exists)
                                    tempStoreFile.Delete();

                                tempDownloadFile.MoveTo(tempStoreFile.FullName);
                            }

                            download.Dispose();

                            using (StreamWriter writer = new StreamWriter(layerFile.Replace(layerFileInfo.Extension, ".uri"), false))
                            {
                                writer.WriteLine(redirectWithoutBBOX);
                            }
                        }
                        catch (Exception ex)
                        {
                            Log.Write(ex);
                        }

                        return getRenderableFromLayerFile(layerFile.Replace(layerFileInfo.Extension, ".tmp"), parentWorld, cache);
                    }
                    else
                    {
                        RenderableObjectList parentRenderable = null;

                        string sourceUri = null;
                        if (layerFile.EndsWith(".tmp"))
                        {
                            //get source url
                            using (StreamReader reader = new StreamReader(layerFile.Replace(".tmp", ".uri")))
                            {
                                sourceUri = reader.ReadLine();
                            }
                        }
                        string refreshString = iter.Current.GetAttribute("Refresh", "");
                        if (refreshString != null && refreshString.Length > 0)
                        {

                            if (iter.Current.Select("Icon").Count > 0)
                            {
                                parentRenderable = new Icons(iter.Current.GetAttribute("Name", ""),
                                     (sourceUri != null ? sourceUri : layerFile),
                                     TimeSpan.FromSeconds(ParseDouble(refreshString)),
                                     parentWorld,
                                     cache);
                            }
                            else
                            {
                                parentRenderable = new RenderableObjectList(
                                     iter.Current.GetAttribute("Name", ""),
                                     (sourceUri != null ? sourceUri : layerFile),
                                     TimeSpan.FromSeconds(ParseDouble(refreshString)),
                                     parentWorld,
                                     cache);
                            }

                        }
                        else
                        {
                            if (iter.Current.Select("Icon").Count > 0)
                            {
                                parentRenderable = new Icons(iter.Current.GetAttribute("Name", ""));
                            }
                            else
                            {
                                parentRenderable = new RenderableObjectList(iter.Current.GetAttribute("Name", ""));
                            }
                        }

                        parentRenderable.ParentList = parentWorld.RenderableObjects;
                        parentRenderable.IsOn = ParseBool(iter.Current.GetAttribute("ShowAtStartup", ""));

                        string description = getInnerTextFromFirstChild(iter.Current.Select("Description"));
                        if (description != null && description.Length > 0)
                            parentRenderable.Description = description;

                        parentRenderable.ShowOnlyOneLayer = ParseBool(iter.Current.GetAttribute("ShowOnlyOneLayer", ""));

                        parentRenderable.MetaData.Add("XmlSource", (sourceUri != null ? sourceUri : layerFile));

                        parentRenderable.MetaData.Add("World", parentWorld);
                        parentRenderable.MetaData.Add("Cache", cache);
                        parentRenderable.ParentList = parentWorld.RenderableObjects;

                        string renderPriorityString = iter.Current.GetAttribute("RenderPriority", "");
                        if (renderPriorityString != null)
                        {
                            if (String.Compare(renderPriorityString, "Icons", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
                            {
                                parentRenderable.RenderPriority = RenderPriority.Icons;
                            }
                            else if (String.Compare(renderPriorityString, "LinePaths", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
                            {
                                parentRenderable.RenderPriority = RenderPriority.LinePaths;
                            }
                            else if (String.Compare(renderPriorityString, "Placenames", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
                            {
                                parentRenderable.RenderPriority = RenderPriority.Placenames;
                            }
                            else if (String.Compare(renderPriorityString, "AtmosphericImages", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
                            {
                                parentRenderable.RenderPriority = RenderPriority.AtmosphericImages;
                            }
                        }

                        string infoUri = iter.Current.GetAttribute("InfoUri", "");

                        if (infoUri != null && infoUri.Length > 0)
                        {
                            if (parentRenderable.MetaData.Contains("InfoUri"))
                            {
                                parentRenderable.MetaData["InfoUri"] = infoUri;
                            }
                            else
                            {
                                parentRenderable.MetaData.Add("InfoUri", infoUri);
                            }
                        }

                        addTiledWFSPlacenameSet(iter.Current.Select("TiledWFSPlacenameSet"), parentWorld, parentRenderable, cache);
                        addExtendedInformation(iter.Current.Select("ExtendedInformation"), parentRenderable);

                        if (parentRenderable.RefreshTimer != null && enableRefresh)
                        {
                            parentRenderable.RefreshTimer.Start();
                        }
                        return parentRenderable;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Write(ex);
                //Log.Write(Log.Levels.Debug, layerFile);
            }
            Log.Write(Log.Levels.Warning, "CONF", "WARNING: no renderable created for " + layerFile);

            return null;
        }
 internal static RenderableObjectList getRenderableFromLayerFile(string layerFile, World parentWorld, Cache cache)
 {
     return getRenderableFromLayerFile(layerFile, parentWorld, cache, true);
 }
		public WorldWindWFSPlacenameFile(
		    string name,
            String wfsBaseUrl,
            string typename,
            String labelfield,
            double north,
            double south,
            double west,
            double east,
			World world,
			Cache cache)
		{
            //TODO:Validate basewfsurl
            this.name = name;
            this.wfsBaseUrl = wfsBaseUrl;
            this.typename = typename;
            this.labelfield = labelfield;
            this.north = north;
            this.south = south;
            this.west = west;
            this.east = east;
            wfsURL = wfsBaseUrl + "&OUTPUTFORMAT=GML2-GZIP&BBOX=" + west + "," + south + "," + east + "," + north;
			this.m_world = world;
			this.m_cache = cache;
        }
		/// <summary>
		/// Initializes a new instance of the <see cref= "T:WorldWind.Renderable.TiledPlacenameSet"/> class.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="parentWorld"></param>
		/// <param name="altitude"></param>
		/// <param name="maximumDisplayAltitude"></param>
		/// <param name="minimumDisplayAltitude"></param>
		/// <param name="placenameBaseUrl"></param>
        /// <param name="labelfield">Field in Feature type used as PlacenameLabel</param>
		/// <param name="fontDescription"></param>
		/// <param name="color"></param>
		/// <param name="iconFilePath"></param>
		public TiledWFSPlacenameSet(
			string name, 
			World parentWorld,
			double altitude,
			double maximumDisplayAltitude,
			double minimumDisplayAltitude,
			string placenameBaseUrl,
            string typename,
            string labelfield,
			FontDescription fontDescription,
			System.Drawing.Color color,
			string iconFilePath,
			Cache cache
			) : base(name, parentWorld.Position, Quaternion.RotationYawPitchRoll(0,0,0))
		{
		    m_name = name;
			m_parentWorld = parentWorld;
			m_altitude = altitude;
			m_maximumDistanceSq = maximumDisplayAltitude*maximumDisplayAltitude;
			m_minimumDistanceSq = minimumDisplayAltitude*minimumDisplayAltitude;
			m_placenameBaseUrl = placenameBaseUrl;
            m_typename = typename;
            m_labelfield = labelfield;
			m_fontDescription = fontDescription;
			m_color = color.ToArgb();
			m_iconFilePath = iconFilePath;
			m_cache = cache;
			
			// Set default render priority
			m_renderPriority = RenderPriority.Placenames;
		}
        private static ImageStore getImageStoreFromXPathNodeIterator(string name, XPathNodeIterator imageAccessorIter, RenderableObjectList parentRenderable, Cache cache)
        {
			double levelZeroTileSizeDegrees = ParseDouble(getInnerTextFromFirstChild(imageAccessorIter.Current.Select("LevelZeroTileSizeDegrees")));
			int numberLevels = Int32.Parse(getInnerTextFromFirstChild(imageAccessorIter.Current.Select("NumberLevels")));
			int textureSizePixels = Int32.Parse(getInnerTextFromFirstChild(imageAccessorIter.Current.Select("TextureSizePixels")));
			string imageFileExtension = getInnerTextFromFirstChild(imageAccessorIter.Current.Select("ImageFileExtension"));
			string permanentDirectory = getInnerTextFromFirstChild(imageAccessorIter.Current.Select("PermanentDirectory"));
			if(permanentDirectory == null || permanentDirectory.Length == 0)
				permanentDirectory = getInnerTextFromFirstChild(imageAccessorIter.Current.Select("PermanantDirectory"));


			TimeSpan dataExpiration = getCacheExpiration(imageAccessorIter.Current.Select("DataExpirationTime"));

			string duplicateTilePath = getInnerTextFromFirstChild(imageAccessorIter.Current.Select("DuplicateTilePath"));
			string cacheDir = getInnerTextFromFirstChild(imageAccessorIter.Current.Select("CacheDirectory"));
			
			if(cacheDir == null || cacheDir.Length == 0)
			{
				cacheDir = String.Format("{0}{1}{2}{1}{3}", cache.CacheDirectory, Path.DirectorySeparatorChar, getRenderablePathString(parentRenderable), name);
			}
			else
			{
				cacheDir = Path.Combine(cache.CacheDirectory, cacheDir);
			}

			if(permanentDirectory != null && permanentDirectory.IndexOf(":") < 0)
			{
				permanentDirectory = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), permanentDirectory);
			}

			if(duplicateTilePath != null && duplicateTilePath.IndexOf(":") < 0)
			{
				duplicateTilePath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), duplicateTilePath);
			}

            byte opacity = 255;

            // case 1 : permanent directory specified.
			if(permanentDirectory != null)
			{
				ImageStore ia = new ImageStore();
				ia.DataDirectory = permanentDirectory;
				ia.LevelZeroTileSizeDegrees = levelZeroTileSizeDegrees;
				ia.LevelCount = numberLevels;
				ia.ImageExtension = imageFileExtension;
				//doesn't work when this is set
				//ia.CacheDirectory = cacheDir;
                
				
				if(duplicateTilePath != null && duplicateTilePath.Length > 0)
				{
					ia.DuplicateTexturePath = duplicateTilePath; 
				}
                return ia;
            }

            // case 2: ImageTileService specified
			XPathNodeIterator imageTileServiceIter = imageAccessorIter.Current.Select("ImageTileService");
			if(imageTileServiceIter.Count > 0)
			{
				imageTileServiceIter.MoveNext();
				
				string serverUrl = getInnerTextFromFirstChild(imageTileServiceIter.Current.Select("ServerUrl"));
				string dataSetName = getInnerTextFromFirstChild(imageTileServiceIter.Current.Select("DataSetName"));
				string serverLogoFilePath = getInnerTextFromFirstChild(imageTileServiceIter.Current.Select("ServerLogoFilePath"));
	
				TimeSpan cacheExpiration = getCacheExpiration(imageTileServiceIter.Current.Select("CacheExpirationTime"));

				if(serverLogoFilePath != null && serverLogoFilePath.Length > 0 && !Path.IsPathRooted(serverLogoFilePath))
				{
					serverLogoFilePath = Path.Combine(
						Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath),
						serverLogoFilePath);
				}
				
				string opacityString = getInnerTextFromFirstChild(imageTileServiceIter.Current.Select("Opacity"));

				if(opacityString != null)
					opacity = byte.Parse(opacityString);

				ImageStore ia = new NltImageStore(dataSetName, serverUrl);
				ia.DataDirectory = null;
				ia.LevelZeroTileSizeDegrees = levelZeroTileSizeDegrees;
				ia.LevelCount = numberLevels;
				ia.ImageExtension = imageFileExtension;
				ia.CacheDirectory = cacheDir;
                ia.ServerLogo = serverLogoFilePath;

                return ia;
            }

            // case 3: WMSAccessor specified
			XPathNodeIterator wmsAccessorIter = imageAccessorIter.Current.Select("WMSAccessor");
			if(wmsAccessorIter.Count > 0)
			{
				wmsAccessorIter.MoveNext();
				
				WorldWind.Net.Wms.WmsImageStore wmsLayerStore = new WorldWind.Net.Wms.WmsImageStore();
			
				wmsLayerStore.ImageFormat = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("ImageFormat"));

				wmsLayerStore.ImageExtension = imageFileExtension;
				wmsLayerStore.CacheDirectory = cacheDir;
				//wmsLayerAccessor.IsTransparent = ParseBool(getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("UseTransparency")));
				wmsLayerStore.ServerGetMapUrl = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("ServerGetMapUrl"));
				wmsLayerStore.Version = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("Version"));
				wmsLayerStore.WMSLayerName = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("WMSLayerName"));

				string username = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("Username"));
				string password = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("Password"));
				string wmsStyleName = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("WMSLayerStyle"));
				string serverLogoPath = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("ServerLogoFilePath"));
				string opacityString = getInnerTextFromFirstChild(wmsAccessorIter.Current.Select("Opacity"));
				
				
				if(serverLogoPath != null && serverLogoPath.Length > 0 && !Path.IsPathRooted(serverLogoPath))
				{
					serverLogoPath = Path.Combine(
						Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath),
						serverLogoPath);
				}
				if(opacityString != null)
					opacity = byte.Parse(opacityString);

                TimeSpan cacheExpiration = getCacheExpiration(imageAccessorIter.Current.Select("CacheExpirationTime"));

			    //if(username != null && username.Length > 0)
			    //    wmsLayerStore.Username = username;

			    //if(password != null)
			    //    wmsLayerAccessor.Password = password;

				if(wmsStyleName != null && wmsStyleName.Length > 0)
					wmsLayerStore.WMSLayerStyle = wmsStyleName;
				else
					wmsLayerStore.WMSLayerStyle = "";

				wmsLayerStore.LevelCount = numberLevels;
				wmsLayerStore.LevelZeroTileSizeDegrees = levelZeroTileSizeDegrees;

                return wmsLayerStore;
            }
            Log.Write(Log.Levels.Warning, "CONF", "WARNING: no valid image store found!");
            return null;
        }
		private static void addQuadTileLayersFromXPathNodeIterator(XPathNodeIterator iter, World parentWorld, RenderableObjectList parentRenderable, Cache cache)
		{
			while(iter.MoveNext())
			{
                string name = getInnerTextFromFirstChild(iter.Current.Select("Name"));
                double distanceAboveSurface = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("DistanceAboveSurface")));
				bool showAtStartup = ParseBool(iter.Current.GetAttribute("ShowAtStartup", ""));

                Log.Write(Log.Levels.Debug+1, "CONF", "adding QuadTileSet "+name);

				double north = 0;
				double south = 0;
				double west = 0;
				double east = 0;
				
				XPathNodeIterator boundingBoxIter = iter.Current.Select("BoundingBox");
				if(boundingBoxIter.Count > 0)
				{
					boundingBoxIter.MoveNext();
					north = ParseDouble(getInnerTextFromFirstChild(boundingBoxIter.Current.Select("North")));
					south = ParseDouble(getInnerTextFromFirstChild(boundingBoxIter.Current.Select("South")));
					west = ParseDouble(getInnerTextFromFirstChild(boundingBoxIter.Current.Select("West")));
					east = ParseDouble(getInnerTextFromFirstChild(boundingBoxIter.Current.Select("East")));
				}

				string terrainMappedString = getInnerTextFromFirstChild(iter.Current.Select("TerrainMapped"));
				string renderStrutsString = getInnerTextFromFirstChild(iter.Current.Select("RenderStruts"));

				TimeSpan dataExpiration = getCacheExpiration(iter.Current.Select("CacheExpirationTime"));
				
				bool terrainMapped = true;

				if(terrainMappedString != null)
				{
					terrainMapped = ParseBool(terrainMappedString);
				}
				XPathNodeIterator imageAccessorIter = iter.Current.Select("descendant::ImageAccessor");

                if (imageAccessorIter.Count == 0)
                {
                    Log.Write(Log.Levels.Warning, "CONF", "skipping QuadTileSet without any ImageAccessor");
                    return;
                }

                int currentStore = 0;
                ImageStore[] imageStores = new ImageStore[imageAccessorIter.Count];

                while (imageAccessorIter.MoveNext())
                {
                    imageStores[currentStore] = getImageStoreFromXPathNodeIterator(name, imageAccessorIter, parentRenderable, cache);
                    currentStore++;
                }

				QuadTileSet qts = null;

				qts = new QuadTileSet(
					name,
					parentWorld,
					distanceAboveSurface,
					north,
					south,
					west,
					east,
					terrainMapped,
					imageStores
					);
                if(imageStores[0].IsDownloadableLayer)
                    qts.ServerLogoFilePath = imageStores[0].ServerLogo;

				qts.CacheExpirationTime = dataExpiration;

				string infoUri = iter.Current.GetAttribute("InfoUri", "");

				if(infoUri != null && infoUri.Length > 0)
				{
					if(qts.MetaData.Contains("InfoUri"))
					{
						qts.MetaData["InfoUri"] = infoUri;
					}
					else
					{
						qts.MetaData.Add("InfoUri", infoUri);
					}
				}

                string effectFile = getInnerTextFromFirstChild(iter.Current.Select("Effect"));
                if (effectFile != null && effectFile.Length > 0)
                {
                    Log.Write(Log.Levels.Debug, "CONF", "QuadTileSet with effect " + effectFile);
                    if (qts.MetaData.Contains("EffectPath"))
                    {
                        qts.MetaData["EffectPath"] = effectFile;
                    }
                    else
                    {
                        qts.MetaData.Add("EffectPath", effectFile);
                    }
                }


				string description = getInnerTextFromFirstChild(iter.Current.Select("Description"));
				if(description != null && description.Length > 0)
					qts.Description = description;

				if(iter.Current.Select("TransparentColor").Count > 0)
				{
					System.Drawing.Color c = getColor(iter.Current.Select("TransparentColor"));
					qts.ColorKey = c.ToArgb();
				}

				if(iter.Current.Select("TransparentMinValue").Count > 0)
				{
					qts.ColorKey = int.Parse(getInnerTextFromFirstChild(iter.Current.Select("TransparentMinValue")));
				}

				if(iter.Current.Select("TransparentMaxValue").Count > 0)
				{
					qts.ColorKeyMax = int.Parse(getInnerTextFromFirstChild(iter.Current.Select("TransparentMaxValue")));
				}

				if(renderStrutsString != null)
				{
					qts.RenderStruts = ParseBool(renderStrutsString);
				}

				qts.ParentList = parentRenderable;
				if(World.Settings.useDefaultLayerStates)
				{
					qts.IsOn = showAtStartup;
				}
				else
				{
					qts.IsOn = IsLayerOn(qts);
				}

				qts.MetaData.Add("XmlSource", (string)parentRenderable.MetaData["XmlSource"]);
				addExtendedInformation(iter.Current.Select("ExtendedInformation"), qts);
				parentRenderable.Add(qts);
			}
		}
		private static RenderableObjectList addChildLayerSet(XPathNodeIterator iter, World parentWorld, RenderableObjectList parentRenderable, Cache cache)
		{
			if(iter.Count > 0)
			{
				while(iter.MoveNext())
				{
					string layerName = iter.Current.GetAttribute("Name", "");
					bool showAtStartup = ParseBool(iter.Current.GetAttribute("ShowAtStartup", ""));
					bool showOnlyOneLayer = ParseBool(iter.Current.GetAttribute("ShowOnlyOneLayer", ""));

					string redirect = iter.Current.GetAttribute("redirect", "");

					if(redirect != null && redirect.Length > 0)
					{
						return ConfigurationLoader.getRenderableFromLayerFile(redirect, parentWorld, cache);
					}

					RenderableObjectList rol = new RenderableObjectList(layerName);
					if(iter.Current.Select("Icon").Count > 0)
					{
						rol = new Icons(layerName);
					}
					
					rol.ParentList = parentRenderable;

					if(World.Settings.useDefaultLayerStates)
					{
						rol.IsOn = showAtStartup;
					}
					else
					{
						rol.IsOn = IsLayerOn(rol);
					}

					string disableExpansionString = iter.Current.GetAttribute("DisableExpansion", "");
					if(disableExpansionString != null)
					{
						rol.DisableExpansion = ParseBool(disableExpansionString);
					}


					rol.ShowOnlyOneLayer = showOnlyOneLayer;
					rol.MetaData.Add("XmlSource", (string)parentRenderable.MetaData["XmlSource"]);

					string renderPriorityString = iter.Current.GetAttribute("RenderPriority", "");
					if(renderPriorityString != null)
					{
                        if (String.Compare(renderPriorityString, "Icons", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
						{
							rol.RenderPriority = RenderPriority.Icons;
						}
                        else if (String.Compare(renderPriorityString, "LinePaths", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
						{
							rol.RenderPriority = RenderPriority.LinePaths;
						}
                        else if (String.Compare(renderPriorityString, "Placenames", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
						{
							rol.RenderPriority = RenderPriority.Placenames;
						}
                        else if (String.Compare(renderPriorityString, "AtmosphericImages", false, System.Globalization.CultureInfo.InvariantCulture) == 0)
						{
							rol.RenderPriority = RenderPriority.AtmosphericImages;
						}
					}

					string description = getInnerTextFromFirstChild(iter.Current.Select("Description"));
					if(description != null && description.Length > 0)
						rol.Description = description;

					string infoUri = iter.Current.GetAttribute("InfoUri", "");

					if(infoUri != null && infoUri.Length > 0)
					{
						if(rol.MetaData.Contains("InfoUri"))
						{
							rol.MetaData["InfoUri"] = infoUri;
						}
						else
						{
							rol.MetaData.Add("InfoUri", infoUri);
						}
					}

					addImageLayersFromXPathNodeIterator(iter.Current.Select("ImageLayer"), parentWorld, rol);
					addQuadTileLayersFromXPathNodeIterator(iter.Current.Select("QuadTileSet"), parentWorld, rol, cache);
					addPolygonFeature(iter.Current.Select("PolygonFeature"), parentWorld, rol);
					addLineFeature(iter.Current.Select("LineFeature"), parentWorld, rol);
					addPathList(iter.Current.Select("PathList"), parentWorld, rol);
					addTiledPlacenameSet(iter.Current.Select("TiledPlacenameSet"), parentWorld, rol);
					addIcon(iter.Current.Select("Icon"), parentWorld, rol, cache);
					addScreenOverlays(iter.Current.Select("ScreenOverlay"), parentWorld, rol, cache);
					addChildLayerSet(iter.Current.Select("ChildLayerSet"), parentWorld, rol, cache);

					addExtendedInformation(iter.Current.Select("ExtendedInformation"), rol);
					parentRenderable.Add(rol);
				}
			}

			return null;
		}
		public static World Load(string filename, Cache cache)
		{
            Log.Write(Log.Levels.Debug, "CONF", "Loading " + filename);

            // get the World Wind Settings through reflection to avoid changing the signature of Load().
            Assembly a = Assembly.GetEntryAssembly();
            Type appType = a.GetType("WorldWind.MainApplication");
            System.Reflection.FieldInfo finfo = appType.GetField("Settings", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetField);
            WorldWindSettings settings = finfo.GetValue(null) as WorldWindSettings;

            XmlReaderSettings readerSettings = new XmlReaderSettings();

            if (settings.ValidateXML)
            {
                Log.Write(Log.Levels.Debug, "CONF", "validating " + filename + " against WorldXmlDescriptor.xsd and LayerSet.xsd");
                readerSettings.ValidationType = ValidationType.Schema;
                /* load the schema to validate against instead of hoping for an inline schema reference */
                XmlSchemaSet schemas = new XmlSchemaSet();
                schemas.Add(null, settings.ConfigPath + "/WorldXmlDescriptor.xsd");
                schemas.Add(null, settings.ConfigPath + "/Earth/LayerSet.xsd");


                readerSettings.Schemas = schemas;
                readerSettings.ValidationEventHandler += new ValidationEventHandler(XMLValidationCallback);
                readerSettings.ValidationFlags |= System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;
            }
            else
            {
                Log.Write(Log.Levels.Debug, "CONF", "loading " + filename + " without validation");
                readerSettings.ValidationType = ValidationType.None;
            }

            try
            {
                XmlReader docReader = XmlReader.Create(filename, readerSettings);
                XPathDocument docNav = new XPathDocument(docReader);
                XPathNavigator nav = docNav.CreateNavigator();

                XPathNodeIterator worldIter = nav.Select("/World[@Name]");
                if (worldIter.Count > 0)
                {
                    worldIter.MoveNext();
                    string worldName = worldIter.Current.GetAttribute("Name", "");
                    double equatorialRadius = ParseDouble(worldIter.Current.GetAttribute("EquatorialRadius", ""));
                    string layerDirectory = worldIter.Current.GetAttribute("LayerDirectory", "");

                    if (layerDirectory.IndexOf(":") < 0)
                    {
                        layerDirectory = Path.Combine(Path.GetDirectoryName(filename), layerDirectory);
                    }

                    TerrainAccessor[] terrainAccessor = getTerrainAccessorsFromXPathNodeIterator(worldIter.Current.Select("TerrainAccessor"),
                        System.IO.Path.Combine(cache.CacheDirectory, worldName));

                    World newWorld = new World(
                        worldName,
                        new Microsoft.DirectX.Vector3(0, 0, 0),
                        new Microsoft.DirectX.Quaternion(0, 0, 0, 0),
                        equatorialRadius,
                        cache.CacheDirectory,
                        (terrainAccessor != null ? terrainAccessor[0] : null)//TODO: Oops, World should be able to handle an array of terrainAccessors
                        );


                    newWorld.RenderableObjects = getRenderablesFromLayerDirectory(layerDirectory, newWorld, cache);

                    return newWorld;
                }
            }
            catch (XmlSchemaException ex)
            {
                Log.Write(Log.Levels.Error, "CONF", "Exception caught during XML parsing: " + ex.Message);
                Log.Write(Log.Levels.Error, "CONF", "File " + filename + " was not read successfully.");
                // TODO: should pop up a message box or something.
                return null;
            }

			return null;
		}
		private static void addIcon(XPathNodeIterator iter, World parentWorld, RenderableObjectList parentRenderable, Cache cache)
		{
			if(iter.Count > 0)
			{
				while(iter.MoveNext())
				{
					XPathNodeIterator nameIter = iter.Current.Select("Name");
					string name = getInnerTextFromFirstChild(nameIter);
		
					double distanceAboveSurface = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("DistanceAboveSurface")));
					double latitude = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("Latitude/Value")));
					double longitude = ParseDouble(getInnerTextFromFirstChild(iter.Current.Select("Longitude/Value")));
					
					string refreshString = iter.Current.GetAttribute("Refresh", "");
					string description = getInnerTextFromFirstChild(iter.Current.Select("Description"));

					string isRotatedString = getInnerTextFromFirstChild(iter.Current.Select("IsRotated"));
					string rotationDegreesString =  getInnerTextFromFirstChild(iter.Current.Select("RotationDegrees"));

					string minimumDisplayAltitudeString = getInnerTextFromFirstChild(iter.Current.Select("MinimumDisplayAltitude"));
					string maximumDisplayAltitudeString = getInnerTextFromFirstChild(iter.Current.Select("MaximumDisplayAltitude"));

					string clickableUrl = getInnerTextFromFirstChild(iter.Current.Select("ClickableUrl"));
					
					string textureFilePath = getInnerTextFromFirstChild(iter.Current.Select("TextureFilePath"));

                    if (textureFilePath.Length > 0 && !Path.IsPathRooted(textureFilePath) && !textureFilePath.ToLower(System.Globalization.CultureInfo.InvariantCulture).StartsWith("http://"))
						// Use absolute path to icon image
						textureFilePath = Path.Combine( 
							Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), textureFilePath );

					if(!Path.IsPathRooted(textureFilePath))
					{
						Path.Combine(
							Path.GetDirectoryName(
							System.Windows.Forms.Application.ExecutablePath),
							textureFilePath);
					}
					
					WorldWind.Renderable.Icon ic = new WorldWind.Renderable.Icon(
						name,
						latitude,
						longitude,
						distanceAboveSurface );
					
					string nameAlwaysVisibleString = nameIter.Current.GetAttribute("AlwaysVisible", "");
					if(nameAlwaysVisibleString != null && nameAlwaysVisibleString.Length > 0)
					{
						ic.NameAlwaysVisible = ParseBool(nameAlwaysVisibleString);
					}

					ic.TextureFileName = textureFilePath;
					ic.Width =	int.Parse(getInnerTextFromFirstChild(iter.Current.Select("IconWidthPixels")));
					ic.Height = int.Parse(getInnerTextFromFirstChild(iter.Current.Select("IconHeightPixels")));
					
					if(refreshString != null && refreshString.Length > 0)
					{
						ic.RefreshInterval = TimeSpan.FromSeconds(ParseDouble(refreshString));
					}

					string infoUri = iter.Current.GetAttribute("InfoUri", "");

					if(infoUri != null && infoUri.Length > 0)
					{
						if(ic.MetaData.Contains("InfoUri"))
						{
							ic.MetaData["InfoUri"] = infoUri;
						}
						else
						{
							ic.MetaData.Add("InfoUri", infoUri);
						}
					}

					if(description != null)
						ic.Description = description;

					if(clickableUrl != null)
						ic.ClickableActionURL = clickableUrl;

					if(maximumDisplayAltitudeString != null)
						ic.MaximumDisplayDistance = ParseDouble(maximumDisplayAltitudeString);

					if(minimumDisplayAltitudeString != null)
						ic.MinimumDisplayDistance = ParseDouble(minimumDisplayAltitudeString);

					string onClickZoomAltString = getInnerTextFromFirstChild(iter.Current.Select("OnClickZoomAltitude"));
					string onClickZoomHeadingString = getInnerTextFromFirstChild(iter.Current.Select("OnClickZoomHeading"));
					string onClickZoomTiltString = getInnerTextFromFirstChild(iter.Current.Select("OnClickZoomTilt"));
					
					if(onClickZoomAltString != null)
						ic.OnClickZoomAltitude = ParseDouble(onClickZoomAltString);

					if(onClickZoomHeadingString != null)
						ic.OnClickZoomHeading = ParseDouble(onClickZoomHeadingString);

					if(onClickZoomTiltString != null)
						ic.OnClickZoomTilt = ParseDouble(onClickZoomTiltString);

					if(isRotatedString != null)
					{
						ic.IsRotated = ParseBool(isRotatedString);
					}

					if(rotationDegreesString != null)
					{
						if(!ic.IsRotated)
							ic.IsRotated = true;

						ic.Rotation = Angle.FromDegrees(ParseDouble(rotationDegreesString));
					}

					addExtendedInformation(iter.Current.Select("ExtendedInformation"), ic);
					
					ic.ParentList = parentRenderable;

					string cachePath = String.Format("{0}{1}{2}{1}{3}{1}{3}", cache.CacheDirectory, Path.DirectorySeparatorChar, getRenderablePathString(parentRenderable), name);

					ic.SaveFilePath = cachePath;

					if(World.Settings.useDefaultLayerStates)
					{
						ic.IsOn = ParseBool(iter.Current.GetAttribute("ShowAtStartup", ""));
					}
					else
					{
						ic.IsOn = IsLayerOn(ic);
					}
					ic.MetaData["XmlSource"] = (string)parentRenderable.MetaData["XmlSource"];

					Icons parentIconList = (Icons)parentRenderable;

					parentIconList.Add(ic);

					addScreenOverlaysToIcon(iter.Current.Select("ScreenOverlay"), parentWorld, ic, cache);
				}
			}
		}
        private static RenderableObjectList getRenderablesFromLayerDirectory(string layerDirectory, World parentWorld, Cache cache)
		{
			RenderableObjectList renderableCollection = new RenderableObjectList(parentWorld.Name);

			DirectoryInfo layerDir = new DirectoryInfo(layerDirectory);
			if(!layerDir.Exists)
			{
				return renderableCollection;
			}

			foreach(FileInfo layerFile in layerDir.GetFiles("*.xml"))
			{
				RenderableObjectList currentRenderable = getRenderableFromLayerFile(layerFile.FullName, parentWorld, cache);
				if(currentRenderable != null)
				{
					renderableCollection.Add(currentRenderable);
				}
			}

			return renderableCollection;
		}
		private static void addScreenOverlaysToIcon(XPathNodeIterator iter, World parentWorld, Icon icon, Cache cache)
		{
			if(iter.Count > 0)
			{
				while(iter.MoveNext())
				{
					string name = getInnerTextFromFirstChild(iter.Current.Select("Name"));
					string imageUri = getInnerTextFromFirstChild(iter.Current.Select("ImageUri"));
					string startXString = getInnerTextFromFirstChild(iter.Current.Select("StartX"));
					string startYString = getInnerTextFromFirstChild(iter.Current.Select("StartY"));
					string widthString = getInnerTextFromFirstChild(iter.Current.Select("Width"));
					string heightString = getInnerTextFromFirstChild(iter.Current.Select("Height"));
					string opacityString = getInnerTextFromFirstChild(iter.Current.Select("Opacity"));
					string showHeaderString = getInnerTextFromFirstChild(iter.Current.Select("ShowHeader"));
					string refreshTimeString = iter.Current.GetAttribute("Refresh", "");
					string alignmentString = getInnerTextFromFirstChild(iter.Current.Select("Alignment"));
					string clickableUrl = getInnerTextFromFirstChild(iter.Current.Select("ClickableUrl"));
					string hideBorderString = getInnerTextFromFirstChild(iter.Current.Select("HideBorder"));

					if(startXString != null && startYString != null)
					{
						int startX = int.Parse(startXString);
						int startY = int.Parse(startYString);

						WorldWind.Renderable.ScreenOverlay overlay = new ScreenOverlay(name, startX, startY, imageUri);
					
						if(widthString != null)
						{
							overlay.Width = int.Parse(widthString);
						}
						if(heightString != null)
						{
							overlay.Height = int.Parse(heightString);
						}

						if(alignmentString != null)
						{
                            if (alignmentString.ToLower(System.Globalization.CultureInfo.InvariantCulture).Equals("left"))
							{
								overlay.Alignment = ScreenAlignment.Left;
							}
                            else if (alignmentString.ToLower(System.Globalization.CultureInfo.InvariantCulture).Equals("right"))
							{
								overlay.Alignment = ScreenAlignment.Right;
							}
						}

						if(clickableUrl != null && clickableUrl.Length > 0)
						{
							overlay.ClickableUrl = clickableUrl;
						}

						if(hideBorderString != null && hideBorderString.Length > 0)
							overlay.HideBorder = ParseBool(hideBorderString);

						string cachePath = String.Format("{0}{1}{2}{1}{3}{1}{3}", cache.CacheDirectory, Path.DirectorySeparatorChar, getRenderablePathString(icon), name);

						if(refreshTimeString != null && refreshTimeString.Length > 0)
						{
							overlay.RefreshTimeSec = ParseDouble(refreshTimeString);
						}

						string description = getInnerTextFromFirstChild(iter.Current.Select("Description"));
						if(description != null && description.Length > 0)
							overlay.Description = description;

						overlay.SaveFilePath = cachePath;
						addExtendedInformation(iter.Current.Select("ExtendedInformation"), overlay);

						string infoUri = iter.Current.GetAttribute("InfoUri", "");

						if(infoUri != null && infoUri.Length > 0)
						{
							if(overlay.MetaData.Contains("InfoUri"))
							{
								overlay.MetaData["InfoUri"] = infoUri;
							}
							else
							{
								overlay.MetaData.Add("InfoUri", infoUri);
							}
						}

						overlay.MetaData.Add("XmlSource", (string)icon.MetaData["XmlSource"]);
						overlay.ParentList = icon.ParentList;
						if(opacityString != null)
						{
							overlay.Opacity = byte.Parse(opacityString);
						}

						if(showHeaderString != null)
						{
							overlay.ShowHeader = ParseBool(showHeaderString);
						}

						if(World.Settings.useDefaultLayerStates)
						{
							overlay.IsOn = ParseBool(iter.Current.GetAttribute("ShowAtStartup", ""));
						}
						else
						{
							overlay.IsOn = IsLayerOn(overlay);
						}

						icon.AddOverlay(overlay);
					}
				}
			}
		}