package com.beem.project.beem.ui;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import com.beem.project.beem.R;
import com.beem.project.beem.service.aidl.IBeemConnectionListener;
import com.beem.project.beem.service.aidl.IXmppConnection;
import com.beem.project.beem.service.aidl.IXmppFacade;
import com.beem.project.beem.utils.Status;

/**
 * This class represents an activity which allows the user to connect to an XMPP
 * server with his username/password.
 * 
 * @author dasilvj
 */
public class Login extends Activity {

	private static final String TAG = "LOG_AS";
	private static final int REQUEST_CODE = 1;
	private static final Intent SERVICE_INTENT = new Intent();
	static {
		SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
	}

	private final Handler mConnectionHandler = new Handler();
	private ConnectionRunnable mConnectionRunnable = new ConnectionRunnable();
	private ProgressDialog mProgressDialog;

	private boolean mIsConnectedService;
	private final ServiceConnection mServConn = new BeemServiceConnection();
	private IXmppFacade mXmppFacade;

	private SharedPreferences mSettings;
	private boolean mIsConfigured;
	private int mRetry;
	private IXmppConnection mXmppConnection;

	/**
	 * Constructor.
	 */
	public Login() {
	}

	/**
	 * Create an about "BEEM" dialog.
	 */
	public void createAboutDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.login_about_title).setMessage(R.string.login_about_msg).setCancelable(false);
		builder.setNeutralButton(R.string.login_about_button, new DialogInterface.OnClickListener() {

			public void onClick(DialogInterface dialog, int whichButton) {
				dialog.cancel();
			}
		});
		AlertDialog aboutDialog = builder.create();
		aboutDialog.show();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.d(TAG, "onCreate");
		mSettings = PreferenceManager.getDefaultSharedPreferences(this);
		setContentView(R.layout.login);
		mProgressDialog = new ProgressDialog(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onStop() {
		super.onStop();
		Log.d(TAG, "onStop " + mIsConnectedService);
		if (mIsConfigured && (mIsConnectedService || mXmppFacade != null)) {
			boolean isConnected = false;
			if (mXmppConnection != null) {
				try {
					isConnected = mXmppConnection.isAuthentificated();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
			unbindService(mServConn);
			if (!isConnected) {
				stopService(SERVICE_INTENT);
			}
			mXmppFacade = null;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onPause() {
		super.onPause();
		Log.d(TAG, "onPause");
		mConnectionHandler.removeCallbacks(mConnectionRunnable);
		mProgressDialog.dismiss();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onResume() {
		super.onResume();
		Log.d(TAG, "onResume");
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onStart() {
		super.onStart();
		Log.d(TAG, "onStart " + mIsConnectedService);
		mIsConfigured = mSettings.getBoolean("PreferenceIsConfigured", false);
		if (mIsConfigured && !mIsConnectedService) {
			try {
				Thread.sleep(1000); // HACK: Pour éviter de rebinder un service
									// pas encore arreter.
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			bindService(Login.SERVICE_INTENT, mServConn, BIND_AUTO_CREATE);
			mIsConnectedService = true;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == REQUEST_CODE) {
			if (resultCode == RESULT_OK) {
				stopService(SERVICE_INTENT);
			}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.login, menu);
		return true;
	}

	/**
	 * Callback for menu item selected.
	 * 
	 * @param item
	 *            the item selected
	 * @return true on success, false otherwise
	 */
	@Override
	public final boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.login_menu_settings:
			startActivity(new Intent(Login.this, Settings.class));
			return true;
		case R.id.login_menu_about:
			createAboutDialog();
			return true;
		default:
			return false;
		}
	}

	/**
	 * Connection runnable.
	 * 
	 * @author nikita
	 */
	private class ConnectionRunnable implements Runnable {

		/**
		 * Constructor.
		 */
		public ConnectionRunnable() {
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run() {
			if (mRetry++ > 3) {
				Toast.makeText(Login.this, R.string.login_max_retry, Toast.LENGTH_LONG).show();
				mConnectionHandler.removeCallbacks(mConnectionRunnable);
			} else {
				mIsConfigured = mSettings.getBoolean("PreferenceIsConfigured", false);
				if (mIsConfigured) {
					bindService(Login.SERVICE_INTENT, mServConn, BIND_AUTO_CREATE);
				}
			}

		}
	}

	/**
	 * Listener use to check the state of the connection with the server.
	 */
	private class BeemConnectionListener extends IBeemConnectionListener.Stub {

		/**
		 * Constructor.
		 */
		public BeemConnectionListener() {
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void connectionClosed() throws RemoteException {
			if (mXmppFacade != null) {
				launchReconnectionHandler();
				mXmppFacade = null;
			}
		}

		@Override
		public void connectionClosedOnError() throws RemoteException {
			if (mXmppFacade != null) {
				launchReconnectionHandler();
				mXmppFacade = null;
			}
		}

		@Override
		public void connectionFailed(String errorMsg) throws RemoteException {
			Log.d(TAG, "CONNECTIONFAILLED");
			if (mXmppFacade != null) {
				Login.this.unbindService(mServConn);
				Login.this.stopService(SERVICE_INTENT);
				mIsConnectedService = false;
				mXmppFacade = null;
			}
			dismissProgressDialog();
			showToast(errorMsg);
			launchReconnectionHandler();
		}

		/**
		 * launch reconnection handler.
		 */
		private void launchReconnectionHandler() {
			mConnectionHandler.postAtTime(mConnectionRunnable, Integer.parseInt(mSettings.getString(
					"settings_key_reco_delay", "10"))
					* 1000 + SystemClock.uptimeMillis());
		}

		/**
		 * Show an error message with a toast.
		 * 
		 * @param errorMsg
		 *            The message to display.
		 */
		private void showToast(final String errorMsg) {
			mConnectionHandler.post(new Runnable() {
				/**
				 * @{inheritDoc
				 */
				@Override
				public void run() {
					Toast.makeText(Login.this, errorMsg, Toast.LENGTH_LONG).show();
					TextView labelError = (TextView) findViewById(R.id.log_as_msg);
					labelError.setText(getString(R.string.login_error_msg, errorMsg));
				}
			});
		}

		/**
		 * Dismiss the progress dialog.
		 */
		private void dismissProgressDialog() {
			mConnectionHandler.post(new Runnable() {

				/**
				 * @{inheritDoc
				 */
				@Override
				public void run() {
					mProgressDialog.dismiss();
				}
			});
		}

		@Override
		public void onConnect() throws RemoteException {
			dismissProgressDialog();
			Log.i(TAG, "Connected.");
			mXmppFacade.changeStatus(Status.CONTACT_STATUS_AVAILABLE, null);
			mRetry = 0;
			startActivity(new Intent(Login.this, ContactList.class));
			finish();
		}

		@Override
		public void reconnectingIn(int seconds) throws RemoteException {
		}

		@Override
		public void reconnectionFailed() throws RemoteException {
		}

		@Override
		public void reconnectionSuccessful() throws RemoteException {
		}
	}

	/**
	 * ServiceConnection use to connect to the Beem Service.
	 */
	private class BeemServiceConnection implements ServiceConnection {
		/**
		 * Constructor.
		 */
		public BeemServiceConnection() {
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.d(TAG, "service connected");
			mXmppFacade = IXmppFacade.Stub.asInterface(service);
			mIsConnectedService = true;
			try {
				mXmppConnection = mXmppFacade.createConnection();
				mXmppConnection.addConnectionListener(new BeemConnectionListener());
				if (!mXmppConnection.isAuthentificated()) {
					mConnectionHandler.post(new Runnable() {
						@Override
						public void run() {
							mProgressDialog.setMessage(getString(R.string.login_login_progress));
							mProgressDialog.show();
						}
					});
					Login.this.startService(Login.SERVICE_INTENT);
				} else {
					startActivity(new Intent(Login.this, ContactList.class));
					finish();
				}
			} catch (RemoteException e) {
				Log.e(TAG, "REMOTE EXCEPTION $" + e.getMessage());
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			Log.d(TAG, "service disconnected");
			mIsConnectedService = false;
			mXmppFacade = null;
		}
	}
}
