/**
   * Builds a suffix net based on the given root node and writes it into a Neo4j-database (via given
   * client).
   *
   * @param token Token of strings (will be nodes within the resulting net)
   * @param rootnode Node/URI to start from
   * @param graph Neo4J-REST-client
   * @param createdNodes Map used to keep track of created nodes. If null, each call will create a
   *     different individual branch.
   * @throws Exception
   */
  private void buildSuffixNet(
      String[] token,
      KnotenUriTupel rootnode,
      Neo4jRestKlient graph,
      Map<String, KnotenUriTupel> createdNodes)
      throws Exception {

    // Keep track of created nodes
    if (createdNodes == null) createdNodes = new HashMap<String, KnotenUriTupel>();

    // Set parent node
    Knoten parentNode = rootnode.getKnoten();
    URI parentURI = rootnode.getUri();

    // Check whether the root node exists within the graph or needs to be created
    if (parentURI == null && graph != null) {
      parentURI = graph.erstelleKnoten(parentNode.getName());
      graph.etikettHinzufuegen(parentURI, "wurzel");
    }

    // Variable for child node
    KnotenUriTupel child;

    // Loop over the token array's elements
    for (int i = 0; i < token.length; i++) {

      // Check whether a node with the current token's name already exists
      if (createdNodes.containsKey(token[i])) {

        // If so, retrieve the node
        child = createdNodes.get(token[i]);

        // Check whether that node is already connected to the current parent node
        if (!parentNode.getKinder().containsKey(token[i])) {

          // If not, make the connection
          parentNode.getKinder().put(token[i], child.getKnoten());

          // Write new pairing to Neo4J DB
          if (graph != null) {
            graph.addRelationship(parentURI, child.getUri(), "child", "{ }");
            graph.eigenschaftHinzufuegen(
                child.getUri(), BERUEHRUNGSZAEHLER_SCHLUESSEL, child.getKnoten().getZaehler() + 1);
          }
        }
      } else {

        // Instantiate new node
        child = new KnotenUriTupel();
        child.setKnoten(new Knoten(token[i]));

        // Connect it to parent
        parentNode.getKinder().put(token[i], child.getKnoten());

        // Put newly created token into DB
        if (graph != null) {
          child.setUri(graph.erstelleKnoten(child.getKnoten().getName()));
          graph.addRelationship(parentURI, child.getUri(), "child", "{ }");
          graph.eigenschaftHinzufuegen(child.getUri(), BERUEHRUNGSZAEHLER_SCHLUESSEL, 1);
        }

        // Remember it as having been created
        createdNodes.put(token[i], child);
      }

      // Increment the counter of the child node
      child.getKnoten().inkZaehler();

      // Set new parent
      parentNode = child.getKnoten();
      parentURI = child.getUri();
    }
  }
  @Override
  public boolean process() throws Exception {

    // Wurzelknoten des zu erstellenden Baumes erstellen
    Knoten wurzelKnoten = new Knoten("^");

    // Graph-Datenbank-Klienten instanziieren
    Neo4jRestKlient graph = null;
    URI wurzelKnotenUri = null;
    if (this.useNeo4j) {

      graph = new Neo4jRestKlient(this.neo4jUri, this.neo4jUsr, this.neo4jPwd);

      // Ersten Knoten in Neo4J-DB einspeisen
      if (!this.individualRootNodes) {
        wurzelKnotenUri = graph.erstelleKnoten(wurzelKnoten.getName());
        graph.etikettHinzufuegen(wurzelKnotenUri, "wurzel");
      }
    }

    // Tupel aus URI und Knoten erstellen
    KnotenUriTupel wurzelKnotenUriTupel = new KnotenUriTupel(wurzelKnoten, wurzelKnotenUri);

    // JSON-Parser instanziieren
    Gson gson = new GsonBuilder().setPrettyPrinting().create();

    // Variable zur Nachhaltung erstellter Graphenknoten
    Map<String, KnotenUriTupel> createdNodes = null;
    if (!this.individualBranches) createdNodes = new HashMap<String, KnotenUriTupel>();

    // Eingabe puffern
    BufferedReader eingabe = new BufferedReader(this.getInputPorts().get(INPUTID).getInputReader());

    // Eingabe einlesen
    String jsonObjekt = eingabe.readLine();
    while (jsonObjekt != null) {

      // JSON-Objekt parsen
      WortAnnotationTupel[][] saetze =
          gson.fromJson(jsonObjekt, new WortAnnotationTupel[0][0].getClass());

      // Saetze durchlaufen
      for (int i = 0; i < saetze.length; i++) {

        WortAnnotationTupel[] satz = saetze[i];

        // Satz in String-Array fassen
        String[] satzArray = new String[satz.length];
        for (int j = 0; j < satz.length; j++) {
          satzArray[j] = satz[j].getWort();
        }

        // Mit dem ermittelten Satz wird das Netz weiter konstruiert
        this.buildSuffixNet(satzArray, wurzelKnotenUriTupel, graph, createdNodes);
      }

      // Naechstes Objekt einlesen
      jsonObjekt = eingabe.readLine();
    }

    // Letztlich wird der Wurzelknoten (und damit der gesamte erstellte
    // Baum) als Bytestrom ausgegeben
    Iterator<Pipe> byteStroeme =
        this.getOutputPorts().get(OUTPUTID).getPipes(BytePipe.class).iterator();
    while (byteStroeme.hasNext()) {
      ObjectOutputStream ausgabeStrom =
          new ObjectOutputStream(((BytePipe) byteStroeme.next()).getOutput());
      ausgabeStrom.writeObject(wurzelKnoten);
      ausgabeStrom.close();
    }

    // Ausgabekanaele schliessen
    this.closeAllOutputs();

    return true;
  }