package com.beem.project.beem.ui;

import java.util.regex.Pattern;

import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.proxy.ProxyInfo;
import org.jivesoftware.smack.util.StringUtils;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.beem.project.beem.R;

/**
 * This class represents an activity which allows the user to create an account
 * on the XMPP server saved in settings.
 * 
 * @author dasilvj
 */
public class CreateAccount extends Activity {

	private static final boolean DEFAULT_BOOLEAN_VALUE = false;
	private static final String DEFAULT_STRING_VALUE = "";
	private static final int DEFAULT_INT_VALUE = 0;
	private static final int DEFAULT_XMPP_PORT = 5222;

	private static final int NOTIFICATION_DURATION = Toast.LENGTH_SHORT;

	private SharedPreferences mSettings;
	private Button mCreateAccountButton;

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

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.create_account);
		initCreateAccountButton();
		mSettings = PreferenceManager.getDefaultSharedPreferences(this);
	}

	/**
	 * Create an account on the XMPP server specified in settings.
	 * 
	 * @param username
	 *            the username of the account.
	 * @param password
	 *            the password of the account.
	 * @return true if the account was created successfully.
	 */
	private boolean createAccount(String username, String password) {
		XMPPConnection xmppConnection = null;
		ConnectionConfiguration connectionConfiguration = null;

		if (getRegisteredProxy() != null) {
			connectionConfiguration = new ConnectionConfiguration(getXMPPServer(), DEFAULT_XMPP_PORT,
					getRegisteredProxy());
		} else {
			connectionConfiguration = new ConnectionConfiguration(getXMPPServer(), DEFAULT_XMPP_PORT);
		}
		if (getRegisteredXMPPTLSUse())
			connectionConfiguration.setSecurityMode(ConnectionConfiguration.SecurityMode.required);

		xmppConnection = new XMPPConnection(connectionConfiguration);
		try {
			xmppConnection.connect();
			AccountManager accountManager = new AccountManager(xmppConnection);
			accountManager.createAccount(username, password);
			Toast toast = Toast.makeText(getApplicationContext(), "Account " + username + " "
					+ getString(R.string.create_account_successfull_after), NOTIFICATION_DURATION);
			toast.show();
		} catch (XMPPException e) {
			Log.e(getString(R.string.create_account_tag), e.getMessage());
			createErrorDialog(e.getMessage());
			return false;
		}
		xmppConnection.disconnect();
		return true;
	}

	/**
	 * Create a dialog containing an error message.
	 * 
	 * @param errMsg
	 *            the error message
	 */
	private void createErrorDialog(String errMsg) {
		Log.v(getString(R.string.create_account_tag), errMsg);
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.create_account_err_dialog_title).setMessage(errMsg).setCancelable(false);
		builder.setNeutralButton(R.string.create_account_close_dialog_button, new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.cancel();
			}
		});
		AlertDialog settingsErrDialog = builder.create();
		settingsErrDialog.show();
	}

	/**
	 * Retrive proxy informations from the preferences.
	 * 
	 * @return Registered proxy informations
	 */
	private ProxyInfo getRegisteredProxy() {
		if (getRegisteredProxyUse()) {
			ProxyInfo proxyInfo = new ProxyInfo(getRegisteredProxyType(), getRegisteredProxyServer(),
					getRegisteredProxyPort(), getRegisteredProxyUsername(), getRegisteredProxyPassword());
			return proxyInfo;
		}
		return null;
	}

	/**
	 * Retrieve proxy password from the preferences.
	 * 
	 * @return Registered proxy password
	 */
	private String getRegisteredProxyPassword() {
		return mSettings.getString(getString(R.string.settings_key_proxy_password), DEFAULT_STRING_VALUE);
	}

	/**
	 * Retrieve proxy port from the preferences.
	 * 
	 * @return Registered proxy port
	 */
	private int getRegisteredProxyPort() {
		return Integer.parseInt(mSettings.getString(getString(R.string.settings_key_proxy_port), DEFAULT_STRING_VALUE));
	}

	/**
	 * Retrieve proxy server from the preferences.
	 * 
	 * @return Registered proxy server
	 */
	private String getRegisteredProxyServer() {
		return mSettings.getString(getString(R.string.settings_key_proxy_server), DEFAULT_STRING_VALUE);
	}

	/**
	 * Retrieve proxy type from the preferences.
	 * 
	 * @return Registered proxy type
	 */
	private ProxyInfo.ProxyType getRegisteredProxyType() {
		ProxyInfo.ProxyType result;
		switch (mSettings.getInt(getString(R.string.settings_key_proxy_type), DEFAULT_INT_VALUE)) {
		case 0:
			result = ProxyInfo.ProxyType.HTTP;
			break;
		case 1:
			result = ProxyInfo.ProxyType.SOCKS4;
			break;
		case 2:
			Log.i(getString(R.string.create_account_tag), "SOCKS5 PROXY");
			result = ProxyInfo.ProxyType.SOCKS5;
			break;
		default:
			result = ProxyInfo.ProxyType.NONE;
			break;
		}
		return result;
	}

	/**
	 * Retrieve proxy use from the preferences.
	 * 
	 * @return Registered proxy use
	 */
	private boolean getRegisteredProxyUse() {
		return mSettings.getBoolean(getString(R.string.settings_key_proxy_use), DEFAULT_BOOLEAN_VALUE);
	}

	/**
	 * Retrieve proxy username from the preferences.
	 * 
	 * @return Registered proxy username
	 */
	private String getRegisteredProxyUsername() {
		return mSettings.getString(getString(R.string.settings_key_proxy_username), DEFAULT_STRING_VALUE);
	}

	/**
	 * Retrieve xmpp server from the preferences.
	 * 
	 * @return Registered xmpp server
	 */
	private String getXMPPServer() {
		TextView xmppServerTextView = (TextView) findViewById(R.id.create_account_username);
		String xmppServer = StringUtils.parseServer(xmppServerTextView.getText().toString());
		return xmppServer;
	}

	/**
	 * Retrieve TLS use from the preferences.
	 * 
	 * @return Registered TLS use
	 */
	private boolean getRegisteredXMPPTLSUse() {
		return mSettings.getBoolean(getString(R.string.settings_key_xmpp_tls_use), DEFAULT_BOOLEAN_VALUE);
	}

	/**
	 * Check if the fields password and confirm password match.
	 * 
	 * @return return true if password & confirm password fields match, else
	 *         false
	 */
	private boolean checkPasswords() {
		final String passwordFieldValue = ((EditText) findViewById(R.id.create_account_password)).getText().toString();
		final String passwordConfirmFielddValue = ((EditText) findViewById(R.id.create_account_confirm_password))
				.getText().toString();

		return passwordFieldValue.equals(passwordConfirmFielddValue);
	}

	/**
	 * Check the format of the email.
	 * 
	 * @return true if the email is valid.
	 */
	private boolean checkEmail() {
		String email = ((TextView) findViewById(R.id.create_account_username)).getText().toString();
		return Pattern.matches("[a-zA-Z0-9._%+-]+@(?:[a-zA-Z0-9-]+.)+[a-zA-Z]{2,4}", email);
	}

	/**
	 * Initialize the "Create this account" button which allows the user to
	 * create an account.
	 */
	private void initCreateAccountButton() {
		mCreateAccountButton = (Button) findViewById(R.id.create_account_button);
		mCreateAccountButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				String usernameFieldValue = ((EditText) findViewById(R.id.create_account_username)).getText()
						.toString();
				String passwordFieldValue = ((EditText) findViewById(R.id.create_account_password)).getText()
						.toString();
				String username = StringUtils.parseName(usernameFieldValue);
				if (!checkEmail())
					createErrorDialog(getString(R.string.create_account_err_username));
				else if (!checkPasswords())
					createErrorDialog(getString(R.string.create_account_err_passwords));
				else {
					if (createAccount(username, passwordFieldValue))
						finish();
				}

			}
		});
		Button createAccountLoginButton = (Button) findViewById(R.id.create_account_login_button);
		createAccountLoginButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				String usernameFieldValue = ((EditText) findViewById(R.id.create_account_username)).getText()
						.toString();
				String username = StringUtils.parseName(usernameFieldValue);
				String passwordFieldValue = ((EditText) findViewById(R.id.create_account_password)).getText()
						.toString();
				if (!checkEmail())
					createErrorDialog(getString(R.string.create_account_err_username));
				else if (!checkPasswords())
					createErrorDialog(getString(R.string.create_account_err_passwords));
				else {
					if (createAccount(username, passwordFieldValue)) {
						SharedPreferences.Editor settingsEditor = mSettings.edit();
						settingsEditor.putString(getString(R.string.settings_key_account_username), usernameFieldValue);
						settingsEditor.putString(getString(R.string.settings_key_account_password), passwordFieldValue);
						settingsEditor.putBoolean(getString(R.string.PreferenceIsConfigured), true);
						settingsEditor.commit();
						finish();
					}
				}
			}
		});
	}
}
