/**
  * Creates a class representation of the whole document.
  *
  * @return class representation of the configuration document
  */
 public CatalogueConfiguration getConfiguration() throws InvalidConfigurationException {
   CatalogueConfiguration configuration = null;
   try {
     FilterCapabilities filterCapabilities = null;
     Element filterCapabilitiesElement =
         (Element) XMLTools.getNode(getRootElement(), "ogc:Filter_Capabilities", nsContext);
     if (filterCapabilitiesElement != null) {
       filterCapabilities =
           new FilterCapabilities100Fragment(filterCapabilitiesElement, getSystemId())
               .parseFilterCapabilities();
     }
     configuration =
         new CatalogueConfiguration(
             parseVersion(),
             parseUpdateSequence(),
             getServiceIdentification(),
             getServiceProvider(),
             getOperationsMetadata(),
             null,
             filterCapabilities,
             getDeegreeParams(),
             getSystemId());
   } catch (XMLParsingException e) {
     e.printStackTrace();
     throw new InvalidConfigurationException(
         "Class representation of the catalog configuration "
             + "document could not be generated: "
             + e.getMessage(),
         e);
   }
   return configuration;
 }
  /**
   * returns the service section of the configuration/capabilities. vendorspecific capabilities are
   * not supported yet
   *
   * @param namespaceURI
   * @return the service section of the configuration/capabilities. vendorspecific capabilities are
   *     not supported yet
   * @throws InvalidCapabilitiesException
   */
  public Capability getCapabilitySection(URI namespaceURI) throws InvalidCapabilitiesException {
    try {
      Node root = this.getRootElement();

      Element element = XMLTools.getRequiredChildElement("Capability", namespaceURI, root);
      Element elem = XMLTools.getRequiredChildElement("Request", namespaceURI, element);
      OperationsMetadata request = parseOperations(elem, namespaceURI);

      elem = XMLTools.getRequiredChildElement("Exception", namespaceURI, element);
      ExceptionFormat eFormat = getExceptionFormat(elem, namespaceURI);

      // vendorspecific capabilities are not supported yet
      // elem = XMLTools.getRequiredChildByName(
      // "VendorSpecificCapabilities", WCSNS, element);

      String version = element.getAttribute("version");
      if (version == null || version.equals("")) {
        version = this.parseVersion();
      }
      String updateSequence = element.getAttribute("updateSequence");
      if (updateSequence == null || updateSequence.equals("")) {
        updateSequence = this.getRootElement().getAttribute("updateSequence");
      }

      return new Capability(version, updateSequence, request, eFormat, null);

    } catch (XMLParsingException e) {
      String s = e.getMessage();
      throw new InvalidCapabilitiesException(
          "Error while parsing the Capability "
              + "Section of the capabilities\n"
              + s
              + StringTools.stackTraceToString(e));
    }
  }
  /**
   * @param provider
   * @param properties
   */
  public GMLFileResource(GMLCRSProvider provider, Properties properties) {
    super(provider, properties, "Dictionary", CommonNamespaces.GML3_2_NS.toASCIIString());
    try {
      transformations = XMLTools.getElements(getRootElement(), TRANSFORM_XPATH, nsContext);

    } catch (XMLParsingException e) {
      LOG.logError(e.getLocalizedMessage(), e);
    }
    cachedWGS84Transformations = new HashMap<CoordinateSystem, Helmert>();
  }
  /*
   * (non-Javadoc)
   *
   * @see org.deegree.crs.configuration.gml.GMLResource#getAvailableCRSIds()
   */
  public List<String[]> getSortedAvailableCRSIds() {
    List<Element> crsIDs = new LinkedList<Element>();
    try {
      crsIDs.addAll(XMLTools.getElements(getRootElement(), ID_XPATH, nsContext));
    } catch (XMLParsingException e) {
      throw new CRSConfigurationException(
          Messages.getMessage("CRS_CONFIG_GET_ALL_ELEMENT_IDS", e.getMessage()), e);
    }

    List<String[]> result = new ArrayList<String[]>();
    for (Element crs : crsIDs) {
      if (crs != null) {
        result.add(new String[] {XMLTools.getStringValue(crs)});
      }
    }
    return result;
  }
  /**
   * Output format parameter is ignored by this method (it will always be GML3 anyway).
   *
   * @param id
   * @param root
   * @return a new request
   * @throws OGCWebServiceException
   */
  public static OGCWebServiceRequest create(String id, Element root) throws OGCWebServiceException {
    try {
      String objectId = getRequiredNodeAsString(root, "ogc:GmlObjectId/@gml:id", nsContext);
      String version = root.getAttribute("version");

      String depth = root.getAttribute("traverseXlinkDepth");
      if (depth == null || depth.length() == 0) {
        throw new MissingParameterValueException(
            "traversexlinkdepth", get("WFS_MISSING_PARAMETER_VALUE", "TRAVERSEXLINKDEPTH"));
      }
      int idepth;
      try {
        idepth = parseInt(depth);
      } catch (NumberFormatException nfe) {
        throw new InvalidParameterValueException(
            "traversexlinkdepth", get("WFS_INVALID_PARAMETER_VALUE", "TRAVERSEXLINKDEPTH", depth));
      }

      String expiry = root.getAttribute("traverseXlinkExpiry");
      int iexpiry = -1;
      if (expiry != null && expiry.length() > 0) {
        try {
          iexpiry = parseInt(expiry);
        } catch (NumberFormatException nfe) {
          throw new InvalidParameterValueException(
              "traversexlinkexpiry",
              get("WFS_INVALID_PARAMETER_VALUE", "TRAVERSEXLINKEXPIRY", expiry));
        }
      }

      return new GetGmlObject(idepth, iexpiry, objectId, version, id, null, null);
    } catch (XMLParsingException e) {
      LOG.logDebug("Stack trace: ", e);
      throw new OGCWebServiceException(
          "getgmlobject", get("WFS_REQUEST_NOT_PARSED", e.getMessage()));
    }
  }
  /**
   * Creates a class representation of the document.
   *
   * @return OGCCapabilities class representation of the configuration document
   * @throws InvalidCapabilitiesException
   */
  @Override
  public OGCCapabilities parseCapabilities() throws InvalidCapabilitiesException {
    LOG.entering();

    LOG.logDebug("Parsing Capabilties Request.");
    ServiceIdentification serviceIdentification = null;
    ServiceProvider serviceProvider = null;
    UserDefinedSymbolization uds = null;
    OperationsMetadata metadata = null;
    Layer layer = null;
    String version = parseVersion();
    try {
      serviceIdentification = parseServiceIdentification();
      serviceProvider = parseServiceProvider();
      LOG.logDebug(
          "Retrieved serviceIdentification and serviceProvider information " + "from the request.");
      metadata = parseOperationsMetadata();
      LOG.logDebug("Retrieved metadData information from the request.");
      uds = parseUserDefinedSymbolization();
      Element layerElem =
          (Element) XMLTools.getRequiredNode(getRootElement(), "./Capability/Layer", nsContext);
      LOG.logDebug("Layer Element retrieved.");
      layer = parseLayers(layerElem, null);
    } catch (XMLParsingException e) {
      String msg =
          "Error parsing the capabilities request to retrieve 'serviceIdentification',"
              + " 'serviceProvider', 'metaData' and 'layer' "
              + e.getMessage();
      throw new InvalidCapabilitiesException(msg);
    } catch (UnknownCRSException e) {
      throw new InvalidCapabilitiesException(getClass().getName(), e.getMessage());
    }
    WMPSCapabilities wmpsCapabilities =
        new WMPSCapabilities(version, serviceIdentification, serviceProvider, uds, metadata, layer);
    LOG.exiting();
    return wmpsCapabilities;
  }
  public Transformation getTransformation(CoordinateSystem sourceCRS, CoordinateSystem targetCRS) {
    if (sourceCRS == null) {
      return null;
    }
    List<Element> toBeRemoved = new ArrayList<Element>(transformations.size());
    List<String> sourceIDs = Arrays.asList(sourceCRS.getIdentifiers());
    List<String> targetIDs = null;
    if (targetCRS != null) {
      targetIDs = Arrays.asList(targetCRS.getIdentifiers());
    } else {
      targetIDs = new ArrayList<String>();
    }
    Transformation result = null;
    for (int i = 0; i < transformations.size() && result == null; ++i) {
      Element transElem = transformations.get(i);
      if (transElem != null) {
        try {
          Element sourceCRSProp =
              XMLTools.getRequiredElement(transElem, PRE + "sourceCRS", nsContext);
          String transformSourceID = null;
          String transformTargetID = null;
          if (sourceCRSProp != null) {
            transformSourceID =
                sourceCRSProp.getAttributeNS(CommonNamespaces.XLNNS.toASCIIString(), "href");
            if ("".equals(transformSourceID)) {
              transformSourceID =
                  XMLTools.getRequiredNodeAsString(
                      sourceCRSProp, "*[1]/" + PRE + "identifier", nsContext);
            }
          }
          if (targetCRS != null) {
            Element targetCRSProp =
                XMLTools.getRequiredElement(transElem, PRE + "targetCRS", nsContext);
            if (targetCRSProp != null) {

              transformTargetID =
                  targetCRSProp.getAttributeNS(CommonNamespaces.XLNNS.toASCIIString(), "href");
              if ("".equals(transformTargetID)) {
                transformTargetID =
                    XMLTools.getRequiredNodeAsString(
                        targetCRSProp, "*[1]/" + PRE + "identifier", nsContext);
              }
            }
          }

          if (sourceIDs.contains(transformSourceID)) {
            result = getProvider().parseTransformation(transElem);
            if (targetCRS == null) {
              // Trying to find a helmert transformation
              LOG.logDebug("Resolving a possible transformation.");
              if (result != null && !(result instanceof Helmert)) {
                result = getTransformation(result.getTargetCRS(), null);
              }
            } else {
              if (!targetIDs.contains(transformTargetID)) {
                LOG.logDebug(
                    "Found a transformation with gml:id: "
                        + transElem.getAttributeNS(CommonNamespaces.GML3_2_NS.toASCIIString(), "id")
                        + ", but the target does not match the source crs, trying to build transformation chain.");
                Transformation second = getTransformation(result.getTargetCRS(), targetCRS);
                if (second != null) {
                  result = new ConcatenatedTransform(result, second);
                } else {
                  LOG.logDebug(
                      "The transformation with gml:id: "
                          + transElem.getAttributeNS(
                              CommonNamespaces.GML3_2_NS.toASCIIString(), "id")
                          + " is not the start of transformation chain, discarding it. ");
                  result = null;
                }
              }
            }
          }

        } catch (XMLParsingException e) {
          toBeRemoved.add(transElem);
          LOG.logWarning(
              "No source CRS id could be found in this transformation(gml:id): "
                  + transElem.getAttributeNS(CommonNamespaces.GML3_2_NS.toASCIIString(), "id")
                  + " this is not correct, removing transformation from cache.");
          LOG.logWarning(e.getMessage());
        }
      }
      if (toBeRemoved.size() > 0) {
        transformations.removeAll(toBeRemoved);
      }
    }
    return result;
  }
  /**
   * Creates a class representation of the <code>deegreeParams</code>- section.
   *
   * @return
   * @throws InvalidConfigurationException
   */
  public CatalogueDeegreeParams getDeegreeParams() throws InvalidConfigurationException {

    CatalogueDeegreeParams deegreeParams = null;

    try {
      Node root = this.getRootElement();
      Element element = XMLTools.getRequiredChildElement("deegreeParams", DEEGREECSW, root);

      // 'deegreecsw:DefaultOnlineResource'-element (mandatory)
      OnlineResource defaultOnlineResource =
          parseOnLineResource(
              XMLTools.getRequiredChildElement("DefaultOnlineResource", DEEGREECSW, element));

      // 'deegreecsw:CacheSize'-element (optional, default: 100)
      int cacheSize = XMLTools.getNodeAsInt(element, "./deegreecsw:CacheSize", nsContext, 100);

      // 'deegreecsw:RequestTimeLimit'-element (optional, default: 2)
      int requestTimeLimit =
          XMLTools.getNodeAsInt(element, "./deegreecsw:RequestTimeLimit", nsContext, 2);

      // 'deegreecsw:Encoding'-element (optional, default: UTF-8)
      String characterSet = XMLTools.getStringValue("Encoding", DEEGREECSW, element, "UTF-8");

      // default output schema used by a catalogue
      String defaultOutputSchema =
          XMLTools.getStringValue("DefaultOutputSchema", DEEGREECSW, element, "OGCCORE");

      // 'deegreecsw:WFSResource'-element (mandatory)
      SimpleLink wfsResource =
          parseSimpleLink(XMLTools.getRequiredChildElement("WFSResource", DEEGREECSW, element));

      // 'deegreecsw:CatalogAddresses'-element (optional)
      Element catalogAddressesElement =
          XMLTools.getChildElement("CatalogAddresses", DEEGREECSW, element);
      OnlineResource[] catalogAddresses = new OnlineResource[0];
      if (catalogAddressesElement != null) {
        // 'deegreecsw:CatalogAddresses'-element (optional)
        ElementList el =
            XMLTools.getChildElements("CatalogAddress", DEEGREECSW, catalogAddressesElement);
        catalogAddresses = new OnlineResource[el.getLength()];
        for (int i = 0; i < catalogAddresses.length; i++) {
          catalogAddresses[i] = parseOnLineResource(el.item(i));
        }
      }

      OnlineResource transInXslt = null;
      Element elem = (Element) XMLTools.getNode(element, "deegreecsw:TransactionInputXSLT", nsc);
      if (elem != null) {
        transInXslt = parseOnLineResource(elem);
      }
      OnlineResource transOutXslt = null;
      elem = (Element) XMLTools.getNode(element, "deegreecsw:TransactionOutputXSLT", nsc);
      if (elem != null) {
        transOutXslt = parseOnLineResource(elem);
      }
      if ((transInXslt != null && transOutXslt == null)
          || (transInXslt == null && transOutXslt != null)) {
        throw new InvalidConfigurationException(
            "if CSW-deegreeParam "
                + "'TransactionInputXSLT' is defined 'TransactionOutputXSLT' must "
                + "be defined too and vice versa!");
      }

      // 'deegreecsw:HarvestRepository'-element (optional)
      Element harvestRepositoryElement =
          XMLTools.getChildElement("HarvestRepository", DEEGREECSW, element);
      JDBCConnection harvestRepository = null;
      if (harvestRepositoryElement != null) {
        // 'deegreecsw:Connection'-element (optional)
        Element connectionElement =
            XMLTools.getChildElement("Connection", DEEGREECSW, harvestRepositoryElement);
        if (connectionElement != null) {
          harvestRepository =
              new JDBCConnection(
                  XMLTools.getRequiredStringValue("Driver", DEEGREECSW, connectionElement),
                  XMLTools.getRequiredStringValue("Logon", DEEGREECSW, connectionElement),
                  XMLTools.getRequiredStringValue("User", DEEGREECSW, connectionElement),
                  XMLTools.getRequiredStringValue("Password", DEEGREECSW, connectionElement),
                  null,
                  null,
                  null);
        }
      }
      deegreeParams =
          new CatalogueDeegreeParams(
              defaultOnlineResource,
              cacheSize,
              requestTimeLimit,
              characterSet,
              wfsResource,
              catalogAddresses,
              harvestRepository,
              defaultOutputSchema,
              transInXslt,
              transOutXslt);
    } catch (XMLParsingException e) {
      throw new InvalidConfigurationException(
          "Error parsing the deegreeParams "
              + "section of the CSW configuration: \n"
              + e.getMessage()
              + StringTools.stackTraceToString(e));
    }
    return deegreeParams;
  }