

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import junit.framework.TestCase;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.base.MapGlobalResolver;
import org.drools.definition.KnowledgePackage;
import org.drools.definitions.impl.KnowledgePackageImp;
import org.drools.event.process.ProcessCompletedEvent;
import org.drools.event.process.ProcessEventListener;
import org.drools.event.process.ProcessNodeLeftEvent;
import org.drools.event.process.ProcessNodeTriggeredEvent;
import org.drools.event.process.ProcessStartedEvent;
import org.drools.persistence.jpa.JPAKnowledgeService;
import org.drools.process.core.Work;
import org.drools.process.core.impl.WorkImpl;
import org.drools.rule.Package;
import org.drools.ruleflow.core.RuleFlowProcess;
import org.drools.runtime.Environment;
import org.drools.runtime.EnvironmentName;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.process.ProcessInstance;
import org.drools.runtime.process.WorkItem;
import org.drools.runtime.process.WorkItemHandler;
import org.drools.runtime.process.WorkItemManager;
import org.drools.workflow.core.Node;
import org.drools.workflow.core.impl.ConnectionImpl;
import org.drools.workflow.core.node.EndNode;
import org.drools.workflow.core.node.StartNode;
import org.drools.workflow.core.node.WorkItemNode;
import org.drools.workflow.instance.node.WorkItemNodeInstance;

import bitronix.tm.resource.jdbc.PoolingDataSource;

public class TestProcessEvent extends TestCase {

    PoolingDataSource ds1;

    @Override
    protected void setUp() throws Exception {
        ds1 = new PoolingDataSource();
        ds1.setUniqueName( "jdbc/testDS1" );
        ds1.setClassName( "org.h2.jdbcx.JdbcDataSource" );
        ds1.setMaxPoolSize( 3 );
        ds1.setAllowLocalTransactions( true );
        ds1.getDriverProperties().put( "user",
                                       "sa" );
        ds1.getDriverProperties().put( "password",
                                       "sasa" );
        ds1.getDriverProperties().put( "URL",
                                       "jdbc:h2:mem:mydb" );
        ds1.init();

    }

    @Override
    protected void tearDown() throws Exception {
        ds1.close();
    }


    public void testPersistenceWorkItems() {
    	KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();

        final Package pkg = new Package( "org.drools.test" );
        RuleFlowProcess process = new RuleFlowProcess();
        process.setId("org.drools.test.TestProcess");
        process.setName("Event Process");
        
        StartNode startNode = new StartNode();
        startNode.setName("Start");
        startNode.setId(1);
        process.addNode(startNode);
        
        
        Work work = new WorkImpl();
        work.setName("TestWorkItem");
        
        WorkItemNode workItemNode = new WorkItemNode();
        workItemNode.setWork(work);
        workItemNode.setName("TestWorkItem");
        workItemNode.setWaitForCompletion(true);
        
        process.addNode(workItemNode);
        
        new ConnectionImpl(
                startNode, Node.CONNECTION_DEFAULT_TYPE,
                workItemNode, Node.CONNECTION_DEFAULT_TYPE
            );

        
        EndNode endNode = new EndNode();
        endNode.setName("End");
        endNode.setId(3);
        process.addNode(endNode);
        new ConnectionImpl(
        	workItemNode, Node.CONNECTION_DEFAULT_TYPE,
            endNode, Node.CONNECTION_DEFAULT_TYPE
        );
        
        pkg.addProcess(process);
        List<KnowledgePackage> pkgs = new ArrayList<KnowledgePackage>();
        pkgs.add( new KnowledgePackageImp( pkg ) );
        kbase.addKnowledgePackages( pkgs );

        EntityManagerFactory emf = Persistence.createEntityManagerFactory( "org.drools.persistence.jpa" );
        Environment env = KnowledgeBaseFactory.newEnvironment();
        env.set( EnvironmentName.ENTITY_MANAGER_FACTORY,
                 emf );

        env.set( EnvironmentName.GLOBALS, new MapGlobalResolver() );
        
        StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env );
        
        ProcessEventListener listener = new ProcessEventListener() {
			public void afterNodeLeft(ProcessNodeLeftEvent event) {
				System.out.println("After node left: " + event.getNodeInstance().getNodeName());				
				if(event.getNodeInstance() instanceof WorkItemNodeInstance){
					WorkItemNodeInstance instance = (WorkItemNodeInstance)event.getNodeInstance();
					WorkItem wi = instance.getWorkItem();
					System.out.println("WorkItem object:" + wi);
					assertNotNull(wi);
				}
			}
			public void afterNodeTriggered(ProcessNodeTriggeredEvent event) {
				System.out.println("After node triggered: " + event.getNodeInstance().getNodeName());				
			}
			public void afterProcessCompleted(ProcessCompletedEvent event) {
				System.out.println("After process completed");				
			}
			public void afterProcessStarted(ProcessStartedEvent event) {
				System.out.println("After process started");				
			}
			public void beforeNodeLeft(ProcessNodeLeftEvent event) {
				System.out.println("Before node left: " + event.getNodeInstance().getNodeName());				
			}
			public void beforeNodeTriggered(ProcessNodeTriggeredEvent event) {
				System.out.println("Before node triggered: " + event.getNodeInstance().getNodeName());				
			}
			public void beforeProcessCompleted(ProcessCompletedEvent event) {
				System.out.println("Before process completed");				
			}
			public void beforeProcessStarted(ProcessStartedEvent event) {
				System.out.println("Before process started");				
			}
        };
        
        ksession.addEventListener(listener);
        TestWorkItemHandler handler = new TestWorkItemHandler();
        ksession.getWorkItemManager().registerWorkItemHandler("TestWorkItem", handler);

        int id = ksession.getId();
        
        ProcessInstance processInstance = ksession.startProcess( "org.drools.test.TestProcess" );
        //ksession.insert( "TestString" );
        System.out.println( "Started process instance " + processInstance.getId() );
        
        WorkItem workItem = handler.getWorkItem();
        assertNotNull( workItem );

        ksession = JPAKnowledgeService.loadStatefulKnowledgeSession( id, kbase, null, env );
        ksession.addEventListener(listener);
        handler = new TestWorkItemHandler();
        ksession.getWorkItemManager().registerWorkItemHandler("TestWorkItem", handler);
        
        ksession.getWorkItemManager().completeWorkItem( workItem.getId(),null );
    }
    
    private class TestWorkItemHandler implements WorkItemHandler {

    	private WorkItem workItem;
    	
    	private TestWorkItemHandler() {
    	}
    	
    	public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
    		this.workItem = workItem;
    		System.out.println("executeWorkItem method called");
    	}

    	public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
    		System.out.println("abortWorkItem method called");
    	}
    	    	
    	public WorkItem getWorkItem() {
    		return workItem;
    	}
    }
    
    
    public static void main(String[] args){
    	try{
    		org.junit.runner.JUnitCore.main("TestProcessEvent");
    	}catch(Exception ex){
    		ex.printStackTrace();
    	}
    }

}
