package com.intellij.flex.uiDesigner.io;
import com.intellij.flex.uiDesigner.LogMessageUtil;
import com.intellij.openapi.components.ServiceManager;
import gnu.trove.TObjectIntProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class StringRegistry {
private final TransactionableStringIntHashMap table = new TransactionableStringIntHashMap(1024, 1);
private StringWriter activeWriter;
public static StringRegistry getInstance() {
return ServiceManager.getService(StringRegistry.class);
}
private void startChange(StringWriter activeWriter) {
table.startTransaction();
assert this.activeWriter == null;
this.activeWriter = activeWriter;
}
private void rollbackChange(StringWriter requestor) {
table.rollbackTransaction();
LogMessageUtil.LOG.assertTrue(activeWriter == null || activeWriter == requestor);
resetAfterChange(requestor);
}
private void commitChange(StringWriter requestor) {
resetAfterChange(requestor);
}
private void resetAfterChange(StringWriter requestor) {
LogMessageUtil.LOG.assertTrue(activeWriter == null || activeWriter == requestor);
activeWriter = null;
}
public void reset() {
table.clear();
assert activeWriter == null;
}
public boolean isEmpty() {
return table.isEmpty();
}
public String[] toArray() {
final String[] strings = new String[table.size()];
table.forEachEntry(new TObjectIntProcedure<String>() {
@Override
public boolean execute(String v, int id) {
strings[id - 1] = v;
return true;
}
});
return strings;
}
private int getNameReference(String string, StringWriter writer) {
assert activeWriter == writer;
int reference = table.get(string);
if (reference == -1) {
reference = table.size() + 1;
table.put(string, reference);
writer.counter++;
writer.out.writeAmfUtf(string, false);
}
return reference;
}
public static class StringWriter {
private final StringRegistry stringRegistry;
private final PrimitiveAmfOutputStream out;
private int counter;
public StringWriter(StringRegistry stringRegistry) {
this(stringRegistry, 1024);
}
public StringWriter() {
this(StringRegistry.getInstance());
}
public StringWriter(int size) {
this(StringRegistry.getInstance(), size);
}
public StringWriter(StringRegistry stringRegistry, int size) {
this.stringRegistry = stringRegistry;
out = new PrimitiveAmfOutputStream(new ByteArrayOutputStreamEx(size));
}
public void startChange() {
//LogMessageUtil.LOG.info("startChange", new Exception());
stringRegistry.startChange(this);
}
public void rollback() {
//LogMessageUtil.LOG.info("rollback", new Exception());
reset();
stringRegistry.rollbackChange(this);
}
public void commit() {
//LogMessageUtil.LOG.info("commit", new Exception());
reset();
stringRegistry.commitChange(this);
}
private void reset() {
counter = 0;
out.reset();
}
public int getReference(@NotNull String string) {
return stringRegistry.getNameReference(string, this);
}
public void write(@NotNull String string, @NotNull PrimitiveAmfOutputStream out) {
out.writeUInt29(getReference(string));
}
public boolean writeNullable(@Nullable String string, PrimitiveAmfOutputStream out) {
if (string == null) {
out.write(0);
return false;
}
else {
out.writeUInt29(getReference(string));
return true;
}
}
public int size() {
return IOUtil.uint29SizeOf(counter) + out.size();
}
public void writeToIfStarted(PrimitiveAmfOutputStream to) {
if (stringRegistry.activeWriter == null) {
assert counter == 0;
to.writeUInt29(0);
return;
}
writeTo(to);
}
public void writeTo(PrimitiveAmfOutputStream to) {
to.writeUInt29(counter);
out.writeTo(to);
commit();
}
public boolean hasChanges() {
return counter != 0;
}
}
}