package org.drools.rule.constraint;

import org.drools.common.InternalWorkingMemory;
import org.drools.reteoo.LeftTuple;
import org.drools.rule.Declaration;
import org.drools.rule.builder.dialect.asm.GeneratorHelper;

import java.util.List;

import static org.drools.rule.builder.dialect.asm.GeneratorHelper.matchDeclarationsToTuple;
import static org.drools.rule.constraint.ASMConditionEvaluatorJitter.jitEvaluator;

public class JittedConditionEvaluator implements ConditionEvaluator {

    private final ArrayConditionEvaluator conditionEvaluator;

    private final Declaration[] declarations;

    private List<GeneratorHelper.DeclarationMatcher> declarationMatchers;

    private Object[] array;

    public JittedConditionEvaluator(ConditionAnalyzer.Condition condition, Declaration[] declarations, ClassLoader classLoader) {
        this.declarations = declarations;
        conditionEvaluator = jitEvaluator(condition, declarations, classLoader);
        if (declarations.length > 0) {
            array = new Object[declarations.length];
            if (declarations.length > 1) {
                declarationMatchers = matchDeclarationsToTuple(declarations);
            }
        }
    }

    public boolean evaluate(Object object, InternalWorkingMemory workingMemory, LeftTuple leftTuple) {
        updateValues(object, workingMemory, leftTuple);
        return conditionEvaluator.evaluate(object, array);
    }

    private void updateValues(Object object, InternalWorkingMemory workingMemory, LeftTuple leftTuple) {
        if (declarations.length == 0) {
            return;
        }

        if (leftTuple == null) {
            for (int i = 0; i < declarations.length; i++) {
                array[i] = declarations[i].getExtractor().getValue(workingMemory, object);
            }
            return;
        }

        if (declarations.length == 1) {
            array[0] = declarations[0].getPattern().getOffset() > leftTuple.getIndex() ?
                    declarations[0].getExtractor().getValue(workingMemory, object) :
                    declarations[0].getExtractor().getValue(workingMemory, leftTuple.get(declarations[0]).getObject());
            return;
        }

        for (GeneratorHelper.DeclarationMatcher declarationMatcher : declarationMatchers) {
            if (declarationMatcher.getRootDistance() > leftTuple.getIndex()) {
                array[declarationMatcher.getOriginalIndex()] = declarationMatcher.getDeclaration().getExtractor().getValue(workingMemory, object);
                continue;
            }
            while (declarationMatcher.getRootDistance() < leftTuple.getIndex()) {
                leftTuple = leftTuple.getParent();
            }
            array[declarationMatcher.getOriginalIndex()] = declarationMatcher.getDeclaration().getExtractor().getValue(workingMemory, leftTuple.getHandle().getObject());
        }
    }
}

@@ -671,37 +671,8 @@
 s;%0A%0A
-    private Object%5B%5D array;%0A%0A
     
@@ -957,114 +957,14 @@
 th %3E
- 0) %7B%0A            array = new Object%5Bdeclarations.length%5D;%0A            if (declarations.length %3E
  1) %7B%0A
-    
     
@@ -1033,30 +1033,16 @@
 tions);%0A
-            %7D%0A
         
@@ -1161,16 +1161,59 @@
         
+return conditionEvaluator.evaluate(object, 
 updateVa
@@ -1254,66 +1254,8 @@
 ple)
-;%0A        return conditionEvaluator.evaluate(object, array
 );%0A 
@@ -1276,12 +1276,16 @@
 ate 
-void
+Object%5B%5D
  upd
@@ -1419,32 +1419,37 @@
           return
+ null
 ;%0A        %7D%0A%0A   
@@ -1437,32 +1437,91 @@
 ull;%0A        %7D%0A%0A
+        Object%5B%5D array = new Object%5Bdeclarations.length%5D;%0A%0A
         if (left
@@ -1712,32 +1712,38 @@
           return
+ array
 ;%0A        %7D%0A%0A   
@@ -2091,16 +2091,22 @@
   return
+ array
 ;%0A      
@@ -2791,20 +2791,42 @@
 ;%0A        %7D%0A
+        return array;%0A
     %7D%0A%7D%0A

remove any internal state from the JittedConditionEvaluator