/**
   * @param envelope
   * @param width
   * @param height
   * @return
   * @throws ThinklabResourceNotFoundException
   */
  private BufferedImage getWMSImage(Envelope envelope, int width, int height)
      throws ThinklabResourceNotFoundException {

    BufferedImage ret = null;
    initializeWms();

    String sig = envelope.toString() + "," + width + "," + height;

    if (_cache.containsKey(sig)) return ImageUtil.clone(_cache.get(sig));

    if (_wms != null) {

      GetMapRequest request = _wms.createGetMapRequest();
      request.setFormat("image/png");
      request.setDimensions("" + width, "" + height);
      request.setTransparent(true);

      // FIXME this assumes the envelope is in lat/lon
      request.setSRS("EPSG:4326");

      String bbox =
          (float) envelope.getMinX()
              + ","
              + (float) envelope.getMinY()
              + ","
              + (float) envelope.getMaxX()
              + ","
              + (float) envelope.getMaxY();

      request.setBBox(bbox);

      for (Layer layer : getWMSLayers()) {
        request.addLayer(layer);
      }

      GetMapResponse response = null;
      try {

        System.out.println(request.getFinalURL());

        response = (GetMapResponse) _wms.issueRequest(request);
        ret = ImageIO.read(response.getInputStream());
      } catch (Exception e) {
        Geospace.get().logger().warn("cannot get WFS imagery: " + e.getLocalizedMessage());
        return null;
      }

      /*
       * FIXME this obviously must have a limit
       */
      if (ret != null) _cache.put(sig, ImageUtil.clone(ret));
    }

    return ret;
  }
 @SuppressWarnings("unchecked")
 private void setImageFormat(WebMapServer wms, GetMapRequest request) {
   List formats = wms.getCapabilities().getRequest().getGetMap().getFormats();
   String str;
   if (getPreferencesStore().getBoolean(PreferenceConstants.P_USE_DEFAULT_ORDER)) {
     str = getPreferencesStore().getDefaultString(PreferenceConstants.P_IMAGE_TYPE_ORDER);
   } else {
     str = getPreferencesStore().getString(PreferenceConstants.P_IMAGE_TYPE_ORDER);
   }
   String[] preferredFormats = str.split(","); // $NON-NLS-1$
   // Select one of the available formats from the WMS server
   // the order of preferred formats is set in the preferences
   for (String format : preferredFormats) {
     if (formats.contains(format)) {
       request.setProperty(GetMapRequest.FORMAT, format);
       request.setTransparent(formatSupportsTransparency(format));
       break;
     }
   }
 }
  @SuppressWarnings("unchecked")
  private void setFilter(WebMapServer wms, GetMapRequest request) {
    Filter mapFilter = null;

    Map<ILayer, Filter> filters = new HashMap<ILayer, Filter>();
    List<ILayer> layers = getContext().getLayers();
    for (ILayer layer : layers) {
      Object layerFilter =
          layer.getStyleBlackboard().get(ProjectBlackboardConstants.LAYER__DATA_QUERY);
      Filter filter;
      if (layerFilter instanceof Query) {
        filter = (Filter) ((Query) layerFilter).getFilter();
      } else if (layerFilter instanceof Filter) {
        filter = (Filter) layerFilter;
      } else {
        filter = mapFilter;
      }
      if (filter != null && filter != Filter.INCLUDE) {
        filters.put(layer, filter);
      }
    }

    if (filters.isEmpty()) return;

    StringBuilder builder = new StringBuilder();
    HashMap hashMap = new HashMap();
    for (Map.Entry<ILayer, Filter> entry : filters.entrySet()) {
      if (entry.getValue() == null) builder.append('(');
      try {
        StringWriter writer = new StringWriter();
        DocumentWriter.writeDocument(entry.getValue(), FilterSchema.getInstance(), writer, hashMap);
        builder.append(writer.toString());
      } catch (OperationNotSupportedException e) {
        WMSPlugin.log(
            "Error writing filter for layer: " + entry.getKey().getID(), e); // $NON-NLS-1$
        builder.append("<Filter/>"); // $NON-NLS-1$
      } catch (IOException e) {
        // SHOULDN'T Happen I don't think...
        assert false;
        WMSPlugin.log(
            "Error writing filter for layer: " + entry.getKey().getID(), e); // $NON-NLS-1$
        builder.append("<Filter/>"); // $NON-NLS-1$
      }
      builder.append(')');
    }

    try {
      String encode = URLEncoder.encode(builder.toString(), "UTF-8"); // $NON-NLS-1$
      request.setVendorSpecificParameter("filter", encode); // $NON-NLS-1$
    } catch (UnsupportedEncodingException e) {
      // better not happen!
      throw (RuntimeException) new RuntimeException().initCause(e);
    }
  }
  public static void main(String[] args) {
    URL url = null;
    try {
      url =
          new URL(
              // "http://www2.dmsolutions.ca/cgi-bin/mswms_gmap?VERSION=1.1.0&REQUEST=GetCapabilities");
              "http://sigel.aneel.gov.br/arcgis/services/SIGEL/Geracao/MapServer/WMSServer?request=getcapabilities");
      // "http://www2.sipam.gov.br/geoserver/wms?service=WMS&request=GetCapabilities");
    } catch (MalformedURLException e) {
      // will not happen
    }

    WebMapServer wms = null;
    try {
      wms = new WebMapServer(url);

      WMSCapabilities capabilities = wms.getCapabilities();

      String serverName = capabilities.getService().getName();
      String serverTitle = capabilities.getService().getTitle();
      System.out.println(
          "Capabilities retrieved from server: " + serverName + " (" + serverTitle + ")");

      System.out.println(capabilities.getService().getOnlineResource());

      // gets the top most layer, which will contain all the others
      Layer rootLayer = capabilities.getLayer();

      System.out.println(rootLayer.getName());

      System.out.println("===============");

      Layer[] layers2 = WMSUtils.getNamedLayers(capabilities);
      List<Layer> layers = capabilities.getLayerList();
      CRSEnvelope env = null;
      int i = 0;
      for (Layer layer : layers2) {
        i++;
        System.out.println("Layer: (" + i + ")" + layer.getName());
        System.out.println("       " + layer.getTitle());
        System.out.println("       " + layer.getChildren().length);
        System.out.println("       " + layer.getBoundingBoxes());
        env = layer.getLatLonBoundingBox();
        System.out.println("       " + env.getLowerCorner() + " x " + env.getUpperCorner());

        List<String> formats = wms.getCapabilities().getRequest().getGetMap().getFormats();

        System.out.println("formats: " + formats);
      }
      System.out.println("===============");

      GetMapRequest request = wms.createGetMapRequest();

      request.setFormat("image/png");
      request.setDimensions(
          "583", "420"); // sets the dimensions of the image to be returned from the server
      request.setTransparent(true);
      request.setSRS("EPSG:4326");
      request.setBBox(env);
      request.addLayer(layers.get(layers.size() - 1));

      System.out.println(request.getFinalURL());

      GetMapResponse response = (GetMapResponse) wms.issueRequest(request);

      ImageIO.write(
          ImageIO.read(response.getInputStream()),
          "png",
          new File("/Users/otos/development/projeto/demoiselle-spatial/tmp/file.png"));

      System.out.println(request.getFinalURL());

    } catch (IOException e) {
      // There was an error communicating with the server
      // For example, the server is down
    } catch (ServiceException e) {
      // The server returned a ServiceException (unusual in this case)
    } catch (SAXException e) {
      // Unable to parse the response from the server
      // For example, the capabilities it returned was not valid
    }
  }
  public synchronized void render(
      Graphics2D destination, ReferencedEnvelope bounds, IProgressMonitor monitor)
      throws RenderException {

    int endLayerStatus = ILayer.DONE;
    try {
      if (bounds == null || bounds.isNull()) {
        bounds = getContext().getImageBounds();
      }

      if (monitor.isCanceled()) return;

      getContext().setStatus(ILayer.WAIT);

      WebMapServer wms = getWMS();

      GetMapRequest request = wms.createGetMapRequest();

      // put in default exception format we understand as a client
      // (if suppoted by the server)
      WMSCapabilities capabilities = wms.getCapabilities();
      if (capabilities
          .getRequest()
          .getGetMap()
          .getFormats()
          .contains(GetMapRequest.EXCEPTION_XML)) {
        request.setExceptions(GetMapRequest.EXCEPTION_XML);
      }
      setImageFormat(wms, request);

      if (monitor.isCanceled()) return;

      double currScale = getContext().getViewportModel().getScaleDenominator();
      List<ILayer> layers = getLayers();
      for (int i = layers.size() - 1; i >= 0; i--) {
        ILayer ilayer = layers.get(i);
        Layer layer;
        double minScale = 0;
        double maxScale = Double.MAX_VALUE;
        layer = ilayer.getResource(org.geotools.data.ows.Layer.class, null);
        // check if there are min/max scale rules
        StyleBlackboard sb = (StyleBlackboard) ilayer.getStyleBlackboard();
        Style style = (Style) sb.lookup(Style.class);
        if (style != null) {
          Rule rule = style.getFeatureTypeStyles()[0].getRules()[0];
          minScale = rule.getMinScaleDenominator();
          maxScale = rule.getMaxScaleDenominator();
        }

        if (currScale >= minScale && currScale <= maxScale) {
          // check for a wms style
          StyleImpl wmsStyle =
              (StyleImpl) ilayer.getStyleBlackboard().get(WMSStyleContent.WMSSTYLE);
          if (wmsStyle != null) {
            request.addLayer(layer, wmsStyle);
          } else {
            request.addLayer(layer);
          }
        }
      }

      if (monitor.isCanceled()) return;

      List<Layer> wmsLayers = getWMSLayers();
      if (wmsLayers == null || wmsLayers.isEmpty()) {
        endLayerStatus = ILayer.WARNING;
        return;
      }

      // figure out request CRS
      String requestCRScode = findRequestCRS(wmsLayers, getViewportCRS(), getContext().getMap());
      // TODO: make findRequestCRS more efficient (we are running CRS.decode at *least* twice)
      CoordinateReferenceSystem requestCRS = CRS.decode(requestCRScode);

      // figure out viewport
      //            ReferencedEnvelope viewport;
      //            Envelope viewportBBox = getViewportBBox();
      //            CoordinateReferenceSystem viewportCRS = getViewportCRS();
      //            if (viewportBBox == null) {
      //                // change viewport to world
      //                viewportBBox = new Envelope(-180, 180, -90, 90);
      //                if (!DefaultGeographicCRS.WGS84.equals(viewportCRS)) { // reproject
      //                    viewport = new ReferencedEnvelope(viewportBBox,
      // DefaultGeographicCRS.WGS84);
      //                    viewportBBox = viewport.transform(viewportCRS, true);
      //                }
      //            }

      ReferencedEnvelope requestBBox = null;
      Envelope backprojectedBBox = null; // request bbox projected to the viewport crs
      //            viewport = new ReferencedEnvelope(viewportBBox, viewportCRS);
      //            requestBBox = calculateRequestBBox(wmsLayers, viewport, requestCRS);

      requestBBox = calculateRequestBBox(wmsLayers, bounds, requestCRS, capabilities.getVersion());

      // check that a request is needed (not out of a bounds, invalid, etc)
      if (requestBBox == NILL_BOX) {
        endLayerStatus = ILayer.WARNING;
        return;
      }
      assert requestBBox.getCoordinateReferenceSystem().equals(requestCRS);

      if (requestBBox.getCoordinateReferenceSystem().equals(getViewportCRS())) {
        backprojectedBBox = (Envelope) requestBBox;
      } else {
        backprojectedBBox = (Envelope) requestBBox.transform(getViewportCRS(), true);
      }

      if (WMSPlugin.isDebugging(Trace.RENDER)) {
        WMSPlugin.trace("Viewport CRS: " + getViewportCRS().getName()); // $NON-NLS-1$
        WMSPlugin.trace("Request CRS: " + requestCRS.getName()); // $NON-NLS-1$
        WMSPlugin.trace("Context Image bounds: " + getContext().getImageBounds()); // $NON-NLS-1$
        WMSPlugin.trace("Request BBox  bounds: " + requestBBox); // $NON-NLS-1$
        WMSPlugin.trace("Backprojected request bounds: " + backprojectedBBox); // $NON-NLS-1$
      }

      Service wmsService = capabilities.getService();
      Dimension maxDimensions = new Dimension(wmsService.getMaxWidth(), wmsService.getMaxHeight());
      //            Dimension imageDimensions =
      // calculateImageDimensions(getContext().getMapDisplay()
      //                    .getDisplaySize(), maxDimensions, getViewportBBox(), backprojectedBBox);
      Dimension imageDimensions =
          calculateImageDimensions(
              getContext().getImageSize(), maxDimensions, bounds, backprojectedBBox);
      if (imageDimensions.height < 1 || imageDimensions.width < 1) {
        endLayerStatus = ILayer.WARNING;
        return;
      }
      request.setDimensions(
          imageDimensions.width + "", imageDimensions.height + ""); // $NON-NLS-1$ //$NON-NLS-2$
      // epsg could be under identifiers or authority.
      Set<ReferenceIdentifier> identifiers = requestCRS.getIdentifiers();
      String srs = identifiers.isEmpty() ? EPSG_4326 : identifiers.iterator().next().toString();
      request.setSRS(srs); // EPSG_4326
      request.setBBox(requestBBox);
      // request.setBBox(requestBBox.getMinX() + "," + requestBBox.getMinY()+ "," +
      // requestBBox.getMaxX()+ "," + requestBBox.getMaxY());

      if (monitor.isCanceled()) return;

      setFilter(wms, request);

      // request.setProperty("DACS_ACS", null);
      BufferedImage image = readImage(wms, request, monitor);

      if (monitor.isCanceled()) return;

      if (image == null) {
        Exception e = new RuntimeException(Messages.BasicWMSRenderer2_unable_to_decode_image);
        throw wrapException(e);
      }

      // backprojectedBBox or viewportBBox
      renderGridCoverage(destination, backprojectedBBox, imageDimensions, requestBBox, image);

    } catch (Exception e) {
      if (e instanceof RenderException) throw (RenderException) e;
      throw new RenderException(e);
    } finally {
      getContext().setStatus(endLayerStatus);
      if (endLayerStatus == ILayer.DONE) {
        // clear the status message (rendering was successful)
        getContext().setStatusMessage(null);
      }
    }
  }