package org.j69.eewiki.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.StringTokenizer;

import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oro.text.perl.Perl5Util;

/**
 * Web用ユーティリティクラス
 * @author <a href="mailto:agata@mobster.jp">Toshitaka Agata</a>
 * @version $Revision: 1.3 $ $Date: 2003/06/30 17:07:41 $
 */
public class WebUtil {

    /** デフォルトファイルエンコーディング */
    public static final String DEFAULT_FILE_ENCODING = "UTF-8";

    /** JISAutoDetect */
    public static final String JIS_AUTO_DETECT = "JISAutoDetect";
    /** UTF-8 */
    public static final String UTF_8           = "UTF-8";
    /** SHIFT_JIS */
    public static final String SHIFT_JIS       = "Shift_JIS";
    /** MS932 */
    public static final String MS932           = "MS932";
    /** MS932 */
    public static final String MICROSOFT       = "MS932";
    /** EUC-JP */
    public static final String EUC_JP          = "EUC-JP";
    /** SJIS */
    public static final String SJIS            = "SJIS";

    /** Perl5Util */
    private static Perl5Util perl = new Perl5Util();

    // ------------------------------------------------------------
    // 文字列置換系
    // ------------------------------------------------------------
	/**
	 * エリアスタイプURL文字列にリンクタグを追加
	 * [[Hogesite:http://hoge.com]] -> <a href="http://hoge.com">Hogesite</a>
	 */
	public static String addLinkTagShadowURL(String src, String target){
		return perl.substitute("s!([^=^\\\"]|^)\\{\\{(.+)\\:(https?\\://[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)\\}\\}!$1<a href=\"$3\" target=\"" + target + "\">$2<\\/a>!g", src);
	}
	/**
	 * エリアスタイプURL文字列にリンクタグを追加
	 * [[Hogesite:http://hoge.com]] -> <a href="http://hoge.com">Hogesite</a>
	 */
	public static String addLinkTagShadowURL(String src){
		return perl.substitute("s!([^=^\\\"]|^)\\{\\{(.+)\\:(https?\\://[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)\\}\\}!$1<a href=\"$2\">$2<\\/a>!g", src);
	}
    /**
     * URL文字列にリンクタグを追加
     */
    public static String addLinkTagURL(String src, String target){
//        return perl.substitute("s!([^=^\\\"]|^)(https?\\://[\\!-~]+)!$1<a href=\"$2\" target=\"" + target + "\">$2<\\/a>!g", src);
		return perl.substitute("s!([^=^\\\"]|^)(https?\\://[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)!$1<a href=\"$2\" target=\"" + target + "\">$2<\\/a>!g", src);
    }
    /**
     * URL文字列にリンクタグを追加
     */
    public static String addLinkTagURL(String src){
//        return perl.substitute("s!([^=^\\\"]|^)(https?\\://[\\!-~]+)!$1<a href=\"$2\">$2<\\/a>!g", src);
		return perl.substitute("s!([^=^\\\"]|^)(https?\\://[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)!$1<a href=\"$2\">$2<\\/a>!g", src);
    }
    /**
     * FTP文字列にリンクタグを追加
     */
    public static String addLinkTagFTP(String src, String target){
//        return perl.substitute("s!([^=^\\\"]|^)(ftp?\\://[\\!-~]+)!$1<a href=\"$2\" target=\"" +  target + "\">$2<\\/a>!g", src);
		return perl.substitute("s!([^=^\\\"]|^)(ftp?\\://[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)!$1<a href=\"$2\" target=\"" +  target + "\">$2<\\/a>!g", src);
    }
    /**
     * FTP文字列にリンクタグを追加
     */
    public static String addLinkTagFTP(String src){
//        return perl.substitute("s!([^=^\\\"]|^)(ftp?\\://[\\!-~]+)!$1<a href=\"$2\">$2<\\/a>!g", src);
		return perl.substitute("s!([^=^\\\"]|^)(ftp?\\://[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)!$1<a href=\"$2\">$2<\\/a>!g", src);
    }
    /**
     * メールアドレスにリンクタグを追加
     */
    public static String addLinkTagMail(String src){
//        return perl.substitute("s!(mailto:)?([\\!-~]+\\@[\\!-~]+)!<a href=\"mailto:$2\">$1$2<\\/a>!g", src);
		return perl.substitute("s!(mailto:)?([\\!-~]+\\@[-_.\\!~*'a-zA-Z0-9;/?:@&=+$,%#]+)!<a href=\"mailto:$2\">$1$2<\\/a>!g", src);
    }
    /**
     * 改行をBRタグに変換
     */
    public static String addBrTag(String src){
         Perl5Util perl = new Perl5Util();
        return perl.substitute("s!(.*)!$1<br>!g", src);
    }
    /**
     * 文字のエスケープ
     */
    public static String escapeChar(String src){
        String tmp = src;
        tmp = perl.substitute("s!&!&amp;!g", tmp);
        tmp = perl.substitute("s!<!&lt;!g", tmp);
        tmp = perl.substitute("s!>!&gt;!g", tmp);
        tmp = perl.substitute("s!\"!&quot;!g", tmp);
        return tmp;
    }
    /**
     * 先頭のスペース・タブを&nbsp;に変換
     * タブはスペース４文字で換算
     */
    public static String escapeSpace(String src){
        String[] lines = StringUtil.split(src, "\n");
        for (int i = 0; i < lines.length; i++) {
            int count = 0;
            for (int j = 0; j < lines[i].length(); j++) {
                String s = lines[i].substring(j, j + 1);
                if(s.equals(" ")) {
                    count += 1;
                } else if(s.equals("\t")){
                    count += 4;
                } else {
                    lines[i] = StringUtil.repeat("&nbsp;", count) + lines[i].substring(j);
                    break;
                }
            }
        }
        return StringUtil.join(lines, "\n");
    }
    /**
     * 全てのリンクタグ追加
     */
    public static String addLinkTagAll(String src){
        String tmp = src;
        tmp = addLinkTagURL(tmp);
        tmp = addLinkTagFTP(tmp);
        tmp = addLinkTagMail(tmp);
        tmp = addBrTag(tmp);
        return tmp;
    }
    /**
     * Null値か空文字ならば、文字列に置き換える
     */
    public static String replaceNull(String str, String newStr){
        if(str == null || str.equals("")){
            return newStr;
        }
        return str;
    }

