@SuppressWarnings({"rawtypes", "unchecked"})
  private void adjustStyles(LayerDefinition layerDefinition, Map<String, ?> layerObj) {
    Object styles = layerObj.get("styles");

    if (styles == null) {
      /* no style */
    } else if (styles instanceof Map) {
      /* one style */
      Map<String, ?> styledef = (Map<String, ?>) styles;
      String name = (String) styledef.get("name");
      if (name == null) {
        return;
      }
      String title = (String) styledef.get("title");
      String legend = (String) styledef.get("legend");
      String sld = (String) styledef.get("styledLayerDescriptor");

      Style style = new LayerDefinition.Style();
      style.setName(name);
      style.setTitle(title);
      style.setLegend(legend);
      style.setSld(sld);
      style.setStyleMap((Map<String, ?>) styledef.get("styleMap"));

      layerDefinition.getStyles().put(name, style);

    } else if (styles instanceof List) {
      /*
       * N styles
       */
      List<Map<String, ?>> stylelist = (List) styles;
      for (Map<String, ?> styledef : stylelist) {

        String name = (String) styledef.get("name");
        if (name == null) {
          name = (String) styledef.get("identifier");
        }
        String title = (String) styledef.get("title");
        String legend = (String) styledef.get("legend");
        String sld = (String) styledef.get("styledLayerDescriptor");

        Style style = new LayerDefinition.Style();
        style.setName(name);
        style.setTitle(title);
        style.setLegend(legend);
        style.setSld(sld);
        style.setStyleMap((Map<String, ?>) styledef.get("styleMap"));

        layerDefinition.getStyles().put(name, style);
      }
    }
  }
  @SuppressWarnings("unchecked")
  private void adjustData(LayerDefinition layerDefinition, Map<String, ?> layerObj) {

    Object data = layerObj.get(".data");

    if (data instanceof FeatureCollection) {
      layerDefinition.setData((FeatureCollection<SimpleFeatureType, SimpleFeature>) data);
    }
  }
  private void adjustGeom(LayerDefinition layerDefinition, Map<String, ?> layerObj)
      throws ParseException {

    String geomAsWkt = (String) layerObj.get("geom");

    if (geomAsWkt == null) {
      return;
    }

    layerDefinition.setGeom(wktReader.read(geomAsWkt));
  }
  public void adjustLayerWmsNameAndUrl(LayerDefinition layerDefinition) throws IOException {
    String layerURL = null;
    String layersParam = null;
    String type = layerDefinition.getLayerType();
    if (isMyPlacesType(layerDefinition)) {

      if (layerDefinition.getWmsurl() != null && layerDefinition.getWmsname() != null) {
        layerURL =
            ConfigValue.LAYER_URLTEMPLATE_MYPLACES.getConfigProperty(props).split("\\?")[0]
                + "?"
                + layerDefinition.getWmsurl().split("\\?")[1];
        layersParam =
            URLEncoder.encode(
                ConfigValue.LAYER_URLTEMPLATE_MYPLACES_LAYERS.getConfigProperty(props), "UTF-8");
      } else {

        String[] splitter = layerDefinition.getLayerid().split("_");
        layerURL =
            String.format(
                ConfigValue.LAYER_URLTEMPLATE_MYPLACES.getConfigProperty(props), splitter[1]);
        layersParam =
            URLEncoder.encode(
                ConfigValue.LAYER_URLTEMPLATE_MYPLACES_LAYERS.getConfigProperty(props), "UTF-8");
      }
    } else if ("wmslayer".equals(type)) {
      layerURL = layerDefinition.getWmsurl();
      layersParam = URLEncoder.encode(layerDefinition.getWmsname(), "UTF-8");
    } else if ("base".equals(type) || "groupMap".equals(type)) {
      layerURL = layerDefinition.getWmsurl();
      if (layerDefinition.getWmsname() != null) {
        layersParam = URLEncoder.encode(layerDefinition.getWmsname(), "UTF-8");
      }

    } else if ("wfslayer".equals(type)) {
      layerURL =
          String.format(
              ConfigValue.LAYER_URLTEMPLATE_WFSLAYER.getConfigProperty(props),
              layerDefinition.getLayerid());
      layersParam = URLEncoder.encode(layerDefinition.getLayerid(), "UTF-8");
    } else if ("statslayer".equals(type)) {
      layerURL =
          String.format(
              ConfigValue.LAYER_URLTEMPLATE_STATSLAYER.getConfigProperty(props),
              layerDefinition.getLayerid());
      layersParam = URLEncoder.encode(layerDefinition.getLayerid(), "UTF-8");
    } else if ("geojson".equals(type)) {

    } else if ("wmtslayer".equals(type)) {
      layerURL = layerDefinition.getWmsurl();
      layersParam = URLEncoder.encode(layerDefinition.getWmsname(), "UTF-8");
      if (layerURL != null) {
        if (layerURL.indexOf('?') != -1) {
          layerURL = layerURL.substring(0, layerURL.indexOf('?'));
        }
      }
    } else {
      throw new IOException("Unknown layertype " + type);
    }

    layerDefinition.setWmsname(layersParam);
    layerDefinition.setWmsurl(layerURL);
  }
  private void adjustTileMatrixSetInfo(LayerDefinition layerDefinition, Map<String, ?> layerObj) {

    if (layerObj == null) {
      return;
    }

    Map<String, ?> contents = (Map<String, ?>) layerObj.get("contents");
    if (contents == null) {
      return;
    }

    /* find REST url information for selected layer */
    /* tileMatrixSetData may contain other layer specs as well */

    Object rawLayers = contents.get("layers");
    if (rawLayers == null) {
      return;
    }

    Map<String, ?> wmtsLayerSpec = null;
    if (rawLayers instanceof List) {
      String layerName = layerDefinition.getWmsname();
      List<Map<String, ?>> wmtsLayers = (List<Map<String, ?>>) rawLayers;

      for (Map<String, ?> wmtsLayerListEl : wmtsLayers) {
        if (!layerName.equals(wmtsLayerListEl.get("identifier"))) {
          continue;
        }

        wmtsLayerSpec = wmtsLayerListEl;
        break;
      }

    } else {
      wmtsLayerSpec = (Map<String, ?>) rawLayers;
    }

    if (wmtsLayerSpec == null) {
      return;
    }

    /* */
    {
      Map<String, ?> resourceUrl = (Map<String, ?>) wmtsLayerSpec.get("resourceUrl");
      if (resourceUrl == null) {
        return;
      }
      Map<String, ?> resourceTileInfo = (Map<String, ?>) wmtsLayerSpec.get("tile");
      if (resourceTileInfo != null) {

        String format = (String) resourceTileInfo.get("format");
        if (format != null) {
          layerDefinition.setFormat(format);
          String template = (String) resourceTileInfo.get("template");
          if (template != null) {
            layerDefinition.setUrlTemplate(format, template);
          }
        }
      }
    }

    List<Map<String, ?>> resourceUrls = (List<Map<String, ?>>) wmtsLayerSpec.get("resourceUrls");
    if (resourceUrls == null) {
      return;
    }

    for (Map<String, ?> resourceTileInfo : resourceUrls) {
      String format = (String) resourceTileInfo.get("format");
      if (format != null) {
        if (layerDefinition.getFormat() == null) {
          layerDefinition.setFormat(format);
        }
        String template = (String) resourceTileInfo.get("template");
        if (template != null) {
          layerDefinition.setUrlTemplate(format, template);
        }
      }
    }

    /*
     * "resourceUrl": { "tile": { "format": "image/png", "template":
     * "http://karttamoottori.maanmittauslaitos.fi/maasto/wmts/1.0.0/taustakartta/default/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png"
     * , "resourceType": "tile" } }, "resourceUrls": [ { "format":
     * "image/png", "template":
     * "http://karttamoottori.maanmittauslaitos.fi/maasto/wmts/1.0.0/taustakartta/default/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png"
     * , "resourceType": "tile" } ]
     */

  }
  @SuppressWarnings({"rawtypes", "unchecked"})
  protected Map<String, LayerDefinition> parseLayersFromJSON(Map<String, ?> obj)
      throws IOException, ParseException {
    Map<String, LayerDefinition> layerDefs = new HashMap<String, LayerDefinition>();

    final Set<String> cacheExclusions = new HashSet<String>();
    final String exclusions = ConfigValue.LAYER_CACHE_EXCLUDE.getConfigProperty(props);
    if (exclusions != null) {
      String[] parts = exclusions.split(",");
      if (parts != null) {
        for (String p : parts) {
          cacheExclusions.add(p);
        }
      }
    }

    final List<Map<String, ?>> layerList = (List<Map<String, ?>>) obj.get("layers");

    for (Map<String, ?> layerObj : layerList) {

      String type = (String) layerObj.get("type");

      if (!("wfslayer".equals(type)
          || "wmslayer".equals(type)
          || "statslayer".equals(type)
          || "base".equals(type)
          || "groupMap".equals(type)
          || "myplaces".equals(type)
          || "geojson".equals(type)
          || "wmtslayer".equals(type))) {
        continue;
      }

      Object xolayerid = layerObj.get("id");
      String layerid = xolayerid.toString();
      String wmsname = (String) layerObj.get("wmsName");
      Number minScale = (Number) layerObj.get("minScale");
      Number maxScale = (Number) layerObj.get("maxScale");
      String wmsurl = (String) layerObj.get("wmsUrl");
      List<Map<String, ?>> tiles = (List<Map<String, ?>>) layerObj.get("tiles");

      LayerDefinition layerDefinition = new LayerDefinition();

      if (maxScale != null) {
        layerDefinition.setMaxScale(maxScale.doubleValue());
      }
      if (minScale != null) {
        layerDefinition.setMinScale(minScale.doubleValue());
      }
      layerDefinition.setWmsname(wmsname);
      layerDefinition.setWmsurl(fixWmsUrl(wmsurl));
      layerDefinition.setLayerid(layerid);
      layerDefinition.setLayerType(type);
      layerDefinition.setTiles(tiles);

      if (isMyPlacesType(layerDefinition)) {
        layerDefinition.setCacheable(false);
      } else if (tiles != null) {
        layerDefinition.setCacheable(false);
      } else {
        if (cacheExclusions.contains(layerid)) {
          layerDefinition.setCacheable(false);
        }
      }

      layerDefinition.setTileMatrixSetId((String) layerObj.get("tileMatrixSetId"));

      adjustLayerWmsNameAndUrl(layerDefinition);

      if (isMyPlacesType(layerDefinition)) {
        layerDefinition.setCredentials(
            ConfigValue.LAYERDEFINITION_CREDENTIALS_MYPLACES.getConfigProperty(props));
      }

      List<Map<String, ?>> subLayer = (List) layerObj.get("subLayer");
      if (subLayer != null) {
        for (Map<String, ?> subLayerObj : subLayer) {
          Object slolayerid = subLayerObj.get("id");
          String sllayerid = slolayerid.toString();
          String slwmsname = (String) subLayerObj.get("wmsName");
          Number slminScale = (Number) subLayerObj.get("minScale");
          Number slmaxScale = (Number) subLayerObj.get("maxScale");
          String slwmsurl = (String) subLayerObj.get("wmsUrl");
          String sltype = (String) subLayerObj.get("type");

          LayerDefinition subLayerDefinition = new LayerDefinition();

          if (slmaxScale != null) {
            subLayerDefinition.setMaxScale(slmaxScale.doubleValue());
          }
          if (slminScale != null) {
            subLayerDefinition.setMinScale(slminScale.doubleValue());
          }
          subLayerDefinition.setWmsname(slwmsname);
          subLayerDefinition.setWmsurl(fixWmsUrl(slwmsurl));
          subLayerDefinition.setLayerid(sllayerid);
          subLayerDefinition.setLayerType(sltype != null ? sltype : type);
          subLayerDefinition.setFormat(layerDefinition.getFormat());
          adjustLayerWmsNameAndUrl(subLayerDefinition);
          adjustStyles(subLayerDefinition, subLayerObj);
          adjustGeom(subLayerDefinition, subLayerObj);
          adjustData(subLayerDefinition, subLayerObj);
          /* format selection by default or by spec for wmts */
          if ("wmtslayer".equals(type)) {
            adjustTileMatrixSetInfo(
                subLayerDefinition, (Map<String, ?>) subLayerObj.get("tileMatrixSetData"));
          } else {
            subLayerDefinition.setFormat("image/png");
          }

          layerDefinition.getSubLayers().add(subLayerDefinition);
        }
      }

      adjustStyles(layerDefinition, layerObj);
      adjustGeom(layerDefinition, layerObj);

      adjustData(layerDefinition, layerObj);

      /* format selection by default or by spec for wmts */
      if ("wmtslayer".equals(type)) {
        adjustTileMatrixSetInfo(
            layerDefinition, (Map<String, ?>) layerObj.get("tileMatrixSetData"));
      } else {
        layerDefinition.setFormat("image/png");
      }

      layerDefs.put(layerDefinition.getLayerid(), layerDefinition);
    }

    return layerDefs;
  }
 public boolean isMyPlacesType(LayerDefinition layerDefinition) {
   return layerDefinition.getLayerType() != null
           && "myplaces".equals(layerDefinition.getLayerType())
       || layerDefinition.getLayerid().indexOf("myplaces") != -1;
 }