/*
 * HttpUtil.java
 * 
 * Author: http://www.hrtdotnet.jp/
 * 
 */
package jp.hrtdotnet.java.net;

import java.net.*;

/**
 * HTTP関係のユーティリティクラスです。
 * 
 * @version 2.0
 * @author hrtdotnet.jp
 * <br>http://www.hrtdotnet.jp/
 * @since 2.0
 */
public class HttpUtil {
    
    private static final String HTTP = "http";
    private static final String HTTPS = "https";
    private static final String HTTP2 = "http://";
    private static final String HTTPS2 = "https://";
    private static final String DELIMITER = "/";
    private static final String DOT = ".";

	// コンストラクタは作成しない
    private HttpUtil(){        
    }

    /**
     * HttpURLConnectionにリファラ(Referer)を設定します。
     * 
     * @param connection HttpURLConnectionオブジェクト
     * @param referer リファラ(Referer)
     * @throws NullPointerException
     *          connectionがnullの場合
     * @since 2.0
     */
    public static void setReferer(HttpURLConnection connection, String referer){
        if (connection == null) {
            throw new NullPointerException("HttpURLConnection-object is null.");
        }
        connection.setRequestProperty("Referer", referer);
    }


    /**
     * HttpURLConnectionにリファラ(Referer)を設定します。
     * 
     * @param connection HttpURLConnectionオブジェクト
     * @return リファラ(Referer)
     * @throws NullPointerException
     *          connectionがnullの場合
     * @since 2.0
     */
    public static String getReferer(HttpURLConnection connection){
        if (connection == null) {
            throw new NullPointerException("HttpURLConnection-object is null.");
        }        
        return connection.getRequestProperty("Referer");
    }
 

    /**
     * HttpURLConnectionにユーザエージェント(User-Agent)を設定します。
     * 
     * @param connection HttpURLConnectionオブジェクト
     * @param userAgent ユーザエージェント(User-Agent)
     * @throws NullPointerException
     *          connectionがnullの場合
     * @since 2.0
     */
    public static void setUserAgent(HttpURLConnection connection, String userAgent){
        if (connection == null) {
            throw new NullPointerException("HttpURLConnection-object is null.");
        }
        connection.setRequestProperty("User-Agent", userAgent);
    }
    

    /**
     * HttpURLConnection からユーザエージェント(User-Agent)を取得します。
     * 
     * @param connection HttpURLConnectionオブジェクト
     * @return ユーザエージェント(User-Agent)
     * @throws NullPointerException
     *          connectionがnullの場合
     * @since 2.0
     */
    public static String getUserAgent(HttpURLConnection connection){
        if (connection == null) {
            throw new NullPointerException("HttpURLConnection-object is null.");
        }
        return connection.getRequestProperty("User-Agent");
    }
    

    /**
     * アクセス制限の認証を行います。
     * 認証可能であるのはWebサーバが行うBasic認証とDigest認証です。
     * 
     * @param user ユーザ名
     * @param pass パスワード
     * @throws NullPointerException
     *          引数がnullの場合
     * @since 2.0
     */
    public static void setAuthentication(final String user, final String pass){

        if (user == null) {
            throw new NullPointerException("User is null.");
        }
        if (pass == null) {
            throw new NullPointerException("Pass is null.");
        }
        
        class InAuth extends Authenticator {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(user , pass.toCharArray());
            }
        }

