package com.beem.project.beem.ui;

import java.util.ArrayList;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.Toast;

import com.beem.project.beem.R;
import com.beem.project.beem.service.XmppConnectionAdapter;

/**
 * This class represents an activity which allows the user to change his account or proxy parameters.
 * @author dasilvj
 */
public class EditSettings extends Activity {

    private static final String LOG_MSG_SETTINGS_SAVED = "Settings saved successfully.";
    private static final String LOG_MSG_XMPP_SETTINGS_REGISTERED = "XMPP Settings has been registered.";
    private static final String LOG_MSG_ACCOUNT_SETTINGS_REGISTERED = "Account Settings has been registered.";
    private static final String LOG_MSG_PROXY_SETTINGS_REGISTERED = "Proxy Settings has been registered.";

    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 String DEFAULT_XMPP_PORT = "5222";

    private static final int NOTIFICATION_DURATION = Toast.LENGTH_SHORT;

    private SharedPreferences mSettings;

    private EditText mAccUsernameField;
    private EditText mAccPasswordField;

    private EditText mXmppServerField;
    private EditText mXmppPortField;
    private CheckBox mXmppUseTlsCheckBox;

    private CheckBox mProxyUseCheckBox;
    private Spinner mProxyTypeSpinner;
    private EditText mProxyServerField;
    private EditText mProxyPortField;
    private EditText mProxyUsernameField;
    private EditText mProxyPasswordField;
    private BroadcastReceiver mReceiver;

    private static final Intent SERVICE_INTENT = new Intent();
    static {
	SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
    }

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

    /**
     * Add a labeled "Account" tab on the tabbed window view passed by parameter.
     * @param tHost a tabbed window view
     */
    private void addAccountTab(TabHost tHost) {
	TabHost.TabSpec accountTab = tHost.newTabSpec(getString(R.string.settings_tab_tag_account));
	accountTab.setIndicator(getString(R.string.settings_tab_label_account));
	accountTab.setContent(R.id.settings_account);
	tHost.addTab(accountTab);
    }

    /**
     * Add a labeled "Proxy" tab on the tabbed window view passed by parameter.
     * @param tHost a tabbed window view
     */
    private void addProxyTab(TabHost tHost) {
	TabHost.TabSpec proxyTab = tHost.newTabSpec(getString(R.string.settings_tab_tag_proxy));
	proxyTab.setIndicator(getString(R.string.settings_tab_label_proxy));
	proxyTab.setContent(R.id.settings_proxy);
	tHost.addTab(proxyTab);
    }

    /**
     * Add a labeled "XMPP" tab on the tabbed window view passed by parameter.
     * @param tHost a tabbed window view
     */
    private void addXMPPTab(TabHost tHost) {
	TabHost.TabSpec personalTab = tHost.newTabSpec(getString(R.string.settings_tab_tag_xmpp));
	personalTab.setIndicator(getString(R.string.settings_tab_label_xmpp));
	personalTab.setContent(R.id.settings_xmpp);
	tHost.addTab(personalTab);
    }

    /**
     * Disable proxy parameters fields.
     */
    private void disableProxyParameters() {
	mProxyTypeSpinner.setEnabled(false);
	mProxyServerField.setEnabled(false);
	mProxyPortField.setEnabled(false);
	mProxyUsernameField.setEnabled(false);
	mProxyPasswordField.setEnabled(false);
	mProxyTypeSpinner.setFocusable(false);
	mProxyServerField.setFocusable(false);
	mProxyPortField.setFocusable(false);
	mProxyUsernameField.setFocusable(false);
	mProxyPasswordField.setFocusable(false);
	mProxyTypeSpinner.setFocusableInTouchMode(false);
	mProxyServerField.setFocusableInTouchMode(false);
	mProxyPortField.setFocusableInTouchMode(false);
	mProxyUsernameField.setFocusableInTouchMode(false);
	mProxyPasswordField.setFocusableInTouchMode(false);
    }

