package com.jsoniter.any;
import com.jsoniter.ValueType;
import com.jsoniter.output.JsonStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
class MapWrapperAny extends Any {
private final Map val;
private Map<String, Any> cache;
public MapWrapperAny(Map val) {
this.val = val;
}
@Override
public ValueType valueType() {
return ValueType.OBJECT;
}
@Override
public Object object() {
fillCache();
return cache;
}
@Override
public boolean toBoolean() {
return size() != 0;
}
@Override
public int toInt() {
return size();
}
@Override
public long toLong() {
return size();
}
@Override
public float toFloat() {
return size();
}
@Override
public double toDouble() {
return size();
}
@Override
public String toString() {
if (cache == null) {
return JsonStream.serialize(val);
} else {
fillCache();
return JsonStream.serialize(cache);
}
}
@Override
public void writeTo(JsonStream stream) throws IOException {
if (cache == null) {
stream.writeVal(val);
} else {
fillCache();
stream.writeVal(cache);
}
}
@Override
public int size() {
return val.size();
}
@Override
public Any get(Object key) {
return fillCacheUntil(key);
}
@Override
public Any get(Object[] keys, int idx) {
if (idx == keys.length) {
return this;
}
Object key = keys[idx];
if (isWildcard(key)) {
fillCache();
HashMap<String, Any> result = new HashMap<String, Any>();
for (Map.Entry<String, Any> entry : cache.entrySet()) {
Any mapped = entry.getValue().get(keys, idx + 1);
if (mapped.valueType() != ValueType.INVALID) {
result.put(entry.getKey(), mapped);
}
}
return Any.rewrap(result);
}
Any child = fillCacheUntil(key);
if (child == null) {
return new NotFoundAny(keys, idx, object());
}
return child.get(keys, idx + 1);
}
@Override
public EntryIterator entries() {
return new WrapperIterator();
}
private Any fillCacheUntil(Object target) {
if (cache == null) {
cache = new HashMap<String, Any>();
}
Any element = cache.get(target);
if (element != null) {
return element;
}
Set<Map.Entry<String, Object>> entries = val.entrySet();
int targetHashcode = target.hashCode();
for (Map.Entry<String, Object> entry : entries) {
String key = entry.getKey();
if (cache.containsKey(key)) {
continue;
}
element = Any.wrap(entry.getValue());
cache.put(key, element);
if (targetHashcode == key.hashCode() && target.equals(key)) {
return element;
}
}
return new NotFoundAny(target, val);
}
private void fillCache() {
if (cache == null) {
cache = new HashMap<String, Any>();
}
Set<Map.Entry<String, Object>> entries = val.entrySet();
for (Map.Entry<String, Object> entry : entries) {
String key = entry.getKey();
if (cache.containsKey(key)) {
continue;
}
Any element = Any.wrap(entry.getValue());
cache.put(key, element);
}
}
private class WrapperIterator implements EntryIterator {
private final Iterator<Map.Entry<String, Object>> iter;
private String key;
private Any value;
private WrapperIterator() {
Set<Map.Entry<String, Object>> entries = val.entrySet();
iter = entries.iterator();
}
@Override
public boolean next() {
if (cache == null) {
cache = new HashMap<String, Any>();
}
if (!iter.hasNext()) {
return false;
}
Map.Entry<String, Object> entry = iter.next();
key = entry.getKey();
value = cache.get(key);
if (value == null) {
value = Any.wrap(entry.getValue());
cache.put(key, value);
}
return true;
}
@Override
public String key() {
return key;
}
@Override
public Any value() {
return value;
}
}
}