        Authenticator auth = new InAuth();
        Authenticator.setDefault(auth);
    }
    
    /**
     * 指定されたURLの、HTTP形式としての正当性を判定します。
     * HttpUtilで使われているメソッドのURLの形式チェックはこのメソッド、もしくは同じ判定方法を利用しています。
     * <br><br>
     * 以下の条件を満たすものが正しいURLだと判断します。
     * <ul>
     * <li>大小関係なく「http://」から始まる</li>
     * <li>大小関係なく「https://」から始まる</li>
     * </ul>
     * 
     * @param url 判定するURL
     * @return 正しい形式であればtrue、正しくなければfalse
     * @since 2.0
     */
    public static boolean checkFormat(String url) {
        if (url == null) {
            throw new NullPointerException("URL is null.");
        }
        String lUrl = url.toLowerCase();
        if (lUrl.startsWith(HTTP2)) {
            // http://
        } else if (lUrl.startsWith(HTTPS2)) {
            // https://
        } else {
            return false;
        }
        return true;
    }

    /**
     * 指定されたURLの、HTTPもしくはHTTPSのプロトコルとしての正当性を判定します。
     * 
     * @param url URLオブジェクト
     * @return HTTPもしくはHTTPSのプロトコルであればtrue、それ以外ならfalse
     * @throws NullPointerException
     *          urlがnullの場合
     * @since 2.0
     */
    public static boolean checkProtocol(URL url) throws NullPointerException {
        if (url == null) {
            throw new NullPointerException("URL is null.");
        }
        return checkProtocol(url.getProtocol());
    }

    /**
     * 指定されたプロトコル(文字列)の、HTTPもしくはHTTPSのプロトコルとしての正当性を判定します。
     * 
     * @param protocol プロトコル
     * @return HTTPもしくはHTTPSのプロトコルであればtrue、それ以外ならfalse
     * @throws NullPointerException
     *          protocolがnullの場合
     * @since 2.0
     */
    public static boolean checkProtocol(String protocol) {
        if (protocol == null) {
            throw new NullPointerException("Protocol is null.");
        }

        if (protocol.compareToIgnoreCase(HTTP) == 0) {
            return true;
        } else if (protocol.compareToIgnoreCase(HTTPS) == 0) {
            return true;
        }
        return false;
    }
    
    /**
     * 指定されたURLから拡張子を抽出します。
     * URLが「http://」もしくは「https://」から始まる場合のみ抽出されます。
     * 拡張子が指定されていないファイルへのURLの場合、空文字列を取得し、
     * 「/」で終わる場合やホスト文字列のみの場合はnullを取得します。
     * <br><br>
     * 以下は URL の形式に対しての抽出結果の例です。
     * <ul>
     * <li>http://www.sample.com/abc.txt → txt</li>
     * <li>http://www.sample.com/.txt → txt</li>
     * <li>http://www.sample.com/abc/ → null</li>
     * <li>http://www.sample.com/abc → &quot;&quot;</li>
     * <li>http://www.sample.com → null</li>
     * </ul>
     * 
     * @param url リソースのURL
     * @return 抽出した拡張子
     * @throws NullPointerException
     *          urlがnullの場合
     * @throws IllegalArgumentException
     *          urlがHTTPもしくはHTTPS形式ではない場合
     * @since 2.0
     */
    public static String getExtension(String url) throws NullPointerException, IllegalArgumentException {
        if (url == null) {
            throw new NullPointerException("URL is null.");
        }
        
        String extension = null;
        String lUrl = url.toLowerCase();
        if (lUrl.startsWith(HTTP2)) {
            // http:// の場合
            extension = getExtension2(url, HTTP2);
        } else if (lUrl.startsWith(HTTPS2)) {
            // https:// の場合
            extension = getExtension2(url, HTTPS2);
        } else {
            throw new IllegalArgumentException("URL is not a http-format.");
        }
        return extension;
    }
    
    private static String getExtension2(String url, String protocol) {
        StringBuffer sbUrl = new StringBuffer(url);
        if (sbUrl.length() > protocol.length()) {
            sbUrl.delete(0, protocol.length());
            int pos = sbUrl.lastIndexOf(DELIMITER);
            if (pos == -1 && protocol.length() > 0) {
                return null;
            } else if (pos == sbUrl.length() - 1) {
                return null;
            } else {
                if (pos == -1) {
                    pos = 0;
                }
                sbUrl.delete(0, pos + 1);
                pos = sbUrl.lastIndexOf(DOT);
                if (pos == -1) {
                    return "";
                } else if (pos == sbUrl.length() - 1) {
                    return "";
                } else {
                    return sbUrl.delete(0, pos + 1).toString();
                }
            }
        }
        throw new IllegalArgumentException("url is not a " + protocol);
    }

    /**
     * 指定した文字列の、HTTP形式としての正当性を判定します。
     * 
     * @param str 対象の文字列
     * @return HTTP形式の文字列であればtrue、それ以外はfalse
     * @since 2.0
     */
    public static boolean isHttpUrl(String str) {

        // nullの場合はfalseを返す
        if (str == null) {
            return false;
        }
        // 先頭が"http://", "https://"であればtrueを返す
        str = str.toLowerCase();
        if (str.startsWith("http://") || str.startsWith("https://")) {
            return true;
        }

        return false;
    }
}