    // ------------------------------------------------------------
    // エンコード系
    // ------------------------------------------------------------
    /**
     * 文字列をBASE64形式でエンコード
     * @param str 元の文字列
     * @return エンコードされた文字列
     */
    public static String encodeURL(String str) throws UnsupportedEncodingException {
        return URLEncoder.encode(str, DEFAULT_FILE_ENCODING);
    }

    /**
     * エンコードされた文字列をBASE64形式でデコード
     * @param base64Str 元の文字列
     * @return エンコードされた文字列
     */
    public static String decodeURL(String base64Str) throws UnsupportedEncodingException {
        return URLDecoder.decode(base64Str, DEFAULT_FILE_ENCODING);
    }

    // ------------------------------------------------------------
    // パラメータ取得系
    // ------------------------------------------------------------

    /**
     * 文字を指定されたコードからデコード
     */
    private static String decode(String str, String enc){
        try{
            return new String(str.getBytes("8859_1"), enc);
        } catch(Throwable ex){
            return str;
        }
    }

    /**
     * リクエストからパラメータの取得（文字列）
     */
    public static String getParameter(HttpServletRequest request, String paramName, String enc) {
        return getParameter(request, paramName, "", enc);
    }
    /**
     * リクエストからパラメータの取得（文字列）
     */
    public static String getParameter(HttpServletRequest request, String paramName, String defaultStr, String enc) {
        String value = request.getParameter(paramName);
        if(value == null || value.equals("")) {
            return defaultStr;
        }
        return decode(value, enc);
    }

    // ------------------------------------------------------------
    // クッキー取得/セット系
    // ------------------------------------------------------------

