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.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 = getSharedPreferences(getString(R.string.settings_filename), MODE_PRIVATE);
    }

    /**
     * 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();
		    }
		}
	    }
	});
    }
}
