package notTest;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Iterator;

import junit.framework.TestCase;

import org.drools.FactHandle;
import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.WorkingMemory;
import org.drools.audit.WorkingMemoryFileLogger;
import org.drools.base.ClassObjectFilter;
import org.drools.compiler.PackageBuilder;
import org.drools.event.BeforeActivationFiredEvent;
import org.drools.event.DefaultAgendaEventListener;

import us.state.mn.hm.model.Applicant;
import us.state.mn.hm.model.ApplicantStatus;
import us.state.mn.hm.model.NegativeResult;

public class NotTest extends TestCase {

    private RuleBase ruleBase;
    private WorkingMemory workingMemory;
    private WorkingMemoryFileLogger logger;

    protected void setUp() throws Exception {
        super.setUp();
        ruleBase = RuleBaseFactory.newRuleBase();
        loadDrl(getClass().getResourceAsStream("notTest.drl"));
        initWorkingMemory();
        logger = new WorkingMemoryFileLogger(workingMemory);
        logger.setFileName("log/trace.xml");
    }

    protected void tearDown() throws Exception {
        super.tearDown();
        logger.writeToDisk();
    }

    public void testNot() throws Exception {

        Applicant applicant = new Applicant("Joe", "Sixpack");
        final NegativeResult negativeResult = new NegativeResult(applicant);
        final FactHandle factHandle;

        workingMemory.insert(applicant);
        applicant.setFirstName(new String("Jon"));
        factHandle = workingMemory.getFactHandle(applicant);
        workingMemory.update(factHandle, applicant);
        workingMemory.insert(negativeResult);
        workingMemory.fireAllRules();
        displayWorkingMemory();

        assertOneApplicantStatusInWorkingMemory();
    }

    @SuppressWarnings("unchecked")
    private void assertOneApplicantStatusInWorkingMemory() {

        final Iterator<ApplicantStatus> applicantStatusIterator =
            workingMemory.iterateObjects(new ClassObjectFilter(ApplicantStatus.class));
        final ApplicantStatus applicantStatus = applicantStatusIterator.next();

        assertFalse("There should be only one ApplicantStatus object in working memory.",
            applicantStatusIterator.hasNext());
        assertEquals(applicantStatus.getStatus(), "Denied");
    }

    private void displayWorkingMemory() {

        final Iterator<?> iterator = workingMemory.iterateObjects();

        System.out.println();
        System.out.println("----Working Memory Facts----");
        while (iterator.hasNext()) {
            final Object fact = iterator.next();
            System.out.println(fact.getClass().getSimpleName() + ": " + fact);
        }
        System.out.println("----------------------------");
    }

    private void initWorkingMemory() {
        workingMemory = ruleBase.newStatefulSession();
        workingMemory.addEventListener(new DefaultAgendaEventListener() {
            @Override
            public void beforeActivationFired(BeforeActivationFiredEvent event,
                WorkingMemory workingMemory) {
                System.out.println("Activated Rule: "
                    + event.getActivation().getRule().getName());
                super.beforeActivationFired(event, workingMemory);
            }
        });
    }

    private void loadDrl(InputStream drlStream) throws Exception {

        final Reader drlReader = new InputStreamReader(drlStream);
        final PackageBuilder builder = new PackageBuilder();

        builder.addPackageFromDrl(drlReader);
        ruleBase.addPackage(builder.getPackage());
    }

}
