package com.venky.swf.db.model.io;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.venky.core.string.StringUtil;
import com.venky.swf.db.Database;
import com.venky.swf.db.annotations.column.ui.mimes.MimeType;
import com.venky.swf.db.model.Model;
import com.venky.swf.db.model.reflection.ModelReflector;
import com.venky.swf.integration.FormatHelper;
public abstract class AbstractModelWriter<M extends Model,T> extends ModelIO<M> implements ModelWriter<M, T>{
protected AbstractModelWriter(Class<M> beanClass) {
super(beanClass);
}
@SuppressWarnings("unchecked")
public Class<T> getFormatClass(){
ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
return (Class<T>) pt.getActualTypeArguments()[1];
}
public MimeType getMimeType(){
return FormatHelper.getMimeType(getFormatClass());
}
public void write(List<M> records, OutputStream os,List<String> fields) throws IOException {
Map<Class<? extends Model> , List<String>> mapFields = new HashMap<Class<? extends Model>, List<String>>();
write (records,os,fields,mapFields);
}
public void write (List<M> records,OutputStream os, List<String> fields, Map<Class<? extends Model>,List<String>> childFields) throws IOException {
FormatHelper<T> helper = FormatHelper.instance(getMimeType(),StringUtil.pluralize(getBeanClass().getSimpleName()),true);
for (M record: records){
T childElement = helper.createChildElement(getBeanClass().getSimpleName());
write(record,childElement,fields,childFields);
}
os.write(helper.toString().getBytes());
}
public void write(M record,T into, List<String> fields){
write(record,into,fields,new HashMap<>());
}
public void write(M record,T into, List<String> fields,Map<Class<? extends Model>,List<String>> childFields) {
FormatHelper<T> formatHelper = FormatHelper.instance(into);
ModelReflector<M> ref = getReflector();
for (String field: fields){
Object value = ref.get(record, field);
if (value == null){
continue;
}
Method fieldGetter = ref.getFieldGetter(field);
Method referredModelGetter = ref.getReferredModelGetterFor(fieldGetter);
if (referredModelGetter != null){
String refElementName = referredModelGetter.getName().substring("get".length());
T refElement = formatHelper.createElementAttribute(refElementName);
write(ref.getReferredModelClass(referredModelGetter) , ((Number)value).intValue(),refElement);
}else {
String attributeName = getAttributeName(field);
String sValue = Database.getJdbcTypeHelper(getReflector().getPool()).getTypeRef(fieldGetter.getReturnType()).getTypeConverter().toStringISO(value);
formatHelper.setAttribute(attributeName, sValue);
}
}
if (!childFields.isEmpty()){
List<Method> childGetters = ref.getChildGetters();
for (Method childGetter : childGetters) {
write(formatHelper,record,childGetter,childFields);
}
}
}
private <R extends Model> void write(FormatHelper<T> formatHelper, M record, Method childGetter, Map<Class<? extends Model>, List<String>> childFields){
@SuppressWarnings("unchecked")
Class<R> childModelClass = (Class<R>) getReflector().getChildModelClass(childGetter);
if (!childFields.containsKey(childModelClass)){
return;
}
ModelWriter<R,T> childWriter = ModelIOFactory.getWriter(childModelClass, getFormatClass());
try {
@SuppressWarnings("unchecked")
List<R> children = (List<R>)childGetter.invoke(record);
for (R child : children){
T childElement = formatHelper.createChildElement(childModelClass.getSimpleName());
childWriter.write(child,childElement,childFields.get(childModelClass),childFields);
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private <R extends Model> void write(Class<R> referredModelClass, int id , T referredModelElement){
Class<T> formatClass = getFormatClass();
ModelWriter<R,T> writer = ModelIOFactory.getWriter(referredModelClass,formatClass);
R referredModel = Database.getTable(referredModelClass).get(id);
ModelReflector<R> referredModelReflector = ModelReflector.instance(referredModelClass);
List<String> uniqueFields = referredModelReflector.getUniqueFields();
for (Iterator<String> fi = uniqueFields.iterator(); fi.hasNext();){
String f = fi.next();
if (referredModelReflector.isFieldHidden(f)){
fi.remove();
}
}
uniqueFields.add("ID");
writer.write(referredModel , referredModelElement, uniqueFields);
}
}