package terse.a1;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;

import terse.vm.Pro;
import terse.vm.Pro.Num;
import terse.vm.Terp;
import terse.vm.Pro.Dict;
import terse.vm.Pro.Str;
import terse.vm.Pro.Vec;

import android.app.Activity;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public abstract class TerseActivity extends Activity {

	public static Terp terp;
	public static String terp_error;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		if (this.terp == null) {
			try {
				this.terp = new AndroidTerp(true, "aaa", "aaa.txt");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				terp_error = e.toString();
			}
		}
	}

	public class AndroidTerp extends Terp {

		protected AndroidTerp(boolean loadPrelude, String imageName,
				String initFilename) throws IOException {
			super(loadPrelude, imageName, initFilename);
		}

		@Override
		public String say(String s, Object... objects) {
			String msg = fmt(s, objects);
			Log.i("Terse", msg);
			return msg;
		}

		@Override
		public void loadPrelude() throws IOException {
			loadReader(preludeReader());
		}

		@Override
		public FileInputStream openFileRead(String filename)
				throws FileNotFoundException {
			return openFileInput(filename);
		}

		@Override
		public FileOutputStream openFileWrite(String filename)
				throws FileNotFoundException {
			return openFileOutput(filename, Context.MODE_WORLD_READABLE
					| Context.MODE_WORLD_WRITEABLE);
		}

		@Override
		public FileOutputStream openFileAppend(String filename)
				throws FileNotFoundException {
			return openFileOutput(filename, Context.MODE_WORLD_READABLE
					| Context.MODE_WORLD_WRITEABLE | Context.MODE_APPEND);
		}
	}

	public InputStreamReader preludeReader() {
		InputStream is = getResources().openRawResource(R.raw.prelude);
		return new InputStreamReader(is);
	}

	public void viewPath(String path, String queryStr) {
		// LayoutParams containerParams = new
		// LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
		// ViewGroup.LayoutParams.WRAP_CONTENT, 0.0f);

		LayoutParams widgetParams = new LayoutParams(
				ViewGroup.LayoutParams.FILL_PARENT,
				ViewGroup.LayoutParams.FILL_PARENT, 1.0f);

		// Url query.
		HashMap<String, String> query = new HashMap<String, String>();
		queryStr = queryStr == null ? "" : queryStr; // Don't be null.

		String[] parts = queryStr.split("&");
		for (String part : parts) {
			String[] kv = part.split("=", 2);
			if (kv.length == 2)
				try {
					query.put(kv[0], URLDecoder.decode(kv[1], "UTF-8"));
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return; // TODO
				}
		}

		String explain;
		if (terp_error != null) {
			explain = "terp_error = " + terp_error;
		} else {
			try {
				// Log.i("TT handler", "Sending to terp: " + url);
				terp.say("Sending to terp: %s", path);
				final Dict d = terp.handleUrl(path, query);
				// Log.i("TT handler", "Result from terp: " + d);
				terp.say("Result from terp: %s", d);
				explain = "DEFAULT EXPLANATION:\n\n" + d.toString();

				Str TYPE = d.cls.terp.newStr("type");
				Str VALUE = d.cls.terp.newStr("value");
				Str TITLE = d.cls.terp.newStr("title");
				Str type = (Str) d.dict.get(TYPE);
				Pro value = d.dict.get(VALUE);
				Pro title = d.dict.get(TITLE);

				if (type.str.equals("list") && value instanceof Vec) {
					final ArrayList<Pro> v = ((Vec) value).vec;
					ArrayList<String> labels = new ArrayList<String>();
					for (int i = 0; i < v.size(); i++) {
						Pro item = v.get(i);
						String label = item instanceof Str ? ((Str) item).str
								: item.toString();
						if (item instanceof Vec && ((Vec) item).vec.size() == 2) {
							label = ((Vec) item).vec.get(0).toString();
							label += "    ["
									+ ((Vec) item).vec.get(1).toString()
											.length() + "]";
						}
						labels.add(label);
						// Log.i("TList", "ADD " + label);
					}
					// Log.i("TList", "SIZE " + v.size());

					ListView listv = new ListView(this);
					listv.setAdapter(new ArrayAdapter<String>(this,
							R.layout.list_item, labels));
					listv.setLayoutParams(widgetParams);
					listv.setTextFilterEnabled(true);

					listv.setOnItemClickListener(new OnItemClickListener() {
						public void onItemClick(AdapterView<?> parent,
								View view, int position, long id) {
							// When clicked, show a toast with the TextView text
							Toast.makeText(getApplicationContext(),
									((TextView) view).getText(),
									Toast.LENGTH_SHORT).show();
							if (v.get(position) instanceof Vec) {
								Vec pair = (Vec) v.get(position);
								if (pair.vec.size() == 2) {
									if (pair.vec.get(0) instanceof Str) {
										String[] words = ((Str) pair.vec.get(0)).str
												.split("\\|");
										Log.i("TT-WORDS",
												terp.arrayToString(words));
										if (words[1].equals("link")) {
											Uri uri = new Uri.Builder()
													.scheme("terse")
													.path(words[2]).build();
											Intent intent = new Intent(
													"android.intent.action.MAIN",
													uri);
											intent.setClass(
													getApplicationContext(),
													MainActivity.class);

											startActivity(intent);
										}
									}
								}
							}
						}
					});
					setContentView(listv);
					return;
				} else if (type.str.equals("edit") && value instanceof Str) {
					final EditText ed = new EditText(this);
					ed.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE
							| InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE
							| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
					ed.setText(((Str) value).str);
					ed.setMinLines(12);
					ed.setLayoutParams(widgetParams);
					ed.setOnKeyListener(new OnKeyListener() {
						public boolean onKey(View v, int keyCode, KeyEvent event) {
							// If the event is a key-down event on the "enter"
							// button
							// if ((event.getAction() == KeyEvent.ACTION_DOWN)
							// &&
							// (keyCode == KeyEvent.KEYCODE_ENTER)) {
							// // Perform action on key press
							// Toast.makeText(TerseActivity.this, ed.getText(),
							// Toast.LENGTH_SHORT).show();
							// return true;
							// }
							return false;
						}
					});

					Button btn = new Button(this);
					btn.setText("Save");
					btn.setOnClickListener(new OnClickListener() {
						public void onClick(View v) {
							// Perform action on clicks
							String text = ed.getText().toString();
							Toast.makeText(TerseActivity.this, text,
									Toast.LENGTH_SHORT).show();
							String action = stringAt(d, "action");
							String query = "";
							if (stringAt(d, "field1") != null)
								query += Terp.fmt("%s=%s&",
										stringAt(d, "field1"),
										stringAt(d, "value1"));
							if (stringAt(d, "field2") != null)
								query += Terp.fmt("%s=%s&",
										stringAt(d, "field2"),
										stringAt(d, "value2"));
							query += Terp.fmt("%s=%s", "text", text);

							Uri uri = new Uri.Builder().scheme("terse")
									.path(action).encodedQuery(query).build();
							Intent intent = new Intent(
									"android.intent.action.MAIN", uri);
							intent.setClass(getApplicationContext(),
									MainActivity.class);
							if (stringAt(d, "field1") != null)
								intent.putExtra(stringAt(d, "field1"),
										stringAt(d, "value1"));
							if (stringAt(d, "field2") != null)
								intent.putExtra(stringAt(d, "field1"),
										stringAt(d, "value2"));
							intent.putExtra("text", text);

							startActivity(intent);
						}
					});

					LinearLayout linear = new LinearLayout(this);
					linear.setOrientation(LinearLayout.VERTICAL);
					linear.addView(btn);
					linear.addView(ed);
					setContentView(linear);
					return;

					// ///////////
					// explain = "EDIT:\n" + value.toString();
					// Fall thru for explainv.setText(explain).
				} else if (type.str.equals("text") && value instanceof Str) {
					explain = "<<< " + title + " >>>\n\n" + value.toString();
					// Fall thru for explainv.setText(explain).
				} else if (type.str.equals("draw") && value instanceof Vec) {
					Vec v = ((Vec) value);
					DrawView dv = new DrawView(this, v.vec);
					dv.setLayoutParams(widgetParams);
					setContentView(dv);
					return;
				} else {
					explain = "Unknown page type: " + type.str
							+ "\n\n##############\n\n";
					explain += value.toString();
					// Fall thru for explainv.setText(explain).
				}

			} catch (Exception ex) {
				explain = "CAUGHT " + ex;
			}
		}

		TextView explainv = new TextView(this);
		explainv.setText(explain);
		explainv.setBackgroundColor(Color.BLACK);

		ScrollView scrollv = new ScrollView(this);
		scrollv.addView(explainv);
		setContentView(scrollv);
	}

	static class DrawView extends View {
		ArrayList<Pro> list;

		public DrawView(Context context, ArrayList<Pro> list) {
			super(context);
			this.list = list;
		}

		protected void onDraw(Canvas canvas) {
			Paint paint = new Paint();
			paint.setColor(Color.GREEN);
			paint.setStrokeWidth(2);
			for (int i = 0; i < list.size(); i++) {
				Pro p = list.get(i);
				String drawtype = stringAt(p, 0);
				if (drawtype.equals("line")) {
					float x1 = floatAt(p, 1);
					float y1 = floatAt(p, 2);
					float x2 = floatAt(p, 3);
					float y2 = floatAt(p, 4);
					canvas.drawLine(x1, y1, x2, y2, paint);
				}
			}
		}
	}

	static String stringAt(Pro p, String i) {
		if (!(p instanceof Dict))
			return null; // "?p?";
		Dict d = (Dict) p;
		Pro x = d.dict.get(d.terp().newStr(i));
		if (!(x instanceof Str))
			return null; // "?x?";
		return ((Str) x).str;
	}

	static String stringAt(Pro p, int i) {
		if (!(p instanceof Vec))
			return null; // "?p?";
		Vec v = (Vec) p;
		int sz = v.vec.size();
		if (sz <= i)
			return null; // "?sz?";
		Pro x = v.vec.get(i);
		if (!(x instanceof Str))
			return null; // "?x?";
		return ((Str) x).str;
	}

	static float floatAt(Pro p, int i) {
		if (!(p instanceof Vec))
			return -1;
		Vec v = (Vec) p;
		int sz = v.vec.size();
		if (sz <= i)
			return -1;
		Pro x = v.vec.get(i);
		if (!(x instanceof Num))
			return -1;
		return (float) ((Num) x).num;
	}
}
