package dk.silverbullet.telemed.questionnaire;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;
import dk.silverbullet.telemed.questionnaire.expression.Constant;
import dk.silverbullet.telemed.questionnaire.expression.Variable;
import dk.silverbullet.telemed.questionnaire.node.IONode;
import dk.silverbullet.telemed.questionnaire.node.Node;
import dk.silverbullet.telemed.questionnaire.node.WebViewNode;
import dk.silverbullet.telemed.questionnaire.output.OutputSkema;
import dk.silverbullet.telemed.rest.client.ServerInformation;
import dk.silverbullet.telemed.utils.Util;
import java.util.*;
public class Questionnaire implements ServerInformation {
private static final String TAG = Util.getTag(Questionnaire.class);
private final Map<String, Variable<?>> valuePool = new HashMap<String, Variable<?>>();
private final Map<String, Variable<?>> skemaValuePool = new HashMap<String, Variable<?>>();
private final Stack<Map<String, Constant<?>>> varStack = new Stack<Map<String, Constant<?>>>();
private final QuestionnaireFragment parentFragment;
private boolean running;
private Node startNode;
private Node currentNode;
private OutputSkema outputSkema;
private Node previousNode;
private boolean backPressed;
private Stack<IONode> ioNodeStack = new Stack<IONode>();
private Activity activity;
@Override
public String getServerUrl() {
return Util.getServerUrl(this);
}
@Override
public String getUserName() {
return Util.getStringVariableValue(this, Util.VARIABLE_USERNAME);
}
@Override
public String getPassword() {
return Util.getStringVariableValue(this, Util.VARIABLE_PASSWORD);
}
@Override
public Context getContext() {
return activity;
}
public Activity getActivity() {
return activity;
}
public void cleanSkemaValuePool() {
skemaValuePool.clear();
}
public Questionnaire(QuestionnaireFragment parentFragment) {
this.parentFragment = parentFragment;
this.activity = parentFragment.getActivity();
}
public void addVariable(Variable<?> output) {
this.valuePool.put(output.getName(), output);
}
public void addSkemaVariable(Variable<?> output) {
this.skemaValuePool.put(output.getName(), output);
}
public void execute() {
try {
int count = 0;
running = true;
long t0 = System.currentTimeMillis();
while (currentNode != null) {
count++;
if (count > 1000000) {
throw new RuntimeException("LOOP COUNT EXCEEDED!");
}
previousNode = currentNode;
currentNode = null;
previousNode.enter();
}
long t1 = System.currentTimeMillis();
Log.d(TAG, "Loop count: " + count + " in " + (t1 - t0));
} finally {
running = false;
}
}
public void setCurrentNode(Node newNode) {
if (null == newNode) {
Toast.makeText(getContext().getApplicationContext(), "NextNode is undefined", Toast.LENGTH_SHORT).show();
return;
}
if (previousNode != null) {
previousNode.leave();
}
currentNode = newNode;
if (!running) {
execute();
}
}
public void setStartNode(Node startNode) {
this.startNode = startNode;
}
public void start() {
Log.d(TAG, "start...");
setCurrentNode(startNode);
execute();
}
public void back() {
backPressed = true;
hideSoftKeyboard();
if (getCurrentNode() == null) {
if (!ioNodeStack.isEmpty()) {
// Handle the special case of WebViewNodes which, trough a webview, have an internal stack. If that
// stack is nonempty, pop it. Otherwise proceed as normal
if (stackTopIsWebViewNode()) {
WebViewNode webViewNode = (WebViewNode) ioNodeStack.peek();
if (webViewNode.canGoBack()) {
webViewNode.goBack();
backPressed = false;
return;
}
}
IONode popped = ioNodeStack.pop();
varStack.pop();
Log.d(TAG, "* Popped: " + popped.getNodeName());
if (!ioNodeStack.isEmpty()) {
IONode peeked = ioNodeStack.peek();
Log.d(TAG, "* Peeked: " + peeked.getNodeName());
}
}
goBack();
}
}
private void hideSoftKeyboard() {
Activity activity = getActivity();
View currentFocus = activity.getCurrentFocus();
if(currentFocus != null && currentFocus instanceof EditText) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
}
}
private boolean stackTopIsWebViewNode() {
return ioNodeStack.peek().getClass() == WebViewNode.class;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void goBack() {
Log.d(TAG, "goBack! stack size:" + ioNodeStack.size());
backPressed = false;
if (ioNodeStack.isEmpty()) {
Log.d(TAG, "Empty stack - terminating!");
parentFragment.getActivity().finish();
} else {
Log.d(TAG, "Going back!");
Set<String> vars = new HashSet<String>(skemaValuePool.keySet());
Map<String, Constant<?>> temp = varStack.pop();
IONode popped = ioNodeStack.pop();
if (!ioNodeStack.isEmpty()) {
Log.d(TAG, "next: " + ioNodeStack.peek().getNodeName());
}
setCurrentNode(popped);
for (String name : vars) {
if (temp.containsKey(name)) {
Log.d(TAG, "***** " + name + "=" + temp.get(name));
skemaValuePool.get(name).setValue((Constant) temp.get(name));
} else {
Log.d(TAG, "***** " + name + " DELETED");
skemaValuePool.remove(name);
}
}
}
}
public void clearStack() {
ioNodeStack.clear();
varStack.clear();
}
@SuppressWarnings("unchecked")
public void logout() {
Variable<Boolean> isLoggedIn = (Variable<Boolean>) getValuePool().get(Util.VARIABLE_IS_LOGGED_IN);
isLoggedIn.setValue(false);
Variable<Boolean> isLoggedInAsAdmin = (Variable<Boolean>) getValuePool().get(Util.VARIABLE_IS_LOGGED_IN_AS_ADMIN);
isLoggedInAsAdmin.setValue(false);
Variable<String> userName = (Variable<String>) getValuePool().get(Util.VARIABLE_USERNAME);
userName.setValue("");
Variable<String> password = (Variable<String>) getValuePool().get(Util.VARIABLE_PASSWORD);
password.setValue("");
MainQuestionnaire.getInstance().adviceActivityOfUserLogout();
setCurrentNode(MainQuestionnaire.getInstance().getMainMenu());
}
public boolean isIONodeStackEmpty() {
return ioNodeStack.isEmpty();
}
public void push(IONode ioNode) {
for (int i = 0; i < ioNodeStack.size(); i++) {
if (ioNodeStack.get(i) == ioNode) {
ioNodeStack.setSize(i + 1);
varStack.setSize(i + 1);
return;
}
}
ioNodeStack.push(ioNode);
// Capture all variables:
Map<String, Constant<?>> temp = new HashMap<String, Constant<?>>();
for (String name : skemaValuePool.keySet()) {
Log.d(TAG, "##### " + name + ": " + skemaValuePool.get(name).getExpressionValue());
temp.put(name, skemaValuePool.get(name).getExpressionValue());
}
varStack.push(temp);
}
public void chainToNextIONode() {
// Make current IONode "Invisible" in the navigation history
if (!isIONodeStackEmpty()) {
ioNodeStack.pop();
varStack.pop();
}
}
public String getFullName() {
if (null != valuePool && valuePool.containsKey(Util.VARIABLE_REAL_NAME)) {
return valuePool.get(Util.VARIABLE_REAL_NAME).getExpressionValue().toString();
}
return "";
}
public Long getUserId() {
if (null != valuePool && valuePool.containsKey(Util.VARIABLE_USER_ID)) {
return (Long) valuePool.get(Util.VARIABLE_USER_ID).getExpressionValue().getValue();
}
return null;
}
public ViewGroup getRootLayout() {
return parentFragment.getRootLayout();
}
public Node getCurrentNode() {
return currentNode;
}
public Map<String, Variable<?>> getValuePool() {
return valuePool;
}
public boolean isBackPressed() {
return backPressed;
}
public void setOutputSkema(OutputSkema outputSkema) {
this.outputSkema = outputSkema;
}
public Map<String, Variable<?>> getSkemaValuePool() {
return skemaValuePool;
}
public OutputSkema getOutputSkema() {
return outputSkema;
}
}