    /**
     * Display a brief notification.
     * @param msg the message to display.
     */
    private void displayNotification(CharSequence msg) {
	Toast toast = Toast.makeText(getApplicationContext(), msg, NOTIFICATION_DURATION);
	toast.show();
    }

    /**
     * Enable proxy parameters fields.
     */
    private void enableProxyParameters() {
	mProxyTypeSpinner.setEnabled(true);
	mProxyServerField.setEnabled(true);
	mProxyPortField.setEnabled(true);
	mProxyUsernameField.setEnabled(true);
	mProxyPasswordField.setEnabled(true);
	mProxyTypeSpinner.setFocusable(true);
	mProxyServerField.setFocusable(true);
	mProxyPortField.setFocusable(true);
	mProxyUsernameField.setFocusable(true);
	mProxyPasswordField.setFocusable(true);
	mProxyTypeSpinner.setFocusableInTouchMode(true);
	mProxyServerField.setFocusableInTouchMode(true);
	mProxyPortField.setFocusableInTouchMode(true);
	mProxyUsernameField.setFocusableInTouchMode(true);
	mProxyPasswordField.setFocusableInTouchMode(true);
    }

    /**
     * Retrieve the value of a CheckBox.
     * @param viewId identifier of the checkbox
     * @return true if the CheckBox is checked, else false
     */
    private boolean getCheckBoxValue(int viewId) {
	final CheckBox checkBox = (CheckBox) findViewById(viewId);
	if (checkBox.isChecked())
	    return true;
	return false;
    }

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

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

    /**
     * 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 String getRegisteredProxyPort() {
	return 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 int getRegisteredProxyType() {
	return mSettings.getInt(getString(R.string.settings_key_proxy_type), DEFAULT_INT_VALUE);
    }

    /**
     * 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 port from the preferences.
     * @return Registered xmpp port
     */
    private String getRegisteredXMPPPort() {
	return mSettings.getString(getString(R.string.settings_key_xmpp_port), DEFAULT_XMPP_PORT);
    }

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

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

    /**
     * Initialize Account tab fields.
     */
    private void initAccountFields() {
	mAccUsernameField = (EditText) findViewById(R.id.settings_account_username);
	mAccPasswordField = (EditText) findViewById(R.id.settings_account_password);
    }

    /**
     * Initialize all of the components displayed in tabs (EditText fields, CheckBoxes, Spinners...).
     */
    private void initFields() {
	initAccountFields();
	initXMPPFields();
	initProxyFields();
    }

    /**
     * Initialize Proxy tab fields.
     */
    private void initProxyFields() {
	mProxyUseCheckBox = (CheckBox) findViewById(R.id.settings_proxy_use);
	mProxyTypeSpinner = (Spinner) findViewById(R.id.settings_proxy_type);
	mProxyServerField = (EditText) findViewById(R.id.settings_proxy_server);
	mProxyPortField = (EditText) findViewById(R.id.settings_proxy_port);
	mProxyUsernameField = (EditText) findViewById(R.id.settings_proxy_username);
	mProxyPasswordField = (EditText) findViewById(R.id.settings_proxy_password);
    }

