package ash.util;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.text.SimpleDateFormat;
import java.text.ParseException;

/**
 * ユーティリティメソッド
 */
public class Util {
	public static boolean isEmpty(Object[] array) {
		return array == null || array.length == 0;
	}
	public static String toString(String[] tokens) {
		if(tokens == null) return "";
		return toString(tokens, 0, tokens.length);
	}
	public static String toString(String[] tokens, int from, int to) {
		if(tokens == null) return "";
		StringBuilder sb = new StringBuilder();
		for(int i = from; i < to; i++) {
			if(i > from) sb.append(" ");
			sb.append(tokens[i]);
		}
		return sb.toString();
	}
	public static String join(String sep, Object... items) {
		StringBuilder sb = new StringBuilder();
		for(Object s : items) {
			if(sb.length() > 0) sb.append(sep);
			if(s != null) sb.append(s.toString());
		}
		return sb.toString();
	}
	public static String[] shiftTokens(String[] tokens) {
		return shiftTokens(tokens, 1);
	}
	public static String[] shiftTokens(String[] tokens, int shift) {
		if(shift == 0) return tokens;
		int n = tokens.length;
		if(n < shift) return null;
		return copyTokens(tokens, shift, n - shift);
	}
	public static String[] addToken(String token, String[] tokens) {
		int n = tokens.length;
		String[] aa = new String[n+1];
		aa[0] = token;
		System.arraycopy(tokens, 0, aa, 1, n);
		return aa;
	}
	public static String[] addTokens(String[] tokens1, String[] tokens2) {
		if(tokens1 == null) return tokens2;
		if(tokens2 == null) return tokens1;
		int n1 = tokens1.length;
		int n2 = tokens2.length;
		String[] aa = new String[n1+n2];
		System.arraycopy(tokens1, 0, aa, 0, n1);
		System.arraycopy(tokens2, 0, aa, n1, n2);
		return aa;
	}
	public static String[] removeTokens(String[] tokens, int from, int count) {
		int n = tokens.length;
		String[] aa = new String[n - count];
		for(int i = 0; i < from; i++) aa[i] = tokens[i];
		for(int j = from + count; j < n; j++) aa[j-count] = tokens[j];
		return aa;
	}

	public static String[] copyTokens(String[] array, int offset, int length) {
		assert (array.length >= offset + length);
		String[] aa = new String[length];
		System.arraycopy(array, offset, aa, 0, length);
		return aa;
	}
	public static String[] toArray(List<String> tokens) {
		return (tokens==null) ? null : tokens.toArray(new String[tokens.size()]);
	}

	/* format = (%[YymdHMSIklAaBbDT])+
	   Y: y: 年, m: 月, d: 日, H: 時, M: 分, S: 秒
	   I: k: l: 時(01-12, 0-23, 1-12)
	   A: a: 曜日, B: b: 月, D: mm/dd/yy, T: hh:mm:ss
	*/
	public static String formatDate(String format, Date date) {
		StringBuilder sb = new StringBuilder();
		boolean escape = false;
		for(int i = 0; i < format.length(); i++) {
			char c = format.charAt(i);
			if(escape) {
				sb.append(String.format("%t" + c, date));
				escape = false;
			} else {
				if(c == '%') {
					escape = true;
				} else {
					sb.append(c);
				}
			}
		}
		return sb.toString();
	}

	static final String DATE_FORMAT = "%tY/%<tm/%<td(%<ta) %<tH:%<tM:%<tS";
	public static String formatDate(Date date) {
		if(date == null) date = new Date();
		return String.format(DATE_FORMAT, date);
	}
	public static String formatDate() {
		return formatDate(new Date());
	}
	public static String formatDate(String format) {
		return formatDate(format, new Date());
	}

