package jp.sourceforge.nicoro;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.URLDecoder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import static jp.sourceforge.nicoro.Log.LOG_TAG;
import jp.sourceforge.nicoro.R;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.Toast;

public class NicoroWebBrowser extends Activity {
	private static final boolean DEBUG_LOGV = Release.IS_DEBUG && true;
	private static final boolean DEBUG_LOGD = Release.IS_DEBUG && true;
	
	private static final String PATTERN_VIDEO_URL =
		"http://www.nicovideo.jp/watch/([a-z0-9]+)";
	private static final String PATTERN_GET_USERID_FROM_USERSESSION =
		"user_session=user_session_([^_]+)_";
	private static final String PATTERN_IS_NOT_HTML =
		"(\\.jpg|\\.jpeg|\\.JPG|\\.JPEG|\\.png|\\.PNG|\\.gif|\\.GIF|\\.js|\\.JS|\\.css|\\.CSS)$";
	private static final String PATTERN_JIKKYO_URL =
		"http://jk.nicovideo.jp/watch/([a-z0-9]+)";
	private static final String PATTERN_JIKKYO_APP =
		"^nicojk:(.+)";
	
	private static final int MSG_ID_RUN_CACHING = 0;
	private static final int MSG_ID_FINISHED_CACHE = 1;
	private static final int MSG_ID_UPDATE_TITLE_URL = 2;
	
	private WebView mWebView;
	private ViewGroup mButtonVideoControl;
	private Button mButtonPlay;
	private ButtonCache mButtonCache;
	private Button mButtonHelp;
	private VariableLabelView mLabelTitleUrl;
	
	/** 動画視聴向けCookie */
	private String mCookieNicoHistory;
	
	// 設定
	private SharedPreferences mSharedPreferences;
	private SharedPreferences.OnSharedPreferenceChangeListener mSharedPreferencesChangeListener;
	/** 認証向けCookie */
	private String mCookieUserSession;
	private String mLastUrl;
	private String mUserAgent;
	
	private String mUserId;
	
	private Matcher mMatcherVideoUrl;
	private Matcher mMatcherGetUserID;
	private Matcher mMatcherIsNotHtml;
	private Matcher mMatcherJikkyoApp;
	private Matcher mMatcherIsNicovideo;
	
