@Override
  public boolean checkAvailable(final @NotNull Editor editor, final @NotNull PsiFile file, final @NotNull MoveInfo info, final boolean down) {
    if (!super.checkAvailable(editor, file, info, down)) return false;

    // updated moved range end to cover multiline tag start
    final Document document = editor.getDocument();
    int movedLineStart = document.getLineStartOffset(info.toMove.startLine);
    final int movedLineEnd = document.getLineEndOffset(info.toMove.endLine - 1);
    XmlElement xmlElementAtStart = getSourceElement(file, movedLineStart, true);
    XmlElement xmlElementAtEnd = getSourceElement(file, movedLineEnd, false);
    if (xmlElementAtStart == null || xmlElementAtEnd == null) return false;
    if (checkInjections(xmlElementAtStart, xmlElementAtEnd)) return false;

    XmlElement movedParent = null;

    if (xmlElementAtEnd == xmlElementAtStart) movedParent = xmlElementAtEnd;
    else if (xmlElementAtEnd instanceof XmlAttribute && xmlElementAtStart instanceof XmlTag && xmlElementAtEnd.getParent() == xmlElementAtStart) {
      movedParent = xmlElementAtStart;
    } else if (xmlElementAtStart instanceof XmlAttribute && xmlElementAtEnd instanceof XmlTag && xmlElementAtStart.getParent() == xmlElementAtEnd) {
      movedParent = xmlElementAtEnd;
    }

    if (movedParent == null) {
      return false;
    }

    final TextRange textRange = movedParent.getTextRange();

    if (movedParent instanceof XmlTag tag) {
      PsiElement parent = tag.getParent();
      if (!(parent instanceof XmlTag) && PsiTreeUtil.getChildrenOfType(parent, XmlTag.class).length < 2) {
        // the only top-level tag
        return info.prohibitMove();
      }
      final TextRange valueRange = getTagContentRange(tag);
      final int valueStart = valueRange.getStartOffset();

      if (HtmlUtil.isHtmlTag(tag) && (HtmlUtil.isScriptTag(tag) || HtmlUtil.STYLE_TAG_NAME.equals(tag.getName()))) {
        info.toMove = new LineRange(tag);
        int nextLine = down ? info.toMove.endLine : info.toMove.startLine - 1;
        info.toMove2 = new LineRange(nextLine, nextLine + 1);
      }

      if (movedLineStart < valueStart && valueStart + 1 < document.getTextLength()) {
        movedLineStart = updateMovedRegionEnd(document, movedLineStart, valueStart + 1, info, down);
      }
      if (movedLineStart < valueStart) {
        movedLineStart = updateMovedRegionStart(document, movedLineStart, tag.getTextRange().getStartOffset(), info, down);
      }
    } else if (movedParent instanceof XmlTagChild || movedParent instanceof XmlAttribute) {
      final int endOffset = textRange.getEndOffset() + 1;
      if (endOffset < document.getTextLength()) movedLineStart = updateMovedRegionEnd(document, movedLineStart, endOffset, info, down);
      movedLineStart = updateMovedRegionStart(document, movedLineStart, textRange.getStartOffset(), info, down);
    }

    final TextRange moveDestinationRange = new UnfairTextRange(
      document.getLineStartOffset(info.toMove2.startLine),
      document.getLineEndOffset(info.toMove2.endLine - 1)
    );

    if (movedParent instanceof XmlAttribute) {
      final XmlTag parent = ((XmlAttribute)movedParent).getParent();

      if (parent != null) {
        final TextRange valueRange = getTagContentRange(parent);

        // Do not move attributes out of tags
        if ( (down && moveDestinationRange.getEndOffset() >= valueRange.getStartOffset()) ||
             (!down && moveDestinationRange.getStartOffset() <= parent.getTextRange().getStartOffset())
          ) {
          return info.prohibitMove();
        }
      }
    }

    if (down) {
      final XmlElement targetParent = getDestinationElement(file, movedParent, moveDestinationRange.getEndOffset(), false);
      if (targetParent != null) {
        if (movedParent instanceof XmlTagChild && targetParent instanceof XmlTag tag) {
          if (targetParent == movedParent) return false;
          if (movedParent instanceof XmlTag && moveTags(info, (XmlTag)movedParent, tag, true)) return true;

          final int offset = tag.isEmpty() ? tag.getTextRange().getStartOffset() : getTagContentRange(tag).getStartOffset();
          updatedMovedIntoEnd(document, info, offset);
          if (tag.isEmpty()) {
            info.toMove2 = new LineRange(targetParent);
          }
        } else if ((movedParent instanceof XmlTagChild && targetParent instanceof XmlTagChild) || targetParent instanceof XmlAttribute) {
          updatedMovedIntoEnd(document, info, targetParent.getTextRange().getEndOffset());
        }
      }
    } else {
      final XmlElement targetParent = getDestinationElement(file, movedParent, moveDestinationRange.getStartOffset(), true);
      if (targetParent != null) {
        if (movedParent instanceof XmlTagChild && targetParent instanceof XmlTag tag) {
          final TextRange tagValueRange = getTagContentRange(tag);

          // We need to update destination range to jump over tag start
          final XmlTag[] subtags = tag.getSubTags();
          XmlTagChild[] children = tag.getValue().getChildren();
          if ((tagValueRange.contains(movedLineStart)
               && (subtags.length > 0 && subtags[0] == movedParent || children.length > 0 && children[0] == movedParent)) ||
              ( tagValueRange.getLength() == 0 && tag.getTextRange().intersects(moveDestinationRange))
             ) {
            final int line = document.getLineNumber(tag.getTextRange().getStartOffset());
            final LineRange toMove2 = info.toMove2;
            info.toMove2 = new LineRange(Math.min(line, toMove2.startLine), toMove2.endLine);
          }
          if (targetParent == movedParent) return false;
          if (movedParent instanceof XmlTag && moveTags(info, (XmlTag)movedParent, tag, false)) return true;

        } else if ((movedParent instanceof XmlTagChild && targetParent instanceof XmlTagChild) || targetParent instanceof XmlAttribute) {
          final int line = document.getLineNumber(targetParent.getTextRange().getStartOffset());
          final LineRange toMove2 = info.toMove2;
          info.toMove2 = new LineRange(Math.min(line, toMove2.startLine), toMove2.endLine);
        }
      }
    }

    if (movedParent instanceof XmlTagChild) {
      // it's quite simple after all...
      info.toMove = new LineRange(movedParent);
    }
    return true;
  }
@Override
  public boolean checkAvailable(final @NotNull Editor editor, final @NotNull PsiFile file, final @NotNull MoveInfo info, final boolean down)