package jp.sourceforge.nicoro;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Set;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

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

public class LoginActivity extends Activity {
	private static final boolean DEBUG_LOGD = Release.IS_DEBUG && true;
	
	public static final String INTENT_NAME_EDIT_LOGIN =
		"jp.sourceforge.nicoro.intent.action.EDIT_LOGIN";

	private SharedPreferences mSharedPreferences;
	private InputMethodManager mInputMethodManager;
	
	private TextView mMailAddress;
	private EditText mInputMailAddress;
	private TextView mPassword;
	private EditText mInputPassword;
	private Button mButtonLogin;
	private Button mButtonWithoutLogin;
	private Button mButtonHelp;
	
	private ProgressBar mProgress;
	private TextView mProgressText;
	
	private String mUserAgent;
	private String mCookieUserSession;
	
	private boolean mIsEditLogin;
	
	private AsyncGetAuthorizeCookie mAsyncGetAuthorizeCookie = null;
	private class AsyncGetAuthorizeCookie extends AsyncTask<Void, Void, String> {
		private HttpPost mHttpRequest;
		private String mTempMail;
		private String mTempPassword;
		
		@Override
		protected void onPreExecute() {
			try {
				mHttpRequest = NicoroAPIManager.createRequestGetAuthorizeCookie(
						mTempMail, mTempPassword, mUserAgent);
			} catch (UnsupportedEncodingException e) {
				Log.e(LOG_TAG, e.toString(), e);
				mHttpRequest = null;
			}
		}

		@Override
		protected String doInBackground(Void... params) {
			if (mHttpRequest == null) {
				return null;
			}
			DefaultHttpClient httpClient = Util.createHttpClient();
			try {
				String cookieUserSession = NicoroAPIManager.getAuthorizeCookie(
						httpClient, mHttpRequest);
				if (DEBUG_LOGD) {
					Log.d(LOG_TAG, Log.buf().append("getAuthorizeCookie: ")
							.append(cookieUserSession)
							.toString());
				}
				return cookieUserSession;
			} catch (ClientProtocolException e) {
				Log.e(LOG_TAG, e.toString(), e);
			} catch (IOException e) {
				Log.e(LOG_TAG, e.toString(), e);
			}
			return null;
		}
		
		@Override
		protected void onPostExecute(String result) {
			if (result == null || result.length() == 0) {
				Util.showErrorToast(getApplicationContext(),
						R.string.toast_login_failed);
				
				// 登録し直し
				showLoginView();
				hideProgressView();
			} else {
				Util.showInfoToast(getApplicationContext(),
						R.string.toast_login_succeeded);
				
				String cookieUserSession = result;
		        SharedPreferences.Editor editor = mSharedPreferences.edit();
		        editor.putString(NicoroConfig.COOKIE_USER_SESSION,
		        		cookieUserSession);
		        NicoroConfig.putMA(editor, mTempMail);
		        NicoroConfig.putPW(editor, mTempPassword);
				editor.commit();
				
				endLogin();
			}
			
			mAsyncGetAuthorizeCookie = null;
		}
		
		public AsyncGetAuthorizeCookie executeWrapper(String mail,
				String password) {
			mTempMail = mail;
			mTempPassword = password;
			return (AsyncGetAuthorizeCookie) execute();
		}
		
		public void stop() {
			if (mHttpRequest != null && !mHttpRequest.isAborted()) {
				mHttpRequest.abort();
			}
		}
	}
	
	private AsyncCheckCookieUserSession mAsyncCheckCookieUserSession = null;
	private class AsyncCheckCookieUserSession extends AsyncTask<Void, Void, Boolean> {
		private HttpUriRequest mHttpRequest;
		
		@Override
		protected void onPreExecute() {
			mHttpRequest =
				NicoroAPIManager.createRequestIsCookieUserSessionValid(
						mCookieUserSession, mUserAgent);
		}
		
