/**
   * Tries to extract a node connector from the node <code>node</code>, throwing an exception if
   * something goes wrong.
   *
   * @param node The node. Not <code>null</code>.
   * @return A connector. Never <code>null</code>.
   * @throws NullPointerException If <code>node==null</code>.
   * @throws XMLExtractorException If something goes wrong while extracting.
   */
  public static Connector<DefaultConstraintAutomaton> tryExtractFrom(final XMLNode node)
      throws XMLExtractorException {

    if (node == null) throw new NullPointerException();

    try {
      if (!node.hasType())
        throw new XMLExtractorException("Every node should have a supported type.");

      return library.newNode(
          node.getName(), node.countSinkEnds(), node.countSourceEnds(), node.getType());
    } catch (final Exception e) {
      throw new XMLExtractorException(
          "I failed to extract a connector from the node named \"" + node.getName() + "\".", e);
    }
  }
  /**
   * Tries to extract a composition of nodes and primitives from the connector <code>connector
   * </code>, throwing an exception if something goes wrong.
   *
   * @param connector The connector. Not <code>null</code>.
   * @return A composition. Never <code>null</code>.
   * @throws NullPointerException If <code>connector==null</code>.
   * @throws XMLExtractorException If something goes wrong while extracting.
   */
  public static Composition<Connector<DefaultConstraintAutomaton>, DefaultConstraintAutomaton>
      tryExtractFrom(final XMLConnector connector) throws XMLExtractorException {

    if (connector == null) throw new NullPointerException();

    try {
      /* Extract node connectors. */
      if (!connector.hasNodes())
        throw new XMLExtractorException("Every connector should consist of at least one node.");

      final Set<String> nodeNames = new HashSet<String>();
      for (final XMLNode n : connector.getNodes()) nodeNames.add(n.getName());

      final List<Connector<DefaultConstraintAutomaton>> nodeConnectors =
          new ArrayList<Connector<DefaultConstraintAutomaton>>();
      for (final XMLNode n : connector.getNodes()) nodeConnectors.add(tryExtractFrom(n));

      /* Extract primitive connectors. */
      if (!connector.hasPrimitives())
        throw new XMLExtractorException(
            "Every connector should consist of at least one primitive.");

      final List<Connector<DefaultConstraintAutomaton>> primitiveConnectors =
          new ArrayList<Connector<DefaultConstraintAutomaton>>();
      for (final XMLPrimitive p : connector.getPrimitives())
        primitiveConnectors.add(tryExtractFrom(p));

      /* Match node connectors with primitive connectors. */
      final Map<String, Iterator<Vertex>> nodeNamesToInputVertices =
          new HashMap<String, Iterator<Vertex>>();
      final Map<String, Iterator<Vertex>> nodeNamesToOutputVertices =
          new HashMap<String, Iterator<Vertex>>();

      for (final Connector<DefaultConstraintAutomaton> c : nodeConnectors) {
        final String nodeName = c.getName();

        nodeNamesToInputVertices.put(nodeName, c.getInputVertices().iterator());

        nodeNamesToOutputVertices.put(nodeName, c.getOutputVertices().iterator());
      }

      for (final Connector<DefaultConstraintAutomaton> c : primitiveConnectors)
        for (final Vertex v : c.getVertices())
          if (v.isInputVertex() || v.isOutputVertex()) {
            final String nodeName = v.getName();
            final Iterator<Vertex> iterator =
                v.isInputVertex()
                    ? nodeNamesToOutputVertices.get(nodeName)
                    : nodeNamesToInputVertices.get(nodeName);

            String newVertexName = null;
            while (iterator.hasNext()
                && nodeNames.contains(newVertexName = iterator.next().getName())) ;

            if (newVertexName == null || nodeNames.contains(newVertexName))
              throw new XMLExtractorException(
                  "The node named \"" + nodeName + "\" has too few ends.");

            c.getBehavior().renameVertex(v.getName(), newVertexName);
            // v.rename(newVertexName);
          }

      /* Validate matching. */
      // final List<Entry<String, Iterator<Vertex>>> nodeNamesToVertices =
      // new ArrayList<Map.Entry<String, Iterator<Vertex>>>();
      // nodeNamesToVertices.addAll(nodeNamesToInputVertices.entrySet());
      // nodeNamesToVertices.addAll(nodeNamesToOutputVertices.entrySet());
      //
      // for (final Entry<String, Iterator<Vertex>> e :
      // nodeNamesToVertices)
      // if (e.getValue().hasNext())
      // throw new XMLExtractorException("The node named \""
      // + e.getKey() + "\" has too many ends.");

      /* Return. */
      final List<Connector<DefaultConstraintAutomaton>> connectors =
          new ArrayList<Connector<DefaultConstraintAutomaton>>();
      connectors.addAll(nodeConnectors);
      connectors.addAll(primitiveConnectors);

      final Composition<Connector<DefaultConstraintAutomaton>, DefaultConstraintAutomaton>
          composition =
              new Composition<Connector<DefaultConstraintAutomaton>, DefaultConstraintAutomaton>(
                  connector.getName());

      for (final Connector<DefaultConstraintAutomaton> c : connectors) composition.addConnector(c);

      return composition;
    } catch (final Exception e) {
      throw new XMLExtractorException(
          "I failed to extract a composition from the connector named \""
              + connector.getName()
              + "\".",
          e);
    }
  }