package org.camunda.bpm.extension.process_test_coverage.listeners;

import java.util.EnumSet;
import java.util.logging.Logger;

import org.camunda.bpm.engine.impl.history.event.HistoricActivityInstanceEventEntity;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.camunda.bpm.engine.impl.history.event.HistoryEventTypes;
import org.camunda.bpm.engine.impl.history.handler.DbHistoryEventHandler;
import org.camunda.bpm.extension.process_test_coverage.junit.rules.CoverageTestRunState;
import org.camunda.bpm.extension.process_test_coverage.model.CoveredFlowNode;

/**
 * Extends the {@link DbHistoryEventHandler} in order to notify the process test
 * coverage of a covered activity.
 */
public class FlowNodeHistoryEventHandler extends DbHistoryEventHandler {

    private Logger logger = Logger.getLogger(this.getClass().getCanonicalName());

    /**
     * The state of the currently running coverage test.
     */
    private CoverageTestRunState coverageTestRunState;

    public FlowNodeHistoryEventHandler() {
    }

    @Override
    public void handleEvent(HistoryEvent historyEvent) {
        super.handleEvent(historyEvent);

        if (coverageTestRunState == null) {
            logger.warning("Coverage history event listener in use but no coverage run state assigned!");
            return;
        }

        if (historyEvent instanceof HistoricActivityInstanceEventEntity) {

            HistoricActivityInstanceEventEntity activityEvent = (HistoricActivityInstanceEventEntity) historyEvent;

            final CoveredFlowNode coveredActivity = new CoveredFlowNode(historyEvent.getProcessDefinitionKey(),
                    activityEvent.getActivityId());

            // Cover event start
            if (isInitialEvent(historyEvent)) {

                coverageTestRunState.addCoveredElement(coveredActivity);

            }
            // Cover event end
            else if (isEndEvent(historyEvent)) {

                coverageTestRunState.endCoveredElement(coveredActivity);
            }

        }

    }

    /**
     * Aimed to be the opposite of
     * {@link DbHistoryEventHandler#isInitialEvent()}.
     * 
     * Future versions of Camunda will probably introduce additional events
     * requiring this method to be updated.
     * 
     * @param historyEvent
     * @return
     */
    private boolean isEndEvent(HistoryEvent historyEvent) {

        EnumSet<HistoryEventTypes> endEventTypes = EnumSet.of(HistoryEventTypes.ACTIVITY_INSTANCE_END,
                HistoryEventTypes.PROCESS_INSTANCE_END,
                HistoryEventTypes.TASK_INSTANCE_COMPLETE,
                HistoryEventTypes.INCIDENT_RESOLVE,
                HistoryEventTypes.CASE_INSTANCE_CLOSE,
                HistoryEventTypes.BATCH_END);

        // They should have handled compare/equals in the enum itself
        for (HistoryEventTypes endEventType : endEventTypes) {

            if (historyEvent.isEventOfType(endEventType)) {

                return true;
            }
        }

        return false;
    }

    public void setCoverageTestRunState(CoverageTestRunState coverageTestRunState) {
        this.coverageTestRunState = coverageTestRunState;
    }
}

@@ -65,68 +65,8 @@
 s;%0A%0A
-import java.util.EnumSet;%0Aimport java.util.logging.Logger;%0A%0A
 impo
@@ -518,16 +518,141 @@
 lowNode;
+%0Aimport org.camunda.bpm.extension.process_test_coverage.util.Api;%0A%0Aimport java.util.EnumSet;%0Aimport java.util.logging.Logger;
 %0A%0A/**%0A *
@@ -2122,100 +2122,663 @@
     
-/**%0A     * Aimed to be the opposite of%0A     * %7B@link DbHistoryEventHandler#isInitialEvent()%7D
+protected boolean isInitialEvent(HistoryEvent historyEvent) %7B%0A        String isInitialEvent = %22isInitialEvent%22;%0A        return Api.feature(DbHistoryEventHandler.class, isInitialEvent, HistoryEvent.class).isSupported() ? super.isInitialEvent(historyEvent):%0A            (Boolean) Api.feature(DbHistoryEventHandler.class, isInitialEvent, String.class).invoke(this, historyEvent.getEventType());%0A    %7D%0A%0A    /**%0A     * Aimed to be the opposite of%0A     * %7B@link DbHistoryEventHandler#isInitialEvent(HistoryEvent event)%7D%0A     * for the purpose of the process test coverage - which just deals with%0A     * history events of type HistoricActivityInstanceEventEntity
 .%0A  
@@ -2826,14 +2826,16 @@
 ill 
-probab
+eventual
 ly i
@@ -2904,16 +2904,95 @@
 updated.
+ Be careful to deal with backwards%0A     * compatibility issues when doing that.
 %0A     * 
@@ -3165,16 +3165,29 @@
 mSet.of(
+%0A            
 HistoryE
@@ -3223,36 +3223,32 @@
 ND,%0A            
-    
 HistoryEventType
@@ -3275,36 +3275,32 @@
 ND,%0A            
- 
-   
 HistoryEventType
@@ -3323,28 +3323,25 @@
 COMPLETE
-,%0A  
+%0A
         
       Hi
@@ -3336,148 +3336,8 @@
     
-      HistoryEventTypes.INCIDENT_RESOLVE,%0A                HistoryEventTypes.CASE_INSTANCE_CLOSE,%0A                HistoryEventTypes.BATCH_END
 );%0A%0A
@@ -3503,22 +3503,30 @@
 ent.
-is
+get
 Event
-Of
 Type(
+).equals(
 endE
@@ -3533,16 +3533,31 @@
 ventType
+.getEventName()
 )) %7B%0A%0A  
@@ -3786,10 +3786,11 @@
 ;%0A    %7D%0A
+%0A
 %7D%0A

make flow node history event handler backwards compatible