package yukihane.inqubus.cookie;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ニコニコ動画のクッキーを扱うための基本クラスです.
 * @author yuki
 */
public abstract class Cookie {

    private static final Logger logger = LoggerFactory.getLogger(Cookie.class);
    private static final Pattern USER_SESSION_PATTERN = Pattern.compile("(user_session_[\\d_]+)");

    public enum BrowserType {

        MSIE, FIREFOX, CHROME, CHROMIUM, OPERA, OTHER
    }

    public static Cookie create(BrowserType type, String dir) {
        switch (type) {
            case MSIE:
                return new CookieWinMsIe();
            case FIREFOX:
                return new CookieWinFirefox();
            case CHROME:
                return new CookieWinCrome();
            case CHROMIUM:
                return new CookieWinChromium();
            case OPERA:
                return new CookieWinOpera();
            default:
                final File f = new File(dir);
                return new CookieDefault(f);
        }
    }

    /**
     * cookieをmapで返します.
     * @return cookie.
     */
    public Map<String, String> get() {
        final Map<String, String> map = new HashMap<>();
        try {
            final String userSessionStr = getNicoUserSession();
            if (StringUtils.isNotEmpty(userSessionStr)) {
                map.put("user_session", userSessionStr);
            }
        } catch (IOException ex) {
            logger.warn("cookieファイル読み込み失敗", ex);
        }
        return map;
    }

    /**
     * ニコニコ動画ユーザセッション文字列を取得します.
     * @return ユーザセッション文字列. 無ければ空文字列.
     * @throws IOException cookie読み込み中のエラー.
     */
    protected abstract String getNicoUserSession() throws IOException;

    /**
     * クッキーファイルを見つけて user_session を返す.
     * @param cookieFileOrDirs cookieが保存されたディレクトリの候補, あるいはcookieファイルの候補.
     * @return ユーザセッション文字列. 無ければ空文字列.
     */
    protected final String getUserSession(String charsetName, File... cookieFileOrDirs) throws IOException {
        for (File file : cookieFileOrDirs) {
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File cookieFile : files) {
                    if (cookieFile.isFile()) {
                        final String userSession = cutUserSession(cookieFile, charsetName);
                        if (StringUtils.isNotEmpty(userSession)) {
                            return userSession;
                        }
                    }
                }
            } else if (file.isFile()) {
                final String userSession = cutUserSession(file, charsetName);
                if (StringUtils.isNotEmpty(userSession)) {
                    return userSession;
                }
            }
        }

        return "";
    }

    /**
     * 文字列から user_session_ で始まる文字列を切り出して返す。数字とアンダーバー以外の文字で切れる。
     * @param cookieStr 切り出す対象文字列
     * @return user_session 文字列。見つからない場合は空文字列。
     */
    protected final String getUserSession(final String cookieStr) {
        final Matcher mather = USER_SESSION_PATTERN.matcher(cookieStr);
        if (mather.find()) {
            return mather.group(1);
        }
        return "";
    }

    private String cutUserSession(File cookieFile, String charsetName) throws IOException {
        final String str = FileUtils.readFileToString(cookieFile, charsetName);
        return getUserSession(str);
    }
}
