/**
   * Uses recurson to get the depth of the input synset (in 'getSynsetDepth()') from a <root> A
   * synset may have multiple parents, thus we returneach possible depth and 'home hierarchy' <root>
   * Thus, we may have the same <root> at different depths in the WordNet hierarchy
   */
  private void treecreeper(
      int depth,
      HashSet<ISynsetID> synsets,
      TreeMap<Integer, HashSet<ISynsetID>> depths,
      ArrayList<Integer> roots) {
    depth++;
    ISynset synset = null;
    HashSet<ISynsetID> hypernyms = new HashSet<ISynsetID>(); // next 'level'(inverse of 'depth')
    for (ISynsetID s : synsets) {
      synset = dict.getSynset(s);
      hypernyms.addAll(synset.getRelatedSynsets(Pointer.HYPERNYM)); // get the <hypernyms>
      hypernyms.addAll(
          synset.getRelatedSynsets(Pointer.HYPERNYM_INSTANCE)); // get the <hypernyms> (instances)
    }

    if (!hypernyms.isEmpty()) {
      for (ISynsetID h : hypernyms) {
        int offset = h.getOffset();
        if (roots.contains(offset)) {
          if (depths.containsKey(depth)) {
            HashSet<ISynsetID> deep = depths.get(depth);
            deep.add(h);
            depths.put(depth, deep);
          } else {
            HashSet<ISynsetID> deep = new HashSet<ISynsetID>();
            deep.add(h);
            depths.put(depth, deep);
          }
        }
      }
      treecreeper(depth, hypernyms, depths, roots);
    }
    return;
  }
  // Given two input synsets, finds the least common subsumer (LCS) of them.
  // If there are multiple candidates for the LCS (due to multiple inheritance in WordNet), the LCS
  // with the
  // greatest depth is chosen (i.e., the candidate whose shortest path to the root is the longest).
  public HashSet<ISynsetID> getLCSbyDepth(ISynset synset1, ISynset synset2, String pos) {
    HashSet<ISynsetID> lcs = new HashSet<ISynsetID>();

    if (synset1.equals(synset2)) {
      HashSet<ISynsetID> identity = new HashSet<ISynsetID>();
      identity.add(synset1.getID());
      return (identity);
    }
    // !!! could be <roots>, in which case there is no subsumer !!!
    double d1 = getSynsetDepth(synset1, pos);
    double d2 = getSynsetDepth(synset2, pos);
    if (d1 == 0.0 && d2 == 0.0) {
      return (lcs); // !!! return empty set !!!
    }
    // !!! *1* of them could be a <root>, in which case there is no subsumer !!!
    // double d1 = getSynsetDepth(synset1, pos);
    // double d2 = getSynsetDepth(synset2, pos);
    if (d1 == 0.0 || d2 == 0.0) {
      if (d1 == 0.0) {
        lcs.add(synset1.getID());
      }
      if (d2 == 0.0) {
        lcs.add(synset2.getID());
      }
      return (lcs); // !!! return !!!
    }
    TreeMap<Integer, HashSet<ISynsetID>> map = new TreeMap<Integer, HashSet<ISynsetID>>();
    // synset 1 <hypernyms>
    HashSet<ISynsetID> s1 = new HashSet<ISynsetID>();
    s1.add(synset1.getID());
    HashSet<ISynsetID> h1 = new HashSet<ISynsetID>();
    getHypernyms(s1, h1); // i.e. fill 'h1' with <hypernyms> of synset1
    // synset 2 <hypernyms>
    HashSet<ISynsetID> s2 = new HashSet<ISynsetID>();
    s2.add(synset2.getID());
    HashSet<ISynsetID> h2 = new HashSet<ISynsetID>();
    getHypernyms(s2, h2); // i.e. fill 'h2' with <hypernyms> of synset2
    h1.retainAll(h2);
    // System.out.println(h1);
    for (ISynsetID h : h1) {
      // System.out.println(dict.getSynset(h));
      // System.out.println(h + "\t\t\t" + getSynsetDepth(h.getOffset(), pos));
      TreeMap<Integer, HashSet<ISynsetID>> set = getSynsetDepth(h.getOffset(), pos);
      for (Integer i : set.keySet()) {

        HashSet<ISynsetID> subset = set.get(i);
        // EasyIn.pause(h + "\t" + i + "\t<" + subset + ">");
        if (map.containsKey(i)) {
          HashSet<ISynsetID> store = map.get(i);
          store.add(h);
          map.put(i, store);
        } else {
          HashSet<ISynsetID> store = new HashSet<ISynsetID>();
          store.add(h);
          map.put(i, store);
        }
      }
    }
    int key = map.lastKey();
    lcs = map.get(key);
    return (lcs);
  }