/*
 * Galatea Dialog Manager:
 * (c)2003 Takuya NISHIMOTO (nishi@hil.t.u-tokyo.ac.jp)
 * Based on Phoenix By Takuya NISHIMOTO and Mitsuhiro KIZU
 *
 * $Id: Util.java,v 1.20 2008/02/14 02:59:34 nishi Exp $
 */
package galatea.util;

import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.net.*;
import java.nio.charset.Charset;

public class Util 
{
	private static String _error = "";
	
	private Util() 
	{
	}
	
	public static void main(String args[]) throws Exception
	{
//		System.out.println(getSystemDefaultCharset().toString());
		String src, s, s1, s2;
//		src = "a\nb c < hoge > <br/><hr/> <audio href=xxx src=\"wav\"/> def <div class=\"ggg\">title</div>";
//		//s1 = Util.removeSpaces(src);
//		//System.out.println(s1);
//		s2 = Util.xmlSafeRemoveSpaces(src);
//		System.out.println(s2);
//		
		s = Util.resolveAdrs("http://aaa.bbb.com/index.vxml", "sub/next.vxml");
		System.out.println(s); // http://aaa.bbb.com/sub/next.vxml
		
		s = Util.resolveAdrs("/lab/common/src/nishi/galatea/gdm-current/phoenix/", 
		"../tests/audio/hoge.wav");
		System.out.println(s);
		
		s = Util.resolveAdrs("/lab/common/src/nishi/galatea/gdm-current/phoenix", 
		"../tests/audio/hoge.wav");
		System.out.println(s);
		 
		s = Util.resolveAdrs("file:C:/lab/common/src/nishi/galatea/gdm-current/phoenix.vxml", 
		"../tests/audio/hoge.wav");
		System.out.println(s);
		 
		s = Util.resolveAdrs("file:D:/lab/common/src/nishi/galatea/gdm-current/phoenix.vxml", 
		"../tests/audio/hoge.wav");
		System.out.println(s);
		
//		String s;
//		s = "if (1<=num && 2>nantoka) {infiniteLoop}";
//		System.out.println(s);
//		s = Util.encodeXmlChars(s);
//		System.out.println(s);
//		s = Util.decodeXmlChars(s);
//		System.out.println(s);
	}
	
	public static String getError()
	{
		return _error;
	}
	
	public static String readURL(String filename)
	{
		_error = "";
		String buf = "";
		if (filename.startsWith("http:")) {
			try {
				URL url = new URL(filename);
				HttpURLConnection uc;
				uc = (HttpURLConnection)url.openConnection();
				uc.setRequestMethod("GET");
				InputStreamReader isr = new InputStreamReader(uc.getInputStream());
				BufferedReader br = new BufferedReader(isr);
				while(true) {
					String line = br.readLine();
					if (line == null) 
						break;
					buf += line;
				}
				br.close();
				uc.disconnect();
			} catch ( Exception e ) {
				_error = e.toString();
			}
		} else {
			_error = "readURL() : unsupported function.";
		}
		return buf;
	}
	
	/**
	 * @returns: 0 (OK) / 1 (ERROR)
	 */
	public static int saveURL(String src, String dest, Charset cs)
	{
		_error = "";
		int ret = 0;
		String content = readURL(src);
		if (_error.equals("")) {
			try { 
				Util.writeToFile(dest, content, cs);
			} catch ( Exception e ) {
				_error = e.toString();
				ret = 1;
			}
		} else {
			ret = 1;
		}
		return ret;
	}
	
	public static void saveUrlAsBinary(String filename, String dest)
	{
		_error = "";
		if (filename.startsWith("http:")) {
			try {
				URL url = new URL(filename);
				HttpURLConnection uc;
				uc = (HttpURLConnection)url.openConnection();
				uc.setRequestMethod("GET");
				InputStream is = uc.getInputStream();

				FileOutputStream fos = new FileOutputStream(dest);

				final int SIZE = 8196;
				byte[] buf = new byte[SIZE];
				while(true) {
					int n = is.read(buf,0,SIZE);
					if (n == -1) break;
					fos.write(buf,0,n);
				}
				
				fos.close();

				is.close();
				uc.disconnect();

			} catch ( Exception e ) {
				_error = e.toString();
			}
		} else {
			_error = "readURL() : unsupported function.";
		}
	}
		
