package org.commcare.android.tests.queries;

import org.commcare.CommCareApplication;
import org.commcare.android.CommCareTestRunner;
import org.commcare.android.util.TestUtils;
import org.javarosa.core.model.condition.EvaluationContext;
import org.javarosa.core.model.instance.FormInstance;
import org.javarosa.core.model.instance.TreeElement;
import org.javarosa.xpath.XPathParseTool;
import org.javarosa.xpath.expr.InFormCacheableExpr;
import org.javarosa.xpath.expr.XPathExpression;
import org.javarosa.xpath.parser.XPathSyntaxException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;

/**
 * Created by amstone326 on 2/2/18.
 */

@Config(application = CommCareApplication.class)
@RunWith(CommCareTestRunner.class)
public class ExpressionCacheTest {

    private FormInstance mainFormInstance;

    @Before
    public void setup() {
        TreeElement root = new TreeElement("root");
        TreeElement data = new TreeElement("data");
        root.addChild(data);
        mainFormInstance = new FormInstance(root);

        TestUtils.initializeStaticTestStorage();
        TestUtils.processResourceTransaction("/inputs/case_test_model_query_lookups.xml");
    }

    @Test
    public void testFasterWithCaching() {
        long timeWithoutCaching = time100Evaluations(false);
        long timeWithCaching = time100Evaluations(true);
        Assert.assertTrue("Evaluation time with caching should be shorter", timeWithCaching < timeWithoutCaching);
    }

    private long time100Evaluations(boolean enableCaching) {
        if (enableCaching) {
            InFormCacheableExpr.enableCaching(mainFormInstance, true);
        } else {
            InFormCacheableExpr.disableCaching();
        }
        EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession();

        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            evaluate("join(',',instance('casedb')/casedb/case[@case_type='unit_test_child_child']" +
                    "[@status='open'][true() and instance('casedb')/casedb/case[@case_id = " +
                    "instance('casedb')/casedb/case[@case_id=current()/index/parent]" +
                    "/index/parent]/test = 'true']/@case_id)",
                    ec);
        }
        return System.currentTimeMillis() - start;
    }

    private static void evaluate(String xpath, EvaluationContext ec) {
        XPathExpression expr;
        try {
            expr = XPathParseTool.parseXPath(xpath);
            expr.eval(ec);
        } catch (XPathSyntaxException e) {
            TestUtils.wrapError(e, "XPath: " + xpath);
        }
    }


    @Test
    public void testAccuracyWithCaching() {
        InFormCacheableExpr.enableCaching(mainFormInstance, true);
        EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession();
        for (int i = 0; i < 3; i++) {
            CaseDbQueryTest.evaluate("join(',',instance('casedb')/casedb/case[@case_type='unit_test_child_child']" +
                            "[@status='open'][true() and instance('casedb')/casedb/case[@case_id = " +
                            "instance('casedb')/casedb/case[@case_id=current()/index/parent]/index/parent]/test = 'true']/@case_id)",
                    "child_ptwo_one_one,child_one_one",
                    ec);
        }
    }

}

@@ -531,24 +531,48 @@
 xException;%0A
+import org.junit.After;%0A
 import org.j
@@ -1283,24 +1283,117 @@
 l%22);%0A    %7D%0A%0A
+    @After%0A    public void teardown() %7B%0A        InFormCacheableExpr.disableCaching();%0A    %7D%0A%0A
     @Test%0A  
@@ -1837,75 +1837,8 @@
 e);%0A
-        %7D else %7B%0A            InFormCacheableExpr.disableCaching();%0A
     

disable caching in teardown