package de.hacksaar.andtuer;

import android.os.AsyncTask;
import android.util.Log;
import de.hacksaar.javatuer.InteractiveLogin;
import de.hacksaar.javatuer.TyshellClient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;

class AsyncTyshell extends AsyncTask<Void, Void, Void> {

	private static final String TAG = "AsyncTyshell";
	private final String hostname;
	private final int port;
	private final String username;
	private final String keyFile;
	private final Prompter prompter;
	private final Queue<String> messages = new LinkedList<>();
	private final Object promptWait = new Object();
	private String promptResultString;
	private boolean promptResultBoolean;
	private boolean disconnect = true;

	AsyncTyshell(String hostname, int port, String username, String keyFile, Prompter prompter) {
		this.hostname = hostname;
		this.port = port;
		this.username = username;
		this.keyFile = keyFile;
		this.prompter = prompter;
	}

	private void awaitPrompt() {
		synchronized (promptWait) {
			try {
				promptWait.wait();
			} catch (InterruptedException e) {
				Log.w(TAG, e);
			}
		}
	}

	public void disconnect() {
		disconnect = false;
		synchronized (promptWait) {
			promptWait.notify();
		}
		synchronized (messages) {
			messages.notify();
		}
	}

	private void readUnlimited(InputStreamReader inputStreamReader) {
		final BufferedReader reader = new BufferedReader(inputStreamReader);
		new Thread(new Runnable() {
			@Override
			public void run() {
				String line;
				try {
					while((line = reader.readLine()) != null) {
						prompter.sendMessage(line);
					}
				} catch (Exception e) {
					Log.w("end read unlimited!", e);
				}
			}
		}).start();
	}

	@Override
	protected Void doInBackground(Void... voids) {
		TyshellClient client = new TyshellClient(hostname, port, new AndroidLogging());
		client.connect(username, keyFile, new AsyncInteractiveLogin());
		readUnlimited(client.getInputStream());
		while (disconnect) {
			String msg = null;
			synchronized (messages) {
				while (disconnect && (msg = messages.poll()) == null) {
					try {
						messages.wait();
					} catch (InterruptedException e) {
						return null;
					}
				}
			}
			if (msg == null) {
				break;
			}
			client.sendCommand(msg);
		}
		client.disconnect();
		return null;
	}

	public void promptResult(boolean result) {
		promptResultBoolean = result;
		synchronized (promptWait) {
			promptWait.notify();
		}
	}

	public void promptResult(String result) {
		promptResultString = result;
		synchronized (promptWait) {
			promptWait.notify();
		}
	}

	public void sendCommand(String string) {
		synchronized (messages) {
			messages.add(string);
			messages.notify();
		}
	}

	public interface Prompter {
		void promptBoolean(String message);

		void promptString(String message);

		void sendMessage(String message);
	}

	private class AsyncInteractiveLogin extends InteractiveLogin {

		AsyncInteractiveLogin() {
		}

		@Override
		public String promptKeyPassphrase(String question) {
			prompter.promptString(question);
			awaitPrompt();
			return promptResultString;
		}

		@Override
		public String promptUserPassword(String question) {
			prompter.promptString(question);
			awaitPrompt();
			return promptResultString;
		}

		@Override
		public boolean promptYesNo(String question) {
			prompter.promptBoolean(question);
			awaitPrompt();
			return promptResultBoolean;
		}

		@Override
		public void showMessage(String s) {
			prompter.sendMessage(s);
		}
	}
}