	private DecimalFormat mDecimalFormatMB;
	
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case MSG_ID_RUN_CACHING:
				mButtonCache.updateState(ButtonCache.STATE_RUN_CACHING,
						(String) msg.obj);
				break;
			case MSG_ID_FINISHED_CACHE:
				mButtonCache.updateState(ButtonCache.STATE_FINISHED_CACHE,
						null);
				break;
			case MSG_ID_UPDATE_TITLE_URL:
				{
					String title = mWebView.getTitle();
					if (title == null) {
		    			mHandler.sendEmptyMessageDelayed(MSG_ID_UPDATE_TITLE_URL,
		    					1000L);
					} else {
		    			StringBuilder builderTitleUrl = mLabelTitleUrl.getTextBuilder();
		    			builderTitleUrl.delete(0, builderTitleUrl.length());
	        			builderTitleUrl.append(title)
	        				.append(" : ").append(mWebView.getUrl());
	            		mLabelTitleUrl.notifyUpdateText();
					}
				}
				break;
			default:
				assert false : msg.what;
				break;
			}
		}
	};

	private IVideoCacheService mVideoCacheService;
	private ServiceConnection mVideoCacheServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mVideoCacheService = IVideoCacheService.Stub.asInterface(service);
			
			try {
				mVideoCacheService.addListener(mVideoCacheServiceCallback);
			} catch (RemoteException e) {
				Log.e(LOG_TAG, e.getMessage(), e);
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			try {
				mVideoCacheService.removeListener(mVideoCacheServiceCallback);
			} catch (RemoteException e) {
				Log.e(LOG_TAG, e.getMessage(), e);
			}
			
			mVideoCacheService = null;
		}
		
	};
	private IVideoCacheServiceCallback mVideoCacheServiceCallback =
		new IVideoCacheServiceCallback.Stub() {
			@Override
			public void onNotifyProgress(String videoNumber,
					int seekOffsetWrite, int contentLength)
					throws RemoteException {
				if (DEBUG_LOGV) {
					Log.v(LOG_TAG, "onNotifyProgress() videoNumber=" + videoNumber
							+ " seekOffsetWrite=" + seekOffsetWrite
							+ " contentLength=" + contentLength);
				}
				if (videoNumber.equals(mButtonCache.getVideoNumber())) {
					final String message = getRunCachingProgressMessage(
							seekOffsetWrite, contentLength);
					mHandler.sendMessage(
							mHandler.obtainMessage(
									MSG_ID_RUN_CACHING, message));
				}
			}
			@Override
			public void onFinished(String videoNumber) throws RemoteException {
				if (videoNumber.equals(mButtonCache.getVideoNumber())) {
					mHandler.sendEmptyMessage(MSG_ID_FINISHED_CACHE);
				}
			}
			@Override
			public void onAllFinished() throws RemoteException {
//				unbindService(mVideoCacheServiceConnection);
			}
	};
	
	private View.OnClickListener mClickListenerPlay = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			try {
	//			String url = mWebView.getOriginalUrl();
				String url = mWebView.getUrl();
				if (url == null) {
					if (DEBUG_LOGD) {
						Log.d(LOG_TAG, "mClickListenerPlay: mWebView.getUrl() is null");
					}
					return;
				}
				
				updateCookieUserSession();
				if (DEBUG_LOGD) {
					Log.d(LOG_TAG, "mCookieUserSession: " + mCookieUserSession);
				}
				mCookieNicoHistory = Util.getCookieValueFromManager(
						url, "nicohistory");
				if (DEBUG_LOGD) {
					Log.d(LOG_TAG, "mCookieNicoHistory: " + mCookieNicoHistory);
				}
				
				if (mCookieUserSession == null
						|| mUserId == null
						|| mCookieNicoHistory == null) {
					throw new FailPreparePlayVideoException();
				}
				
	    		mMatcherVideoUrl = Util.getMatcher(mMatcherVideoUrl,
	    				PATTERN_VIDEO_URL,
	    				url);
				String videoNumber = Util.getFirstMatch(mMatcherVideoUrl);
				if (videoNumber == null) {
					throw new FailPreparePlayVideoException();
				}
//				mLastVideoNumber = videoNumber;
				Intent intent = NicoroAPIManager.createVideoPlayerIntent(
						getApplicationContext(),
						videoNumber, mCookieUserSession, mCookieNicoHistory,
						mUserId, mUserAgent);
				if (intent == null) {
					throw new FailPreparePlayVideoException();
				}
				// キャッシュ処理が動作していれば停止
				if (mVideoCacheService != null) { 
					try {
						mVideoCacheService.stopCache(videoNumber);
					} catch (RemoteException e) {
						Log.e(LOG_TAG, e.getMessage(), e);
					}
				}
				startActivityIfNeeded(intent, 0);
			} catch (FailPreparePlayVideoException e) {
		        if (!NicoroAPIManager.checkIsCookieUserSessionValid(mCookieUserSession, mUserAgent)) {
		        	// 何らかの理由でログアウト状態
		        	Util.showErrorToast(v.getContext(), R.string.toast_play_fail_not_login);
		        	// ログイン画面へ
		        	mClickListenerNotLogin.onClick(v);
		        } else {
		        	String extraMessage = e.getExtraMessage();
		        	if (extraMessage == null) {
			        	// 原因不明で再生失敗
		        		extraMessage = getString(R.string.errormessage_play_fail_unknown);
		        	}
					Util.showErrorDialog(NicoroWebBrowser.this,
							extraMessage,
							false);
		        }
			}
		}
	};
	private View.OnClickListener mClickListenerNotLogin = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
        	// ログイン画面へ
        	// TODO: ログイン後に元の動画のURLに移動しない
			mWebView.loadUrl("https://secure.nicovideo.jp/secure/login_form");
		}
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

        getWindow().requestFeature(Window.FEATURE_PROGRESS);
		
        setContentView(R.layout.nicoro_webbrowser);
        
        // 例外対策
        CookieSyncManager.createInstance(getApplicationContext());
        
        if (mSharedPreferences == null) {
        	mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        }
        mCookieUserSession = mSharedPreferences.getString(NicoroConfig.COOKIE_USER_SESSION, null);
		CookieManager cookieManager = CookieManager.getInstance();
		cookieManager.removeExpiredCookie();
