/** @return Point in layered pane coordinate system */
  static Pair<Point, Short> chooseBestHintPosition(
      Project project,
      Editor editor,
      int line,
      int col,
      LightweightHint hint,
      boolean awtTooltip,
      short preferredPosition) {
    HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
    Dimension hintSize = hint.getComponent().getPreferredSize();
    JComponent editorComponent = editor.getComponent();
    JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();

    Point p1;
    Point p2;
    boolean isLookupShown = LookupManager.getInstance(project).getActiveLookup() != null;
    if (isLookupShown) {
      p1 = hintManager.getHintPosition(hint, editor, HintManager.UNDER);
      p2 = hintManager.getHintPosition(hint, editor, HintManager.ABOVE);
    } else {
      LogicalPosition pos = new LogicalPosition(line, col);
      p1 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.UNDER);
      p2 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.ABOVE);
    }

    if (!awtTooltip) {
      p1.x = Math.min(p1.x, layeredPane.getWidth() - hintSize.width);
      p1.x = Math.max(p1.x, 0);
      p2.x = Math.min(p2.x, layeredPane.getWidth() - hintSize.width);
      p2.x = Math.max(p2.x, 0);
    }

    boolean p1Ok = p1.y + hintSize.height < layeredPane.getHeight();
    boolean p2Ok = p2.y >= 0;

    if (isLookupShown) {
      if (p1Ok) return new Pair<Point, Short>(p1, HintManager.UNDER);
      if (p2Ok) return new Pair<Point, Short>(p2, HintManager.ABOVE);
    } else {
      if (preferredPosition != HintManager.DEFAULT) {
        if (preferredPosition == HintManager.ABOVE) {
          if (p2Ok) return new Pair<Point, Short>(p2, HintManager.ABOVE);
        } else if (preferredPosition == HintManager.UNDER) {
          if (p1Ok) return new Pair<Point, Short>(p1, HintManager.UNDER);
        }
      }

      if (p1Ok) return new Pair<Point, Short>(p1, HintManager.UNDER);
      if (p2Ok) return new Pair<Point, Short>(p2, HintManager.ABOVE);
    }

    int underSpace = layeredPane.getHeight() - p1.y;
    int aboveSpace = p2.y;
    return aboveSpace > underSpace
        ? new Pair<Point, Short>(new Point(p2.x, 0), HintManager.UNDER)
        : new Pair<Point, Short>(p1, HintManager.ABOVE);
  }
  private static boolean fitsLayeredPane(
      JLayeredPane pane, JComponent component, RelativePoint desiredLocation, HintHint hintHint) {
    if (hintHint.isAwtTooltip()) {
      Dimension size = component.getPreferredSize();
      Dimension paneSize = pane.getSize();

      Point target = desiredLocation.getPointOn(pane).getPoint();
      Balloon.Position pos = hintHint.getPreferredPosition();
      int pointer = BalloonImpl.getPointerLength(pos, false) + BalloonImpl.getNormalInset();
      if (pos == Balloon.Position.above || pos == Balloon.Position.below) {
        boolean heightFit =
            target.y - size.height - pointer > 0
                || target.y + size.height + pointer < paneSize.height;
        return heightFit && size.width + pointer < paneSize.width;
      } else {
        boolean widthFit =
            target.x - size.width - pointer > 0 || target.x + size.width + pointer < paneSize.width;
        return widthFit && size.height + pointer < paneSize.height;
      }
    } else {
      final Rectangle lpRect =
          new Rectangle(
              pane.getLocationOnScreen().x,
              pane.getLocationOnScreen().y,
              pane.getWidth(),
              pane.getHeight());
      Rectangle componentRect =
          new Rectangle(
              desiredLocation.getScreenPoint().x,
              desiredLocation.getScreenPoint().y,
              component.getPreferredSize().width,
              component.getPreferredSize().height);
      return lpRect.contains(componentRect);
    }
  }
  ParameterInfoComponent(
      Object[] objects,
      Editor editor,
      @NotNull ParameterInfoHandler handler,
      boolean requestFocus) {
    super(new BorderLayout());
    myRequestFocus = requestFocus;

    if (!ApplicationManager.getApplication().isUnitTestMode()) {
      JComponent editorComponent = editor.getComponent();
      JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
      myWidthLimit = layeredPane.getWidth();
    }

    NORMAL_FONT = UIUtil.getLabelFont();
    BOLD_FONT = NORMAL_FONT.deriveFont(Font.BOLD);

    myObjects = objects;

    setBackground(BACKGROUND_COLOR);

    myHandler = handler;
    myPanels = new OneElementComponent[myObjects.length];
    final JPanel panel = new JPanel(new GridBagLayout());
    for (int i = 0; i < myObjects.length; i++) {
      myPanels[i] = new OneElementComponent();
      panel.add(
          myPanels[i],
          new GridBagConstraints(
              0,
              i,
              1,
              1,
              1,
              0,
              GridBagConstraints.WEST,
              GridBagConstraints.HORIZONTAL,
              new Insets(0, 0, 0, 0),
              0,
              0));
    }
    if (myRequestFocus) {
      AccessibleContextUtil.setName(
          this, "Parameter Info. Press TAB to navigate through each element. Press ESC to close.");
    }

    final JScrollPane pane = ScrollPaneFactory.createScrollPane(panel);
    pane.setBorder(null);
    pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    add(pane, BorderLayout.CENTER);

    myCurrentParameterIndex = -1;
  }