/**
   * Get the four coordinates that represent the bounding box which includes all the layers
   * indicated for a WMTS Server
   *
   * @param urlServer Url of the WMTS server to connect and get the data
   * @param crs CRS of the bounding box
   * @param layers List of layers to include in the bounding box calculated
   * @return A list of coordinates that represents the bounding box calculated (minX, minY, maxX,
   *     maxY). null if haven't valid bounding box
   */
  private List<String> getWMTSLayersBoundingBox(String urlServer, String crs, String layerId) {
    List<String> boundingBox = new ArrayList<String>();
    WMTSBoundingBox bBox = null;
    String[] crsSplit = crs.split(":");
    String regExpCrs =
        "(.*)(:?)"
            .concat(crsSplit[0])
            .concat("((:)(.*)(:)")
            .concat(crsSplit[1])
            .concat("|(:)")
            .concat(crsSplit[1])
            .concat(")");
    try {
      // get WMTS manager
      WMTSOGCManager wmtsMan = WMTSOGCLocator.getManager();
      WMTSClient wmtsClient = wmtsMan.createWMTSClient(urlServer);
      wmtsClient.connect(true, null);
      if (StringUtils.isNotEmpty(layerId)) {
        WMTSLayer layer = getLayerWMTSById(wmtsClient, layerId);
        if (layer != null) {
          // TODO
          // Need a list of bounding box of the layer
          // to calculate which is the most appropiate
          // WMTSBoundingBox bBox = layer.getBBox();
          List<WMTSTileMatrixSetLink> tileMatrixSetLink = layer.getTileMatrixSetLink();
          Iterator<WMTSTileMatrixSetLink> itTileMatrix = tileMatrixSetLink.iterator();
          while (itTileMatrix.hasNext()) {
            WMTSTileMatrixSetLink wmtsTileMatrixSetLink = itTileMatrix.next();
            WMTSTileMatrixSet tileMatrixSet = wmtsTileMatrixSetLink.getTileMatrixSet();
            String supportedCRS = tileMatrixSet.getSupportedCRS();
            if (supportedCRS.equals(crs) || supportedCRS.matches(regExpCrs)) {
              bBox = tileMatrixSet.getBoundingBox();
              break;
            }
          }
          if (bBox != null) {
            double[] lowerCorner = bBox.getLowerCorner();
            double[] upperCorner = bBox.getUpperCorner();

            boundingBox.add(String.valueOf(lowerCorner[0]));
            boundingBox.add(String.valueOf(lowerCorner[1]));
            boundingBox.add(String.valueOf(upperCorner[0]));
            boundingBox.add(String.valueOf(upperCorner[1]));
          }
        }
      }
    } catch (Exception exc) {
      logger.error("Exception on getWMTSLayersBoundingBox", exc);
      throw new ServerGeoException();
    }
    return boundingBox;
  }
  /*
   * (non-Javadoc)
   * @see es.gva.dgti.gvgeoportal.service.ogc.OGCInfoService
   * #getCapabilitiesFromWMTS(String, String, boolean)
   */
  public WMTSInfo getCapabilitiesFromWMTS(
      String urlServerWMTS, TreeSet<String> listCrs, boolean useCrsSelected)
      throws ServerGeoException {

    TreeSet<String> formatsSupported = new TreeSet<String>();
    TreeSet<String> crsSupported = new TreeSet<String>();
    boolean isFormatsSupported = false;

    WMTSInfo wmtsInfo = new WMTSInfo();
    // put url on object WMSInfo
    wmtsInfo.setServiceUrl(urlServerWMTS);

    // Create hashmap to add the layers getted to the WMTSInfo object
    Map<String, org.gvsig.framework.web.ogc.WMTSLayer> layersMap =
        new HashMap<String, org.gvsig.framework.web.ogc.WMTSLayer>();

    // get WMTS manager
    WMTSOGCManager wmtsMan = WMTSOGCLocator.getManager();

    try {
      WMTSClient wmtsClient = wmtsMan.createWMTSClient(urlServerWMTS);
      wmtsClient.connect(true, null);

      WMTSServiceIdentification wmtsServIden = wmtsClient.getServiceIdentification();

      // set server info
      wmtsInfo.setServiceAbstract(wmtsServIden.getAbstract());
      wmtsInfo.setServiceTitle(wmtsServIden.getTitle());
      wmtsInfo.setVersion(wmtsServIden.getServiceTypeVersion());
      wmtsInfo.setServiceType(wmtsServIden.getServiceType());

      // set id of the request wmst (service title + calendar)
      int hashCode = (wmtsServIden.getTitle() + Calendar.getInstance()).hashCode();
      wmtsInfo.setId(hashCode);

      // set tile matrix and check if has support to crs of the map
      List<String> patternList = new ArrayList<String>();
      if (!listCrs.isEmpty()) {
        for (String crs : listCrs) {
          String[] crsSplit = crs.split(":");
          String pattern =
              "(.*)(:?)"
                  .concat(crsSplit[0])
                  .concat("((:)(.*)(:)")
                  .concat(crsSplit[1])
                  .concat("|(:)")
                  .concat(crsSplit[1])
                  .concat(")");
          patternList.add(pattern);
        }
      }

      // hashmap with: identifier of tile matrix, supported crs
      Map<String, String> tileMatrixCrsSupported = new HashMap<String, String>();
      TreeSet<String> tileMatrixSelectedId = new TreeSet<String>();
      List<WMTSTileMatrixSet> tileMatrixSet = wmtsClient.getTileMatrixSet();
      for (int i = 0; i < tileMatrixSet.size(); i++) {
        WMTSTileMatrixSet tileMatrix = tileMatrixSet.get(i);
        String identifier = tileMatrix.getIdentifier();
        String supportedCRS = tileMatrix.getSupportedCRS();
        crsSupported.add(supportedCRS);
        // add to map the tile matrix with its crs supported
        tileMatrixCrsSupported.put(identifier, supportedCRS);
        if (!listCrs.isEmpty()) {
          if (listCrs.contains(supportedCRS)) {
            tileMatrixSelectedId.add(identifier);
          } else {
            // check supportedCrs with the expReg generated by the
            // list of crs passed
            for (String expReg : patternList) {
              if (supportedCRS.matches(expReg)) {
                tileMatrixSelectedId.add(identifier);
              }
            }
          }
        }
      }
      // Add map of tile matrix and the tile matrix selected to WMTSInfo
      // object
      wmtsInfo.setTileMatrixCrsSupported(tileMatrixCrsSupported);
      wmtsInfo.setTileMatrixSelectedId(tileMatrixSelectedId);

      // Only set layers if has a tile matrix with crs of the map
      // supported
      // or crs is null
      WMTSThemes layerListAsThemes = wmtsClient.getLayerListAsThemes();
      // Create tree with layer values
      List<TreeNode> tree = new ArrayList<TreeNode>();

      // Create children layers
      for (int i = 0; i < layerListAsThemes.getChildCount(); i++) {
        WMTSTheme wmtsTheme = layerListAsThemes.getChildren(i);
        WMTSLayer layer = wmtsTheme.getLayer();
        TreeSet<String> wmtsLinkSelected = new TreeSet<String>();
        TreeSet<String> wmtsLinkSupported = new TreeSet<String>();
        // check crs
        List<WMTSTileMatrixSetLink> tileMatrixSetLink = layer.getTileMatrixSetLink();
        for (int j = 0; j < tileMatrixSetLink.size(); j++) {
          WMTSTileMatrixSetLink wmtsLink = tileMatrixSetLink.get(j);
          wmtsLinkSupported.add(wmtsLink.getTileMatrixSetId());
          if (!tileMatrixSelectedId.isEmpty()
              && tileMatrixSelectedId.contains(wmtsLink.getTileMatrixSetId())) {
            wmtsLinkSelected.add(wmtsLink.getTileMatrixSetId());
          }
        }
        // check format
        TreeSet<String> setFormats = new TreeSet<String>();
        setFormats.addAll(layer.getFormat());
        String format = getFirstFormatSupported(setFormats);
        formatsSupported.addAll(setFormats);
        if ((!wmtsLinkSelected.isEmpty() || listCrs.isEmpty()) && format != null) {
          isFormatsSupported = true;
          TreeNode node = new TreeNode(layer.getIdentifier());
          node.setTitle(layer.getTitle());
          node.setFolder(false);
          tree.add(node);

          // Add layer to layer map
          org.gvsig.framework.web.ogc.WMTSLayer wmtsLayer =
              new org.gvsig.framework.web.ogc.WMTSLayer();
          TreeSet<String> crsSet = new TreeSet<String>();
          crsSet.addAll(layer.getSrsList());
          wmtsLayer.setCrs(crsSet);
          wmtsLayer.setName(layer.getIdentifier());
          wmtsLayer.setTitle(layer.getTitle());
          wmtsLayer.setFormatSelected(format);
          wmtsLayer.setFormatsSupported(setFormats);
          if (listCrs.isEmpty()) {
            wmtsLayer.setTileMatrixSelected(wmtsLinkSupported);
          } else {
            wmtsLayer.setTileMatrixSelected(wmtsLinkSelected);
          }
          layersMap.put(layer.getIdentifier(), wmtsLayer);
        }
      }
      wmtsInfo.setFormatsSupported(formatsSupported);
      wmtsInfo.setLayersTree(tree);
      wmtsInfo.setLayers(layersMap);
      wmtsInfo.setIsFormatsSupported(isFormatsSupported);
      wmtsInfo.setCrsSupported(crsSupported);
    } catch (Exception exc) {
      logger.error("Exception on getCapabilitiesFromWMS", exc);
      throw new ServerGeoException();
    }

    return wmtsInfo;
  }