/**
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2004 satoshi akabane(akabane@logical-paradox.org)
 *
 */
package org.logical_paradox.common.util;

import java.util.ArrayList;
import org.logical_paradox.common.lang.Random;

/**
 * 汎用の文字列ユーティリティ
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.12 $
 */
public class StringUtils {
	// ランダムテキストの要素
	public static final String RANDOM_TEXT_SEED ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	/** 乱数ジェネレータ */
	public static final Random r = new Random(Random.PLUS_OR_ZERO);

	/**
	 * コンストラクタ
	 *
	 */
	private StringUtils() {
	}
	/**
	 * 文字列がnullまたは空かどうかを返す
	 * @param msg 検証対象文字列
	 * @return true:空 / false:何か指定されている
	 */
	public static final boolean isEmpty(String msg) {
		return msg == null || msg.trim().length() == 0;
	}
	/**
	 * 文字列がnullでなく，かつ空でもないかどうかを返す
	 * @param msg 検証対象文字列
	 * @return true:なにかしかの文字列 / false:nullまたは空
	 */
	public static final boolean isNotEmpty(String msg) {
		return isEmpty(msg) == false;
	}
	/**
	 * 文字列を文字列に変換する
	 * 引数にnullが与えられた場合，空文字""に変換して返す
	 * @param str 変換対象の文字列
	 * @return 変換された文字列(絶対にnullを戻さないことを保証している)
	 */
	public static final String toString(String str) {
		return str != null ? str : "";
	}
	/**
	 * 数文字の桁数を揃える
	 * 足りない桁は'0'で補完される
	 * @param num 数字
	 * @param cols 桁数
	 * @return 0補完された文字列
	 */
	public static final String formatColumns(long num, int cols) {
		String n = "" + num;
		if(n.length() >= cols) {
			return n;
		}
		String base = sequence('0', cols -1) + n;
		if(base.length() == cols) {
			// 1桁の場合
			return base;
		} else {
			return base.substring(base.length() - cols);
		}
	}
	/**
	 * 文字列が整数変換可能かどうかを返す
	 * @param msg 検証対象文字列
	 * @return true:変換可能 / false:変換不能
	 */
	public static final boolean isIntStr(String msg) {
		boolean rc = true;
		try {
			Integer.parseInt(msg);
		} catch(NumberFormatException ne) {
			rc = false;
		}
		return rc;
	}
	/**
	 * 文字列が多倍長整数に変換可能かどうかを返す
	 * @param msg 検証対象文字列
	 * @return true:変換可能 / false:変換不能
	 */
	public static final boolean isLongStr(String msg) {
		boolean rc = true;
		try {
			Long.parseLong(msg);
		} catch(NumberFormatException ne) {
			rc = false;
		}
		return rc;
	}
	/**
	 * 文字列中に含まれる制御キャラクタを全て除去する
	 * @param str 除去対象の文字列
	 * @return 除去された文字列
	 */
	public static final String trimControlChars(String str) {
		StringBuffer sb = new StringBuffer();
		char[] characters = str.toCharArray();
		
		for(int i = 0; i < characters.length; i++) {
			// ISO制御コード以外の場合はそのまま追加する
			if(characters[i] >= '\u0020') {
				sb.append(characters[i]);
			}
		}
		return sb.toString();
	}
	/**
	 * 空文字列だけの行をカットする
	 * @param lines 行
	 * @return トリミングされた行
	 */
	public static final String[] trimEmptyLines(String[] lines) {
		ArrayList l = new ArrayList();
		for(int i = 0; i < lines.length; i++) {
			if(isEmpty(lines[i]) == false) {
				l.add(lines[i]);
			}
		}

		return (String[])l.toArray(new String[0]);
	}
	/**
	 * 指定されたテキスト内に存在する単語の出現位置を全て返す
	 * @param text 検索対象文字列
	 * @return 検索文字列
	 */
	public static Integer[] searchWordIndexes(String text, String word) {
		ArrayList locations = new ArrayList();
		int bgn = 0;
		do {
			bgn = text.indexOf(word, bgn);
			if(bgn >= 0 && bgn < text.length()) {
				locations.add(new Integer(bgn));
				bgn++;
			}
		} while(bgn >= 0);

		return (Integer[])locations.toArray(new Integer[0]);
	}
	/**
	 * ランダムな文字列を返す
	 * @param length 長さ
	 * @param fixed true:固定長 / false:可変長
	 * @return 生成された文字列
	 */
	public static final String randomText(int length, boolean fixed) {
		StringBuffer sb = new StringBuffer();

		if(fixed == false) {
			// 文字列長が可変長として指定された場合は，実際に出力される文字列の長さを決定する
			length = (int) (Math.random() * 8) +1;
		}

		// ランダムな文字列を生成する
		for(int i = 0; i < length; i++) {
			sb.append(RANDOM_TEXT_SEED.charAt((int) (Math.random() * RANDOM_TEXT_SEED.length())));
		}

		return sb.toString();
	}
	/**
	 * ランダムな文字列を返す
	 * @param minlength 最小の長さ
	 * @param maxlength 最大の長さ
	 * @return 生成された文字列
	 */
	public static final String randomTextRange(int minlength, int maxlength) {
		int range = r.nextInt() % (maxlength - minlength) +1;
		int length = r.nextInt() % range + minlength;
		StringBuffer sb = new StringBuffer();

		for(int i = 0; i < length; i++) {
			sb.append(RANDOM_TEXT_SEED.charAt((int) (r.nextInt() % RANDOM_TEXT_SEED.length())));
		}

		return sb.toString();
	}
	/**
	 * 数文字の桁数を揃える
	 * 足りない桁は'0'で補完される
	 * @param num 数字
	 * @param cols 桁数
	 * @return 0補完された文字列
	 */
	public static final String formatColumns(int num, int cols) {
		String n = "" + num;
		if(n.length() >= cols) {
			return n;
		}
		String base = sequence('0', cols -1) + n;
		if(base.length() == cols) {
			// 1桁の場合
			return base;
		} else {
			return base.substring(base.length() - cols);
		}
	}
	/**
	 * 指定文字を指定個数連結した文字列を返す
	 * @param c 連結するキャラクタ
	 * @param count 連結数
	 * @return 結合された文字列
	 */
	public static final String sequence(char c, int count) {
		StringBuffer sb = new StringBuffer();
		String cc = "" + c + c;
		for(; count > 1; count-=2) {
			sb.append(cc);
		}
		if(count % 2 == 1) {
			sb.append(c);
		}

		return sb.toString();
	}
	/**
	 * 64bitの2進数フォーマットに変換する．
	 * @param l 変換対象のロングワード
	 * @return 変換された文字列(64文字固定)
	 */
	public static final String format64bit(long l) {
		String bit64String = "0000000000000000000000000000000000000000000000000000000000000000" + Long.toBinaryString(l);
		return bit64String.substring(bit64String.length() - 64, bit64String.length());
	}

}
