package org.itscool.commons.util;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * 文字列エンコーディングに関するユーティリティクラスです
 * @author kano
 */
public class StringUtil {
    
    
    /**
     * 文字列の前後の空白(半角・全角)文字を削除する関数
     * @param strData 対象の文字列
     * @return 文字列の前後の空白文字を削除した文字列を返す
     */
    public static String trimSpace( String strData ){
        int iStart = 0;
        int iEnd   = 0;
        // 文字列の先頭から全角空白でない文字開始位置を決定する
        for ( iStart=0; iStart < strData.length()-1 ; iStart++ ) {
            if ( ( strData.charAt(iStart) != '　' ) && ( strData.charAt(iStart) != ' ' ) ) break;
        }
        // 文字列の終端から全角空白文字でない文字終了位置を決定する
        for ( iEnd=strData.length()-1; iEnd>=iStart; iEnd-- ) {
            if ( ( strData.charAt( iEnd ) != '　' ) && ( strData.charAt(iEnd) != ' ' ) )break;
        }
        if( iStart <= iEnd ) {
            // 開始位置から終了位置までの文字を抜き出す
            strData = strData.substring( iStart, iEnd + 1 );
        } else {
            strData = "";
        }
        return strData;
    }
    
    /**
     * Unicode形式の文字列を「\\u・16進数」形式の文字列に変換します
     * @param str 変換対象となる文字列を指定してください
     * @return 「\\u・16進数」形式の文字列を返します
     */
    public static String encodeHex(String str){
        char[] buf1 = str.toCharArray();
        String buf2 = new String("");
        
        for (int i = 0; i < buf1.length; i++) {
            buf2 += "\\u" + (Integer.toString(buf1[i], 16)).toUpperCase();
        }
        return buf2;
    }
    
    /**
     * 「\\u・16進数」形式の文字列をUnicode形式の文字列に変換します
     * @param unicodeStr 変換対象となる文字列を指定してください
     * @return Unicode形式の文字列の文字列を返します
     */
    public static String decodeHex(String unicodeStr){
        StringTokenizer st = new StringTokenizer(unicodeStr, "\\u");
        int tokenNum = st.countTokens();
        if(unicodeStr.indexOf("\\u") == -1){
            //Hexで無い
            return unicodeStr;
        }
        char[] chars = new char[tokenNum];
        for( int i=0; i<tokenNum; i++ ){
            String str = st.nextToken();
            if( str == null || str.length() == 0 ){
                continue;
            }
            /* 16進数を作成 */
            Integer integer = Integer.decode("0x" + str);
            chars[i] = (char)integer.intValue();
        }
        String newStr = new String(chars);
        return newStr;
    }
    
    /**
     * Unicode形式の文字列を「\\u・16進数」形式の文字列に変換します
     * @param byteData 変換対象となる文字列のバイトデータを指定してください
     * @param encode エンコーディング名を指定して下さい
     * @return 「\\u・16進数」形式の文字列を返します
     */
    public static String encodeHex(byte[] byteData, String encode){
        String str = "";
        try{
            str = new String(byteData, encode);
        }catch(UnsupportedEncodingException uee ){
            uee.printStackTrace();
        }
        char[] buf1 = str.toCharArray();
        String buf2 = new String("");
        
        for (int i = 0; i < buf1.length; i++) {
            buf2 += "\\u" + (Integer.toString(buf1[i], 16)).toUpperCase();
        }
        return buf2;
    }
    
    /**
     * 「\\u・16進数」形式の文字列をUnicode形式の文字列に変換します
     * @param unicodeStr 変換対象となる文字列を指定してください
     * @return Unicode形式の文字列の文字列を返します
     */
    public static byte[] decodeHex(String unicodeStr, String encode){
        byte[] byteData = null;
        String strData = decodeHex(unicodeStr);
        try{
            byteData = strData.getBytes("ISO-8859-1");
        }catch(UnsupportedEncodingException uee ){
            return null;
        }
        return byteData;
    }
    
    /**
     * 指定された文字列を指定されたエンコーディングに変換します
     * @param str 変換対象となる文字列を指定してください
     * @param encode エンコーディング名を指定して下さい
     * @return 変換後の文字列
     */
    public static String convEncode(String str, String encode){
        try{
            str = new String(str.getBytes("ISO-8859-1"), encode);
        }catch(Exception e){
            
        }
        return str;
    }
    
    public static String convEncode(byte[] byteData, String encode){
        String str = new String(byteData);
        try{
            str = new String(byteData, encode);
        }catch(UnsupportedEncodingException uee){
            uee.printStackTrace();
        }
        return str;
    }
    
    
    public static boolean isLowerChar(char c){
        if ( 'a' <= c && c <= 'z'){        //小文字アルファベット
            return true;
        }else{
            return false;
        }
    }
    
