/**
   * The write class selects the encoding parameter considering the image format requested. Then,
   * the correct writer will encode the img given by the render into the servlet output stream
   *
   * @param wmsResponse The object used later to build the HTTP response.
   * @param output The output stream
   * @param format desired image format
   * @param img The output image.
   * @param pixelSize be provided by the server
   * @throws IOException If a problem has been encountered while handling the output stream.
   */
  public static void write(
      WMSResponse wmsResponse,
      OutputStream output,
      String format,
      BufferedImage img,
      double pixelSize)
      throws IOException {

    if (format.equalsIgnoreCase(ImageFormats.JPEG.toString())) {
      writeJPEG(wmsResponse, output, img);
      wmsResponse.setResponseCode(200);
      LOGGER.debug("JPEG written to the output stream.");
    } else if (format.equalsIgnoreCase(ImageFormats.PNG.toString())) {
      writePNG(wmsResponse, output, img, pixelSize);
      wmsResponse.setResponseCode(200);
      LOGGER.debug("PNG written to the output stream.");
    } else if (format.equalsIgnoreCase(ImageFormats.TIFF.toString())) {
      writeTIFF(wmsResponse, output, img, pixelSize);
      LOGGER.debug("TIFF written to the output stream.");
      wmsResponse.setResponseCode(200);
    } else {
      WMS.exceptionDescription(
          wmsResponse,
          output,
          "The format requested is invalid. "
              + "Please check the server capabilities to ask for a supported format.");
    }
  }
  /**
   * Handles the getCapabilities request and gives the XML formated server capabilities to the
   * outputStream
   *
   * @param output servlet outputStream
   * @param wmsResponse HttpServletResponse modified for WMS use
   * @throws WMSException
   * @throws UnsupportedEncodingException
   */
  public void getCap(OutputStream output, WMSResponse wmsResponse)
      throws WMSException, UnsupportedEncodingException {
    PrintStream pr = new PrintStream(output, false, "UTF-8");
    WMSCapabilities cap = new WMSCapabilities();
    // Setting service WMS metadata
    cap.setService(getService());
    // Setting Capability parameters
    // Setting Layers capabilities
    Capability c = new Capability();
    // Bounding box of the highest layer is dummy
    Envelope dummy = new Envelope(WEST, EAST, SOUTH, NORTH);
    EXGeographicBoundingBox bb = getGeographicBoundingBox(dummy, "EPSG:4326");
    Layer availableLayers = new Layer();
    availableLayers.setEXGeographicBoundingBox(bb);
    BoundingBox bBox = new BoundingBox();
    bBox.setCRS("EPSG:4326");
    bBox.setMaxx(EAST);
    bBox.setMinx(WEST);
    bBox.setMaxy(NORTH);
    bBox.setMiny(SOUTH);
    availableLayers.getBoundingBox().add(bBox);
    for (Layer e : layerMap.values()) {
      availableLayers.getLayer().add(e);
    }
    // Server supported CRS
    availableLayers.getCRS().addAll(authCRS);
    availableLayers.setName("Available_layers");
    availableLayers.setTitle("Server available layers");
    c.setLayer(availableLayers);
    // Setting the request capabilities
    // GetMap capabilities
    Request req = new Request();
    req.setGetMap(getMapOperation(wmsResponse));
    // GetCap capabilities
    req.setGetCapabilities(getCapOperation(wmsResponse));
    // GetFeatureInfo capabilities
    req.setGetFeatureInfo(getFeatureOperation(wmsResponse));
    c.setRequest(req);
    cap.setCapability(c);

    try {
      // Marshalling the WMS Capabilities into an XML response
      Marshaller marshaller = jaxbContext.createMarshaller();
      NamespacePrefixMapper mapper = new NamespaceMapper();
      marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper);

      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

      wmsResponse.setContentType("text/xml;charset=UTF-8");
      marshaller.marshal(cap, pr);

    } catch (JAXBException ex) {
      wmsResponse.setContentType("text/xml;charset=UTF-8");
      wmsResponse.setResponseCode(500);
      pr.append(
          "<?xml version='1.0' encoding=\"UTF-8\"?><ServiceExceptionReport xmlns=\"http://www.opengis.net/ogc\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.3.0\" xsi:schemaLocation=\"http://www.opengis.net/ogc http://schemas.opengis.net/wms/1.3.0/exceptions_1_3_0.xsd\"><ServiceException>Something went wrong</ServiceException></ServiceExceptionReport>");
      pr.append(ex.toString());
      ex.printStackTrace(pr);
    }
  }
  /**
   * This method permits to write the result image from the wms request in a jpeg format
   *
   * @param wmsResponse The object used later to build the HTTP response.
   * @param output The output stream
   * @param img The output image
   * @throws IOException
   */
  private static void writeJPEG(WMSResponse wmsResponse, OutputStream output, BufferedImage img)
      throws IOException {
    wmsResponse.setContentType(ImageFormats.JPEG.toString());

    JPEGEncodeParam jEnc = new JPEGEncodeParam();
    JAI.create("Encode", img, output, "JPEG", jEnc);

    output.close();
  }
 private OnlineResource buildOnlineResource(WMSResponse wmsResponse, String key, String title) {
   OnlineResource oRGet = new OnlineResource();
   String map = (String) properties.getProperty(key);
   if (map == null) {
     oRGet.setHref(wmsResponse.getRequestUrl());
   } else {
     oRGet.setHref(map);
   }
   oRGet.setTitle(title);
   return oRGet;
 }
  /**
   * This method permits to write the result image from the wms request in a png format
   *
   * @param wmsResponse The object used later to build the HTTP response.
   * @param output The output stream
   * @param img The output image
   * @param pixelSize The size of the pixels.
   * @throws IOException
   */
  private static void writePNG(
      WMSResponse wmsResponse, OutputStream output, BufferedImage img, double pixelSize)
      throws IOException {
    wmsResponse.setContentType(ImageFormats.PNG.toString());

    int dpm = (int) (1000 / pixelSize + 1);
    PNGEncodeParam pEnc = PNGEncodeParam.getDefaultEncodeParam(img);
    pEnc.setPhysicalDimension(dpm, dpm, 1);
    JAI.create("Encode", img, output, "PNG", pEnc);

    output.close();
  }
  /**
   * This method permits to write the result image from the wms request in a tiff format
   *
   * @param wmsResponse The object used later to build the HTTP response.
   * @param output The output stream
   * @param img The output image
   * @throws IOException
   */
  private static void writeTIFF(
      WMSResponse wmsResponse, OutputStream output, BufferedImage img, double pixelSize)
      throws IOException {
    wmsResponse.setContentType(ImageFormats.TIFF.toString());
    int dpm = (int) (1000 / pixelSize + 1);
    long[] resolution = {dpm, 1};

    TIFFField xRes =
        new TIFFField(X_RES_TAG, TIFFField.TIFF_RATIONAL, 1, new long[][] {resolution});
    TIFFField yRes =
        new TIFFField(Y_RES_TAG, TIFFField.TIFF_RATIONAL, 1, new long[][] {resolution});
    TIFFEncodeParam tep = new TIFFEncodeParam();
    tep.setExtraFields(new TIFFField[] {xRes, yRes});
    JAI.create("Encode", img, output, "TIFF", tep);
    output.close();
  }