package com.peterhi.io;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import com.peterhi.ClassComparator;
import com.peterhi.property.PropDescriptor;
import com.peterhi.property.PropException;
import com.peterhi.property.PropModel;
interface PmIoConstants {
int RT_NULL = 0;
int RT_BOOLEAN = 1;
int RT_BYTE = 2;
int RT_CHARACTER = 3;
int RT_SHORT = 4;
int RT_INTEGER = 5;
int RT_LONG = 6;
int RT_FLOAT = 7;
int RT_DOUBLE = 8;
int RT_INTEGER24 = 9;
int RT_INTEGERX_SIGNED = 10;
int RT_INTEGERX_UNSIGNED = 11;
int RT_BOOLEANS = 12;
int RT_BYTES = 13;
int RT_CHARS = 14;
int RT_SHORTS = 15;
int RT_INTS = 16;
int RT_LONGS = 17;
int RT_FLOATS = 18;
int RT_DOUBLES = 19;
int RT_INT24S = 20;
int RT_INTXS = 21;
int RT_UINTXS = 22;
int RT_CLASS = 23;
int RT_CLASSES = 24;
int RT_STRING = 25;
int RT_PROPMODEL = 26;
int RT_HASHSET = 27;
int RT_ARRAYLIST = 28;
int RT_HASHMAP = 29;
int RT_ARRAY = 30;
int NULL = 0;
int BOOL = 1;
int BYTE = 2;
int CHAR = 3;
int SHORT = 4;
int INT = 5;
int LONG = 6;
int FLOAT = 7;
int DOUBLE = 8;
int INT24 = 9;
int INTX = 10;
int UINTX = 11;
int BOOLS = 12;
int BYTES = 13;
int CHARS = 14;
int SHORTS = 15;
int INTS = 16;
int LONGS = 17;
int FLOATS = 18;
int DOUBLES = 19;
int INT24S = 20;
int INTXS = 21;
int UINTXS = 22;
int TYPE = 23;
int TYPES = 24;
int TYPE_EXPR = 25;
int STRING = 26;
int HASH_SET = 27;
int ARRAY_LIST = 28;
int HASH_MAP = 29;
int PROPERTY_SINK = 30;
int ARRAY = 31;
}
class PmLookup implements Map<Class<?>, List<PropModel>> {
private final Map<Class<?>, List<PropModel>> map;
private final PropModel root;
public PmLookup(PropModel root) throws PropException {
if (root == null) {
String message = "The root is null.";
throw new IllegalArgumentException(message);
}
Map<Class<?>, List<PropModel>> map =
new TreeMap<Class<?>, List<PropModel>>(
ClassComparator.getSingleton());
build(root, map);
elevate(root, map);
this.root = root;
this.map = Collections.unmodifiableMap(map);
}
public PmLookup(TypeExpr types, int[] counts) throws InstantiationException,
IllegalAccessException {
if (types == null) {
String message = "The types is null.";
throw new IllegalArgumentException(message);
}
if (counts == null) {
String message = "The counts is null.";
throw new IllegalArgumentException(message);
}
types.verify(true);
if (types.size() != counts.length) {
String message = "Types and counts size mismatch.";
throw new IllegalArgumentException(message);
}
Map<Class<?>, List<PropModel>> map =
new TreeMap<Class<?>, List<PropModel>>(
ClassComparator.getSingleton());
this.root = instantiate(types, counts, map);
this.map = Collections.unmodifiableMap(map);
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public List<PropModel> get(Object key) {
return map.get(key);
}
@Override
public List<PropModel> put(Class<?> key, List<PropModel> value) {
return map.put(key, value);
}
@Override
public List<PropModel> remove(Object key) {
return map.remove(key);
}
@Override
public void putAll(Map<? extends Class<?>, ? extends List<PropModel>> m) {
map.putAll(m);
}
@Override
public void clear() {
map.clear();
}
@Override
public Set<Class<?>> keySet() {
return map.keySet();
}
@Override
public Collection<List<PropModel>> values() {
return map.values();
}
@Override
public Set<java.util.Map.Entry<Class<?>, List<PropModel>>> entrySet() {
return map.entrySet();
}
public PropModel getRootModel() {
return root;
}
public int count() {
int count = 0;
for (List<PropModel> list : values()) {
count += list.size();
}
return count;
}
public int indexOf(PropModel model) {
int counter = 0;
for (List<PropModel> list : values()) {
for (PropModel element : list) {
if (element.equals(model)) {
return counter;
}
counter++;
}
}
return -1;
}
public PropModel get(int index) {
int counter = 0;
for (List<PropModel> list : values()) {
for (PropModel element : list) {
if (counter == index) {
return element;
}
counter++;
}
}
return null;
}
public Class<?>[] getTypes() {
return keySet().toArray(new Class[size()]);
}
private void build(Object current, Map<Class<?>, List<PropModel>> map)
throws PropException {
if (current == null) {
return;
}
if (current instanceof Collection) {
Collection<?> c = (Collection<?> )current;
for (Object e : c) {
build(e, map);
}
} else if (current instanceof Map) {
Map<?, ?> m = (Map<?, ?> )current;
for (Map.Entry<?, ?> e : m.entrySet()) {
Object k = e.getKey();
Object v = e.getValue();
build(k, map);
build(v, map);
}
} else if (current instanceof PropModel) {
PropModel model = (PropModel )current;
Class<?> type = model.getClass();
List<PropModel> list = map.get(type);
if (list == null) {
list = new ArrayList<PropModel>();
map.put(type, list);
}
if (list.contains(model)) {
return;
}
list.add(model);
Set<PropDescriptor> descs = PropDescriptor.getDescriptors(type);
for (PropDescriptor desc : descs) {
Object v = desc.get(model);
build(v, map);
}
} else if (current.getClass().isArray()) {
int length = Array.getLength(current);
for (int i = 0; i < length; i++) {
Object e = Array.get(current, i);
build(e, map);
}
}
}
private void elevate(PropModel root, Map<Class<?>, List<PropModel>> map) {
Class<?> type = root.getClass();
List<PropModel> list = map.get(type);
list.remove(root);
list.add(0, root);
}
private PropModel instantiate(TypeExpr classes, int[] counts,
Map<Class<?>, List<PropModel>> map) throws InstantiationException,
IllegalAccessException {
Class<?>[] types = classes.getTypes();
for (int i = 0; i < types.length; i++) {
Class<?> type = types[i];
int count = counts[i];
List<PropModel> list = new ArrayList<PropModel>();
for (int j = 0; j < count; j++) {
list.add((PropModel )type.newInstance());
}
map.put(type, list);
}
Class<?> mtype = classes.getMainType();
List<PropModel> mlist = map.get(mtype);
return mlist.get(0);
}
}