	/**
	 * @returns: path
	 */
	public static String mktemp()
	{
		return mktemp("");
	}
	
	
	/**
	 * @returns: path
	 */
	public static String mktemp(String suffix)
	{
		_error = "";
		String ret = "";
		String prefix = "galatea";
		try { 
			File temp = File.createTempFile(prefix, suffix);
			//File temp = TempFileManager.createTempFile(prefix, suffix);
			temp.deleteOnExit();
			if ( temp != null ) {
				ret = temp.getAbsolutePath();
			}
		} catch ( Exception e ) {
			_error = e.toString();
		}
		return ret;
	}
	
	
//	public static void send(String msg)
//	{
//		System.out.println(msg);
//		System.out.flush();
//	}

	// [I] "http://hoge/hoge.wav"
	// [O] ".wav"
	public static String getSuffix(String str) {
		int pos = str.lastIndexOf('.');
		if (pos == -1) return "";
		return str.substring(pos);
	}
	
	public static void halt(String msg)
	{
		System.err.println(msg);
		while(true) {
			try { 
				Thread.sleep(1000);
			} catch (Exception e) {e.printStackTrace();}
		}
	}
	
	
//	public static void runtimeError(String msg)
//	{
//		System.err.println(msg);
//	}
	
	
	public static String removeSpaces(String str)
	{
		StringBuffer retStr = new StringBuffer("");
		
		if(str == null)
			return "";
		
		StringTokenizer st = new StringTokenizer(str, " \t\n\r");
		while (st.hasMoreTokens()) {
			retStr.append(st.nextToken());
		}
		
		if(retStr.length() == 0)
			return "";
		
		return retStr.toString();
		
	}
	
	
	/**
	 * あやしい
	 */
	public static String xmlSafeRemoveSpaces(String str)
	{
		if (str == null)
			return "";
		
		StringBuffer retStr = new StringBuffer("");
		String token;
		boolean inTag = false;
		
		StringTokenizer st = new StringTokenizer(str, " \t\n\r");
		while (st.hasMoreTokens()) {
			token = st.nextToken();
			// 最初の文字が < であれば inTag = true
			// 最後の文字が > であれば inTag = false
			if (token.startsWith("<") ) {
				if (!token.equals("<")) {
					inTag = true;
				}
			}
			if (token.endsWith(">") ) {
				inTag = false;
			}
			retStr.append(token);
			if ( inTag ) {
				retStr.append(" ");
			}
		}
		
		if(retStr.length() == 0)
			return "";
		
		return retStr.toString();
	}
	
	
	public static String removeNewLines(String str)
	{
		StringBuffer retStr = new StringBuffer("");
		
		if(str == null)
			return "";
		
		StringTokenizer st = new StringTokenizer(str, "\n\r");
		while (st.hasMoreTokens()) {
			retStr.append(st.nextToken());
		}
		
		if(retStr.length() == 0)
			return "";
		
		return retStr.toString();
		
	}
	
	
	/**
	 * < > を &lt; &gt; に変換する．
	 */
	public static String encodeXmlChars(String s)
	{
		if (s==null) return "";
		StringBuffer t = new StringBuffer("");
		for ( int i = 0; i < s.length(); i++ ) {
			char ch = s.charAt(i);
			if ( ch == '<' ) {
				t.append("&lt;");
			} else if ( ch == '>' ) {
				t.append("&gt;");
			} else if ( ch == '&' ) {
				t.append("&amp;");
			} else {
				t.append(ch);
			}
		}
		return t.toString();
	}
	
	
	public static String decodeXmlChars(String s)
	{
		if ( s == null ) return "";
		String ret = s;
		ret = ret.replaceAll("&lt;", "<");
		ret = ret.replaceAll("&gt;", ">");
		ret = ret.replaceAll("&amp;", "&");
		return ret;
	}
	
	
	/**
	 * base   : http://aaa.bbb.com/index.vxml
	 * rel    : sub/next.vxml
	 * return : http://aaa.bbb.com/sub/next.vxml
	 *
	 * base   : http://aaa.bbb.com/index.vxml
	 * rel    : sub/next.vxml#hoge
	 * return : http://aaa.bbb.com/sub/next.vxml#hoge
	 * 
	 * TODO:
	 * [50 VXMLDoc main] enter(VxmlAudio) 
	 * 
	 * file:C:/workspace/galatea/files/tests/vxml/audio.vxml# ../audio/sin-11k.wav 
	 * ../audio/sin-11k.wav
	 */
	public static String resolveAdrs(String base, String rel)
	{
		String prefix = "";
		if ( base == null || rel == null ) {
			return "";
		}
		// hack
		if (base.endsWith("#")) {
			if(rel.startsWith("#")) {
				return base + rel.replaceFirst("#","");
			}
		}
		if (base.startsWith("file:") && base.charAt(6) == ':') {
			prefix = base.substring(0,7);
			base = base.substring(7);
		}
		
		String s = "";
		try {
			URI u1 = new URI(base);
			URI u2 = new URI(rel);
			URI u3 = u1.resolve(u2);
			s = u3.toString(); 
			
			/*
			 String fragment = Util.getUriFragment(rel);
			 if ( fragment != null ) {
			 s += "#" + fragment;
			 }
			 */
			
		} catch ( URISyntaxException e ) {
			s = "error:resolveAdrs(base="+base+" rel="+rel+")";
		}
		
		return prefix + s;
	}
	
	
	// in:  hogehoge.vxml#fragment
	// out: fragment
	public static String getUriFragment(String uri)
	{
		String fragment = Util.getFirstGroup("^[^#]+#(.*)$", uri);
		if (fragment == null) {
			return "";
		}
		return fragment;
	}
	
	
	// in:  file:/a/b/c/hogehoge.vxml#fragment
	// out: file:/a/b/c
	public static String getUriDirectory(String uri)
	{
		String dir = "file:/";
		int p = uri.lastIndexOf('/');
		if (p >= 0) {
			dir = uri.substring(0, p);
		}
		return dir;
	}
	
	
	// in:  hogehoge.vxml#fragment
	// out: hogehoge.vxml
	public static String getUriWithoutFragment(String uri)
	{
		String path = Util.getFirstGroup("^([^#]+)#.*$", uri);
		if (path == null) {
			return uri;
		}
		return path;
	}
	
	
	/**
	 * http のリクエストから file 部分を取得する
	 * in:  /dir/file.cgi?a=aval&b=bval&c=cval
	 * out: /dir/file.cgi
	 */
	public static String getFileNameFromRequest(String str)
	{
		String f = Util.getFirstGroup("^([^\\?]+)\\?.*$", str);
		if (f == null) {
			return str; // ? がない場合は全体が fileName
		}
		return f;
	}
	

