package org.commcare.session;

import org.commcare.suite.model.StackFrameStep;
import org.javarosa.core.model.data.UncastData;
import org.javarosa.core.model.instance.FormInstance;
import org.javarosa.core.model.instance.TreeElement;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

public class SessionInstanceBuilder {
    public static final String KEY_LAST_QUERY_STRING = "LAST_QUERY_STRING";
    public static final String KEY_ENTITY_LIST_EXTRA_DATA = "entity-list-data";

    public static FormInstance getSessionInstance(SessionFrame frame, String deviceId,
                                                  String appversion, String username,
                                                  String userId,
                                                  Hashtable<String, String> userFields) {
        TreeElement sessionRoot = new TreeElement("session", 0);

        addSessionNavData(sessionRoot, frame);
        addMetadata(sessionRoot, deviceId, appversion, username, userId);
        addUserProperties(sessionRoot, userFields);

        return new FormInstance(sessionRoot, "session");
    }

    private static void addSessionNavData(TreeElement sessionRoot, SessionFrame frame) {
        TreeElement sessionData = new TreeElement("data", 0);
        addDatums(sessionData, frame);
        addUserQueryData(sessionData, frame);
        sessionRoot.addChild(sessionData);
    }

    /**
     * Add datums chosen by user to the session
     */
    private static void addDatums(TreeElement sessionData, SessionFrame frame) {
        for (StackFrameStep step : frame.getSteps()) {
            if (SessionFrame.STATE_DATUM_VAL.equals(step.getType())) {
                Vector<TreeElement> matchingElements =
                        sessionData.getChildrenWithName(step.getId());
                if (matchingElements.size() > 0) {
                    matchingElements.elementAt(0).setValue(new UncastData(step.getValue()));
                } else {
                    addData(sessionData, step.getId(), step.getValue());
                }
            }
        }
    }

    /**
     * Add data to session tracking queries user made before entering form
     */
    private static void addUserQueryData(TreeElement sessionData, SessionFrame frame) {
        for (StackFrameStep step : frame.getSteps()) {
            Object textSearch = step.getExtra(KEY_LAST_QUERY_STRING);
            if (textSearch != null) {
                addData(sessionData, "stringquery", "1");
            }
            Object entitySelectCalloutSearch = step.getExtra(KEY_ENTITY_LIST_EXTRA_DATA);
            if (entitySelectCalloutSearch != null) {
                addData(sessionData, "calloutquery", "1");
            }
        }
    }

    private static void addMetadata(TreeElement sessionRoot, String deviceId,
                                    String appversion, String username,
                                    String userId) {
        TreeElement sessionMeta = new TreeElement("context", 0);

        addData(sessionMeta, "deviceid", deviceId);
        addData(sessionMeta, "appversion", appversion);
        addData(sessionMeta, "username", username);
        addData(sessionMeta, "userid", userId);

        sessionRoot.addChild(sessionMeta);
    }

    private static void addUserProperties(TreeElement sessionRoot,
                                          Hashtable<String, String> userFields) {
        TreeElement user = new TreeElement("user", 0);
        TreeElement userData = new TreeElement("data", 0);
        user.addChild(userData);
        for (Enumeration en = userFields.keys(); en.hasMoreElements(); ) {
            String key = (String)en.nextElement();
            addData(userData, key, userFields.get(key));
        }

        sessionRoot.addChild(user);

    }

    private static void addData(TreeElement root, String name, String data) {
        TreeElement datum = new TreeElement(name);
        datum.setValue(new UncastData(data));
        root.addChild(datum);
    }

}

@@ -226,16 +226,64 @@
 Element;
+%0Aimport org.javarosa.core.util.OrderedHashtable;
 %0A%0Aimport
@@ -2407,22 +2407,22 @@
         
-Object
+String
  textSea
@@ -2431,43 +2431,27 @@
 h = 
-step.getExtra(KEY_LAST_QUERY_STRING
+getStringQuery(step
 );%0A 
@@ -2531,36 +2531,525 @@
  %22stringquery%22, 
-%221%22)
+textSearch);%0A            %7D%0A%0A            String calloutResultCount = getCalloutSearchResultCount(step);%0A            if (calloutResultCount != null) %7B%0A                addData(sessionData, %22fingerprintquery%22, calloutResultCount);%0A            %7D%0A        %7D%0A    %7D%0A%0A    private static String getStringQuery(StackFrameStep step) %7B%0A        Object extra = step.getExtra(KEY_LAST_QUERY_STRING);%0A        if (extra != null && extra instanceof String && !%22%22.equals(extra)) %7B%0A            return (String) extra
 ;%0A            %7D%0A
@@ -3037,35 +3037,132 @@
 tra;%0A       
+ %7D%0A
      
-%7D%0A 
    
+return null;%0A    %7D%0A%0A    private static String getCalloutSearchResultCount(StackFrameStep step) %7B%0A
         Obje
@@ -3239,28 +3239,24 @@
 A);%0A        
-    
 if (entitySe
@@ -3284,75 +3284,156 @@
 null
-) %7B%0A                addData(sessionData, %22calloutquery%22, %221%22);%0A    
+ && entitySelectCalloutSearch instanceof OrderedHashtable) %7B%0A            return %22%22 + ((OrderedHashtable)entitySelectCalloutSearch).keySet().size();%0A
     
@@ -3442,33 +3442,44 @@
   %7D%0A        
-%7D
+return null;
 %0A    %7D%0A%0A
     private 
@@ -3458,32 +3458,33 @@
 rn null;%0A    %7D%0A%0A
+%0A
     private stat

Set query audit values to something useful