package com.ripple.core.coretypes;
import com.ripple.core.fields.Field;
import com.ripple.core.fields.PathSetField;
import com.ripple.core.fields.Type;
import com.ripple.core.serialized.BinaryParser;
import com.ripple.core.serialized.BytesSink;
import com.ripple.core.serialized.SerializedType;
import com.ripple.core.serialized.TypeTranslator;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
public class PathSet extends ArrayList<PathSet.Path> implements SerializedType {
public static byte PATH_SEPARATOR_BYTE = (byte) 0xFF;
public static byte PATHSET_END_BYTE = (byte) 0x00;
public PathSet(){}
public static class Hop {
public static byte TYPE_ACCOUNT = (byte) 0x01;
public static byte TYPE_CURRENCY = (byte) 0x10;
public static byte TYPE_ISSUER = (byte) 0x20;
public static final int TYPE_ACCOUNT_CURRENCY_ISSUER = TYPE_CURRENCY | TYPE_ACCOUNT | TYPE_ISSUER;
public static final int TYPE_ACCOUNT_CURRENCY = TYPE_CURRENCY | TYPE_ACCOUNT;
public static int VALID_TYPE_MASK = ~(TYPE_ACCOUNT | TYPE_CURRENCY | TYPE_ISSUER);
public AccountID account;
public AccountID issuer;
public Currency currency;
private int type;
public boolean hasIssuer() {
return issuer != null;
}
public boolean hasCurrency() {
return currency != null;
}
public boolean hasAccount() {
return account != null;
}
public int getType() {
if (type == 0) {
synthesizeType();
}
return type;
}
static public Hop fromJSONObject(JSONObject json) {
Hop hop = new Hop();
if (json.has("account")) {
hop.account = AccountID.fromAddress(json.getString("account"));
}
if (json.has("issuer")) {
hop.issuer = AccountID.fromAddress(json.getString("issuer"));
}
if (json.has("currency")) {
hop.currency = Currency.fromString(json.getString("currency"));
}
if (json.has("type")) {
hop.type = json.getInt("type");
}
return hop;
}
public void synthesizeType() {
type = 0;
if (hasAccount()) type |= TYPE_ACCOUNT;
if (hasCurrency()) type |= TYPE_CURRENCY;
if (hasIssuer()) type |= TYPE_ISSUER;
}
public JSONObject toJSONObject() {
JSONObject object = new JSONObject();
object.put("type", getType());
if (hasAccount()) object.put("account", account.toJSON());
if (hasIssuer()) object.put("issuer", issuer.toJSON());
if (hasCurrency()) object.put("currency", currency.toJSON());
return object;
}
}
public static class Path extends ArrayList<Hop> {
static public Path fromJSONArray(JSONArray array) {
Path path = new Path();
int nHops = array.length();
for (int i = 0; i < nHops; i++) {
JSONObject hop = array.getJSONObject(i);
path.add(Hop.fromJSONObject(hop));
}
return path;
}
public JSONArray toJSONArray() {
JSONArray array = new JSONArray();
for (Hop hop : this) {
array.put(hop.toJSONObject());
}
return array;
}
}
public JSONArray toJSONArray() {
JSONArray array = new JSONArray();
for (Path path : this) {
array.put(path.toJSONArray());
}
return array;
}
// SerializedType interface implementation
@Override
public Object toJSON() {
return toJSONArray();
}
@Override
public void toBytesSink(BytesSink buffer) {
int n = 0;
for (Path path : this) {
if (n++ != 0) {
buffer.add(PATH_SEPARATOR_BYTE);
}
for (Hop hop : path) {
int type = hop.getType();
buffer.add((byte) type);
if (hop.hasAccount()) {
buffer.add(hop.account.bytes());
}
if (hop.hasCurrency()) {
buffer.add(hop.currency.bytes());
}
if (hop.hasIssuer()) {
buffer.add(hop.issuer.bytes());
}
}
}
buffer.add(PATHSET_END_BYTE);
}
@Override
public Type type() {
return Type.PathSet;
}
@Override
public String toHex() {
return translate.toHex(this);
}
@Override
public byte[] toBytes() {
return translate.toBytes(this);
}
public static class Translator extends TypeTranslator<PathSet> {
@Override
public PathSet fromParser(BinaryParser parser, Integer hint) {
PathSet pathSet = new PathSet();
PathSet.Path path = null;
while (!parser.end()) {
byte type = parser.readOne();
if (type == PATHSET_END_BYTE) {
break;
}
if (path == null) {
path = new PathSet.Path();
pathSet.add(path);
}
if (type == PATH_SEPARATOR_BYTE) {
path = null;
continue;
}
PathSet.Hop hop = new PathSet.Hop();
path.add(hop);
if ((type & Hop.TYPE_ACCOUNT) != 0) {
hop.account = AccountID.translate.fromParser(parser);
}
if ((type & Hop.TYPE_CURRENCY) != 0) {
hop.currency = Currency.translate.fromParser(parser);
}
if ((type & Hop.TYPE_ISSUER) != 0) {
hop.issuer = AccountID.translate.fromParser(parser);
}
}
return pathSet;
}
@Override
public PathSet fromJSONArray(JSONArray array) {
PathSet paths = new PathSet();
int nPaths = array.length();
for (int i = 0; i < nPaths; i++) {
JSONArray path = array.getJSONArray(i);
paths.add(Path.fromJSONArray(path));
}
return paths;
}
}
static public Translator translate = new Translator();
public static PathSetField pathsetField(final Field f) {
return new PathSetField(){ @Override public Field getField() {return f;}};
}
static public PathSetField Paths = pathsetField(Field.Paths);
}