	/**
	 * http のリクエストからquery値を取得する
	 * in:  /dir/file.cgi?a=aval&b=bval&c=cval
	 * out: ["a":"aval", "b":"bval", "c":"cval"]
	 */
	public static StringHashArray getQueryFromRequest(String str)
	{
		StringHashArray ha = new StringHashArray();
		String f = Util.getFirstGroup("^[^\\?]+\\?(.*)$", str);
		if (f == null) {
			return ha; // ? がない場合は空のデータを返す
		}
		String items[] = f.split("&");
		for (int i = 0; i < items.length; i++) {
			String tmp[] = items[i].split("=");
			if (tmp.length == 2) {
				ha.set(tmp[0], tmp[1]);
			}
		}
		return ha;
	}
	

	/**
	 * Usage: Util.getFirstGroup("^[^#]+#(.*)$", uri)
	 * 行全体がマッチしなくてはならない
	 */
	public static String getFirstGroup(String pat, String str)
	{
		Pattern p = Pattern.compile(pat);
		Matcher m = p.matcher(str);
		if (m.matches()) {
			return m.group(1);
		}
		return null;
	}
	
	
	/**
	 * f1: sub/file.vxml#a f2: sub/file.vxml#b -> true
	 */
	public static boolean isSameFile(String f1, String f2)
	{
		boolean b = false;
		try {
			URI u1 = new URI(f1);
			URI u2 = new URI(f2);
			
			// f1 の path で f2 の fragment を持つ URI を生成する
			URI u3 = new URI
			(u1.getScheme(), 
					u1.getUserInfo(),
					u1.getHost(),
					u1.getPort(),
					u1.getPath(),
					u1.getQuery(),
					u2.getFragment());
			if ( u2.equals(u3) )
				b = true;
		} catch ( URISyntaxException e ) {}
		return b;
	}
	
	
	public static void writeToFile(String file, String content, Charset cs) throws Exception
	{
		FileOutputStream fos = new FileOutputStream(file);
		OutputStreamWriter osw = new OutputStreamWriter(fos, cs);
		BufferedWriter bw = new BufferedWriter(osw);
		bw.write(content);
		bw.close();
		osw.close();
		fos.close();
	}
	
	
	public static String loadFromFile(String file, Charset cs) throws Exception
	{
		String content = "";
		try {
			FileInputStream fis = new FileInputStream(file);
			InputStreamReader isr = new InputStreamReader(fis, cs);
			BufferedReader reader = new BufferedReader(isr);
			String line;
			while ((line = reader.readLine()) != null) {
				content += line;
				content += "\n";
			}
			reader.close();
			isr.close();
			fis.close();
		} catch (FileNotFoundException e) {
			content = null;
		}
		return content;
	}
	
	
	/**
	 * In : "tokyo kyoto osaka"
	 * In : "tokyo   kyoto    osaka"
	 * Out: new Vector() of String
	 *
	 * Usage:
	 *   cmdlist: to @AM-MCL set Speak = あ;to @AM-MCL set Speak = い
	 *
	 *   List v = Util.makeTokenizedList(cmdlist, ";");
	 *   for (int i = 0; i < v.size(); i++ ) {
	 *       String cmd = (String)v.get(i);
	 *       _send(cmd);
	 *   }
	 */
	public static ArrayList<String> makeTokenizedList(String src, String delim)
	{
		ArrayList<String> v = new ArrayList<String>();
		
		// If the flag is false, delimiter characters serve to separate tokens.
		StringTokenizer st = new StringTokenizer(src, delim, false);
		while (st.hasMoreTokens()) {
			v.add((String)st.nextToken());
		}
		return v;
	}
	
	
	public static String removeTags(String str)
	{
		String s = str.replaceAll("<[^>]*>", "");
		return s;
	}
	
	
	public static String getStringHead(String str)
	{
		str = Util.removeNewLines(str);
		if ( str.length() > 40 ) {
			str = str.substring(0,40) + "...";
		}
		return str;
	}
	
	
	public static String getDocumentFromTemplate(String html, StringHashArray replaces) {
		String ret = html;
		for (int i = 0; i < replaces.size(); i++) {
			String key = replaces.getKey(i);
			String val = replaces.getAsString(i);
			ret = replaceAll(ret,key,val);
		}
		return ret;
	}

