package com.intellij.lang.javascript.flex.debug;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.frame.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class XmlObjectEvaluator {
private final FakeCompositeNode myRootNode;
static final Font MONOSPACED_FONT;
static {
final Font font = UIUtil.getToolTipFont();
MONOSPACED_FONT = new Font("Monospaced", Font.PLAIN, font == null ? 12 : font.getSize());
}
public XmlObjectEvaluator(final @NotNull XValue value, final @NotNull XFullValueEvaluator.XFullValueEvaluationCallback callback) {
myRootNode = new FakeCompositeNode(value, callback);
}
public void startEvaluation() {
myRootNode.myValue.computeChildren(myRootNode);
}
private static class FakeCompositeNode implements XCompositeNode {
private final XValue myValue;
private final XFullValueEvaluator.XFullValueEvaluationCallback myCallback;
private final FakeCompositeNode myParent;
private final List<FakeCompositeNode> myChildren = new ArrayList<>();
private static final String XML_MARKER = " class='XML@";
private static final String XMLLIST_MARKER = " class='XMLList'";
public FakeCompositeNode(final @NotNull XValue value, final @NotNull XFullValueEvaluator.XFullValueEvaluationCallback callback) {
myValue = value;
myCallback = callback;
myParent = null;
}
private FakeCompositeNode(final @NotNull XValue value, final @NotNull FakeCompositeNode parent) {
myValue = value;
myCallback = null;
myParent = parent;
}
@Override
public void setAlreadySorted(boolean alreadySorted) {
}
@Override
public void addChildren(@NotNull XValueChildrenList children, boolean last) {
if (getRootNode().myCallback.isObsolete()) {
return;
}
for (int i = 0; i < children.size(); i++) {
final XValue value = children.getValue(i);
final FakeCompositeNode node = new FakeCompositeNode(value, this);
myChildren.add(node);
value.computeChildren(node);
}
getRootNode().myCallback.evaluated(getRootNode().toPresentableSting(0), MONOSPACED_FONT);
}
private FakeCompositeNode getRootNode() {
FakeCompositeNode node = this;
while (node.myCallback == null) {
node = node.myParent;
}
return node;
}
private String toPresentableSting(final int level) {
final StringBuilder buffer = new StringBuilder();
final String rawText = ((FlexValue)myValue).getResult();
if (rawText.contains(XMLLIST_MARKER)) {
for (FakeCompositeNode child : myChildren) {
buffer.append(child.toPresentableSting(level));
}
return buffer.toString();
}
final int xmlMarkerIndex = rawText.indexOf(XML_MARKER);
final int xmlInfoStartIndex = xmlMarkerIndex < 0 ? -1 : rawText.indexOf(" ", xmlMarkerIndex + XML_MARKER.length());
final int xmlInfoEndIndex = xmlMarkerIndex < 0 ? -1 : rawText.lastIndexOf("'");
if (xmlInfoStartIndex > 0 && xmlInfoEndIndex > xmlInfoStartIndex) {
final String xmlInfo = rawText.substring(xmlInfoStartIndex, xmlInfoEndIndex);
final boolean isElement = xmlInfo.startsWith(FlexValue.ELEMENT_MARKER + "<") && xmlInfo.endsWith(">");
final boolean isEmptyElement = isElement && xmlInfo.endsWith("/>");
final boolean isText = !isElement && xmlInfo.startsWith(FlexValue.TEXT_MARKER);
if (isText || isElement) {
if (isText) {
appendIndent(buffer, level);
buffer.append(xmlInfo.substring(FlexValue.TEXT_MARKER.length()));
buffer.append("\n");
}
else if (isEmptyElement) {
appendIndent(buffer, level);
buffer.append(xmlInfo.substring(FlexValue.ELEMENT_MARKER.length()));
buffer.append("\n");
}
else {
final String startTag = xmlInfo.substring(FlexValue.ELEMENT_MARKER.length());
final int spaceIndex = startTag.indexOf(" ");
final String tagName = startTag.substring(1, spaceIndex > 0 ? spaceIndex : startTag.length() - 1);
appendIndent(buffer, level);
buffer.append(startTag);
buffer.append("\n");
for (FakeCompositeNode child : myChildren) {
buffer.append(child.toPresentableSting(level + 1));
}
appendIndent(buffer, level);
buffer.append("</").append(tagName).append("> ");
buffer.append("\n");
}
}
}
return buffer.toString();
}
private static void appendIndent(final StringBuilder buffer, final int level) {
for (int i = 0; i < level; i++) {
buffer.append(" ");
}
}
@Override
public void tooManyChildren(int remaining) {
}
@Override
public void setErrorMessage(@NotNull String errorMessage) {
}
@Override
public void setErrorMessage(@NotNull String errorMessage, @Nullable XDebuggerTreeNodeHyperlink link) {
}
@Override
public void setMessage(@NotNull String message,
final Icon icon, @NotNull final SimpleTextAttributes attributes, @Nullable XDebuggerTreeNodeHyperlink link) {
}
@Override
public boolean isObsolete() {
return false;
}
}
}