package ch.wlkl.shell;

import static ch.wlkl.shell.EnvMan.env;

import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Strings extends Top {
	
	final static Pattern oneWord = Pattern.compile("\\s*(\\S+)");
	final private static Matcher xQuoteMatcher = Pattern.compile("[^\"\\\\\n]+").matcher("");
	
	public static String unquote(String src) {
		if (src.length() == 0)
			return src;
		
		final char qu = src.charAt(0);
		String res = "";
		int ex, bx = 1;
		
		while (true) {
			ex = src.indexOf(qu, bx);	
			if (ex < 0)
				sFail("non terminated string: " + src);
			if (ex == src.length() - 1 )
				return res + src.substring(bx, ex);
			if (src.charAt(ex+1) != qu)
				sFail("single quote at position " + ex + " in string: " + src);
			res += src.substring(bx, ex) + qu;
			bx = ex+2;
		}
	}

	public static String quote(String src) {
		if (src == null)
			return "\"\"";
		int fx = 0;
		int px;
		String q = "\"";
		while(true) {
			px = src.indexOf('\"', fx);
			if (px < 0)
				break;
			q = q + src.substring(fx, fx = 1 + px) + '"';
		}
		return q + src.substring(fx) + '"';
	}

	public static String hex(CharSequence src) {
		StringBuffer b = new StringBuffer(2 * src.length());
		for (int ix=0; ix < src. length(); ix ++) {
			char c = src.charAt(ix);
			if (c < 256)
				b.append(String.format("%2h", c));
			else
				b.append("\\u(").append(String.format("%h", c)).append(')');			
		}
		return b.toString();
	}
	
	public static String xUnquote(String src) {
		if (src == null || src.length() <= 1)
			sFail("cannot unquote this string: <" + src + ">");
		
		StringBuffer buf = new StringBuffer("");
		final char qu = src.charAt(0);
		char c = 0;
		int sx = 1, qx = 0, bx = 0; 
		
		while (true) {
			if (qx < sx)
				if ((qx = src.indexOf(qu, sx)) < 0)
					qx = src.length();
			if (bx < sx)
				if ((bx = src.indexOf('\\', sx)) < 0)
					bx = src.length();
			if (bx < qx) {
				if (bx + 1>= src.length())
					sFail("backslash at end of String: <" + src + ">");
				buf.append(src, sx, bx).append((c = src.charAt(bx+1)) == 'n' ? '\n' : c == 't' ? 't' : c);
				sx = bx+2;
			} else {
				if (qx + 1 == src.length())
					return buf.append(src, sx, qx).toString();
				else
					sFail("quote within String: <" + src + ">");
			}
		}
	}

	public static String xQuote(String src) {
		if (src == null)
			return "\"\"";
		StringBuffer buf = new StringBuffer("\"");
		int nx = 0;
		xQuoteMatcher.reset(src);
		while (true) {
			if (xQuoteMatcher.lookingAt()) {
				buf.append(xQuoteMatcher.group());
				nx = xQuoteMatcher.end();
			} 
			if (nx >= src.length())
				return buf.append('"').toString();
			buf.append('\\').append(src.charAt(nx) == '\n' ? 'n' : src.charAt(nx));
			xQuoteMatcher.region(++nx, src.length());
		}
	}

	public static String fill(String rep, int len) {
		StringBuffer b = new StringBuffer(rep == null || rep.equals("") ? " " : rep);
		while (b.length() < len)
			b.append(b);
		return b.substring(0, len);
	}

	public static String cat(Collection<String> lst, String le, String mi, String ri) {
		StringBuffer b = new StringBuffer(le);
		boolean first = true;
		for (String s : lst) {
			if (first)
				first = false;
			else
				b.append(mi);
			b.append(s);
		}
		return b.append(ri).toString();
	}

	public static String cat(Collection<String> lst, String mi) {
		return cat(lst, "", mi, "");
	}

	public static void words() {
		Matcher match = oneWord.matcher("");
		String one;
		while (null != (one = env().read())) {
			match.reset(one);
			while (match.lookingAt()) {
				env().write(match.group(1));
				match.region(match.end(), one.length());
			} 
		}
	} 

	public static void wc(boolean wrLines) {
		Matcher match = oneWord.matcher("");
		String one;
		int lc = 0, wc = 0, cc = 0;
		while (null != (one = env().read())) {
			lc ++;
			cc += one.length();
			
			match.reset(one);
			while (match.lookingAt()) {
				wc++;
				match.region(match.end(), one.length());
			} 
			if (wrLines)
				env().write(one);
		}
		env().write("counted " + lc + " lines, " + wc + " words, " + cc + " chars");
	} 
}