    /**
     * クッキーの値を取得
     * 指定されたクッキーが存在しない場合、空文字を返します。
     * クッキーの値はBASE64でエンコードされているものとみなして、
     * BASE64でデコードして取り出されます。
     * @param request HttpServletRequest
     * @param name クッキーの名前
     * @return クッキーの値, クッキーが存在しない場合空文字
     */
    public static String getCookieValue(HttpServletRequest request, String name) throws UnsupportedEncodingException {
        return getCookieValue(request, name, "");
    }
    /**
     * クッキーの値を取得
     * 指定されたクッキーが存在しない場合、デフォルト値を返します。
     * クッキーの値はBASE64でエンコードされているものとみなして、
     * BASE64でデコードして取り出されます。
     * @param request HttpServletRequest
     * @param name クッキーの名前
     * @param defaultValue デフォルト値
     * @return クッキーの値, クッキーが存在しない場合defaltValueの値
     */
    public static String getCookieValue(HttpServletRequest request, String name, String defaultValue) throws UnsupportedEncodingException {
        Cookie cookie = getCookie(request, name);
        return cookie != null ? decodeURL(cookie.getValue()) : defaultValue;
    }
    /**
     * クッキーの取得
     * 指定されたクッキーが存在しない場合、nullを返します。
     * @param request HttpServletRequest
     * @param name クッキーの名前
     * @return クッキー, クッキーが存在しない場合null
     */
    public static Cookie getCookie(HttpServletRequest request, String name) {
        Cookie[] cookies = request.getCookies();
        if(cookies == null) return null;

        for (int i = 0; i < cookies.length; i++) {
            if(cookies[i].getName().equals(name))
                return cookies[i];
        }
        return null;
    }
    /**
     * クッキーの値をセット
     * クッキーの値はBASE64でエンコードされてセットされます。
     * @param request HttpServletRequest
     * @param name クッキーの名前
     * @param name クッキーの値
     */
    public static void setCookieValue(HttpServletResponse response, String name, String value) throws UnsupportedEncodingException {
        response.addCookie(makeCookie(name, value));
    }

    /**
     * クッキーを生成
     * クッキーを新しく生成します。
     * クッキーの値はBASE64でエンコードされてセットされます。
     * @param request HttpServletRequest
     * @param name クッキーの名前
     * @param value クッキーの値
     * @return 生成されたクッキー
     */
    public static Cookie makeCookie(String name, String value) throws UnsupportedEncodingException  {
        Cookie cookie = new Cookie(name, encodeURL(value));
        return cookie;
    }
    /**
     * クッキーの削除
     * クッキーを削除します。
     * @param request HttpServletRequest
     * @param name クッキーの名前
     */
    public static void removeCookie(HttpServletResponse response, String name){
        Cookie cookie = new Cookie(name, "");
        cookie.setMaxAge(0); //生存期間30日
        response.addCookie(cookie);
    }

    // ------------------------------------------------------------
    // その他
    // ------------------------------------------------------------

    /** 日付文字列取得用SimpleDateFormat */
    private static final SimpleDateFormat format =
        new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    /**
     * 日付文字列の取得
     * @return 2001/01/01 10:10:10 形式の現在日付文字列
     */
    public static String getTimestamp(){
        synchronized(format) {
            return format.format(new Date());
        }
    }

    /**
     * デコード
     * 物理ファイル名をタイトル名へ変換
     * @return
     */
    public static String getDecodeFileName(String phyfilename_) {

        String decodeFileName = null;
        try {
            StringBuffer sb = new StringBuffer();
            for (int i = 0 ; i < phyfilename_.length()  - 1 ; i++) {
                if (i % 2 == 0) {
                    String buff = phyfilename_.substring(i, i + 2);
                    sb.append("%" + buff);
                }
            }
            String base64Str = sb.toString();
            decodeFileName = URLDecoder.decode(base64Str, DEFAULT_FILE_ENCODING);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return decodeFileName;
    }

    /**
     * エンコード
     * タイトル名を物理ファイル名に変換
     * @return
     */
    public static String getEncodeFileName(String filename_) throws CharacterCodingException {

        if (filename_==null)
            return "";

        String encodeFileName = null;

        // すでに変換されている場合は処理をエスケープ
        // でも%で判断はダサい？
        if (filename_.indexOf("%") == -1) {
            Charset charset = Charset.forName(DEFAULT_FILE_ENCODING);
            ByteBuffer dupBuffer = charset.encode(StringUtil.trim(filename_, ' '));
            // position をリセット
            dupBuffer.position(0);

            StringBuffer sb = new StringBuffer();
            for (int i = 0 ; i < dupBuffer.limit() ; i++) {
                sb.append(Integer.toHexString((int)dupBuffer.get() & 0xff));
            }
            encodeFileName = sb.toString();
        }
        else {
            encodeFileName = filename_.replaceAll("%", "");
        }
        return encodeFileName.toUpperCase();
    }

    /**
     * リクエストからローケルを取得する
     * @return　ローケル
     * TODO　現状jaでなければenとしてしまう仕様...今後更なる国際化を（汗）
     */
    public static Locale getLocale(HttpServletRequest request) {
        String Languages = request.getHeader("accept-language");
        StringTokenizer st = new StringTokenizer(Languages, ",");
        if (st.hasMoreTokens()) {
            String Language = (String)st.nextToken();
            if ("ja".equals(Language)) {
                return new Locale("ja", "");
            }
        }
        return new Locale("en", "");
    }

}