    /**
     * Initialize proxy's types spinner of the proxy tab.
     */
    private void initProxyTypesSpinner() {
	ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.proxy_types,
	    android.R.layout.simple_spinner_item);
	adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
	mProxyTypeSpinner.setAdapter(adapter);
    }

    /**
     * Initialize the checkbox allowing user to use a proxy.
     */
    private void initProxyUseCheckBox() {
	mProxyUseCheckBox.setOnClickListener(new OnClickListener() {

	    public void onClick(View v) {
		if (mProxyUseCheckBox.isChecked()) {
		    enableProxyParameters();
		} else {
		    disableProxyParameters();
		}
	    }
	});
    }

    /**
     * Initialize "save" buttons allowing user to save settings.
     */
    private void initSaveButtons() {
	final ArrayList<Integer> views = new ArrayList<Integer>();
	Button saveButton = null;

	views.add(R.id.settings_account_button_save);
	views.add(R.id.settings_proxy_button_save);
	views.add(R.id.settings_xmpp_button_save);

	for (int i = 0; i < views.size(); i++) {
	    saveButton = (Button) findViewById(views.get(i));
	    saveButton.setFocusable(true);
	    saveButton.setOnClickListener(new View.OnClickListener() {

		public void onClick(View v) {
		    saveSettings();
		    setResult(69);
		}
	    });
	}
    }

    /**
     * Initialize tabbed window view by adding tabs and setting the default tab.
     */
    private void initTabbedWindow() {
	TabHost tHost = (TabHost) this.findViewById(R.id.settings_tab_host);
	tHost.setup();
	addAccountTab(tHost);
	addXMPPTab(tHost);
	addProxyTab(tHost);
	tHost.setCurrentTab(0);
    }

    /**
     * Initialize XMPP tab fields.
     */
    private void initXMPPFields() {
	mXmppServerField = (EditText) findViewById(R.id.settings_xmpp_server);
	mXmppPortField = (EditText) findViewById(R.id.settings_xmpp_port);
	mXmppUseTlsCheckBox = (CheckBox) findViewById(R.id.settings_xmpp_use_tls);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.edit_settings);
	initTabbedWindow();
	initFields();
	mSettings = getSharedPreferences(getString(R.string.settings_filename), MODE_PRIVATE);
	mReceiver = new BeemBroadcastReceiver();
    }

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

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
	Intent i = null;
	switch (item.getItemId()) {
	    case R.id.settings_menu_create_account:
		i = new Intent(this, CreateAccount.class);
		startActivity(i);
		return true;
	    case R.id.settings_menu_login:
		setResult(69);
		this.stopService(SERVICE_INTENT);
		finish();
		return true;
	    default:
		return false;
	}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onResume() {
	super.onResume();
	this.registerReceiver(mReceiver, new IntentFilter(XmppConnectionAdapter.BEEM_CONNECTION_CLOSED));
	refreshAccountTabFields();
	refreshXMPPTabFields();
	refreshProxyTabFields();

	if (!mProxyUseCheckBox.isChecked())
	    disableProxyParameters();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected void onPause() {
	super.onPause();
	this.unregisterReceiver(mReceiver);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onStart() {
	super.onStart();
	initProxyTypesSpinner();
	initProxyUseCheckBox();
	initSaveButtons();
    }

    /**
     * Refresh values of "Account" tab fields.
     */
    private void refreshAccountTabFields() {
	mAccUsernameField.setText(getRegisteredAccountUsername());
	mAccPasswordField.setText(getRegisteredAccountPassword());
    }

    /**
     * Refresh values of "Account" tab fields.
     */
    private void refreshProxyTabFields() {
	mProxyUseCheckBox.setChecked(getRegisteredProxyUse());
	mProxyTypeSpinner.setSelection(getRegisteredProxyType());
	mProxyServerField.setText(getRegisteredProxyServer());
	mProxyPortField.setText(getRegisteredProxyPort());
	mProxyUsernameField.setText(getRegisteredProxyUsername());
	mProxyPasswordField.setText(getRegisteredProxyPassword());
    }

    /**
     * Refresh values of "Account" tab fields.
     */
    private void refreshXMPPTabFields() {
	mXmppServerField.setText(getRegisteredXMPPServer());
	mXmppPortField.setText(getRegisteredXMPPPort());
	mXmppUseTlsCheckBox.setChecked(getRegisteredXMPPTLSUse());
    }

    /**
     * Register account settings changes in SharedPreferences.Editor object passed by parameter.
     * @param settingsEditor the editor to use.
     */
    private void registerAccountSettingsChanges(SharedPreferences.Editor settingsEditor) {
	final String usernameFieldValue = mAccUsernameField.getText().toString();
	final String passwordFieldValue = mAccPasswordField.getText().toString();

	if (!getRegisteredAccountUsername().equals(usernameFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_account_username), usernameFieldValue);
	if (!getRegisteredAccountPassword().equals(passwordFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_account_password), passwordFieldValue);
	Log.i(getString(R.string.edit_settings_tag), LOG_MSG_ACCOUNT_SETTINGS_REGISTERED);
    }

    /**
     * Register proxy settings changes in SharedPreferences.Editor object passed by parameter.
     * @param settingsEditor the editor to use.
     */
    private void registerProxySettingsChanges(SharedPreferences.Editor settingsEditor) {
	final int proxyTypeFieldValue = mProxyTypeSpinner.getSelectedItemPosition();
	final String serverFieldValue = mProxyServerField.getText().toString();
	final String portFieldValue = mProxyPortField.getText().toString();
	final String usernameFieldValue = mProxyUsernameField.getText().toString();
	final String passwordFieldValue = mProxyPasswordField.getText().toString();

	if (getRegisteredProxyType() != proxyTypeFieldValue)
	    settingsEditor.putInt(getString(R.string.settings_key_proxy_type), proxyTypeFieldValue);
	if (!getRegisteredProxyServer().equals(serverFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_proxy_server), serverFieldValue);
	if (!getRegisteredProxyPort().equals(portFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_proxy_port), portFieldValue);
	if (!getRegisteredProxyUsername().equals(usernameFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_proxy_username), usernameFieldValue);
	if (!getRegisteredProxyPassword().equals(passwordFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_proxy_password), passwordFieldValue);
	Log.i(getString(R.string.edit_settings_tag), LOG_MSG_PROXY_SETTINGS_REGISTERED);
    }

    /**
     * Register XMPP settings changes in SharedPreferences.Editor object passed by parameter.
     * @param settingsEditor the editor to use.
     */
    private void registerXMPPSettingsChanges(SharedPreferences.Editor settingsEditor) {
	final boolean tlsUseCheckBoxValue = getCheckBoxValue(R.id.settings_xmpp_use_tls);
	final String serverFieldValue = mXmppServerField.getText().toString();
	final String portFieldValue = mXmppPortField.getText().toString();

	if (getRegisteredXMPPTLSUse() != tlsUseCheckBoxValue)
	    settingsEditor.putBoolean(getString(R.string.settings_key_xmpp_tls_use), tlsUseCheckBoxValue);
	if (!getRegisteredXMPPServer().equals(serverFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_xmpp_server), serverFieldValue);
	if (!getRegisteredXMPPPort().equals(portFieldValue))
	    settingsEditor.putString(getString(R.string.settings_key_xmpp_port), portFieldValue);
	Log.i(getString(R.string.edit_settings_tag), LOG_MSG_XMPP_SETTINGS_REGISTERED);
    }

    /**
     * Save settings in shared preferences.
     */
    private void saveSettings() {
	final SharedPreferences.Editor settingsEditor = mSettings.edit();
	final boolean proxyUseCheckBoxValue = getCheckBoxValue(R.id.settings_proxy_use);

	if (getRegisteredProxyUse() != proxyUseCheckBoxValue)
	    settingsEditor.putBoolean(getString(R.string.settings_key_proxy_use), proxyUseCheckBoxValue);
	if (proxyUseCheckBoxValue)
	    registerProxySettingsChanges(settingsEditor);
	registerAccountSettingsChanges(settingsEditor);
	registerXMPPSettingsChanges(settingsEditor);
	String password = mAccPasswordField.getText().toString();
	String username = mAccUsernameField.getText().toString();
	String port = mXmppPortField.getText().toString();
	if ("".equals(password) || "".equals(username)
	    || "".equals(port))
	    settingsEditor.putBoolean(getString(R.string.PreferenceIsConfigured), false);
	else
	    settingsEditor.putBoolean(getString(R.string.PreferenceIsConfigured), true);

	if (settingsEditor.commit()) {
	    displayNotification(getText(R.string.settings_saved_ok));
	    Log.i(getString(R.string.edit_settings_tag), LOG_MSG_SETTINGS_SAVED);
	}
    }

    private class BeemBroadcastReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
	    EditSettings.this.setResult(69);
	}
    }
}