//		cookieManager.removeAllCookie();
        if (NicoroAPIManager.checkIsCookieUserSessionValid(mCookieUserSession, mUserAgent)) {
        	// 前回保存時のuser session Cookieを有効化
			mMatcherGetUserID = Util.getMatcher(mMatcherGetUserID,
					PATTERN_GET_USERID_FROM_USERSESSION,
					mCookieUserSession);
			mUserId = Util.getFirstMatch(mMatcherGetUserID);
        	cookieManager.setCookie("nicovideo.jp", mCookieUserSession);
        } else {
        	mCookieUserSession = null;
        	mUserId = null;
    		cookieManager.setCookie("nicovideo.jp", "user_session=");
        }
        // レイアウト崩れ対策
    	cookieManager.setCookie("nicovideo.jp", "nofix=1");
        
    	mButtonVideoControl = (ViewGroup) findViewById(R.id.button_video_control);
        mButtonPlay = (Button) findViewById(R.id.button_play);
        mButtonCache = new ButtonCache(
        		(Button) findViewById(R.id.button_cache));
        
        mButtonHelp = (Button) findViewById(R.id.button_help);
        mButtonHelp.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(getApplicationContext(), NicoroHelp.class);
				startActivityIfNeeded(intent, 0);
			}
        });
        boolean visibleHelpButton = mSharedPreferences.getBoolean(getString(R.string.pref_key_visible_help_button), true);
        if (visibleHelpButton) {
        	mButtonHelp.setVisibility(View.VISIBLE);
        } else {
        	mButtonHelp.setVisibility(View.GONE);
        }
        
        mLabelTitleUrl = (VariableLabelView) findViewById(R.id.web_title_url);
        
        mWebView = (WebView) findViewById(R.id.webview);
        final WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
        webSettings.setSavePassword(true);
        boolean zoomControl = mSharedPreferences.getBoolean(getString(R.string.pref_key_browser_zoom_controls), true);
        webSettings.setBuiltInZoomControls(zoomControl);
        mWebView.setWebChromeClient(new WebChromeClient() {
        	@Override
        	public void onProgressChanged(WebView view, int newProgress) {
        		super.onProgressChanged(view, newProgress);
        		NicoroWebBrowser.this.setProgress(newProgress * 100);
        	}
        });
        mWebView.setWebViewClient(new WebViewClient() {
        	@Override
        	public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
        		if (!isReload) {
        			if (url.equals("http://jk.nicovideo.jp/")) {
        				// ヒント表示
        				Util.showInfoToast(getApplicationContext(),
        						R.string.toast_explain_launch_jikkyo);
        			}
        		}
        	}
        	
        	@Override
        	public void onLoadResource(WebView view, String url) {
        		onChangePage(view, url);
        	}
        	
        	@Override
        	public void onPageStarted(WebView view, String url, Bitmap favicon) {
//        		onChangePage(view, url);
        		
        		// 念のため前のをキャンセル
        		mHandler.removeMessages(MSG_ID_UPDATE_TITLE_URL);
    			mHandler.sendEmptyMessageDelayed(MSG_ID_UPDATE_TITLE_URL,
    					1000L);
        	}
        	
        	@Override
        	public void onPageFinished(WebView view, String url) {
        	}
        	
        	@Override
        	public boolean shouldOverrideUrlLoading(WebView view, String url) {
        		mMatcherJikkyoApp = Util.getMatcher(mMatcherJikkyoApp,
        				PATTERN_JIKKYO_APP, url);
        		if (mMatcherJikkyoApp.find()) {
        			// 実況アプリ起動ボタン
        			startJikkyo(mMatcherJikkyoApp.group(1));
        			return true;
        		}
        		mMatcherIsNicovideo = Util.getMatcher(mMatcherIsNicovideo,
        				NicoroAPIManager.PATTERN_NICOVIDEO_URL, url);
        		if (!mMatcherIsNicovideo.find()) {
        			// 外部サイトへのリンクの場合はIntent投げる
        			Intent intent = new Intent(Intent.ACTION_VIEW,
        					Uri.parse(url));
        			intent.addCategory(Intent.CATEGORY_BROWSABLE);
        			startActivityIfNeeded(intent, 0);
        			return true;
        		}
        		
        		return false;
        	}
        });
        
        WebBackForwardList backForwardList = null;
        if (savedInstanceState != null) {
        	backForwardList = mWebView.restoreState(savedInstanceState);
        }
        
        String url = null;
        Intent intent = getIntent();
        if (intent != null) {
        	String action = intent.getAction();
        	if (action != null && action.equals(Intent.ACTION_VIEW)) {
	        	Uri uri = intent.getData();
	        	if (uri != null) {
	        		url = uri.toString();
	        	}
        	}
        }
        if (url == null) {
        	String defaultUrl;
        	if (backForwardList != null) {
        		defaultUrl = backForwardList.getCurrentItem().getUrl();
        	} else {
        		defaultUrl = "http://www.nicovideo.jp/";
        	}
    		mLastUrl = mSharedPreferences.getString(NicoroConfig.LAST_URL, defaultUrl);
        } else {
        	mLastUrl = url;
        }
        
        mUserAgent = mSharedPreferences.getString(NicoroConfig.USER_AGENT,
        		null);
        if (mUserAgent == null) {
        	mUserAgent = mWebView.getSettings().getUserAgentString();
        	SharedPreferences.Editor editor = mSharedPreferences.edit();
        	editor.putString(NicoroConfig.USER_AGENT, mUserAgent);
        	editor.commit();
        }
        
        mSharedPreferencesChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
			@Override
			public void onSharedPreferenceChanged(
					SharedPreferences sharedPreferences, String key) {
				if (key.equals(getString(R.string.pref_key_visible_help_button))) {
			        boolean visibleHelpButton = mSharedPreferences.getBoolean(key, true);
			        if (visibleHelpButton) {
			        	mButtonHelp.setVisibility(View.VISIBLE);
			        } else {
			        	mButtonHelp.setVisibility(View.GONE);
			        }
				} else if (key.equals(getString(R.string.pref_key_browser_zoom_controls))) {
			        boolean zoomControl = mSharedPreferences.getBoolean(key, true);
			        mWebView.getSettings().setBuiltInZoomControls(zoomControl);
				}
			}
        };
        mSharedPreferences.registerOnSharedPreferenceChangeListener(mSharedPreferencesChangeListener);
        
        mDecimalFormatMB = new DecimalFormat();
        mDecimalFormatMB.applyPattern("0");
        mDecimalFormatMB.setMaximumFractionDigits(2);
        mDecimalFormatMB.setMinimumFractionDigits(2);
        
        mWebView.loadUrl(mLastUrl);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		
		if (mButtonVideoControl.getVisibility() == View.VISIBLE) {
			// ボタン表示更新
			String videoNumber = mButtonCache.getVideoNumber();
			if (mWebView != null) {
				mMatcherVideoUrl = Util.getMatcher(mMatcherVideoUrl,
						PATTERN_VIDEO_URL,
						mWebView.getUrl());
				if (mMatcherVideoUrl.find()) {
					videoNumber = mMatcherVideoUrl.group(1);
				}
			}
			updateButtons(videoNumber);
		}
	}
	
	@Override
	protected void onPause() {
		super.onPause();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
        mSharedPreferences.unregisterOnSharedPreferenceChangeListener(mSharedPreferencesChangeListener);
        if (mVideoCacheService != null) {
        	unbindService(mVideoCacheServiceConnection);
        }
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// 1.6向けなのでonKeyDownでback key監視
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			if (mWebView.canGoBack()) {
				mWebView.goBack();
				return true;
			}
		}
		return super.onKeyDown(keyCode, event);
	}
	
	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		return super.onKeyUp(keyCode, event);
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		mWebView.saveState(outState);
	}
	
	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		mWebView.restoreState(savedInstanceState);
	}
	
	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
        String url = null;
        if (intent != null) {
        	String action = intent.getAction();
        	if (action != null && action.equals(Intent.ACTION_VIEW)) {
	        	Uri uri = intent.getData();
	        	if (uri != null) {
	        		url = uri.toString();
	        	}
        	}
        }
        if (url != null) {
        	mLastUrl = url;
            mWebView.loadUrl(mLastUrl);
        }
	}
	
	private void downloadVideo(DefaultHttpClient httpClient, String url, String cookie, String filePath) throws ClientProtocolException, IOException {
		HttpUriRequest httpRequest = new HttpGet(url);
		httpRequest.addHeader("Cookie", cookie);
		httpRequest.setHeader("User-Agent", mUserAgent);
		HttpResponse httpResponse = httpClient.execute(
				httpRequest
				);
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, "downloadVideo httpResponse>>>");
			Util.logHeaders(LOG_TAG, httpResponse.getAllHeaders());
			Log.d(LOG_TAG, "<<<httpResponse end");
		}
		if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			HttpEntity httpEntity = httpResponse.getEntity();
			InputStream inDownload = null;
			FileOutputStream outDownload = null;
			try {
				inDownload = httpEntity.getContent();
				outDownload = new FileOutputStream(filePath);
				byte[] buffer = new byte[1024*8];
				while (true) {
					int read = inDownload.read(buffer);
					if (read < 0) {
						break;
					}
					outDownload.write(buffer, 0, read);
				}
			} finally {
				if (inDownload != null) {
					inDownload.close();
				}
				if (outDownload != null) {
					outDownload.close();
				}
			}
		}
		Log.d(LOG_TAG, "downloadVideo done.");
	}
	
	private void updateCookieUserSession() {
		String cookieUserSession = Util.getCookieValueFromManager(
				"nicovideo.jp", "user_session");
		if (cookieUserSession == null || cookieUserSession.length() == 0) {
			// ログアウト状態
			mCookieUserSession = null;
			mUserId = null;
		} else if (!cookieUserSession.equals(mCookieUserSession)) {
	        SharedPreferences.Editor editor = mSharedPreferences.edit();
	        editor.putString(NicoroConfig.COOKIE_USER_SESSION, cookieUserSession);
			editor.commit();
			mCookieUserSession = cookieUserSession;
			mMatcherGetUserID = Util.getMatcher(mMatcherGetUserID,
					PATTERN_GET_USERID_FROM_USERSESSION,
					mCookieUserSession);
			mUserId = Util.getFirstMatch(mMatcherGetUserID);
		}
	}
	
	private void onChangePage(WebView view, String url) {
		// 外部サイトなら特別処理省略
		if (url.indexOf("nicovideo.jp") < 0) {
			return;
		}
		// 画像他なら特別処理省略
		mMatcherIsNotHtml = Util.getMatcher(mMatcherIsNotHtml,
				PATTERN_IS_NOT_HTML,
				url);
		if (mMatcherIsNotHtml.find()) {
			return;
		}
		
		boolean wasLogout;
		if (url.equals("https://secure.nicovideo.jp/secure/logout")) {
			// ログアウト
			mCookieUserSession = null;
			mUserId = null;
    		CookieManager cookieManager = CookieManager.getInstance();
    		cookieManager.removeExpiredCookie();
    		cookieManager.setCookie("nicovideo.jp", "user_session=");
        	wasLogout = true;
		} else {
			wasLogout = false;
		}
		
		// ページ移動に備えて基本的にWebViewのcurrent URLで確認
		String urlCurrent = view.getUrl();
		if (urlCurrent == null) {
			urlCurrent = url;
		}
		
		if (!wasLogout) {
    		if (mCookieUserSession == null && urlCurrent.indexOf("nicovideo.jp") >= 0) {
    			updateCookieUserSession();
    		}
		}
		
		final int lastVisibilityButtonVideoControl = mButtonVideoControl.getVisibility();
		mMatcherVideoUrl = Util.getMatcher(mMatcherVideoUrl,
				PATTERN_VIDEO_URL,
				urlCurrent);
		if (mMatcherVideoUrl.find()) {
			final String videoNumber = mMatcherVideoUrl.group(1);
			mButtonVideoControl.setVisibility(View.VISIBLE);
			updateButtons(videoNumber);
		} else {
//			mButtonVideoControl.setVisibility(View.GONE);
			mButtonVideoControl.setVisibility(View.INVISIBLE);
		}
		
		if (lastVisibilityButtonVideoControl != mButtonVideoControl.getVisibility()) {
			// TODO ズームコントロールが邪魔なので何とかしていったん消したい
//	        final WebSettings webSettings = mWebView.getSettings();
//	        if (webSettings.getBuiltInZoomControls()) {
//	        	webSettings.setBuiltInZoomControls(false);
//	        	mHandler.postDelayed(new Runnable() {
//					@Override
//					public void run() {
//						mWebView.getSettings().setBuiltInZoomControls(true);
//					}
//	        	}, 1000L);
//	        }
		}
		
//		if (DEBUG_LOG) {
//    		CookieManager cookieManager = CookieManager.getInstance();
//    		String cookie = cookieManager.getCookie(urlCurrent);
//    		if (cookie != null) {
//    			Log.d(LOG_TAG, "URL=" + url
//    					+ " Cookie=" + cookie);
//    		}
//		}
		
		mMatcherIsNicovideo = Util.getMatcher(mMatcherIsNicovideo,
				NicoroAPIManager.PATTERN_NICOVIDEO_URL, urlCurrent);
		if (mMatcherIsNicovideo.find()) { 
	        SharedPreferences.Editor editor = mSharedPreferences.edit();
	        editor.putString(NicoroConfig.LAST_URL, urlCurrent);
			editor.commit();
    		mLastUrl = urlCurrent;
		}
	}
	
	private void updateButtons(String videoNumber) {
		mButtonCache.setVideoNumber(videoNumber);
		if (mCookieUserSession == null) {
			mButtonPlay.setText(R.string.button_not_login);
			mButtonPlay.setTextColor(0xffff0000);
	        mButtonPlay.setOnClickListener(mClickListenerNotLogin);
	        mButtonCache.updateState(ButtonCache.STATE_NOT_LOGIN, null);
		} else {
			final boolean isSwf = videoNumber.startsWith("nm");
			
			if (isSwf) {
				mButtonPlay.setText(R.string.button_play_swf);
			} else {
				mButtonPlay.setText(R.string.button_play_normal);
			}
			mButtonPlay.setTextColor(0xff000000);
			mButtonPlay.setOnClickListener(mClickListenerPlay);
			
			try {
				if (VideoLoader.isFinishedCache(videoNumber)) {
					mButtonCache.updateState(ButtonCache.STATE_FINISHED_CACHE, null);
				} else {
					if (mVideoCacheService == null) {
						if (mButtonCache.getState() == ButtonCache.STATE_WAIT_START_CACHE) {
							// 実行開始してからServiceがまだ作られてない
							// 状態そのまま
						} else {
    	    				if (isSwf) {
    	    					mButtonCache.updateState(ButtonCache.STATE_NOT_CACHED_TARGET_SWF, null);
    	    				} else {
    	    					mButtonCache.updateState(ButtonCache.STATE_NOT_CACHED, null);
    	    				}
						}
					} else {
						final int cacheState = mVideoCacheService.getCacheState(videoNumber);
						switch (cacheState) {
						case VideoCacheService.CACHE_STATE_NOT_RUN:
							// ここまでの分岐で未キャッシュであること確定
    	    				if (isSwf) {
    	    					mButtonCache.updateState(ButtonCache.STATE_NOT_CACHED_TARGET_SWF, null);
    	    				} else {
    	    					mButtonCache.updateState(ButtonCache.STATE_NOT_CACHED, null);
    	    				}
    	    				break;
						case VideoCacheService.CACHE_STATE_WAIT_START:
	    					mButtonCache.updateState(ButtonCache.STATE_WAIT_START_CACHE, null);
	    					break;
						case VideoCacheService.CACHE_STATE_RUNNING:
							final int contentLength = mVideoCacheService.getContentLength(videoNumber);
							final int seekOffsetWrite = mVideoCacheService.getProgress(videoNumber);
							final String message = getRunCachingProgressMessage(
									seekOffsetWrite, contentLength);
	    					mButtonCache.updateState(ButtonCache.STATE_RUN_CACHING,
	    							message);
							break;
						default:
							assert false : "VideoCacheService#getCacheState return unknown value=" + cacheState;
							break;
						}
					}
				}
			} catch (RemoteException e) {
				Log.e(LOG_TAG, e.getMessage(), e);
			}
		}
	}
	
	private class ButtonCache {
		static final int STATE_NOT_CACHED = 0;
		static final int STATE_WAIT_START_CACHE = 1;
		static final int STATE_RUN_CACHING = 2;
		static final int STATE_FINISHED_CACHE = 3;
		static final int STATE_NOT_LOGIN = 4;
		static final int STATE_NOT_CACHED_TARGET_SWF = 5;
		
		private Button mButton;
		private int mState;
		private String mVideoNumber;
		
		private View.OnClickListener mClickListenerCacheStart =
			new View.OnClickListener() {
			@Override
			public void onClick(View v) {
//				String url = mWebView.getOriginalUrl();
				String url = mWebView.getUrl();
				if (url == null) {
					if (DEBUG_LOGD) {
						Log.d(LOG_TAG, "mClickListenerCacheStart: mWebView.getUrl() is null");
					}
					return;
				}
				
				updateCookieUserSession();
				if (DEBUG_LOGD) {
					Log.d(LOG_TAG, "mCookieUserSession: " + mCookieUserSession);
				}
				
	    		mMatcherVideoUrl = Util.getMatcher(mMatcherVideoUrl,
	    				PATTERN_VIDEO_URL,
	    				url);
				String videoNumber = Util.getFirstMatch(mMatcherVideoUrl);
				assert videoNumber != null;
				
//				Intent intent = new Intent(getApplicationContext(), VideoCacheService.class);
				Intent intent = new Intent(IVideoCacheService.class.getName());
				intent.putExtra(AbstractNicoroPlayer.INTENT_NAME_VIDEO_NUMBER, videoNumber);
				intent.putExtra(VideoCacheService.INTENT_NAME_COOKIE_USER_SESSION, mCookieUserSession);
//				ComponentName cn = startService(intent);
//				assert cn != null;
				if (mVideoCacheService == null) {
					boolean bindResult = bindService(intent,
							mVideoCacheServiceConnection, Context.BIND_AUTO_CREATE);
	//				if (DEBUG_LOGD) {
	//					Log.d(LOG_TAG, "bindResult=" + bindResult);
	//				}
					if (bindResult) {
						mButtonCache.updateState(ButtonCache.STATE_WAIT_START_CACHE, null);
					} else {
			        	Util.showErrorToast(v.getContext(), R.string.toast_cache_fail_bind);
					}
				} else {
					try {
						mVideoCacheService.addStartCache(videoNumber, mCookieUserSession);
						mButtonCache.updateState(ButtonCache.STATE_WAIT_START_CACHE, null);
					} catch (RemoteException e) {
						Log.e(LOG_TAG, e.getMessage(), e);
			        	Util.showErrorToast(v.getContext(), R.string.toast_cache_fail_bind);
					}
				}
			}
		};
		
		private View.OnClickListener mClickListenerCacheAlreadyStart =
			new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Util.showErrorToast(v.getContext(), R.string.toast_cache_already_start);
			}
		};
		
		ButtonCache(Button button) {
			mButton = button;
			mState = -1;
			mVideoNumber = null;
		}
		
		void updateState(int state, String additionalMessage) {
			mState = state;
			String text;
			switch (state) {
			case STATE_NOT_CACHED:
				mButton.setText(R.string.button_cache_start);
				mButton.setTextColor(0xff000000);
				mButton.setOnClickListener(mClickListenerCacheStart);
				break;
			case STATE_WAIT_START_CACHE:
				mButton.setText(R.string.button_wait_start_cache);
				mButton.setTextColor(0xff808080);
				mButton.setOnClickListener(mClickListenerCacheAlreadyStart);
				break;
			case STATE_RUN_CACHING:
				text = getString(R.string.button_run_caching);
				if (additionalMessage != null) {
					text += " " + additionalMessage;
				}
				mButton.setText(text);
				mButton.setTextColor(0xff808080);
				mButton.setOnClickListener(mClickListenerCacheAlreadyStart);
				break;
			case STATE_FINISHED_CACHE:
				mButton.setText(R.string.button_finished_cache);
				mButton.setTextColor(0xff808080);
				mButton.setOnClickListener(mClickListenerCacheAlreadyStart);
				break;
			case STATE_NOT_LOGIN:
				mButton.setText(R.string.button_not_login);
				mButton.setTextColor(0xffff0000);
		        mButton.setOnClickListener(mClickListenerNotLogin);
				break;
			case STATE_NOT_CACHED_TARGET_SWF:
//				mButton.setText(R.string.button_play_swf);
				mButton.setText(R.string.button_cache_start);
				mButton.setTextColor(0xff000000);
				mButton.setOnClickListener(mClickListenerCacheStart);
				break;
			default:
				assert false : "unknown state=" + state;
				break;
			}
		}
		
		int getState() {
			return mState;
		}
		
		void setVideoNumber(String videoNumber) {
			mVideoNumber = videoNumber;
		}
		String getVideoNumber() {
			return mVideoNumber;
		}
	}
	
	String getRunCachingProgressMessage(int seekOffsetWrite, int contentLength) {
		if (seekOffsetWrite >= 0 && contentLength >= 0) {
			float seekOffsetWriteMB = seekOffsetWrite / (float) (1024 * 1024);
			float contentLengthMB = contentLength / (float) (1024 * 1024);
			final String message = mDecimalFormatMB.format(seekOffsetWriteMB)
			+ "MB/" + mDecimalFormatMB.format(contentLengthMB) + "MB";
			return message;
		} else {
			final String message = "-.--MB/-.--MB";
			return message;
		}
	}
	
	private void startJikkyo(String number) {
		// TODO
		try {
			Intent intent = NicoroAPIManager.createJikkyoPlayerIntent(
					getApplicationContext(),
					number, mCookieUserSession, mCookieNicoHistory,
					mUserId, mUserAgent);
			startActivityIfNeeded(intent, 0);
		} catch (FailPreparePlayVideoException e) {
		}
	}
	
	// メニュー関連
	
	private static final int MENU_ID_TOP = (Menu.FIRST + 1);
    private static final int MENU_ID_RELOAD = (Menu.FIRST + 2);
    private static final int MENU_ID_CONFIG = (Menu.FIRST + 3);
    private static final int MENU_ID_HELP = (Menu.FIRST + 4);
    private static final int MENU_ID_FINISH = (Menu.FIRST + 5);
    private static final int MENU_ID_OTHER = (Menu.FIRST + 6);
    private static final int MENU_ID_CLEAR_CACHE = (Menu.FIRST + 7);
    private static final int MENU_ID_BOOKMARKS = (Menu.FIRST + 8);

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	menu.add(Menu.NONE, MENU_ID_BOOKMARKS, Menu.NONE,
    			R.string.menu_boookmarks);
    	menu.add(Menu.NONE, MENU_ID_RELOAD, Menu.NONE,
    			R.string.menu_reload);
    	menu.add(Menu.NONE, MENU_ID_CONFIG, Menu.NONE,
    			R.string.menu_config)
    			.setIcon(android.R.drawable.ic_menu_preferences);
    	menu.add(Menu.NONE, MENU_ID_HELP, Menu.NONE,
    			R.string.menu_help)
    			.setIcon(android.R.drawable.ic_menu_help);
    	menu.add(Menu.NONE, MENU_ID_FINISH, Menu.NONE,
    			R.string.menu_finish)
    			.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
    	{
	    	SubMenu menuOther = menu.addSubMenu(Menu.NONE, MENU_ID_OTHER, Menu.NONE,
	    			R.string.menu_other)
	    			.setIcon(android.R.drawable.ic_menu_more);
	    	menuOther.add(Menu.NONE, MENU_ID_TOP, Menu.NONE,
	    			R.string.menu_top);
	    	menuOther.add(Menu.NONE, MENU_ID_CLEAR_CACHE, Menu.NONE,
	    			R.string.menu_clear_cache);
    	}
    	
    	return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
    	return super.onPrepareOptionsMenu(menu);
    }
	
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	Intent intent;
    	switch (item.getItemId()) {
    	case MENU_ID_TOP:
    		mWebView.loadUrl("http://www.nicovideo.jp/");
    		return true;
    	case MENU_ID_RELOAD:
    		mWebView.reload();
    		return true;
    	case MENU_ID_CONFIG:
			intent = new Intent(getApplicationContext(), NicoroConfig.class);
			startActivity(intent);
    		return true;
    	case MENU_ID_HELP:
			intent = new Intent(getApplicationContext(), NicoroHelp.class);
			startActivityIfNeeded(intent, 0);
    		return true;
    	case MENU_ID_FINISH:
    		finish();
    		return true;
    	case MENU_ID_OTHER:
    		// none
    		return true;
    	case MENU_ID_CLEAR_CACHE:
    		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
    		alertDialogBuilder.setTitle(R.string.menu_clear_cache);
    		alertDialogBuilder.setMessage(R.string.confirm_clear_cache);
    		alertDialogBuilder.setCancelable(true);
    		alertDialogBuilder.setPositiveButton(android.R.string.yes,
    				new DialogInterface.OnClickListener() {
    			@Override
    			public void onClick(DialogInterface dialog, int which) {
    	    		VideoLoader.deleteAllCacheFile();
    			}
    		});
    		alertDialogBuilder.setNegativeButton(android.R.string.no, null);
    		alertDialogBuilder.show();
    		return true;
    	case MENU_ID_BOOKMARKS:
			intent = new Intent(getApplicationContext(), Bookmarks.class);
    		if (mWebView != null) {
				intent.putExtra(Bookmarks.INTENT_NAME_TITLE, mWebView.getTitle());
				intent.putExtra(Bookmarks.INTENT_NAME_URL, mWebView.getUrl());
    		} else {
    			Util.showErrorToast(getApplicationContext(), R.string.toast_webview_not_ready);
    		}
			startActivityIfNeeded(intent, 0);
    		return true;
    	default:
    		assert false;
    		break;
    	}
    	return false;
    }
}
