package org.commcare.util.cli;

import org.commcare.core.network.ModernHttpRequester;
import org.commcare.modern.session.SessionWrapper;
import org.commcare.modern.util.Pair;
import org.commcare.session.CommCareSession;
import org.commcare.session.RemoteQuerySessionManager;
import org.commcare.suite.model.DisplayUnit;
import org.javarosa.core.model.instance.ExternalDataInstance;
import org.javarosa.core.model.instance.TreeElement;
import org.javarosa.core.services.locale.Localization;
import org.javarosa.xml.ElementParser;
import org.javarosa.xml.TreeElementParser;
import org.javarosa.xml.util.InvalidStructureException;
import org.javarosa.xml.util.UnfullfilledRequirementsException;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * Screen to allow users to choose items from session menus.
 *
 * @author ctsims
 */
public class QueryScreen extends Screen {

    protected RemoteQuerySessionManager remoteQuerySessionManager;
    Hashtable<String, DisplayUnit> userInputDisplays;
    SessionWrapper sessionWrapper;
    String[] fields;
    String mTitle;
    String currentMessage;

    @Override
    public void init(SessionWrapper sessionWrapper) throws CommCareSessionException {
        this.sessionWrapper = sessionWrapper;
        remoteQuerySessionManager =
                RemoteQuerySessionManager.buildQuerySessionManager(sessionWrapper,
                        sessionWrapper.getEvaluationContext());
        userInputDisplays = remoteQuerySessionManager.getNeededUserInputDisplays();

        int count = 0;
        fields = new String[userInputDisplays.keySet().size()];
        for (Map.Entry<String, DisplayUnit> displayEntry : userInputDisplays.entrySet()) {
            fields[count] = displayEntry.getValue().getText().evaluate(sessionWrapper.getEvaluationContext());
        }
        mTitle = "Case Claim";

    }

    public boolean processSuccess(InputStream responseData) {
        Pair<ExternalDataInstance, String> instanceOrError =
                buildExternalDataInstance(responseData,
                        remoteQuerySessionManager.getStorageInstanceName());
        if (instanceOrError.first == null) {
            currentMessage = "Query response format error: " + instanceOrError.second;
            return false;
        } else if (isResponseEmpty(instanceOrError.first)) {
            currentMessage = "Query response was empty";
            return false;
        } else {
            sessionWrapper.setQueryDatum(instanceOrError.first);
            return true;
        }
    }

    /**
     * @return Data instance built from xml stream or the error message raised during parsing
     */
    public static Pair<ExternalDataInstance, String> buildExternalDataInstance(InputStream instanceStream,
                                                                               String instanceId) {
        TreeElement root;
        try {
            KXmlParser baseParser = ElementParser.instantiateParser(instanceStream);
            root = new TreeElementParser(baseParser, 0, instanceId).parse();
        } catch (InvalidStructureException | IOException
                | XmlPullParserException | UnfullfilledRequirementsException e) {
            return new Pair<>(null, e.getMessage());
        }
        return new Pair<>(ExternalDataInstance.buildFromRemote(instanceId, root), "");
    }

    private boolean isResponseEmpty(ExternalDataInstance instance) {
        return !instance.getRoot().hasChildren();
    }

    public void answerPrompts(Hashtable<String, String> answers) {
        for(String key: answers.keySet()){
            remoteQuerySessionManager.answerUserPrompt(key, answers.get(key));
        }
    }

    public URL getBaseUrl(){
        return remoteQuerySessionManager.getBaseUrl();
    }

    public Hashtable<String, String> getQueryParams(){
        return remoteQuerySessionManager.getRawQueryParams();
    }

    public String getScreenTitle() {
        return mTitle;
    }

    @Override
    public void prompt(PrintStream out) {

    }

    @Override
    public String[] getOptions() {
        return fields;
    }

    @Override
    public boolean handleInputAndUpdateSession(CommCareSession session, String input) {
        return true;
    }

    public Hashtable<String, DisplayUnit> getUserInputDisplays(){
        return userInputDisplays;
    }

    public String getCurrentMessage(){
        return currentMessage;
    }
}

@@ -29,62 +29,8 @@
 i;%0A%0A
-import org.commcare.core.network.ModernHttpRequester;%0A
 impo
@@ -259,16 +259,65 @@
 ayUnit;%0A
+import org.commcare.suite.model.MenuDisplayable;%0A
 import o
@@ -427,63 +427,8 @@
 nt;%0A
-import org.javarosa.core.services.locale.Localization;%0A
 impo
@@ -704,16 +704,53 @@
 ption;%0A%0A
+import java.io.ByteArrayInputStream;%0A
 import j
@@ -862,20 +862,36 @@
 ava.
-util.HashMap
+nio.charset.StandardCharsets
 ;%0Aim
@@ -958,55 +958,107 @@
 en t
-o allow users to choose items from session menu
+hat displays user configurable entry texts and makes%0A * a case query to the server with these field
 s.%0A 
@@ -1074,14 +1074,15 @@
 hor 
-ctsims
+wspride
 %0A */
@@ -2095,26 +2095,141 @@
 aim%22;%0A%0A    %7D
+%0A    public InputStream makeQueryRequestReturnStream() %7B%0A        // TODO Implement this%0A        return null;%0A    %7D
 %0A%0A
+%0A
     public b
@@ -4383,16 +4383,119 @@
  out) %7B%0A
+        for (int i=0; i%3C fields.length; i++) %7B%0A            out.println(i + %22) %22 + fields%5Bi%5D);%0A        %7D
 %0A    %7D%0A%0A
@@ -4679,35 +4679,480 @@
 ) %7B%0A        
-return true
+String%5B%5D answers = input.split(%22,%22);%0A        Hashtable%3CString, String%3E userAnswers = new Hashtable%3C%3E();%0A        int count = 0;%0A        for (Map.Entry%3CString, DisplayUnit%3E displayEntry : userInputDisplays.entrySet()) %7B%0A            userAnswers.put(displayEntry.getKey(), answers%5Bcount%5D);%0A            count ++;%0A        %7D%0A        answerPrompts(userAnswers);%0A        InputStream response = makeQueryRequestReturnStream();%0A        return processSuccess(response)
 ;%0A    %7D%0A%0A   

refactor QuerySCreen