package com.intellij.flex.uiDesigner.mxml;
import com.intellij.flex.uiDesigner.InvalidPropertyException;
import com.intellij.flex.uiDesigner.ProblemsHolder;
import com.intellij.flex.uiDesigner.io.ByteRange;
import com.intellij.flex.uiDesigner.io.PrimitiveAmfOutputStream;
import com.intellij.lang.javascript.flex.AnnotationBackedDescriptor;
import com.intellij.lang.javascript.psi.JSVariable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.xml.XmlTag;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
class InjectedASWriter implements ValueReferenceResolver {
private final THashMap<String, MxmlObjectReference> idReferenceMap = new THashMap<>();
private final THashMap<JSVariable, VariableReference> variableReferenceMap = new THashMap<>();
private final List<Binding> bindingItems = new ArrayList<>();
private final BaseWriter writer;
private final ProblemsHolder problemsHolder;
private ByteRange declarationsRange;
final static ValueWriter IGNORE = new ValueWriter() {
@Override
public PropertyProcessor.PropertyKind write(AnnotationBackedDescriptor descriptor, XmlElementValueProvider valueProvider,
PrimitiveAmfOutputStream out, BaseWriter writer,
boolean isStyle, Context parentContext) {
throw new UnsupportedOperationException();
}
};
public InjectedASWriter(BaseWriter writer, ProblemsHolder problemsHolder) {
this.writer = writer;
this.problemsHolder = problemsHolder;
}
@NotNull
@Override
public VariableReference getValueReference(JSVariable jsVariable) {
return variableReferenceMap.get(jsVariable);
}
@Override
public VariableReference getNullableValueReference(JSVariable jsVariable) {
return variableReferenceMap.get(jsVariable);
}
@NotNull
@Override
public MxmlObjectReference getValueReference(String id) {
return idReferenceMap.get(id);
}
@Nullable
public MxmlObjectReference getNullableValueReference(String id) {
return idReferenceMap.get(id);
}
public ValueWriter processProperty(XmlElementValueProvider valueProvider, String name, @Nullable String type, boolean isStyle,
@NotNull MxmlObjectReferenceProvider mxmlObjectReferenceProvider) throws InvalidPropertyException {
final PsiLanguageInjectionHost host = valueProvider.getInjectedHost();
return host == null ? null : processProperty(host, name, type, isStyle, mxmlObjectReferenceProvider);
}
public ValueWriter processProperty(PsiElement host, String name, @Nullable String type, boolean isStyle, @NotNull MxmlObjectReferenceProvider mxmlObjectReferenceProvider)
throws InvalidPropertyException {
final InjectedPsiVisitor visitor = new InjectedPsiVisitor(host, type, problemsHolder);
InjectedLanguageUtil.enumerate(host, visitor);
//noinspection ThrowableResultOfMethodCallIgnored
if (visitor.getInvalidPropertyException() != null) {
throw visitor.getInvalidPropertyException();
}
else {
final Binding binding = visitor.getBinding();
if (binding != null) {
if (binding instanceof VariableBinding) {
JSVariable variable = ((VariableBinding)binding).variable;
VariableReference variableReference = variableReferenceMap.get(variable);
if (variableReference == null) {
variableReferenceMap.put(variable, new VariableReference(variable));
}
else {
variableReference.markAsMultipleReferred();
}
}
if (mxmlObjectReferenceProvider instanceof Context && ((Context)mxmlObjectReferenceProvider).getParentScope().staticObjectPointToScope || mxmlObjectReferenceProvider instanceof InnerComponentContext) {
MxmlWriter.LOG.warn("IDEA-86372 " + host.getText());
}
else {
binding.setTarget(mxmlObjectReferenceProvider.getMxmlObjectReference(), writer.getNameReference(name), isStyle);
bindingItems.add(binding);
}
return IGNORE;
}
else {
return visitor.getValueWriter();
}
}
}
public void readDeclarations(MxmlWriter mxmlWriter, XmlTag tag) {
declarationsRange = writer.getBlockOut().startRange();
mxmlWriter.processDeclarations(tag);
writer.getBlockOut().endRange(declarationsRange);
}
public void write() {
writeDeclarations();
writeBinding(writer.getOut());
}
private void writeDeclarations() {
ByteRange range = declarationsRange;
if (range == null) {
range = writer.getBlockOut().startRange();
writer.getOut().writeShort(0);
writer.getBlockOut().endRange(range);
}
else {
declarationsRange = null;
}
writer.prepend(range);
}
private void writeBinding(PrimitiveAmfOutputStream out) {
if (bindingItems.isEmpty()) {
out.writeShort(0);
return;
}
final int bindingSizePosition = out.allocateShort();
int size = bindingItems.size();
for (Binding binding : bindingItems) {
int beforePosition = out.size();
try {
binding.write(out, writer, this);
continue;
}
catch (UnsupportedOperationException e) {
MxmlWriter.LOG.warn("unsupported injected AS: " + e.getMessage());
}
catch (Throwable e) {
problemsHolder.add(e);
}
size--;
out.getByteOut().setPosition(beforePosition);
}
out.putShort(size, bindingSizePosition);
}
void putMxmlObjectReference(@NotNull String explicitId, @NotNull MxmlObjectReference mxmlObjectReference) {
idReferenceMap.put(explicitId, mxmlObjectReference);
}
}