package com.venky.swf.integration;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.venky.core.io.ByteArrayInputStream;
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.SWFHttpResponse;
import com.venky.swf.db.model.io.ModelIOFactory;
import com.venky.swf.db.model.io.ModelReader;
import com.venky.swf.db.model.io.ModelWriter;
import com.venky.swf.db.model.reflection.ModelReflector;
import com.venky.swf.path.Path;
import com.venky.swf.views.BytesView;
import com.venky.swf.views.View;
public class IntegrationAdaptor<M extends Model,T> {
ModelReader<M,T> reader ;
ModelWriter<M,T> writer ;
ModelReflector<M> modelReflector;
Class<T> formatClass ;
private IntegrationAdaptor(Class<M> modelClass,Class<T> formatClass){
this.formatClass = formatClass;
this.reader = ModelIOFactory.getReader(modelClass, formatClass);
this.writer = ModelIOFactory.getWriter(modelClass, formatClass);
this.modelReflector = ModelReflector.instance(modelClass);
}
public Class<T> getFormatClass(){
return formatClass;
}
public MimeType getMimeType(){
return FormatHelper.getMimeType(getFormatClass());
}
public static <M extends Model,T> IntegrationAdaptor<M, T> instance(Class<M> modelClass,Class<T> formatType){
IntegrationAdaptor<M, T> adaptor = null;
MimeType mimeType = FormatHelper.getMimeType(formatType);
switch (mimeType){
case APPLICATION_JSON:
case APPLICATION_XML:
adaptor = new IntegrationAdaptor<M, T>(modelClass, formatType);
break;
default:
break;
}
return adaptor;
}
public List<M> readRequest(Path path){
try {
InputStream is = path.getRequest().getInputStream();
is = new ByteArrayInputStream(StringUtil.readBytes(is));
return reader.read(is);
}catch(IOException ex){
throw new RuntimeException(ex);
}
}
public View createResponse(Path path, List<M> models){
return createResponse(path,models, null);
}
public View createResponse(Path path, List<M> m, List<String> includeFields) {
return createResponse(path, m, includeFields, new HashMap<>());
}
public View createResponse(Path path, List<M> m, List<String> includeFields, Map<Class<? extends Model>, List<String>> childFields) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writer.write(m, baos, getFields(includeFields),childFields);
return new BytesView(path, baos.toByteArray());
}catch (IOException ex){
throw new RuntimeException(ex);
}
}
public View createResponse(Path path, M m){
return createResponse(path, m,null);
}
public View createResponse(Path path, M m, List<String> includeFields) {
return createResponse(path, m,includeFields, new HashMap<>());
}
public View createResponse(Path path, M m, List<String> includeFields, Map<Class<? extends Model>, List<String>> childFields) {
FormatHelper<T> helper = FormatHelper.instance(getMimeType(),modelReflector.getModelClass().getSimpleName(),false);
T element = helper.getRoot();
T elementAttribute = helper.getElementAttribute(modelReflector.getModelClass().getSimpleName());
if (elementAttribute == null) {
elementAttribute = element;
}
writer.write(m, elementAttribute , getFields(includeFields), childFields);
return new BytesView(path, helper.toString().getBytes());
}
private List<String> getFields(List<String> includeFields) {
List<String> fields = includeFields;
if (fields == null){
fields = modelReflector.getFields();
Iterator<String> fi = fields.iterator();
while (fi.hasNext()){
String field = fi.next();
if (modelReflector.isFieldHidden(field) && !"ID".equalsIgnoreCase(field)){
fi.remove();
}
}
}
return fields;
}
public void writeResponse(List<M> m, OutputStream os){
writeResponse(m, os,null);
}
public void writeResponse(List<M> m, OutputStream os,List<String> includeFields){
try {
writer.write(m, os, getFields(includeFields));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public View createStatusResponse(Path path, Throwable th){
IntegrationAdaptor<SWFHttpResponse,T> respAdaptor = IntegrationAdaptor.instance(SWFHttpResponse.class, getFormatClass());
SWFHttpResponse response = Database.getTable(SWFHttpResponse.class).newRecord();
if (th == null){
response.setStatus("OK");
return respAdaptor.createResponse(path,response,Arrays.asList("STATUS"));
}else {
response.setStatus("FAILED");
response.setError(th.getMessage());
return respAdaptor.createResponse(path,response,Arrays.asList(new String[]{"STATUS","ERROR"}));
}
}
}