package http.resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import nebula.data.Broker;
import nebula.data.DataRepos;
import nebula.data.DataStore;
import nebula.data.DataWatcher;
import nebula.data.Entity;
import nebula.data.impl.EditableEntity;
import nebula.data.json.DataHelper;
import nebula.data.json.JsonHelperProvider;
import nebula.flow.FlowEngine;
import nebula.lang.Flow;
import nebula.lang.Flow.Step;
import nebula.lang.RuntimeContext;
import nebula.lang.Type;
import nebula.server.Resource;
import nebula.server.ResourceEngine;
public class FlowResouce extends AbstractResouce implements ResourceEngine {
static final String Field_Flow_ID = "FlowID";
static final String Field_Step_Name = "StepName";
static final String Field_GetAction_Name = "$getaction";
static final String Field_Action_Name = "$action";
final FlowEngine engine;
private Flow flow;
private final DataStore<Entity> datastore;
private final Map<String, DataHelper<Entity, Reader, Writer>> stepJsons;
private final Map<String, DataHelper<Entity, Reader, Writer>> stepRawJsons;
// private final DataRepos dataRepos;
private long id;
public FlowResouce(final DataRepos dataRepos, DataStore<Entity> datas, Type type, String id) {
super("text/json", 1, 1);
// this.dataRepos = dataRepos;
this.datastore = datas;
this.id = Long.parseLong(id);
Broker.brokerOf(type).addWatcher(new DataWatcher<Type>() {
@Override
public boolean onUpdate(Type newData, Type oldData) {
flow = (Flow) newData;
return false;
}
});
this.engine = new FlowEngine(dataRepos, this.flow);
stepJsons = new HashMap<String, DataHelper<Entity, Reader, Writer>>();
for (Step step : this.flow.getSteps()) {
stepJsons.put(step.getName(), JsonHelperProvider.getFlowHelper(type, step.getType()));
}
stepRawJsons = new HashMap<String, DataHelper<Entity, Reader, Writer>>();
for (Step step : this.flow.getSteps()) {
stepRawJsons.put(step.getName(), JsonHelperProvider.getHelper(step.getType()));
}
// jsonflow = JsonHelperProvider.getHelper(type);
}
@Override
protected void get(HttpServletRequest req) throws IOException {
Entity data = datastore.get(id).editable();
if (!req.getParameterMap().containsKey("history")) {
List<Entity> steps = data.get("steps");
Entity currentStepEntity = steps.get(steps.size() - 1);
Step currentStep = flow.getSteps().get((String) currentStepEntity.get(Step.Field_ActualCurrrentStep));
DataHelper<Entity, Reader, Writer> jsonStep = this.stepJsons.get(currentStep.getName());
data.put(Flow.Field_CurrrentStepEntity, currentStepEntity);
datastore.clearChanges();
long newModified = System.currentTimeMillis();
ByteArrayOutputStream bout = null;
try {
bout = new ByteArrayOutputStream();
Writer write = new OutputStreamWriter(bout);
jsonStep.stringifyTo(data, write);
write.flush();
this.lastModified = newModified;
this.cache = bout.toByteArray();
} finally {
try {
if (bout != null) bout.close();
} catch (Exception e) {
}
}
} else {
List<Entity> steps = data.get("steps");
datastore.clearChanges();
long newModified = System.currentTimeMillis();
ByteArrayOutputStream bout = null;
boolean start = true;
try {
bout = new ByteArrayOutputStream();
Writer write = new OutputStreamWriter(bout);
write.write('{');
write.write("\"ID\":");
write.write(String.valueOf(data.getID()));
write.write(',');
write.write("\"steps\":[");
for (Entity entity : steps) {
if(!start){
write.write(',');
}
write.write('{');
Step currentStep = flow.getSteps().get((String) entity.get(Step.Field_ActualCurrrentStep));
DataHelper<Entity, Reader, Writer> jsonStep = this.stepRawJsons.get(currentStep.getName());
write.write("\"StepName\":");
write.write('\"');
write.write(currentStep.getName());
write.write('\"');
write.write(',');
write.write("\"StepData\":");
jsonStep.stringifyTo(entity, write);
write.write("}");
start = false;
}
write.write("]");
write.write("}");
write.flush();
this.lastModified = newModified;
this.cache = bout.toByteArray();
} finally {
try {
if (bout != null) bout.close();
} catch (Exception e) {
}
}
}
}
@Override
protected void put(HttpServletRequest req) throws IOException {
Entity readonly = datastore.get(id);
if (readonly != null) {
Entity data = readonly.editable();
List<Entity> steps = data.get("steps");
Entity currentStepEntity = steps.get(steps.size() - 1);
Step currentStep = flow.getSteps().get((String) currentStepEntity.get(Step.Field_ActualCurrrentStep));
DataHelper<Entity, Reader, Writer> jsonStep = this.stepJsons.get(currentStep.getName());
data.put(Flow.Field_CurrrentStepEntity, currentStepEntity);
jsonStep.readFrom(data, new InputStreamReader(req.getInputStream()));
currentStepEntity = data.getEntity(Flow.Field_CurrrentStepEntity);
String action = req.getParameter("$action");
if (action != null && !"save".equals(action)) {
RuntimeContext context = new RuntimeContext();
engine.stepSubmit(context, action, (EditableEntity) data);
}
} else {
throw new RuntimeException("Cann't find object " + id);
}
}
@Override
protected void delete(HttpServletRequest req) {
throw new RuntimeException("Cann't find object " + flow.getName());
}
@Override
public Resource resolve(String path) {
// TODO Auto-generated method stub
return null;
}
}