package com.unprompted.tildefriends;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.Process;
import java.lang.Thread;
import java.nio.file.FileSystems;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class MainActivity extends Activity {
	WebView web_view;
	String base_url;
	Process process;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);

		web_view = (WebView)findViewById(R.id.web);
		String arch = System.getProperty("os.arch");
		Log.w("tildefriends", String.format("getFilesDir() is %s", getFilesDir().toString()));
		Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
		Log.w("tildefriends", String.format("os.arch is %s", arch));

		try {
			ZipInputStream zip = new ZipInputStream(new BufferedInputStream(new FileInputStream(getPackageResourcePath().toString())));
			ZipEntry entry = null;
			String lookup = String.format("bin/%s/tildefriends", arch);
			Log.w("tildefriends", "Looking for " + lookup);
			while ((entry = zip.getNextEntry()) != null) {
				if (entry.getName().equals(lookup)) {
					Log.w("tildefriends", "Extracting " + entry.getName());
					FileOutputStream out = new FileOutputStream(getFilesDir().toString().concat("/tildefriends"));
					byte[] buffer = new byte[32768];
					int count;
					while ((count = zip.read(buffer)) != -1) {
						out.write(buffer, 0, count);
					}
					out.close();
					new File(getFilesDir().toString() + "/tildefriends").setExecutable(true);
				}
				zip.closeEntry();
			}
		} catch (java.io.FileNotFoundException e) {
			Log.w("tildefriends", "FileNotFoundException extracting executable");
			Log.w("tildefriends", e.toString());
		} catch (java.io.IOException e) {
			Log.w("tildefriends", "IOException extracting executable");
			Log.w("tildefriends", e.toString());
		}

		String port_file_path = getFilesDir().toString() + "/port.txt";
		base_url = "http://127.0.0.1:12345/";

		MainActivity activity = this;

		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
					WatchService watcher = FileSystems.getDefault().newWatchService();
					Paths.get(getFilesDir().toString()).register(
						watcher,
						StandardWatchEventKinds.ENTRY_CREATE,
						StandardWatchEventKinds.ENTRY_MODIFY);
					while (true) {
						WatchKey key = watcher.take();
						for (WatchEvent event : key.pollEvents()) {
							if (event.context().toString().equals("port.txt")) {
								Log.w("tildefriends", "Observed file write: " + event.context().toString());
								base_url = "http://127.0.0.1:" + String.valueOf(read_port(port_file_path)) + "/";
								activity.runOnUiThread(() -> {
									web_view.loadUrl(base_url);
								});
								watcher.close();
								break;
							}
						}
						if (!key.reset()) {
							Log.w("tildefriends", "watcher is no longer valid");
							break;
						}
					}
				} catch (java.io.IOException e) {
					Log.w("tildefriends", "IOException: " + e.toString());
				} catch (InterruptedException e) {
					Log.w("tildefriends", "InterruptedException: " + e.toString());
				}
			}
		}).start();

		String exe = getFilesDir().toString() + "/tildefriends";
		ProcessBuilder builder = new ProcessBuilder(exe, "run", "-z", getPackageResourcePath().toString(), "-a", "out_http_port_file=" + port_file_path, "-p", "0");
		Log.w("tildefriends", "files = " + getFilesDir().toString());
		Log.w("tildefriends", "exe = " + exe);
		builder.directory(getFilesDir());
		builder.inheritIO();
		try {
			process = builder.start();
		} catch (java.io.IOException e) {
			Log.w("tildefriends", "IOException starting process: " + e.toString());
		}

		web_view.getSettings().setJavaScriptEnabled(true);
		web_view.getSettings().setDatabaseEnabled(true);
		web_view.getSettings().setDomStorageEnabled(true);

		web_view.setWebChromeClient(new WebChromeClient() {
			@Override
			public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
				new AlertDialog.Builder(view.getContext())
					.setTitle("Tilde Friends")
					.setMessage(message)
					.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
					{
						public void onClick(DialogInterface dialog, int which)
						{
							result.confirm();
						}
					})
					.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
					{
						public void onClick(DialogInterface dialog, int which)
						{
							result.cancel();
						}
					})
					.create()
					.show();
				return true;
			}

			@Override
			public boolean onConsoleMessage(android.webkit.ConsoleMessage consoleMessage) {
				Log.d("tildefriends", consoleMessage.message() + " -- From line " + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId());
				return true;
			}
		});

		web_view.setWebViewClient(new WebViewClient() {
			@Override
			public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
			{
				if (request.getUrl() != null && request.getUrl().toString().startsWith(base_url)) {
					return false;
				} else {
					view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, request.getUrl()));
					return true;
				}
			}
		});

		Button refresh = (Button)findViewById(R.id.refresh);
		refresh.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				web_view.reload();
			}
		});
	}

	@Override
	protected void onDestroy()
	{
		if (process != null) {
			Log.w("tildefriends", "Killing process.");
			process.destroyForcibly();
			Log.w("tildefriends", "Process killed.");
			process = null;
		}
		super.onDestroy();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState)
	{
		super.onSaveInstanceState(outState);
		web_view.saveState(outState);
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState)
	{
		super.onRestoreInstanceState(savedInstanceState);
		web_view.restoreState(savedInstanceState);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK && web_view.canGoBack()) {
			web_view.goBack();
			return true;
		} else if (keyCode == KeyEvent.KEYCODE_FORWARD && web_view.canGoForward()) {
			web_view.goForward();
			return true;
		} else if (keyCode == KeyEvent.KEYCODE_REFRESH) {
			web_view.reload();
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	private int read_port(String path) {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(path));
			return Integer.parseInt(reader.readLine());
		} catch (java.io.FileNotFoundException e) {
			e.printStackTrace();
		} catch (java.io.IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (reader != null) {
					reader.close();
				}
			} catch (java.io.IOException e) {
			}
		}
		return -1;
	}
}
