package terse.vm;


import java.util.Arrays;
import java.util.regex.Pattern;

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

public class Static {

	public static class TalkException extends RuntimeException {
		private static final long serialVersionUID = 1L;
		Terp terp;
		String msg;
		Object[] args;

		public TalkException(Terp t, String msg, Object... args) {
			this.terp = t;
			this.msg = msg;
			this.args = args;
			terp.say("TalkException: msg=<%s>", msg);
			for (int i = 0; i < args.length; i++) {
				terp.say("TalkException: args[%d] : %s : <%s>", i,
						(args[i] instanceof Pro) ? ((Pro) args[i]).cls.name
								: args[i].getClass().getName(), args[i]
								.toString());
			}
			breakHere(this);
		}

		@Override
		public String toString() {
			return fmt(msg, args);
		}
	}

	public static final String PRELUDE = "prelude.txt";

	public static void breakHere(Object x) {
		x.toString();
	}

	public static String fmt(String s, Object... objects) {
		return String.format(s, objects);
	}

	public static String htmlEscape(String s) {
		return s.replace("&", "&amp;").replace("<", "&lt;")
				.replace(">", "&gt;").replace("\"", "&quot;");
	}

	public static String arrayToString(Expr[] a) {
		String z = "[ ";
		for (Expr e : a) {
			z += fmt("%s, ", e.toString());
		}
		return z + "]";
	}

	public static String arrayToString(Pro[] a) {
		String z = "[ ";
		for (Pro e : a) {
			z += fmt("%s, ", e.toString());
		}
		return z + "]";
	}

	public static String arrayToString(String[] a) {
		if (a == null)
			return "<NULL[]>";
		String z = "[ ";
		for (String e : a) {
			z += fmt("\"%s\", ", e);
		}
		return z + "]";
	}

	public static String repeat(int n, String s) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < n; i++) {
			sb.append(s);
		}
		return sb.toString();
	}

	// Little functions to avoid List objects for small arrays.
	// append() builds arrays in O(n**2) time, but n is usually very small.
	public static String[] strs(String... strings) {
		return strings;
	}

	public static String[] emptyStrs = new String[0];

	public static String[] append(String[] arr, String s) {
		if (arr == null || arr.length == 0) {
			return new String[] { s };
		}
		String[] z = Arrays.copyOf(arr, arr.length + 1);
		z[arr.length] = s;
		return z;
	}

	public static String[] filterOutEmptyStrings(String[] a) {
		int count = 0;
		for (int i = 0; i < a.length; i++) {
			if (a[i].length() > 0)
				++count;
		}
		String[] z = new String[count];
		int j = 0;
		for (int i = 0; i < a.length; i++) {
			if (a[i].length() > 0) {
				z[j] = a[i];
				++j;
			}
		}
		return z;
	}

	public static Expr[] exprs(Expr... exprs) {
		return exprs;
	}

	public static Expr[] emptyExprs = new Expr[0];

	public static Expr[] append(Expr[] arr, Expr s) {
		if (arr == null || arr.length == 0) {
			return new Expr[] { s };
		}
		Expr[] z = Arrays.copyOf(arr, arr.length + 1);
		z[arr.length] = s;
		return z;
	}

	public static Pro[] pros(Pro... pros) {
		return pros;
	}

	public static Pro[] emptyPros = new Pro[0];

	public static Pro[] append(Pro[] arr, Pro s) {
		if (arr == null || arr.length == 0) {
			return new Pro[] { s };
		}
		Pro[] z = Arrays.copyOf(arr, arr.length + 1);
		z[arr.length] = s;
		return z;
	}

	public static int[] ints(int... ints) {
		return ints;
	}

	public static int[] emptyInts = new int[0];

	public static int[] append(int[] arr, int s) {
		if (arr == null || arr.length == 0) {
			return new int[] { s };
		}
		int[] z = Arrays.copyOf(arr, arr.length + 1);
		z[arr.length] = s;
		return z;
	}

	// I got infinite recursion trying to use Java split() with quoted pattern.
	// So i write a simple one myself:
	public static String[] splitNonEmpty(String src, char delim) {
		String[] z = emptyStrs;
		while (src.length() > 0) {
			int i = src.indexOf(delim);
			if (i < 0) {
				// Not found; take the rest.
				z = append(z, src);
				break;
			} else if (i > 0) {
				z = append(z, src.substring(0, i));
				src = src.substring(i + 1);
			} else { // i == 0
				// Don't append empty string.
				src = src.substring(1);
			}
		}
		return z;
	}

	public static Pattern htmlTagP = Pattern
			.compile("[A-Za-z][-A-Za-z0-9_.:]*");

	public static String stringAt(Pro p, String i) {
		return stringAt(p, i, null);
	}

	public static String stringAt(Pro p, String i, String dflt) {
		if (!(p instanceof Dict))
			return dflt;
		Dict d = (Dict) p;
		Pro x = d.dict.get(d.terp().newStr(i));
		if (!(x instanceof Str))
			return dflt;
		return ((Str) x).str;
	}
	public static Pro proAt(Pro p, String i) {
		if (!(p instanceof Dict))
			return p.terp().instNil;
		Dict d = (Dict) p;
		return d.dict.get(d.terp().newStr(i));
	}

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

	public 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;
	}

}
