code: package eu.fbk.dh.tint.simplifier.rules;
  
  import com.google.common.collect.HashMultimap;
  import edu.stanford.nlp.ling.CoreAnnotations;
  import edu.stanford.nlp.ling.CoreLabel;
  import edu.stanford.nlp.ling.IndexedWord;
  import edu.stanford.nlp.pipeline.Annotation;
  import edu.stanford.nlp.semgraph.SemanticGraph;
  import edu.stanford.nlp.semgraph.SemanticGraphCoreAnnotations;
  import edu.stanford.nlp.semgraph.SemanticGraphEdge;
  import edu.stanford.nlp.util.CoreMap;
  import eu.fbk.dh.tint.digimorph.annotator.DigiMorphAnnotations;
  import eu.fbk.dh.tint.inverse.digimorph.annotator.InverseDigiMorph;
  
  import java.util.List;
  import java.util.Map;
  import java.util.Stack;
  import java.util.TreeSet;
  
  import static eu.fbk.dh.tint.simplifier.Simplifier.getHistory;
  
  /**
   * Created by alessio on 15/02/17.
   */
  
  public class ReplaceSubordinateRule implements SimplificationRule {
  
      static TreeSet<String> getPersons(SemanticGraph semanticGraph, IndexedWord word, CoreMap sentence) {
          Stack<IndexedWord> wordsToCheck = new Stack<>();
          wordsToCheck.add(word);
  
          int index = word.index();
  
          while (!wordsToCheck.isEmpty()) {
              IndexedWord thisWord = wordsToCheck.pop();
              List<SemanticGraphEdge> outEdgesSorted = semanticGraph.getOutEdgesSorted(thisWord);
              for (SemanticGraphEdge semanticGraphEdge : outEdgesSorted) {
                  IndexedWord dependent = semanticGraphEdge.getDependent();
                  String pos = dependent.get(CoreAnnotations.PartOfSpeechAnnotation.class);
                  if (pos.equals("VA")) {
                      index = Math.min(index, dependent.index());
                      wordsToCheck.push(dependent);
                  }
              }
          }
  
          CoreLabel token = sentence.get(CoreAnnotations.TokensAnnotation.class).get(index - 1);
          String morpho = token.get(DigiMorphAnnotations.MorphoAnnotation.class);
          String[] parts = morpho.split("\\s+");
          TreeSet<String> persons = new TreeSet<>();
          for (int i = 1; i < parts.length; i++) {
              String[] vParts = parts[i].split("\\+");
              if (!vParts[1].equals("v")) {
                  continue;
              }
  
              persons.add(vParts[5] + "+" + vParts[6]);
          }
          return persons;
      }
  
      @Override public String apply(Annotation annotation, Map<Integer, HashMultimap<Integer, Integer>> children) {
  
          InverseDigiMorph dm = new InverseDigiMorph();
  
          int conj = 0;
          List<CoreMap> sentences = annotation.get(CoreAnnotations.SentencesAnnotation.class);
          CoreMap sentence = sentences.get(0);
  
          //
  
          SemanticGraph semanticGraph = sentence
                  .get(SemanticGraphCoreAnnotations.BasicDependenciesAnnotation.class);
  
          IndexedWord node = semanticGraph.getNodeByIndex(conj + 1);
          List<IndexedWord> history = getHistory(semanticGraph, node);
          if (history.size() == 1) {
              return null;
          }
          IndexedWord verb = history.get(1);
          CoreLabel token = sentence.get(CoreAnnotations.TokensAnnotation.class).get(verb.index() - 1);
          String pos = token.get(CoreAnnotations.PartOfSpeechAnnotation.class);
          if (!pos.startsWith("V")) {
              return null;
          }
  
          // todo: check subject in parse tree
          // todo: check clitics
  
          String morpho = token.get(DigiMorphAnnotations.MorphoAnnotation.class);
          String[] parts = morpho.split("\\s+");
          TreeSet<String> persons = new TreeSet<>();
          String tempo = null;
          for (int i = 1; i < parts.length; i++) {
              String[] vParts = parts[i].split("\\+");
              if (!vParts[1].equals("v")) {
                  continue;
              }
  
              String modo = vParts[2];
              if (!modo.equals("cong")) {
                  continue;
              }
  
              tempo = vParts[3];
              persons.add(vParts[5] + "+" + vParts[6]);
          }
  
          IndexedWord next = null;
          if (persons.size() != 1) {
              for (int i = 2; i < history.size(); i++) {
                  if (history.get(i).get(CoreAnnotations.PartOfSpeechAnnotation.class).startsWith("V")) {
                      next = history.get(i);
                      break;
                  }
              }
              persons = getPersons(semanticGraph, next, sentence);
          }
  
          StringBuffer stringBuffer = new StringBuffer();
          stringBuffer.append(token.lemma());
          stringBuffer.append("+v+indic+").append(tempo);
          stringBuffer.append("+nil+");
  
          // Add person
          stringBuffer.append(persons.last());
  
          String find = stringBuffer.toString();
  
          System.out.println(find);
          String inverseMorphology = dm.getInverseMorphology(find);
  
          System.out.println(inverseMorphology);
          System.out.println(morpho);
          System.out.println(tempo);
          System.out.println(persons);
  
  //        System.out.println(annotation.get(UDPipeAnnotations.UDPipeOriginalAnnotation.class));
  //        System.out.println(sentence.get(CoreAnnotations.TokensAnnotation.class).get(2)
  //                .get(UDPipeAnnotations.FeaturesAnnotation.class));
  //        System.out.println(token
  //                .get(UDPipeAnnotations.FeaturesAnnotation.class));
  //
  //        System.out.println(children.get(0).get(verb.index()));
  //        System.out.println(children);
  //        System.out.println(verb.get(UDPipeAnnotations.FeaturesAnnotation.class));
  
  //        try {
  //            System.out.println(JSONOutputter.jsonPrint(annotation));
  //        } catch (IOException e) {
  //            e.printStackTrace();
  //        }
  //        System.out.println(getHistory(semanticGraph, node));
  //        System.out.println(semanticGraph.getOutEdgesSorted(node));
  //        System.out.println(semanticGraph.getIncomingEdgesSorted(node));
  //        System.out.println(node);
          return null;
      }
  }
  