/**
   * Returns the fold that should be collapsed/expanded in the caret row
   *
   * @param hierarchy hierarchy under which all folds should be collapsed/expanded.
   * @param dot caret position offset
   * @param lineStart offset of the start of line
   * @param lineEnd offset of the end of line
   * @return the fold that meet common criteria in accordance with the caret position
   */
  private static Fold getLineFold(FoldHierarchy hierarchy, int dot, int lineStart, int lineEnd) {
    Fold caretOffsetFold = FoldUtilities.findOffsetFold(hierarchy, dot);

    // beginning searching from the lineStart
    Fold fold = FoldUtilities.findNearestFold(hierarchy, lineStart);

    while (fold != null
        && (fold.getEndOffset() <= dot
            || // find next available fold if the 'fold' is one-line
            // or it has children and the caret is in the fold body
            // i.e. class A{ |public void method foo(){}}
            (!fold.isCollapsed() && fold.getFoldCount() > 0 && fold.getStartOffset() + 1 < dot))) {

      // look for next fold in forward direction
      Fold nextFold =
          FoldUtilities.findNearestFold(
              hierarchy,
              (fold.getFoldCount() > 0) ? fold.getStartOffset() + 1 : fold.getEndOffset());
      if (nextFold != null && nextFold.getStartOffset() < lineEnd) {
        if (nextFold == fold) return fold;
        fold = nextFold;
      } else {
        break;
      }
    }

    // a fold on the next line was found, returning fold at offset (in most cases inner class)
    if (fold == null || fold.getStartOffset() > lineEnd) {

      // in the case:
      // class A{
      // }     |
      // try to find an offset fold on the offset of the line beginning
      if (caretOffsetFold == null) {
        caretOffsetFold = FoldUtilities.findOffsetFold(hierarchy, lineStart);
      }

      return caretOffsetFold;
    }

    // no fold at offset found, in this case return the fold
    if (caretOffsetFold == null) return fold;

    // skip possible inner class members validating if the innerclass fold is collapsed
    if (caretOffsetFold.isCollapsed()) return caretOffsetFold;

    // in the case:
    // class A{
    // public vo|id foo(){} }
    // 'fold' (in this case fold of the method foo) will be returned
    if (caretOffsetFold.getEndOffset() > fold.getEndOffset() && fold.getEndOffset() > dot) {
      return fold;
    }

    // class A{
    // |} public void method foo(){}
    // inner class fold will be returned
    if (fold.getStartOffset() > caretOffsetFold.getEndOffset()) return caretOffsetFold;

    // class A{
    // public void foo(){} |}
    // returning innerclass fold
    if (fold.getEndOffset() < dot) return caretOffsetFold;

    return fold;
  }