gt:                 List<String> rootInstanceUris = new ArrayList<String>();
context: package org.freya.util;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.concurrent.atomic.AtomicInteger;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.freya.annotate.lucene.LuceneAnnotator;
  import org.freya.model.ClassElement;
  import org.freya.model.InstanceListElement;
  import org.freya.model.JokerElement;
  import org.freya.model.OntologyElement;
  import org.freya.model.PropertyElement;
  import org.freya.model.ResultGraph;
  import org.freya.model.SerializableURI;
  import org.freya.model.TripleElement;
  import org.freya.rdf.query.CATConstants;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Component;
  
  @Component
  public class GraphUtils {
      public static AtomicInteger idCounter = new AtomicInteger();
  
      private static final Log logger = LogFactory.getLog(GraphUtils.class);
  
      @Autowired LuceneAnnotator luceneAnnotator;
  
      /**
       * this method creates the root ResultGraph node
       * 
       * @param columnData
       * @return
       */
      public List<ResultGraph> getResultGraph(List<TripleElement> triples)
                      throws Exception {
          List<ResultGraph> nonOptimizedGraph = new ArrayList<ResultGraph>();
  
          nonOptimizedGraph = getGraphFrom(triples);
          logger.info("\n Graph consistent:" + isGraphConsistent(nonOptimizedGraph));
          logger.info("before optimization:\n" + nonOptimizedGraph.toString());
          // here optimise graph
          logger.info("\n Now calling optimizeGraph method...");
          List<ResultGraph> optimizedGraph = optimizeGraph(nonOptimizedGraph);
          logger.info("after optimization:\n" + optimizedGraph.toString());
          logger.info("\n Optimized graph consistent:"
                          + isGraphConsistent(optimizedGraph));
          logger.info("\n Is data lost?"
                          + isDataLost(nonOptimizedGraph, optimizedGraph));
          return optimizedGraph;
      }
  
      public static boolean isDataLost(List<ResultGraph> nonOptimizedFinalGraph,
                      List<ResultGraph> optimizedGraph) {
          List<String> afterOptimizationUris = new ArrayList<String>();
          boolean result = false;
          for (ResultGraph node : optimizedGraph) {
              String uri = node.getURI();
              afterOptimizationUris.add(uri);
          }
          for (ResultGraph node : nonOptimizedFinalGraph) {
              String uri = node.getURI();
              if (!afterOptimizationUris.contains(uri)) {
                  result = true;
              }
          }
          return result;
      }
  
      /**
       * Consistent graph: 1) each node must have EITHER at least one incoming, OR at least one outcoming; 2) all
       * outcoming ids must match with ids of existing nodes
       * 
       * @param graph
       * @return
       */
      public static boolean isGraphConsistent(List<ResultGraph> graph) {
          boolean consistent = true;
          // check graph consistency
          List<Integer> ids = new ArrayList<Integer>();
          List<Integer> outcomings = new ArrayList<Integer>();
          for (ResultGraph node : graph) {
              ids.add(node.getId());
              if (node.getAdjacencies() != null)
                  outcomings.addAll(node.getAdjacencies());
          }
          for (ResultGraph node : graph) {
              List<Integer> adjs = node.getAdjacencies();
              for (Integer num : adjs) {
                  if (!ids.contains(num)) {
                      logger.info("Node with id:" + num
                                      + " does not exist, and is referenced by another node!");
                      consistent = false;
                  }
              }
              // check point 1: whether there exist at least one incoming or
              // outcoming node
              if (!outcomings.contains(node.getId()) && (adjs.size() <= 0))
                  consistent = false;
          }
          return consistent;
      }
  
      /**
       * updates adjacencies by reading elements from the newGraph and updating the elements with the same URI in the
       * oldGraph; this methods basically 'adds' new adjacencies from newGraph to the elements in the old graph
       * 
       * @param finalGraph
       * @param rootNodesForLastElement
       */
      public static List<ResultGraph> updateGraphWithNewAdjacencies(
                      List<ResultGraph> oldGraph, List<ResultGraph> newGraph) {
          // find rootNodesForLastElement in finalGraph and updateAdjacencies
          HashMap<Integer, ResultGraph> oldGraphMap =
                          new HashMap<Integer, ResultGraph>();
          for (ResultGraph node : oldGraph) {
              oldGraphMap.put(node.getId(), node);
          }
          for (ResultGraph node : newGraph) {
              ResultGraph old = (ResultGraph) oldGraphMap.get(node.getId());
              if (node != null && old != null) {
                  logger.info("old graph has adjacencies:" + old.getAdjacencies());
                  logger.info("updated node HAS these adjacencies:"
                                  + node.getAdjacencies());
                  // if (old.getAdjacencies() == null)
                  // old.setAdjacencies(new ArrayList());
                  // if (node.getAdjacencies() != null)
                  old.getAdjacencies().addAll(node.getAdjacencies());
                  // if (old != null)
                  oldGraphMap.put(node.getId(), old);
              } else {
                  logger
                                  .info("WARNING::::The node with this id does not exist in the new graph which should have info about updated nodes!!!!:"
                                                  + node.getId());
                  logger.debug("old element is:" + old);
                  logger.debug("new element is:" + node);
                  old.getAdjacencies().addAll(node.getAdjacencies());
                  oldGraphMap.put(node.getId(), old);
                  // oldGraphMap.put(node.getId(), node);
                  // logger.debug("Adding it to the map...");
              }
          }
          List<ResultGraph> updatedGraph = new ArrayList<ResultGraph>();
          for (Integer key : oldGraphMap.keySet()) {
              updatedGraph.add(oldGraphMap.get(key));
          }
          return updatedGraph;
      }
  
      /**
       * building the graph: iterate through triples now and for the first row create one resultGraph per element, so
       * rt(c), rt(b), rt(a) the first resultGraph rt(c) becomes root, then rt(b) is his adjacent, whose adjacent is
       * rt(a), so we now have structure rt(c)-hasAdjacent- rt(b)-hasAdjacent- rt(a) so the first element becomes root
       * namely rt(c), and the last element becomes LASTCHILD now iterate through the rest of the table and check (case 1)
       * if the FIRST ELEMENT in a row = ROOT then do this: create ResultGraph for d and e and add d as a child of root,
       * and add e as a child of d, so now we have rt(c)-hasChild- rt(b)-hasChild- rt(a) rt(c)-hasChild- rt(d)-hasChild-
       * rt(e) (case 2) else if the FIRST ELEMENT in a row == LASTCHILD then do this: add d to be a child of the
       * lastChild, and e to be the child of d; for example if our table was a-b-c c-d-e so now we have rt(a)-hasChild-
       * rt(b)-hasChild- rt(c)-hasChild- rt(d)-hasChild- rt(e) where rt(a)=ROOT and rt(e)=LASTCHILD (case 3) else if the
       * LAST ELEMENT in a row ==ROOT so for example c-b-a e-d-c create ResultGraph e, and d, e becomes ROOT, than d is a
       * child of e, and ROOT is added as a child of e, so now we have rt(e)-hasChild- rt(d)-hasChild- rt(c)-hasChild-
       * rt(b)-hasChild- rt(a) (case 4) else if the LAST ELEMENT in a row==LASTCHILD for example: a-b-c e-d-c this becomes
       * the case 1, but need to add property to ResultGraph (orientationOpposite=true) so, first change the table to
       * c-b-a c-d-e and then apply the same algorithm as for the case 1, and set the property for orientation to be true
       * 
       * @param triples
       * @return
       */
      public List<ResultGraph> getGraphFrom(List<TripleElement> triples) {
          List<ResultGraph> finalGraph = new ArrayList<ResultGraph>();
          logger.info("generating graph from these triples: " + triples.toString());
          TripleElement firstTriple = triples.get(0);
          logger.info("taking first triple: " + firstTriple.toString());
          int numberOfElements;
          List<ResultGraph> rootNodes = null;
          List<ResultGraph> otherNodes = null;
          List<ResultGraph> rootNodesForLastElement = null;
          List<ResultGraph> otherNodesForLastElement = null;
          List<String> setOfValues=null;
          HashMap<String, List<ResultGraph>> graphFromTheFirstTripleElement;
          try {
              // the FIRST element in the first triple
              graphFromTheFirstTripleElement =
                              getResultGraphFromOntologyElement(firstTriple.getElements()
                                              .get(0));
              logger.debug("Taking first element in the triple: "
                              + firstTriple.getElements().get(0).toString());
              logger.debug("generated graph:" + graphFromTheFirstTripleElement);
              // logger.debug("Graph from the first triple element:"
              // + graphFromTheFirstTripleElement.toString());
              rootNodes = (List<ResultGraph>) graphFromTheFirstTripleElement.get("root");
              otherNodes =
                              (List<ResultGraph>) graphFromTheFirstTripleElement.get("other");
              finalGraph.addAll(rootNodes);
              finalGraph.addAll(otherNodes);
              logger.info("Graph from the first node:" + finalGraph.toString());
              numberOfElements=firstTriple.getElements().size();
              // Check if the second element in triple contains result
              setOfValues = firstTriple.getElements().get(1).get(0).getResults();
              if (firstTriple.getElements().size() > 2 && setOfValues!=null) {
                  // the SECOND element in the first triple
                  List<ResultGraph> rootNodesForTheSecondElement = null;
                  List<ResultGraph> otherNodesForTheSecondElement = null;
                  logger
                                  .debug("generating graph for the second element in the first triple which is:::::::::::::::::::"
                                                  + firstTriple.getElements().get(1).toString());
                  HashMap<String, List<ResultGraph>> secondElInTheFirstTriple =
                                  getResultGraphFromOntologyElement(firstTriple.getElements()
                                                  .get(1));
                  rootNodesForTheSecondElement =
                                  (List<ResultGraph>) secondElInTheFirstTriple.get("root");
                  otherNodesForTheSecondElement =
                                  (List<ResultGraph>) secondElInTheFirstTriple.get("other");
                  // finalGraph.addAll(rootNodesForTheSecondElement);
                  // finalGraph.addAll(otherNodesForTheSecondElement);
                  // the THIRD element in the first triple
                  HashMap<String, List<ResultGraph>> lastGraphElementFromTheTriple =
                                  getResultGraphFromOntologyElement(firstTriple.getElements()
                                                  .get(2));
                  rootNodesForLastElement =
                                  (List<ResultGraph>) lastGraphElementFromTheTriple.get("root");
                  otherNodesForLastElement =
                                  (List<ResultGraph>) lastGraphElementFromTheTriple.get("other");
                  //
                  // finalGraph.addAll(rootNodesForLastElement);
                  // finalGraph.addAll(otherNodesForLastElement);
                  // now connect elements from the first triple
                  if (rootNodesForTheSecondElement != null
                                  && rootNodesForTheSecondElement.size() > 0) {
                      Iterator<ResultGraph> iMiddle =
                                      rootNodesForTheSecondElement.iterator();
                      if (iMiddle.hasNext()) {
                          for (ResultGraph node : rootNodes) {
                              logger.debug("for node:" + node.toString());
                              // for (ResultGraph
                              // propertyNode:rootNodesForTheSecondElement){
                              // probaj ovo pa vidi je l ima veze ovde je negde
                              // problem
                              ResultGraph propertyNode = (ResultGraph) iMiddle.next();
                              node.getAdjacencies().add(propertyNode.getId());
                              logger.debug("adding adjs propeprty node:"
                                              + propertyNode.toString());
                          }
                      }
                      // logger.info("e ovo je sada pojebano*****************************\n"+finalGraph.toString());
                      if (rootNodesForTheSecondElement != null)
                          finalGraph.addAll(rootNodesForTheSecondElement);
                      if (otherNodesForTheSecondElement != null)
                          finalGraph.addAll(otherNodesForTheSecondElement);
                  }
                  if (rootNodesForLastElement != null
                                  && rootNodesForTheSecondElement != null) {
                      Iterator<ResultGraph> iLast = rootNodesForLastElement.iterator();
                      // for (ResultGraph lastEl : rootNodesForLastElement) {
                      for (ResultGraph middleElement : rootNodesForTheSecondElement) {
                          if (iLast.hasNext()) {
                              ResultGraph lastElement = (ResultGraph) iLast.next();
                              middleElement.getAdjacencies().add(lastElement.getId());
                          }
                      }
                      if (rootNodesForLastElement != null)
                          finalGraph.addAll(rootNodesForLastElement);
                      if (otherNodesForLastElement != null)
                          finalGraph.addAll(otherNodesForLastElement);
                  }
                  logger.debug("Graph from the first TRIPLE looks like this:"
                                  + finalGraph.toString());
                  // now process other triples
                  int numberOfRows = triples.size();
                  // we compare classes which are in 'other' part of
                  // the map as they are used to 'connect' graph; but we must
                  // also compare instance uris :(
                  ResultGraph first = null;
                  List<String> firstInstanceRoots = new ArrayList<String>();
                  ResultGraph third = null;
                  List<String> thirdInstanceRoots = new ArrayList<String>();
                  List<String> rootUris = new ArrayList<String>();
  