protected boolean loadTile(Tile tile, java.net.URL url) {
    if (WWIO.isFileOutOfDate(url, this.placeNameServiceSet.getExpiryTime())) {
      // The file has expired. Delete it then request download of newer.
      this.getDataFileStore().removeFile(url);
      String message = Logging.getMessage("generic.DataFileExpired", url);
      Logging.logger().fine(message);
      return false;
    }

    PlaceNameChunk tileData;
    synchronized (this.fileLock) {
      tileData = readTileData(tile, url);
    }

    if (tileData == null) {
      // Assume that something's wrong with the file and delete it.
      this.getDataFileStore().removeFile(url);
      tile.getPlaceNameService()
          .markResourceAbsent(tile.getPlaceNameService().getTileNumber(tile.row, tile.column));
      String message = Logging.getMessage("generic.DeletedCorruptDataFile", url);
      Logging.logger().fine(message);
      return false;
    }

    tile.setDataChunk(tileData);
    WorldWind.getMemoryCache(Tile.class.getName()).add(tile.getFileCachePath(), tile);
    return true;
  }
  /**
   * @param placeNameServiceSet the set of PlaceNameService objects that PlaceNameLayer will render.
   * @throws IllegalArgumentException if {@link
   *     gov.nasa.worldwind.layers.placename.PlaceNameServiceSet} is null
   */
  public PlaceNameLayer(PlaceNameServiceSet placeNameServiceSet) {
    if (placeNameServiceSet == null) {
      String message = Logging.getMessage("nullValue.PlaceNameServiceSetIsNull");
      Logging.logger().fine(message);
      throw new IllegalArgumentException(message);
    }

    //
    this.placeNameServiceSet = placeNameServiceSet.deepCopy();
    for (int i = 0; i < this.placeNameServiceSet.getServiceCount(); i++) {
      // todo do this for long as well and pick min
      int calc1 =
          (int)
              (PlaceNameService.TILING_SECTOR.getDeltaLatDegrees()
                  / this.placeNameServiceSet
                      .getService(i)
                      .getTileDelta()
                      .getLatitude()
                      .getDegrees());
      int numLevels = (int) Math.log(calc1);
      navTiles.add(
          new NavigationTile(
              this.placeNameServiceSet.getService(i),
              PlaceNameService.TILING_SECTOR,
              numLevels,
              "top"));
    }

    if (!WorldWind.getMemoryCacheSet().containsCache(Tile.class.getName())) {
      long size = Configuration.getLongValue(AVKey.PLACENAME_LAYER_CACHE_SIZE, 2000000L);
      MemoryCache cache = new BasicMemoryCache((long) (0.85 * size), size);
      cache.setName("Placename Tiles");
      WorldWind.getMemoryCacheSet().addCache(Tile.class.getName(), cache);
    }
  }
  /**
   * Causes resources used by the World Window to be freed. The World Window cannot be used once
   * this method is called. An OpenGL context for the window must be current.
   */
  public void shutdown() {
    WorldWind.getDataFileStore().removePropertyChangeListener(this);

    if (this.inputHandler != null) {
      this.inputHandler.dispose();
      this.inputHandler = new NoOpInputHandler();
    }

    // Clear the texture cache
    if (this.getGpuResourceCache() != null) this.getGpuResourceCache().clear();

    // Dispose all the layers //  TODO: Need per-window dispose for layers
    if (this.getModel() != null && this.getModel().getLayers() != null) {
      for (Layer layer : this.getModel().getLayers()) {
        try {
          layer.dispose();
        } catch (Exception e) {
          Logging.logger()
              .log(
                  java.util.logging.Level.SEVERE,
                  Logging.getMessage("WorldWindowGLCanvas.ExceptionWhileShuttingDownWorldWindow"),
                  e);
        }
      }
    }

    SceneController sc = this.getSceneController();
    if (sc != null) sc.dispose();
  }
 static Angle computeColumnLongitude(int column, Angle delta) {
   if (delta == null) {
     String msg = Logging.getMessage("nullValue.AngleIsNull");
     Logging.logger().severe(msg);
     throw new IllegalArgumentException(msg);
   }
   return Angle.fromDegrees(-180 + delta.getDegrees() * column);
 }
 static Angle computeRowLatitude(int row, Angle delta) {
   if (delta == null) {
     String msg = Logging.getMessage("nullValue.AngleIsNull");
     Logging.logger().severe(msg);
     throw new IllegalArgumentException(msg);
   }
   return Angle.fromDegrees(-90d + delta.getDegrees() * row);
 }
 static int computeColumn(Angle delta, Angle longitude) {
   if (delta == null || longitude == null) {
     String msg = Logging.getMessage("nullValue.AngleIsNull");
     Logging.logger().severe(msg);
     throw new IllegalArgumentException(msg);
   }
   return (int) ((longitude.getDegrees() + 180d) / delta.getDegrees());
 }
 /**
  * @param that the task to compare
  * @return -1 if <code>this</code> less than <code>that</code>, 1 if greater than, 0 if equal
  * @throws IllegalArgumentException if <code>that</code> is null
  */
 public int compareTo(RequestTask that) {
   if (that == null) {
     String msg = Logging.getMessage("nullValue.RequestTaskIsNull");
     Logging.logger().severe(msg);
     throw new IllegalArgumentException(msg);
   }
   return this.tile.getPriority() == that.tile.getPriority()
       ? 0
       : this.tile.getPriority() < that.tile.getPriority() ? -1 : 1;
 }
 protected double parseDouble(StringBuilder sb) {
   double value = 0;
   try {
     value = Double.parseDouble(sb.toString());
   } catch (NumberFormatException e) {
     Logging.logger()
         .log(
             Level.FINE,
             Logging.getMessage("layers.PlaceNameLayer.ExceptionAttemptingToReadFile", ""),
             e);
   }
   return value;
 }
 /**
  * Get the estimated size in bytes of the placenames not in a specified file store for the given
  * sector and resolution.
  *
  * <p>Note that the target resolution must be provided in radians of latitude per texel, which is
  * the resolution in meters divided by the globe radius.
  *
  * @param sector the sector to estimate.
  * @param resolution the target resolution, provided in radians of latitude per texel.
  * @param fileStore the file store to examine. If null the current World Wind file cache is used.
  * @return the estimated size in byte of the missing placenames.
  * @throws IllegalArgumentException if the sector is null or the resolution is less than zero.
  */
 public long getEstimatedMissingDataSize(Sector sector, double resolution, FileStore fileStore) {
   try {
     PlaceNameLayerBulkDownloader downloader =
         new PlaceNameLayerBulkDownloader(
             this,
             sector,
             resolution,
             fileStore != null ? fileStore : this.getDataFileStore(),
             null);
     return downloader.getEstimatedMissingDataSize();
   } catch (Exception e) {
     String message =
         Logging.getMessage("generic.ExceptionDuringDataSizeEstimate", this.getName());
     Logging.logger().severe(message);
     throw new RuntimeException(message);
   }
 }
  public ImageInterpolator(Dimension gridSize, float[] xs, float[] ys, int depth, int cellSize) {
    if (gridSize == null) {
      String message = Logging.getMessage("nullValue.DimensionIsNull");
      Logging.logger().severe(message);
      throw new IllegalStateException(message);
    }

    if (gridSize.width < 2 || gridSize.height < 2) {
      String message = Logging.getMessage("generic.DimensionsTooSmall");
      Logging.logger()
          .log(
              java.util.logging.Level.SEVERE,
              message,
              new Object[] {gridSize.width, gridSize.height});
      throw new IllegalStateException(message);
    }

    if (xs == null || ys == null || xs.length < 4 || ys.length < 4) {
      String message = Logging.getMessage("Grid.ArraysInvalid");
      Logging.logger().severe(message);
      throw new IllegalStateException(message);
    }

    if (depth < 0) {
      String message = Logging.getMessage("Grid.DepthInvalid");
      Logging.logger().severe(message);
      throw new IllegalStateException(message);
    }

    if (cellSize < 1) {
      String message = Logging.getMessage("Grid.CellSizeInvalid");
      Logging.logger().severe(message);
      throw new IllegalStateException(message);
    }

    this.gridSize = gridSize;
    this.cellSize = cellSize;

    this.xs = xs;
    this.ys = ys;

    this.root = this.makeRootCell(0, this.gridSize.width - 1, 0, this.gridSize.height - 1);
    this.root.build(depth, this.cellSize);
    this.root.computeBounds(this.gridSize, this.xs, this.ys);
  }
  @Override
  protected void doRender(DrawContext dc) {
    this.referencePoint = this.computeReferencePoint(dc);

    int serviceCount = this.placeNameServiceSet.getServiceCount();
    for (int i = 0; i < serviceCount; i++) {
      PlaceNameService placeNameService = this.placeNameServiceSet.getService(i);
      if (!isServiceVisible(dc, placeNameService)) continue;

      double minDistSquared =
          placeNameService.getMinDisplayDistance() * placeNameService.getMinDisplayDistance();
      double maxDistSquared =
          placeNameService.getMaxDisplayDistance() * placeNameService.getMaxDisplayDistance();

      if (isSectorVisible(
          dc, placeNameService.getMaskingSector(), minDistSquared, maxDistSquared)) {
        ArrayList<Tile> baseTiles = new ArrayList<Tile>();
        NavigationTile navTile = this.navTiles.get(i);
        // drill down into tiles to find bottom level navTiles visible
        List<NavigationTile> list = navTile.navTilesVisible(dc, minDistSquared, maxDistSquared);
        for (NavigationTile nt : list) {
          baseTiles.addAll(nt.getTiles());
        }

        for (Tile tile : baseTiles) {
          try {
            drawOrRequestTile(dc, tile, minDistSquared, maxDistSquared);
          } catch (Exception e) {
            Logging.logger()
                .log(
                    Level.FINE,
                    Logging.getMessage("layers.PlaceNameLayer.ExceptionRenderingTile"),
                    e);
          }
        }
      }
    }

    this.sendRequests();
    this.requestQ.clear();
  }
  protected void downloadTile(final Tile tile, DownloadPostProcessor postProcessor) {
    if (!this.isNetworkRetrievalEnabled()) return;

    if (!WorldWind.getRetrievalService().isAvailable()) return;

    java.net.URL url;
    try {
      url = tile.getRequestURL();
      if (WorldWind.getNetworkStatus().isHostUnavailable(url)) return;
    } catch (java.net.MalformedURLException e) {
      Logging.logger()
          .log(
              java.util.logging.Level.SEVERE,
              Logging.getMessage("layers.PlaceNameLayer.ExceptionCreatingUrl", tile),
              e);
      return;
    }

    Retriever retriever;

    if ("http".equalsIgnoreCase(url.getProtocol()) || "https".equalsIgnoreCase(url.getProtocol())) {
      if (postProcessor == null) postProcessor = new DownloadPostProcessor(this, tile);
      retriever = new HTTPRetriever(url, postProcessor);
    } else {
      Logging.logger()
          .severe(
              Logging.getMessage("layers.PlaceNameLayer.UnknownRetrievalProtocol", url.toString()));
      return;
    }

    // Apply any overridden timeouts.
    Integer cto = AVListImpl.getIntegerValue(this, AVKey.URL_CONNECT_TIMEOUT);
    if (cto != null && cto > 0) retriever.setConnectTimeout(cto);
    Integer cro = AVListImpl.getIntegerValue(this, AVKey.URL_READ_TIMEOUT);
    if (cro != null && cro > 0) retriever.setReadTimeout(cro);
    Integer srl = AVListImpl.getIntegerValue(this, AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT);
    if (srl != null && srl > 0) retriever.setStaleRequestLimit(srl);

    WorldWind.getRetrievalService().runRetriever(retriever, tile.getPriority());
  }
  protected static PlaceNameChunk readTileData(Tile tile, java.net.URL url) {
    java.io.InputStream is = null;

    try {
      String path = url.getFile();
      path =
          path.replaceAll(
              "%20", " "); // TODO: find a better way to get a path usable by FileInputStream

      java.io.FileInputStream fis = new java.io.FileInputStream(path);
      java.io.BufferedInputStream buf = new java.io.BufferedInputStream(fis);
      is = new java.util.zip.GZIPInputStream(buf);

      GMLPlaceNameSAXHandler handler = new GMLPlaceNameSAXHandler();
      javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser().parse(is, handler);
      return handler.createPlaceNameChunk(tile.getPlaceNameService());
    } catch (Exception e) {
      // todo log actual error
      Logging.logger()
          .log(
              Level.FINE,
              Logging.getMessage(
                  "layers.PlaceNameLayer.ExceptionAttemptingToReadFile", url.toString()),
              e);
    } finally {
      try {
        if (is != null) is.close();
      } catch (java.io.IOException e) {
        Logging.logger()
            .log(
                Level.FINE,
                Logging.getMessage(
                    "layers.PlaceNameLayer.ExceptionAttemptingToReadFile", url.toString()),
                e);
      }
    }

    return null;
  }
    @Override
    protected ByteBuffer handleXMLContent() throws IOException {
      // Check for an exception report
      String s = WWIO.byteBufferToString(this.getRetriever().getBuffer(), 1024, null);
      if (s.contains("<ExceptionReport>")) {
        // TODO: Parse the xml and include only the message text in the log message.

        StringBuilder sb = new StringBuilder(this.getRetriever().getName());

        sb.append("\n");
        sb.append(WWIO.byteBufferToString(this.getRetriever().getBuffer(), 2048, null));
        Logging.logger().warning(sb.toString());

        return null;
      }

      this.saveBuffer();

      return this.getRetriever().getBuffer();
    }
  /**
   * @param className the full name, including package names, of the component to create
   * @return the new component
   * @throws WWRuntimeException if the <code>Object</code> could not be created
   * @throws IllegalArgumentException if <code>className</code> is null or zero length
   */
  public static Object createComponent(String className) throws WWRuntimeException {
    if (className == null || className.length() == 0) {
      Logging.logger().severe("nullValue.ClassNameIsNull");
      throw new IllegalArgumentException(Logging.getMessage("nullValue.ClassNameIsNull"));
    }

    try {
      Class c = Class.forName(className.trim());
      return c.newInstance();
    } catch (Exception e) {
      Logging.logger().log(Level.SEVERE, "WorldWind.ExceptionCreatingComponent", className);
      throw new WWRuntimeException(
          Logging.getMessage("WorldWind.ExceptionCreatingComponent", className), e);
    } catch (Throwable t) {
      Logging.logger().log(Level.SEVERE, "WorldWind.ErrorCreatingComponent", className);
      throw new WWRuntimeException(
          Logging.getMessage("WorldWind.ErrorCreatingComponent", className), t);
    }
  }
  /**
   * @param classNameKey the key identifying the component
   *
   * @return the new component
   *
   * @throws IllegalStateException    if no name could be found which corresponds to <code>classNameKey</code>
   * @throws IllegalArgumentException if <code>classNameKey<code> is null
   * @throws WWRuntimeException       if the component could not be created
   */
  public static Object createConfigurationComponent(String classNameKey)
      throws IllegalStateException, IllegalArgumentException {
    if (classNameKey == null || classNameKey.length() == 0) {
      Logging.logger().severe("nullValue.ClassNameKeyNullZero");
      throw new IllegalArgumentException(Logging.getMessage("nullValue.ClassNameKeyNullZero"));
    }

    String name = Configuration.getStringValue(classNameKey);
    if (name == null) {
      Logging.logger()
          .log(Level.SEVERE, "WorldWind.NoClassNameInConfigurationForKey", classNameKey);
      throw new WWRuntimeException(
          Logging.getMessage("WorldWind.NoClassNameInConfigurationForKey", classNameKey));
    }

    try {
      return WorldWind.createComponent(name.trim());
    } catch (Throwable e) {
      Logging.logger().log(Level.SEVERE, "WorldWind.UnableToCreateClassForConfigurationKey", name);
      throw new IllegalStateException(
          Logging.getMessage("WorldWind.UnableToCreateClassForConfigurationKey", name), e);
    }
  }