		@Override
		protected Boolean doInBackground(Void... params) {
	        return NicoroAPIManager.checkIsCookieUserSessionValid(mHttpRequest);
		}
		
		@Override
		protected void onPostExecute(Boolean result) {
			if (result) {
				Util.showInfoToast(getApplicationContext(),
						R.string.toast_login_succeeded);
				
				endLogin();
			} else {
		        SharedPreferences.Editor editor = mSharedPreferences.edit();
		        editor.putString(NicoroConfig.COOKIE_USER_SESSION,
		        		null);
		        editor.commit();
				
		        // 再ログイン
				// 非同期処理に渡すので念のためコピー作成
				String mail = mInputMailAddress.getText().toString();
				String password = mInputPassword.getText().toString();
				
				mAsyncGetAuthorizeCookie = new AsyncGetAuthorizeCookie();
				mAsyncGetAuthorizeCookie.executeWrapper(mail, password);
			}
			
			mAsyncCheckCookieUserSession = null;
		}
		
		public void stop() {
			if (mHttpRequest != null && !mHttpRequest.isAborted()) {
				mHttpRequest.abort();
			}
		}
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		String lastUncaught = NicoroApplication.getInstance(this).processLastUncaughtException();
		if (lastUncaught == null) {
	        onCreateMain();
		} else {
		    // 前回の強制終了情報表示
		    // TODO: LoginActivity以外を直接起動した場合に表示されない、設定でログイン編集呼び出した場合に表示される可能性有り
		    Util.createCloseDialog(this,
		            getString(R.string.dialog_title_last_uncaught_exception),
		            lastUncaught,
		            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    onCreateMain();
                }
		    }, new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    onCreateMain();
                }
		    }).show();
		}
	}
	
	private void onCreateMain() {
        setContentView(R.layout.login);
        getLoginView();
        getProgressView();
        
        Intent intent = getIntent();
        mIsEditLogin = (intent != null
                && INTENT_NAME_EDIT_LOGIN.equals(intent.getAction()));
        
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
                getApplicationContext());
        mSharedPreferences = sp;
        
        mUserAgent = sp.getString(NicoroConfig.USER_AGENT, null);
        
        String ma = NicoroConfig.getMA(sp);
        String pw = NicoroConfig.getPW(sp);
        if (ma != null) {
            mInputMailAddress.setText(ma);
        }
        if (pw != null) {
            mInputPassword.setText(pw);
        }
        
        if (mIsEditLogin) {
            showLoginView();
        } else {
            if (ma == null || pw == null) {
                // ログインView表示
                showLoginView();
            } else {
                // Cookie確認
                mCookieUserSession = sp.getString(
                        NicoroConfig.COOKIE_USER_SESSION, null);
                mAsyncCheckCookieUserSession = new AsyncCheckCookieUserSession();
                mAsyncCheckCookieUserSession.execute();
                
                showProgressView();
            }
        }
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		
        if (mAsyncGetAuthorizeCookie != null) {
        	mAsyncGetAuthorizeCookie.cancel(false);
        	mAsyncGetAuthorizeCookie.stop();
        }
        if (mAsyncCheckCookieUserSession != null) {
        	mAsyncCheckCookieUserSession.cancel(false);
        	mAsyncCheckCookieUserSession.stop();
        }
	}
	
	private void getLoginView() {
		if (mMailAddress == null) {
			mMailAddress = (TextView) findViewById(R.id.mail_address);
		}
		if (mInputMailAddress == null) {
			mInputMailAddress = (EditText) findViewById(R.id.input_mail_address);
		}
		if (mPassword == null) {
			mPassword = (TextView) findViewById(R.id.password);
		}
		if (mInputPassword == null) {
			mInputPassword = (EditText) findViewById(R.id.input_password);
		}
		if (mButtonLogin == null) {
			mButtonLogin = (Button) findViewById(R.id.button_login);
			mButtonLogin.setOnClickListener(new LoginButtonListener());
		}
		if (mButtonWithoutLogin == null) {
			mButtonWithoutLogin = (Button) findViewById(R.id.button_without_login);
			mButtonWithoutLogin.setOnClickListener(new WithoutLoginButtonListener());
		}
		if (mButtonHelp == null) {
			mButtonHelp = (Button) findViewById(R.id.button_help);
			mButtonHelp.setOnClickListener(new HelpButtonListener());
		}
	}
	
	private void getProgressView() {
		if (mProgress == null) {
			mProgress = (ProgressBar) findViewById(R.id.progress);
		}
		if (mProgressText == null) {
			mProgressText = (TextView) findViewById(R.id.progress_text);
		}
	}
	
	private void showLoginView() {
		mMailAddress.setVisibility(View.VISIBLE);
		mInputMailAddress.setVisibility(View.VISIBLE);
		mPassword.setVisibility(View.VISIBLE);
		mInputPassword.setVisibility(View.VISIBLE);
		mButtonLogin.setVisibility(View.VISIBLE);
		if (!mIsEditLogin) {
			mButtonWithoutLogin.setVisibility(View.VISIBLE);
			mButtonHelp.setVisibility(View.VISIBLE);
		}
	}

	private void hideLoginView() {
		mMailAddress.setVisibility(View.INVISIBLE);
		mInputMailAddress.setVisibility(View.INVISIBLE);
		mPassword.setVisibility(View.INVISIBLE);
		mInputPassword.setVisibility(View.INVISIBLE);
		mButtonLogin.setVisibility(View.INVISIBLE);
		mButtonWithoutLogin.setVisibility(View.INVISIBLE);
		mButtonHelp.setVisibility(View.INVISIBLE);
	}

	private void showProgressView() {
		mProgress.setVisibility(View.VISIBLE);
		mProgressText.setVisibility(View.VISIBLE);
	}

	private void hideProgressView() {
		mProgress.setVisibility(View.INVISIBLE);
		mProgressText.setVisibility(View.INVISIBLE);
	}
	
	private void endLogin() {
		if (mIsEditLogin) {
			
		} else {
			launchNicoroWebBrowser(getIntent());
		}
		finish();
	}

	private void launchNicoroWebBrowser(Intent srcIntent) {
		Intent launchIntent = new Intent(
				srcIntent.getAction(), srcIntent.getData(),
				getApplicationContext(), NicoroWebBrowser.class);
		Set<String> categories = srcIntent.getCategories();
		if (categories != null) {
		    for (String category : categories) {
		        launchIntent.addCategory(category);
		    }
		}
		startActivityIfNeeded(launchIntent, 0);
	}
	
	private class LoginButtonListener implements View.OnClickListener {
		@Override
		public void onClick(View v) {
			// 非同期処理に渡すので念のためコピー作成
			String mail = mInputMailAddress.getText().toString();
			String password = mInputPassword.getText().toString();
			
			mAsyncGetAuthorizeCookie = new AsyncGetAuthorizeCookie();
			mAsyncGetAuthorizeCookie.executeWrapper(mail, password);
			
			hideLoginView();
			showProgressView();
			if (mInputMethodManager == null) {
				Context context = getApplicationContext();
				mInputMethodManager = (InputMethodManager) context.getSystemService(
						Context.INPUT_METHOD_SERVICE);
			}
			mInputMethodManager.hideSoftInputFromWindow(
					mInputMailAddress.getWindowToken(), 0);
		}
	}

	private class WithoutLoginButtonListener implements View.OnClickListener {
		@Override
		public void onClick(View v) {
			endLogin();
		}
	}

	private class HelpButtonListener implements View.OnClickListener {
		@Override
		public void onClick(View v) {
			startActivityIfNeeded(
					new Intent(getApplicationContext(), NicoroHelp.class),
					0);
		}
	}
}
