package org.itscool.commons.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UrlUtil{
    /**
     * Stringで記述されたキーワードkeyと比較対照となるstrで
     * パス情報の比較を行います。<br>
     * 比較キーワードkeyにはワイルドカードとして"**"及び"*"を使用する
     * ことができます。<br>
     * "*"を指定した場合はURL"/"から次の"/"までの任意の文字列に相当します。<br>
     * "**"は任意のディレクトリ階層に相当します。<br>
     * "**"を指定した場合は最後に指定された"/"以降の文字列が比較の対象となります<br>
     * <br>
     *【比較の例】<br>
     * aaa/layout.do  と aaa/layout.do             は等価 <br>
     * / *.do         と /layout.do                は等価 <br>
     * / *.do         と /servlet/layout.do        は違う<br>
     * /servlet/ *.do と /servlet/layout.do        は等価<br>
     * / * / *.do     と /servlet/layout.do        は等価<br>
     * / * / *.do     と /servlet/layout/layout.do は違う<br>
     * / * / * / *.do と /servlet/layout/layout.do は等価<br>
     * / ** / *.do    と /servlet/layout/layout.do は等価<br>
     * / * /servlet/  と /aaa/servlet/             は等価<br>
     * 
     * @param key 比較するURLキーワード
     * @param str 比較対照となるURL文字列
     * @return 同じ文字列ならtrueを返します
     */
    public static boolean isURLMatch(String key, String str){
        boolean ret = true;
        String stackKey = new String(key);
        String stackStr = new String(str);
        
        while(stackKey != null || stackKey.length() <= 0 ){
            // 最初に'/'が見つかる位置を検索
            int keyPartPos = stackKey.indexOf("/");
            int strPartPos = stackStr.indexOf("/");
            
            // "/"がない場合は文字列の長さをセット
            if( keyPartPos == -1){    
                keyPartPos = stackKey.length();
            }
            if( strPartPos == -1){
                strPartPos = stackStr.length();
            }
            
            //スタック文字列の先頭から'/'までの部分文字列を取得
            String keyPart = stackKey.substring(0, keyPartPos);
            String strPart = stackStr.substring(0, strPartPos);
            
            if( keyPart.equals("**")){    //ディレクトリのワイルドカードが指定された場合
                keyPartPos = stackKey.lastIndexOf("/");
                strPartPos = stackStr.lastIndexOf("/");
                if( strPartPos == -1 ){
                	return false;
                }
                keyPart = stackKey.substring(keyPartPos, keyPartPos);
                strPart = stackStr.substring(strPartPos, strPartPos);
                
            }
            
            //スタック文字列の先頭から'/'までの部分文字列を比較
            ret = isPartMatch(keyPart, strPart);
            if(!ret){
                return false;
            }
            if( keyPartPos == stackKey.length()){
                return true;
            }
            stackKey = stackKey.substring(keyPartPos+1, stackKey.length());
            stackStr = stackStr.substring(strPartPos+1, stackStr.length());
        }
        
        return ret;
    }
    
    /**
     * 文字列の単純比較を行います<br>
     * "*"は任意の文字列長のワイルドカードとなります<br>
     * キーワードに"*"が含まれている場合は、"*"以降のキーワードとそれに位置する
     * 比較対照の文字列が等価であるか検査します<br>
     * @param key 比較するキーワード
     * @param str 比較対照となる文字列
     * @return 同じ文字列ならtrueを返します
     */
    private static boolean isPartMatch(String key, String str){
        boolean ret = true;
        char[] keyList = key.toCharArray();
        char[] strList = str.toCharArray();
        
        //オフセットが文字列長に達するか、比較する文字列の判定結果が
        //分かるまでループ
        for(int keyOffset=0, strOffset = 0; keyOffset<keyList.length; 
            keyOffset++, strOffset++){
            char c = keyList[keyOffset];
            if( c == '*'){    //ワイルドカードが指定されている場合
                //keyListの残り部分とstrListにセットされたkeyList
                //の残り部分のサイズ分だけ文字列を比較する
                String keyPart = key.substring(keyOffset+1, key.length());
                int strPos = str.length() - keyPart.length();
                String strPart = str.substring(strPos, str.length());
                
                return keyPart.equals(strPart);
                
            }else{
            	if(keyOffset >= strList.length){
            		return false;
            	}
                //char同士の比較
                if(keyList[keyOffset] != strList[strOffset]){
                    ret = false;
                    return ret;
                }
            }
        }
        
        return ret;
    }
    
    /**
     * クエリー文字列をHashMapで取得します
     * @param queryString クエリー文字列
     * @return クエリー文字列の配列
    */
    public static HashMap getQueryString(String queryString){
    	HashMap queryStrings = new HashMap();
    	
    	int startPos;
    	int equalPos;
    	int valuePos;
    	
    	if( queryString == null || queryString.length() == 0){
    		return queryStrings;
    	}
    	
    	while(queryString.length() > 0 ){
    		startPos = 0;
			equalPos = queryString.indexOf("=");
			valuePos = queryString.indexOf("&");
    	
	    	if( equalPos == -1 ){
	    		System.out.println("non query");
	    		return queryStrings;
	    	}
			if( valuePos == -1 ){
				valuePos = queryString.length();
			}
	    	
	    	String key = queryString.substring(startPos, equalPos);
			String value = queryString.substring(equalPos+1, valuePos);
			queryStrings.put(key, value);
    	    
			if( queryString.length() > valuePos ){
				queryString = queryString.substring(valuePos+1, queryString.length());
			}else{
				break;
			}
			
    	}
    	return queryStrings;
    }
    
    /**
	 * URL名からURLを作るのはURLオブジェクトの生成そのものの処理です。 
	 * プログラムは以下のようになりますが簡単ですね。
	 * 
	 * @param urlName URL名
	 * @return URLインスタンス
	 * @throws MalformedURLException
	 */
	public static URL getURLFromURLName(String urlName)
			throws MalformedURLException {

		return (new URL(urlName));
	}

	/**
	 * ファイル名 ファイル名をURLに変換するのには若干の処理が必要です。 
	 * ポイントは以下の3点。 パス名の区切り記号を"/"に変換
	 * 相対パスが指定されたときにはカレントディレクトリをシステムプロパティ
	 * から獲得して補完 パス名の先頭に"/"があることを保証(Windows対応)
	 * プログラムは以下のようになります。
	 * URLのコンストラクタがMalformedURLExceptionをスローするのは誤った
	 * URL名が指定された場合で、これはこのプログラムのバグなので、
	 * InternalErrorをスローしなおすようになっています。
	 * この処理によってメソッドのthrowsからMalformedURLExceptionを
	 * 外すことを可能にしています。
	 * 
	 * @param filename ファイル名
	 * @return URLインスタンス
	 */
	public static URL getURLFromFileName(String filename) {
		try {
			char sep = File.separator.charAt(0);
			String file = filename.replace(sep, '/');
			if (file.charAt(0) != '/') {
				String dir = System.getProperty("user.dir");
				dir = dir.replace(sep, '/') + '/';
				if (dir.charAt(0) != '/') {
					dir = "/" + dir;
				}
				file = dir + file;
			}
			return (new URL("file", "", file));
		} catch (MalformedURLException e) {
			throw (new InternalError("can't convert from filename"));
		}
	}

	/**
	 * リソース名 リソース名に対応するURLを獲得するためには
	 * java.lang.ClassのgetResourceメソッドを使用します。
	 * これもメソッド一発です
	 * 
	 * @param resourceName リソース名
	 * @param clazz クラス情報
	 * @return URLインスタンス
	 */
	public static URL getURLFromResourceName(String resourceName, Class clazz) {
		return (clazz.getResource(resourceName));
	}

	/**
	 * URL名またはファイル名 URL名またはファイル名のいずれが指定されたかを
	 * 自動的に判別しURLに変換する機能があると便利です。
	 * プログラムは次のようになります。 
	 * 
	 * @param name ファイル名
	 * @return URLインスタンス
	 */
	public static URL getURLFromFileOrURLName(String name) {
		try {
			return (new URL(name));
		} catch (MalformedURLException e) {
		}
		return (getURLFromFileName(name));
	}
	
	public static String replacePath(String oldPath){
		String newPath;
		Pattern pattern = Pattern.compile("%20");
		Matcher matcher = pattern.matcher(oldPath);
		newPath = matcher.replaceAll(" ");

		return newPath;
	}
}
