/*
* Copyright 2008-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nominanuda.dataview;
import java.util.Collection;
import java.util.Collections;
import com.nominanuda.zen.common.Check;
import com.nominanuda.zen.obj.Arr;
import com.nominanuda.zen.obj.JsonType;
import com.nominanuda.zen.obj.Obj;
public final class DataView<T> {
private Collection<String> wildcardProps = Collections.emptySet();// = Arrays.asList("id", "title");
private DataViewDef viewDef;
private PropertyReader<T> pReader;// = (PropertyReader<T>)new MapPropertyReader<T>();
public Obj render(T obj) {
Check.illegalargument.assertTrue(pReader.accepts(obj));
return compileObject(obj, viewDef);
}
//TODO array of array not supported
private Obj compileObject(T m, DataViewDef viewDef) {
Obj res = Obj.make();
for(String k : pReader.readableProps(m)) {
if(! (viewDef.isTraversable(k) || wildcardProps.contains(k))) {
continue;
}
Object v = pReader.read(m, k);
if(v == null) {
continue;
} else if(v instanceof Collection<?>) {
if(viewDef.isTraversable(k)) {
Arr arr = res.arr(k);
for(Object o : (Collection<?>)v) {
Object x = evalScalarOrObject(k, o, viewDef);
arr.add(x);
}
}
} else {
Object x = evalScalarOrObject(k, v, viewDef);
if(x != null) {
res.put(k, x);
}
}
}
return res;
}
private Object evalScalarOrObject(String k, Object v, DataViewDef viewDef) {
if(v == null) {
return null;
} else if(JsonType.isNullablePrimitive(v)) {
return v;
} else if(pReader.accepts(v)) {
T m = (T)v;
if(viewDef.isTraversable(k)) {
return compileObject(m, viewDef.traverse(k));
} else if(hasAny(m, wildcardProps)) {
Obj o = Obj.make();
for(String p : wildcardProps) {
if(pReader.hasProp(m, p)) {
o.put(p, pReader.read(m, p));
}
}
return o;
} else {
return compileObject(m, viewDef.traverseNoChek(k));
}
} else {//bail out
throw new IllegalArgumentException(
"type "+v.getClass().getName() + " not supported @ "+viewDef.soFar());
}
}
private boolean hasAny(T t, Collection<String> props) {
for(String p : pReader.readableProps(t)) {
if(props.contains(p)) {
return true;
}
}
return false;
}
public void setWildcardProps(Collection<String> wildcardProps) {
this.wildcardProps = wildcardProps;
}
public void setViewDef(String viewDef) {
this.viewDef = new DataViewDef(viewDef);
}
public void setPropertyReader(PropertyReader<T> pReader) {
this.pReader = pReader;
}
}