/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * 
 *      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.
*/

//created on: Aug 2, 2012
package simulation

//list any import classes here.
import org.jbpm.simulation.impl.events.*;
import java.util.Date;
import org.jbpm.simulation.AggregatedSimulationEvent;
import org.jbpm.simulation.impl.SystemOutLogger;

//declare any global variables here
global java.util.List simulation;
global java.util.List summary;
global java.util.List processEventsOnly;
global SystemOutLogger logger;


declare ActivityName
    name : String
    type : String
    id : String
end 

rule "Insert activity names"
no-loop
salience 10
    when
        ActivitySimulationEvent( $name : activityName, $id : activityId )
        not ActivityName( name == $name )
    then
        insert( new ActivityName( $name, "abstract", $id ) );

end

rule "Insert activity names for ht"
no-loop
salience 10
    when
        HumanTaskActivitySimulationEvent( $name : activityName, $id : activityId )
        not ActivityName( name == $name )
    then
        insert( new ActivityName( $name, "ht", $id ) );

end

rule "Insert event names"
no-loop
salience 10
    when
        EndSimulationEvent( $name : activityName, $id : activityId )
        not ActivityName( name == $name )
    then
        insert( new ActivityName( $name, "event", $id ) );

end

rule "Calculate average duration for end event"
salience 20
no-loop
    when
        $ac : ActivityName($name : name, type=="abstract", $id : id)
        $event : ActivitySimulationEvent(activityId == $id, used == false)
        accumulate(
        ActivitySimulationEvent($duration : duration, activityName == $name ),
        $min : min( $duration ),
        $avg : average( $duration ),
        $max : max( $duration ),
        $count : count( $duration ) )
    then
        logger.log("Duration for activity " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" + $max + " count " + $count);
    
        AggregatedActivitySimulationEvent aggEvent = new AggregatedActivitySimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max, (Number)$count, $event.getType());
        simulation.add(aggEvent);
        modify ($event) {
            setAggregatedEvent((AggregatedSimulationEvent)processEventsOnly.get(processEventsOnly.size()==0 ? 0: processEventsOnly.size()-1)),
            setUsed(true)
        }

end

rule "Calculate average duration for activity"
salience 20
no-loop
    when
        $ac : ActivityName($name : name, type=="abstract", $id : id)
        $event : ActivitySimulationEvent(activityId == $id, used == false)
        accumulate(
        ActivitySimulationEvent($duration : duration, activityName == $name ),
        $min : min( $duration ),
        $avg : average( $duration ),
        $max : max( $duration ),
        $count : count( $duration ) )
    then
        logger.log("Duration for activity " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" + $max + " count " + $count);
    
        AggregatedActivitySimulationEvent aggEvent = new AggregatedActivitySimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max, (Number)$count, $event.getType());
        simulation.add(aggEvent);
        modify ($event) {
            setAggregatedEvent((AggregatedSimulationEvent)processEventsOnly.get(processEventsOnly.size()==0 ? 0: processEventsOnly.size()-1)),
            setUsed(true)
        }

end

