package org.bonitasoft.simulation.reporting;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bonitasoft.simulation.engine.DefinitionPool;
import org.bonitasoft.simulation.engine.ResourcePool;
import org.bonitasoft.simulation.engine.RuntimeResource;
import org.bonitasoft.simulation.model.TimeUnit;
import org.bonitasoft.simulation.model.instance.SimActivityInstance;
import org.bonitasoft.simulation.model.instance.SimDataInstance;
import org.bonitasoft.simulation.model.instance.SimProcessInstance;
import org.bonitasoft.simulation.model.loadprofile.LoadProfile;
import org.bonitasoft.simulation.model.process.ResourceAssignement;
import org.bonitasoft.simulation.model.process.SimActivity;
import org.bonitasoft.simulation.model.process.SimData;
import org.bonitasoft.simulation.model.process.SimNumberData;
import org.bonitasoft.simulation.model.process.SimProcess;
import org.bonitasoft.simulation.model.resource.Resource;
public abstract class SimReport {
protected ISimulationStore store ;
protected LoadProfile loadProfile;
protected long simEndDate;
protected long simStartDate;
protected long timespan;
private long nextInterval;
protected String workspace;
protected Map<String, RuntimeResource> resourceConso;
protected long executionStart;
private static final int INSTANCE_BUFFER_SIZE = 1000;
public SimReport(String workspace, LoadProfile lp ,ISimulationStore iSimulationStore, long simStartDate,long simEndDate, long timespan, Map<String, RuntimeResource> resourceConso, long executionStart ) throws Exception{
this.loadProfile = lp ;
this.store = iSimulationStore ;
this.simStartDate = simStartDate ;
this.simEndDate = simEndDate ;
this.timespan = timespan ;
this.workspace = workspace ;
this.resourceConso = resourceConso;
this.executionStart =executionStart ;
}
public SimulationReportResultSet createSimulationReportResultSet(String processName) throws Exception{
SimulationReportResultSet result = new SimulationReportResultSet();
Set<String> availableUnit = new HashSet<String>();
for(Resource r : DefinitionPool.getInstance().getResourceDefinitions()){
result.addResourceResultSet(r.getName(), new ResourceResultSet(ResourcePool.getInstance().getResourceInstances().get(r.getName())));
availableUnit.add(r.getCostUnit()) ;
}
result.addProcessResultSet(processName, new ProcessResultSet(DefinitionPool.getInstance().getProcessDefinition(processName),availableUnit));
for(SimData d : DefinitionPool.getInstance().getProcessDefinition(processName).getData()){
result.addDataResultSet(d.getName(), new DataResultSet(d)) ;
}
for(SimActivity a : DefinitionPool.getInstance().getActivityDefinition(processName)){
result.addActivityResultSet(a.getName(), new ActivityResultSet(DefinitionPool.getInstance().getProcessDefinition(processName),a)) ;
}
nextInterval = simStartDate + timespan ;
List<SimProcessInstance> instances = store.getStoredFinishedProcessInstances(INSTANCE_BUFFER_SIZE) ;
while(instances.size() > 0){
for(SimProcessInstance instance : instances){
long instanceEnd = instance.getEndDate() ;
long startDate = instance.getStartDate() ;
if(instanceEnd >= nextInterval && nextInterval != simEndDate){
updateProcessResultSet(nextInterval,result) ;
updateActivityResultSet(nextInterval,result) ;
updateResourceResultSet(nextInterval,result) ;
nextInterval = nextInterval + timespan ;
if(nextInterval > simEndDate){
nextInterval = simEndDate ;
}
}
Set<SimActivityInstance> parsed = new HashSet<SimActivityInstance>();
parseProcessInstance(instance.getStartElemInstances(),parsed,result);
updateDataResultSet(instance, result) ;
ProcessResultSet rSet = result.getProcessResultSet(processName) ;
rSet.setInstanceTime(instanceEnd-startDate);
for(Resource r : DefinitionPool.getInstance().getResourceDefinitions()){
result.getResourceResultSet(r.getName()).updateResourceConsumption();
result.getResourceResultSet(r.getName()).updateResourceCost();
long workableTime = r.getPlanning().getWorkingPlanningDuration(startDate, instanceEnd)*resourceConso.get(r.getName()).getInstances().size() ;
result.getResourceResultSet(r.getName()).updateResourceUse(workableTime);
}
for(SimProcess p : DefinitionPool.getInstance().getProcessDefinition()){
result.getProcessResultSet(p.getName()).updateCost() ;
result.getProcessResultSet(p.getName()).updateTime() ;
result.getProcessResultSet(p.getName()).updateWaitingTime() ;
}
}
instances = store.getStoredFinishedProcessInstances(INSTANCE_BUFFER_SIZE) ;
}
updateProcessResultSet(simEndDate,result) ;
updateActivityResultSet(simEndDate,result) ;
updateResourceResultSet(simEndDate,result) ;
for(Resource r : DefinitionPool.getInstance().getResourceDefinitions()){
result.getResourceResultSet(r.getName()).computeFinalResourceConsumption();
result.getResourceResultSet(r.getName()).computeFinalResourceCost();
long workedTime = r.getPlanning().getWorkingPlanningDuration(simStartDate, simEndDate) * resourceConso.get(r.getName()).getInstances().size() ;
result.getResourceResultSet(r.getName()).computeFinalResourceUse(workedTime);
}
for(SimActivity a : DefinitionPool.getInstance().getActivityDefinition(processName)){
result.getActivityResultSet(a.getName()).computeFinalTime() ;
result.getActivityResultSet(a.getName()).computeFinalWaitingTime() ;
}
for(SimData d : DefinitionPool.getInstance().getProcessDefinition(processName).getData()){
if(d instanceof SimNumberData){
result.getDataResultSet(d.getName()).computeFinalValues() ;
}else{
result.getDataResultSet(d.getName()).computeFinalRepartion(loadProfile.getTotalInjectedInstances()) ;
}
}
for(SimProcess p : DefinitionPool.getInstance().getProcessDefinition()){
result.getProcessResultSet(p.getName()).computeFinalCost() ;
result.getProcessResultSet(p.getName()).computeFinalTime() ;
result.getProcessResultSet(p.getName()).computeFinalWaitingTime() ;
}
return result ;
}
private void parseProcessInstance(Set<SimActivityInstance> activityInstances,Set<SimActivityInstance> parsed , SimulationReportResultSet result) {
for(SimActivityInstance a : activityInstances){
if(a.getStartDate() != 0){
parsed.add(a);
if(a.getFinishDate() > 0){
updateProcessResultSet(a,result) ;
updateActivityResultSet(a,result) ;
updateResourceResultSet(a,result) ;
if(a.hasNext()){
for(SimActivityInstance nextInstance : a.getNext()){
if(!parsed.contains(nextInstance)){
parseProcessInstance(Collections.singleton(nextInstance),parsed,result) ;
}
}
}
}
}
}
}
private void updateResourceResultSet(long instant,SimulationReportResultSet result) {
for(ResourceResultSet rSet : result.getResourceResultSets()){
rSet.getAvgCost().put(nextInterval, rSet.getIntermediateCost()) ;
double useDuration = rSet.getIntermediateUseDuration() ;
long last = nextInterval - timespan ;
long workedTime = (long)rSet.getResource().getPlanning().getWorkingPlanningDuration(last, instant) ;
if(workedTime > 0){
double avg = (double) useDuration /(double) workedTime ;
double average = (double) avg / resourceConso.get(rSet.getResource().getName()).getInstances().size() ;
if(average > 1.0){//TODO findout why ??
average = 1.0 ;
}
rSet.getAvgUse().put(nextInterval, average) ;
}else{
rSet.getAvgUse().put(nextInterval, 0.0) ;
}
rSet.reset() ;
}
}
private void updateActivityResultSet(long instant,SimulationReportResultSet result) {
for(ActivityResultSet rSet : result.getActivityResultSets()){
rSet.getAvgTime().put(nextInterval, rSet.getIntermediateAvgTime()) ;
rSet.getMaxTime().put(nextInterval, rSet.getIntermediateMaxTime()) ;
if(rSet.getIntermediateMinTime() == Long.MAX_VALUE){
rSet.getMinTime().put(nextInterval,0L) ;
}else{
rSet.getMinTime().put(nextInterval, rSet.getIntermediateMinTime()) ;
}
rSet.getMedTime().put(nextInterval, rSet.getIntermediateMedTime()) ;
rSet.getAvgWaitingTime().put(nextInterval, rSet.getIntermediateAvgWaitingTime()) ;
rSet.getMaxWaitingTime().put(nextInterval, rSet.getIntermediateMaxWaitingTime()) ;
if(rSet.getIntermediateMinWaitingTime() == Long.MAX_VALUE){
rSet.getMinWaitingTime().put(nextInterval,0L) ;
}else{
rSet.getMinWaitingTime().put(nextInterval, rSet.getIntermediateMinWaitingTime()) ;
}
rSet.getMedWaitingTime().put(nextInterval, rSet.getIntermediateMedWaitingTime()) ;
rSet.reset() ;
}
}
private void updateProcessResultSet(long instant,SimulationReportResultSet result) {
for(ProcessResultSet rSet : result.getProcessResultSets()){
rSet.getAvgTime().put(nextInterval, rSet.getIntermediateAvgTime()) ;
rSet.getMaxTime().put(nextInterval, rSet.getIntermediateMaxTime()) ;
if(rSet.getTotalMinTime() == Long.MAX_VALUE){
rSet.getMinTime().put(nextInterval,0L) ;
}else{
rSet.getMinTime().put(nextInterval, rSet.getIntermediateMinTime()) ;
}
rSet.getMedTime().put(nextInterval, rSet.getIntermediateMedTime()) ;
rSet.getAvgWaitingTime().put(nextInterval, rSet.getIntermediateAvgWaitingTime()) ;
rSet.getMaxWaitingTime().put(nextInterval, rSet.getIntermediateMaxWaitingTime()) ;
if(rSet.getIntermediateMinWaitingTime() == Long.MAX_VALUE){
rSet.getMinWaitingTime().put(nextInterval,0L) ;
}else{
rSet.getMinWaitingTime().put(nextInterval, rSet.getIntermediateMinWaitingTime()) ;
}
rSet.getMedWaitingTime().put(nextInterval, rSet.getIntermediateMedWaitingTime()) ;
rSet.reset() ;
}
}
private void updateDataResultSet(SimProcessInstance instance,SimulationReportResultSet result) {
for(SimDataInstance d : instance.getDataInstance()){
DataResultSet rSet = result.getDataResultSet(d.getDefinition().getName()) ;
if(d.getDefinition() instanceof SimNumberData){
rSet.addValue((Double) d.getValue()) ;
}else{
if(d.getValue() instanceof Boolean){
rSet.addOcuurence(String.valueOf(d.getValue())) ;
}else{
rSet.addOcuurence(d.getValue().toString()) ;
}
}
}
}
private void updateResourceResultSet(SimActivityInstance a,SimulationReportResultSet result) {
for(ResourceAssignement ra : ((SimActivity)a.getDefinition()).getAssignedResources()){
ResourceResultSet rSet = result.getResourceResultSet(ra.getResource().getName()) ;
int cons = rSet.getInstanceConsumption() ;
cons = cons + ra.getQuantity() ;
rSet.setInstanceConsumption(cons) ;
double cost = rSet.getInstanceCost() ;
cost = cost + ra.getResource().getFixedCost() + ( ra.getQuantity()*(ra.getResource().getTimeCost() * (double)ra.getDuration()/(long)getTimeUnitInMillisecond(ra.getResource().getTimeUnit())));
rSet.setInstanceCost(cost) ;
long use = rSet.getInstanceUseDuration() ;
use = use +( ra.getQuantity()* ra.getDuration());
rSet.setInstanceUseDuration(use) ;
}
}
private void updateActivityResultSet(SimActivityInstance a,SimulationReportResultSet result) {
ActivityResultSet rSet = result.getActivityResultSet(a.getDefinition().getName()) ;
long instanceDuration = a.getFinishDate() - a.getStartDate() ;
long instanceWaintingDuration = instanceDuration - ((SimActivity) a.getDefinition()).getExecutionTime() ;
rSet.setInstanceTime(rSet.getInstanceTime() + instanceDuration);
rSet.setInstanceWaitingTime(rSet.getInstanceWaitingTime() + instanceWaintingDuration);
rSet.updateTime() ;
rSet.updateWaitingTime() ;
}
private void updateProcessResultSet(SimActivityInstance a,SimulationReportResultSet result) {
ProcessResultSet rSet = result.getProcessResultSet(((SimActivity)a.getDefinition()).getParentProcessName()) ;
for(ResourceAssignement ri : ((SimActivity)a.getDefinition()).getAssignedResources()){
String unit = ri.getResource().getCostUnit() ;
double cost = ri.getResource().getFixedCost() + (ri.getQuantity()* (ri.getResource().getTimeCost() * (double) ri.getDuration()/(long)getTimeUnitInMillisecond(ri.getResource().getTimeUnit())));
rSet.updateInstanceCost(unit, cost) ;
}
}
private long getTimeUnitInMillisecond(TimeUnit timeUnit) {
switch(timeUnit){
case DAY : return 86400000;
case MINUTE : return 60000;
case MONTH : return 2629800000L;
case WEEK : return (long) (86400000*7);
case HOUR : return 3600000 ;
case YEAR : return 31557600000L;
}
return 0;
}
protected abstract String sotreReport(String processName) throws Exception;
protected abstract void fillResourceSheet(List<ResourceResultSet> resultSets) throws Exception;
protected abstract void fillLiteralsDataSheet(List<DataResultSet> resultSets) throws Exception;
protected abstract void fillNumberDataSheet(List<DataResultSet> resultSets) throws Exception;
protected abstract void fillActivitySheet(List<ActivityResultSet> resultSets) throws Exception;
protected abstract void fillResourceTimeSheet(List<ResourceResultSet> resultSets) throws Exception;
protected abstract void fillActivityTimeSheet(List<ActivityResultSet> resultSets) throws Exception;
protected abstract void fillDataReportSheet(List<DataResultSet> resultSets) throws Exception;
protected abstract void fillResourceReportSheet() throws Exception;
protected abstract void fillActivityReportSheet(List<ActivityResultSet> resultSets) throws Exception;
protected abstract void fillProcessTimeSheet(ProcessResultSet processResultSet) throws Exception;
protected abstract void fillProcessCostSheet(ProcessResultSet processResultSet) throws Exception;
protected abstract void fillProcessSheet(ProcessResultSet processResultSet) throws Exception;
protected abstract void fillLoadProfileSheet() throws Exception;
protected abstract void fillGeneralSheet() throws Exception;
public String generate() throws Exception {
if(!DefinitionPool.getInstance().getProcessDefinition().isEmpty()){
SimProcess proc = DefinitionPool.getInstance().getProcessDefinition().get(0) ;
SimulationReportResultSet resultSet = createSimulationReportResultSet(proc.getName()) ;
fillResourceReportSheet() ;
fillGeneralSheet();
fillLoadProfileSheet() ;
fillProcessSheet(resultSet.getProcessResultSet(proc.getName())) ;
fillProcessTimeSheet(resultSet.getProcessResultSet(proc.getName()));
fillProcessCostSheet(resultSet.getProcessResultSet(proc.getName()));
fillResourceSheet(resultSet.getResourceResultSets());
fillResourceTimeSheet(resultSet.getResourceResultSets());
fillActivityReportSheet(resultSet.getActivityResultSets());
fillActivitySheet(resultSet.getActivityResultSets());
fillActivityTimeSheet(resultSet.getActivityResultSets());
if(!resultSet.getDataResultSets().isEmpty()){
fillDataReportSheet(resultSet.getDataResultSets()) ;
fillNumberDataSheet(resultSet.getDataResultSets());
fillLiteralsDataSheet(resultSet.getDataResultSets());
}
return sotreReport(proc.getName()) ;
}
return null ;
}
}