    public static boolean isUpperChar(char c){
        if('A' <= c && c <= 'Z' ) {       //大文字アルファベット
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * 大文字が含まれる文字列を小文字に変換し、間に"_"を挿入する関数です<br>
     * 例) HelloKitty -> hello_kitty<br>
     * 大文字が連続する場合<br>
     * 例) HTTPprotocol -> http_protocol
     * 
     */
    public static String cnvUpperNameToUnderScoreName(String str){
        if( str == null || str.length() == 0){
            return str;
        }
        char[] chars  = str.toCharArray();
        StringBuffer sb = new StringBuffer("");
        int len = chars.length;
        //大文字連続フラグ
        boolean oomojiRenzokuFg = false;
        for(int i=0; i<len; i++){
            if(i==0){
                sb.append(Character.toLowerCase(chars[i]));
                continue;
            }
            if(Character.isUpperCase(chars[i])){
                //大文字が続く場合
                if( (i+1) < len && Character.isUpperCase(chars[i+1])){
                    sb.append(Character.toLowerCase(chars[i]));
                    sb.append(Character.toLowerCase(chars[i+1]));
                    i++;
                    oomojiRenzokuFg = true;
                }else{
                    //大文字が連続していた場合
                    if( oomojiRenzokuFg == true ){
                        //大文字連続フラグを解除
                        oomojiRenzokuFg = false;
                        sb.append(Character.toLowerCase(chars[i]));
                        //次の文字が存在する場合
                        if( i < len ){
                            sb.append("_");
                        }
                    }else{
                        sb.append("_");
                        sb.append(Character.toLowerCase(chars[i]));
                    }
                }
            }else{
                sb.append(chars[i]);
            }
        }
        return sb.toString();
    }
    
    /**
     * 先頭文字を大文字に変換し、かつアンダースコア(_)が含まれる文字列から
     * アンダースコアを除去し、その後に続く1文字を大文字に変換します
     */
    public static String cnvUnderScorNameToUpperName(String str){
        if( str == null || str.length() == 0){
            return str;
        }
        char[] chars  = str.toCharArray();
        StringBuffer sb = new StringBuffer("");
        int len = chars.length;
        for(int i=0; i<len; i++){
            if( i==0 ){
                sb.append(Character.toUpperCase(chars[i]));
                continue;
            }
            if( chars[i] == '_' ){
                if( (i+1) < len ){
                    sb.append(Character.toUpperCase(chars[i+1]));
                    i++;
                }else{
                    sb.append(Character.toLowerCase(chars[i]));
                }
            }else{
                sb.append(Character.toLowerCase(chars[i]));
            }
        }
        return sb.toString();
    }
    
    /**
     * 先頭文字を小文字に変換し、かつアンダースコア(_)が含まれる文字列から
     * アンダースコアを除去し、その後に続く1文字を小文字に変換します
     */
    public static String cnvUnderScorNameToLowerName(String str){
        if( str == null || str.length() == 0){
            return str;
        }
        char[] chars  = str.toCharArray();
        StringBuffer sb = new StringBuffer("");
        int len = chars.length;
        for(int i=0; i<len; i++){
            if( i==0 ){
                sb.append(Character.toLowerCase(chars[i]));
                continue;
            }
            if( chars[i] == '_' ){
                if( (i+1) < len ){
                    sb.append(Character.toUpperCase(chars[i+1]));
                    i++;
                }else{
                    sb.append(Character.toLowerCase(chars[i]));
                }
            }else{
                sb.append(Character.toLowerCase(chars[i]));
            }
        }
        return sb.toString();
    }
    
    /**
	 * 区切り文字を含む1レコードのデータを項目単位で
	 * 抽出し、結果をListインスタンスにセットします
	 * @param line 区切り文字を含むの1レコードデータ
     * @param key 区切り文字
	 * @return list 抽出されたデータのリストを返します
	 */
	public static List split(String line, String key){
		ArrayList result = new ArrayList();
		// 1行をデータの要素に分割
		StringTokenizer st = new StringTokenizer(line, key);
        if( st.countTokens() == 0 ){
            result.add(line);
            return result;
        }
		while (st.hasMoreTokens()) {
			String data = st.nextToken();
            if( data == null ) continue;
            //CSV形式でかつ両端に"がセットされている可能性がある場合
			if( data.length() > 2 && key.equals(",") ){
				int len = data.length();
				int firstDblQuate = data.indexOf("\"");
				int lastDblQuate = data.lastIndexOf("\"");
				// 両端にダブルクォーテーションがある場合は除去
				if( firstDblQuate == 0 && lastDblQuate == len-1){
					data = data.substring(1, lastDblQuate);
				}
            }
            result.add(data);
		}
		return result;
	}

    public static void main(String[] argv){
        System.out.println(StringUtil.cnvUpperNameToUnderScoreName("HelloShowActionSuccess"));
        System.out.println(StringUtil.cnvUpperNameToUnderScoreName("HTTPprotocol"));
        
        System.out.println(cnvUnderScorNameToUpperName("hello_good_by"));
        System.out.println(cnvUnderScorNameToUpperName("HELLO_GOOD_BY2"));
        System.out.println(cnvUnderScorNameToLowerName("HELLO_GOOD_BY_TABLE"));
        System.out.println(cnvUnderScorNameToUpperName("h_"));
        System.out.println(cnvUnderScorNameToUpperName("_"));
    }
    
}