	// String.replaceAll は key と val は正規表現として解釈する
	// この replaceAll は文字列として単純に置換を行う
	public static String replaceAll(String src, String key, String val) {
		String ret = "";
		int pos = 0;
		while (pos < src.length()) {
			int found = -1;
			found = src.indexOf(key, pos);
			if (found < 0){
				ret += src.substring(pos);
				break;
			} else {
				ret += src.substring(pos, found);
				ret += val;
				pos = found + key.length();
			}
		}
		return ret;
	}
	
	public static String readInputStream(InputStream is, Charset cs) {
		BufferedReader br = new BufferedReader(new InputStreamReader(is,cs));
		String buf = "";
		while(true) {
			String line = null;
			try {
				line = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (line == null) 
				break;
			buf += line;
			buf += "\n";
		} try {
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return buf;
	}
	
	
	public static long getCurrentTimeInMillis() {
		return Calendar.getInstance().getTimeInMillis();
	}

	/**
	 * @return default is UTF-8
	 * windows : os.name="Windows XP" & os.arch="x86"  : Shift_JIS
	 * linux   : os.name="Linux"      & os.arch="i386" : EUC-JP
	 */
	public static Charset getSystemDefaultCharset() {
		// System.out.println(System.getProperty("os.name"));
		// System.out.println(System.getProperty("os.arch"));
		String osName = System.getProperty("os.name");
		String osArch = System.getProperty("os.arch");
		Charset charset = Charset.forName("UTF-8"); // default
		if (osName.startsWith("Windows") && osArch.equalsIgnoreCase("x86")) {
			charset = Charset.forName("Shift_JIS");
		}
		if (osName.equals("Linux") && osArch.equalsIgnoreCase("i386")) {
			charset = Charset.forName("EUC-JP");
		}
		return charset;
	}

	public static boolean isWindows() {
		String osName = System.getProperty("os.name");
		if (osName.startsWith("Windows")) {
			return true;
		}
		return false;
	}

	public static boolean isLinux() {
		String osName = System.getProperty("os.name");
		if (osName.startsWith("Linux")) {
			return true;
		}
		return false;
	}

	public static String getNormalizedFileName(String org) {
		String filename = org;
		if (Util.isWindows()) {
			filename = filename.replaceAll("\\\\", "/");
		}
		return filename;
	}
	
	public static String getPlatformFileName(String org) {
		String ret = org;
		if (Util.isWindows()) {
			ret = ret.replaceAll("/", "\\\\");
		}
		return ret;
	}
	
	public static String getPlatformWorkDir() {
		String dir = "/data/galatea-tmp";
		if (Util.isWindows()) {
			dir = "c:/tmp";
		}
		return dir;
	}
}
