package org.maachang.util;

import java.io.ByteArrayOutputStream;

/**
 * URLDecode.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangBase 1.00
 */
public class URLDecode {

    /**
     * デフォルトキャラクタセット.
     */
    private static final String DEFAULT_CHARSET = "UTF8";

    /**
     * URLデコード. <BR>
     * <BR>
     * URLをエンコードします.<BR>
     * この処理はマルチバイト系の文字情報をエンコードします. <BR>
     * 
     * @param url
     *            対象のURLを設定します.
     * @param charset
     *            対象のキャラクタセットを設定します.
     */
    public static final String convert(String url) {
        return convert(url, null);
    }

    /**
     * URLデコード. <BR>
     * <BR>
     * URLをエンコードします.<BR>
     * この処理はマルチバイト系の文字情報をエンコードします. <BR>
     * 
     * @param url
     *            対象のURLを設定します.
     * @param charset
     *            対象のキャラクタセットを設定します.
     */
    public static final String convert(String url, String charset) {

        if (url == null || (url = url.trim()).length() <= 0) {
            return null;
        }
        if (charset == null || (charset = charset.trim()).length() <= 0) {
            charset = DEFAULT_CHARSET;
        }

        String ret = url;

        try {

            int len = url.length();
            ByteArrayOutputStream ba = new ByteArrayOutputStream();

            for (int i = 0; i < len; i++) {
                char c = url.charAt(i);
                if (c == '%') {
                    ba.write((hexChar(url.charAt(i + 1)) << 4)
                            | hexChar(url.charAt(i + 2)));
                    i += 2;
                } else if (c == '+') {
                    ba.write((int) (' ' & 0x000000ff));
                } else {
                    ba.write((int) (c & 0x000000ff));
                }
            }

            ret = new String(ba.toByteArray(), charset);
            ba.close();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return ret;

    }

    /**
     * 指定文字列をバイナリに変換.
     */
    private static final int hexChar(char c) throws Exception {

        int ret = 0;
        if (c >= '0' && c <= '9') {
            ret = ((int) (c - '0') & 0x0000000f);
        } else if (c >= 'a' && c <= 'f') {
            ret = ((int) (c - 'a') & 0x0000000f) + 10;
        } else if (c >= 'A' && c <= 'F') {
            ret = ((int) (c - 'A') & 0x0000000f) + 10;
        } else {
            throw new Exception("16進[" + c + "]数値ではありません");
        }
        return ret;
    }
}