	public static final String DATE_FMT1 = "yyMMddHHmmss";
	public static final String DATE_FMT2 = "yy/MM/dd HH:mm:ss";
	private static SimpleDateFormat dformat1 = new SimpleDateFormat(DATE_FMT1);
	private static SimpleDateFormat dformat2 = new SimpleDateFormat(DATE_FMT2);
	/**
	 * 許容度の高い日付の文字列表現を Date に変換する。<br>
	 * 2009/05/06 14:45:00, 09/05/06_14:45, 5/6 14:45 ==> '09/05/06 14:45:00'
	 * @param time 日付の文字列表現
	 * @return 変換した日付
	 */
	public static Date parseDate(String time) {
		Date date = parseDate(time, dformat1);	// 090508161000
		if(date == null)
			date = parseDate(time, dformat2);	// 09/05/08 16:10:00
		if(date == null)
			date = parseRelaxedDate(time);		// 5/8_16:10
		return date;
	}
	static final String DATEPAT =
	//   $1                            $5       $7
		"((\\d+)([/-]\\d+)?([/-]\\d+)?)((\\s+|_)((\\d+)(:\\d+)?(:\\d+)?))?";
	//    $2    $3         $4           $6       $8    $9      $10
	static private Pattern datePat = Pattern.compile(DATEPAT);
	private static Date parseRelaxedDate(String dateString) {
		Matcher m = datePat.matcher(dateString);
		if(!m.find()) return null;
		String date = m.group(1);
		if(date == null) {				// date = ""
			date = Util.formatDate("%y/%m/%d", new Date());
		} else if(m.group(3) == null) {	// date = 06
			date = Util.formatDate("%y/%m/", new Date()) + date;
		} else if(m.group(4) == null) {	// date = 05/06
			date = Util.formatDate("%y/", new Date()) + date;
		}
		String time = m.group(7);
		if(time == null) {
			time = "00:00:00";
		} else if(m.group(9) == null) {		// minute
			time += ":00:00";
		} else if(m.group(10) == null) {	// second
			time += ":00";
		}
		return parseDate(date + " " + time, dformat2);
	}
	private static Date parseDate(String time, SimpleDateFormat dformat) {
		try {
			return dformat.parse(time);
		} catch(ParseException e) {
			return null;
		}
	}

	//                               $3       $4       $5
	static final String TIMEPAT = "(((\\d+):)?(\\d+):)?(\\d+)";
	static private Pattern timePat = Pattern.compile(TIMEPAT);
	/**
	 * 時間間隔の文字列表現から秒数を求める。
	 * 1:00:00, 60:00, 3600 ==> 3600, 15:00 ==> 900
	 * @param timeString 時間間隔の文字列表現(H:M:S)
	 * @return 変換した秒数
	 */
	public static int parseTime(String timeString) {
		Matcher m = timePat.matcher(timeString);
		if(!m.find()) return -1;
		int hour = parseInt(m.group(3));
		int minute = parseInt(m.group(4));
		int sec = parseInt(m.group(5));
		return ((hour * 60) + minute) * 60 + sec;
	}
	private static int parseInt(String s) {
		return (s != null) ? Integer.parseInt(s) : 0;
	}

	final static String[] timeUnits = { " sec", " msec", " usec", " nsec" };
	public static String elapsedTime(long startTime) {
		return time(System.nanoTime() - startTime);
	}
	public static String time(long nanoTime) {
		double time = nanoTime;
		int i = timeUnits.length - 1;
		while(1000.0 <= time && 0 < i) {
			time /= 1000.0;
			i--;
		}
		time = (long)(time * 100 + 0.5) / 100.0; // 小数点以下２桁まで表示
		return ("" + time + timeUnits[i]);
	}

	final static String[] sizeUnits = { " GB", " MB", " KB", " B " };
	public static String fileSize(long byteSize) {
		double size = byteSize;
		int i = sizeUnits.length - 1;
		while(1024.0 <= size && 0 < i) {
			size /= 1024.0;
			i--;
		}
		size = ((long)(size * 10 + 0.5) / 10.0);
		return "" + size + sizeUnits[i];
	}
	public static String fileSizeKB(long size) {
		return "" + ((long)(size * 100 / 1024.0 + 0.5) / 100.0) + " KB";
	}
}
