/**
   * Tries to find node that is direct or indirect previous node of the given node.
   *
   * <p>E.g. there is a possible use-case:
   *
   * <pre>
   *                     n1
   *                  /    \
   *                n21    n22
   *                 |      |
   *                n31    n32
   * </pre>
   *
   * Let's assume that target node is <code>'n32'</code>. 'n31' is assumed to be returned from this
   * method then.
   *
   * <p><b>Note:</b> current method avoids going too deep if found node type is the same as start
   * node type
   *
   * @return direct or indirect previous node of the given one having target type if possible;
   *     <code>null</code> otherwise
   */
  private static boolean findPreviousNode(
      AlignmentInColumnsConfig config,
      ASTNode from,
      IElementType targetType,
      boolean processFrom,
      boolean processParent,
      NodeProcessor processor) {
    if (from == null) return false;

    for (ASTNode prev = processFrom ? from : from.getTreePrev();
        prev != null;
        prev = prev.getTreePrev()) {
      IElementType prevType = prev.getElementType();
      if (prevType == targetType) {
        if (processor.targetTypeFound(prev)) return true;
      } else if (config.getWhiteSpaceTokenTypes().contains(prevType)) {
        if (processor.whitespaceFound(prev)) return true;
      }

      if (findPreviousNode(config, prev.getLastChildNode(), targetType, true, false, processor))
        return true;
    }

    if (processParent) {
      for (ASTNode parent = from.getTreeParent(); parent != null; parent = parent.getTreeParent()) {
        if (findPreviousNode(config, parent, targetType, false, false, processor)) return true;
      }
    }
    return false;
  }