rule "Calculate average duration for human activity"
salience 20
no-loop
    when
        ActivityName($name : name, type == "ht", $id : id)
        $event : HumanTaskActivitySimulationEvent(activityId == $id, used == false)
        accumulate(
        HumanTaskActivitySimulationEvent($waitTime : waitTime, activityName == $name ),
        $minwt : min( $waitTime ),
        $avgwt : average( $waitTime ),
        $maxwt : max( $waitTime ) )
        
        accumulate(
        HumanTaskActivitySimulationEvent($duration : duration, activityName == $name ),
        $min : min( $duration ),
        $avg : average( $duration ),
        $max : max( $duration ),
        $count : count( $duration ) )
        
        accumulate(
        HumanTaskActivitySimulationEvent($resourceUtilization : resourceUtilization, activityName == $name ),
        $minru : min( $resourceUtilization ),
        $avgru : average( $resourceUtilization ),
        $maxru : max( $resourceUtilization ) )
        
        accumulate(
        HumanTaskActivitySimulationEvent($resourceCost : resourceCost, activityName == $name ),
        $minrc : min( $resourceCost ),
        $avgrc : average( $resourceCost ),
        $maxrc : max( $resourceCost ) )
        
    then
        logger.log("Duration for human activity " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" 
        + $max + " is avgwt: " + $avgwt + "; minwt: " + $minwt + "; maxwt:" + $maxwt
         + " is avgru: " + $avgru + "; minru: " + $minru + "; maxru:" + $maxru + " count " + $count + " avg cost " + $avgrc + " min cost " + $minrc + " max cost " + $maxrc );
    
        HTAggregatedSimulationEvent aggEvent = new HTAggregatedSimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max,
         (Number)$minwt, (Number)$avgwt, (Number)$maxwt, (Number)$minru, (Number)$avgru, (Number)$maxru, (Number)$count, (Number)$avgrc, (Number)$minrc, (Number)$maxrc, $event.getType());
        simulation.add(aggEvent);
        modify ($event) {
            setAggregatedEvent((AggregatedSimulationEvent)processEventsOnly.get(processEventsOnly.size()==0 ? 0: processEventsOnly.size()-1)),
            setUsed(true)
        }

end

rule "Calculate end event duration" 
salience 100
no-loop
    when
        ActivityName($name : name, type == "event", $id : id)
        $event : EndSimulationEvent(activityId == $id, used == false)
        accumulate(
        EndSimulationEvent($processDuration : processDuration),
        $min : min( $processDuration ),
        $avg : average( $processDuration ),
        $max : max( $processDuration ),
        $count : count( $processDuration ) )
    then
        logger.log("Duration for end event " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" + $max);
    
        AggregatedEndEventSimulationEvent aggEvent = new AggregatedEndEventSimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max, (Number)$count, $event.getType());
        simulation.add(aggEvent);
        modify ($event) {
            setAggregatedEvent((AggregatedSimulationEvent)processEventsOnly.get(processEventsOnly.size()==0 ? 0: processEventsOnly.size()-1)),
            setUsed(true)
        }
        
end
         

rule "Calculate average duration for process"
salience 3
no-loop
    when
        accumulate(
        ProcessInstanceEndSimulationEvent($pathId : pathId, $duration : processDuration, $processId : processId, $processName : processName, $processVersion : processVersion),
        $min : min( $duration ),
        $avg : average( $duration ),
        $max : max( $duration ),
        $processSet : collectSet($processId+"@"+$processName+"@"+$processVersion),
        $pathIds : collectList($pathId) )
        eval($processSet.size() > 0)
    then
        logger.log("Duration for processs is avg: " + $avg + "; min: " + $min + "; max:" + $max + " " + $processSet);
    
        AggregatedProcessSimulationEvent aggEvent = new AggregatedProcessSimulationEvent($processSet, (Number)$min, (Number)$avg, (Number)$max);
        aggEvent.calculatePaths($pathIds);
        simulation.add(aggEvent);
        processEventsOnly.add(aggEvent);

end

rule "Calculate process summary" 
salience 100
no-loop
    when
        accumulate(
        AggregatedProcessSimulationEvent($pathInfo : pathInfo, $minExecutionTime : minExecutionTime, $avgExecutionTime : avgExecutionTime, $maxExecutionTime : maxExecutionTime, 
        $processId : processId, $processName : processName, $processVersion : processVersion),
        $min : min( $minExecutionTime ),
        $avg : average( $avgExecutionTime ),
        $max : max( $maxExecutionTime ),
        $processSet : collectSet($processId+"@"+$processName+"@"+$processVersion),
        $pathIds : collectList($pathInfo) )
        eval($processSet.size() > 0)
    then
        logger.log("SUMMARY: Duration for processs is avg: " + $avg + "; min: " + $min + "; max:" + $max + " " + $processSet);
    
        AggregatedProcessSimulationEvent aggEvent = new AggregatedProcessSimulationEvent($processSet, (Number)$min, (Number)$avg, (Number)$max);
        aggEvent.calculateAggregatedPaths($pathIds);
        summary.add(aggEvent);
        
end

rule "Calculate human activity summary"
salience 200
no-loop
    when
        ActivityName($name : name, type == "ht", $id : id)
        accumulate(
        HTAggregatedSimulationEvent($numberOfInstances: numberOfInstances, $minExecutionTime : minExecutionTime, $avgExecutionTime : avgExecutionTime, $maxExecutionTime : maxExecutionTime,
        $minWaitTime : minWaitTime, $avgWaitTime : avgWaitTime, $maxWaitTime : maxWaitTime,
        $minResourceUtilization : minResourceUtilization, $avgResourceUtilization : avgResourceUtilization, $maxResourceUtilization : maxResourceUtilization,$resourceCost : avgResourceCost,
        activityName == $name ),
        $minwt : min( $minWaitTime ),
        $avgwt : average( $avgWaitTime ),
        $maxwt : max( $maxWaitTime ),
        $min : min( $minExecutionTime ),
        $avg : average( $avgExecutionTime ),
        $max : max( $maxExecutionTime ),
        $count : max( $numberOfInstances ),
        $minru : min( $minResourceUtilization ),
        $avgru : average( $avgResourceUtilization ),
        $maxru : max( $maxResourceUtilization ),
        $minrc : min( $resourceCost ),
        $avgrc : average( $resourceCost ),
        $maxrc : max( $resourceCost ) )
        eval($count != null)
        
    then        
        logger.log("SUMMARY Duration for human activity " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" 
        + $max + " is avgwt: " + $avgwt + "; minwt: " + $minwt + "; maxwt:" + $maxwt
         + " is avgru: " + $avgru + "; minru: " + $minru + "; maxru:" + $maxru + " count " + $count + " avg cost " + $avgrc + " min cost " + $minrc + " max cost " + $maxrc);
    
        HTAggregatedSimulationEvent aggEvent = new HTAggregatedSimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max, (Number)$minwt, (Number)$avgwt, (Number)$maxwt,
        (Number)$minru, (Number)$avgru, (Number)$maxru, (Number)$count, (Number)$avgrc, (Number)$minrc, (Number)$maxrc, "");
        summary.add(aggEvent);

end

rule "Calculate activity summary"
salience 200
no-loop
    when
        ActivityName($name : name, type=="abstract", $id : id)
        accumulate(
        AggregatedActivitySimulationEvent($numberOfInstances: numberOfInstances, $minExecutionTime : minExecutionTime, $avgExecutionTime : avgExecutionTime, $maxExecutionTime : maxExecutionTime,
        activityName == $name ),
        $min : min( $minExecutionTime ),
        $avg : average( $avgExecutionTime ),
        $max : max( $maxExecutionTime ),
        $count : max( $numberOfInstances ) )
        eval($count != null)
        
    then
        logger.log("SUMMARY Duration for activity " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" + $max + " count " + $count);
    
        AggregatedActivitySimulationEvent aggEvent = new AggregatedActivitySimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max, (Number)$count, "");
        summary.add(aggEvent);

end

rule "Calculate end event summary"
salience 200
no-loop
    when
        ActivityName($name : name, type=="event", $id : id)
        accumulate(
        AggregatedEndEventSimulationEvent($numberOfInstances: numberOfInstances, $minProcessDuration : minProcessDuration, $avgProcessDuration : avgProcessDuration, $maxProcessDuration : maxProcessDuration,
        activityName == $name ),
        $min : min( $minProcessDuration ),
        $avg : average( $avgProcessDuration ),
        $max : max( $maxProcessDuration ),
        $count : max( $numberOfInstances ) )
        eval($count != null)
        
    then
        logger.log("SUMMARY Duration for end event " + $name + " is avg: " + $avg + "; min: " + $min + "; max:" + $max + " count " + $count);
    
        AggregatedEndEventSimulationEvent aggEvent = new AggregatedEndEventSimulationEvent($name, $id, (Number)$min, (Number)$avg, (Number)$max, (Number)$count, "");
        summary.add(aggEvent);

end