/*
* This file is part of the Remote Sensor Actuator Interface (ReSAI).
*
* Copyright(c) Andreas Kipp, Frederic Siepmann
* http://opensource.cit-ec.de/projects/resai
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*
*/

/**
 * Main activity to control login and communication with ReSAI.
 *
 * @author akipp
 */

package de.unibi.airobots.resaidroid;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;

import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import de.unibi.airobots.resaidroid.communication.Communicator;
import de.unibi.airobots.resaidroid.communication.XmppConnection;
import de.unibi.airobots.resaidroid.constants.Constants.Commands;
import de.unibi.airobots.resaidroid.constants.Constants.Properties;
import de.unibi.airobots.resaidroid.constants.ReturnCodes;
import de.unibi.airobots.resaidroid.constants.ServerConfig;
import de.unibi.airobots.resaidroid.helper.EasyDialog;
import de.unibi.airobots.resaidroid.helper.TimeConverter;

public class ReSAIDroid extends Activity {

	private static final String TAG = "ReSAIDroid";
	private FileInputStream fis;
	private FileOutputStream fos;

	private EditText txtServerIp;
	private EditText txtServerHostName;
	private EditText txtServerName;
	private EditText txtServerPort;
	private EditText txtLogin;
	private EditText txtPassword;
	private TextView lblStatus;

	private Button btnConnect;

	final Handler messageHandler = new Handler();
	private Message mIn;
	private PacketListener packetListener;
	protected TabComponentMap cm;
	protected String component = "";
	
	private Communicator com = new XmppConnection();

	/**
	 * Called when the activity is first created. Initialize the layout and
	 * create listener for the buttons.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.startup);

		Resources res = getResources();
		cm = new TabComponentMap(res);	
		component = cm.getComponent(TAG);

		packetListener = new MyPacketListener();
		
		txtServerIp = (EditText) findViewById(R.id.txtServerIp);
		txtServerHostName = (EditText) findViewById(R.id.txtServerHostName);
		txtServerName = (EditText) findViewById(R.id.txtServerName);
		txtServerPort = (EditText) findViewById(R.id.txtServerPort);
		txtLogin = (EditText) findViewById(R.id.txtLogin);
		txtPassword = (EditText) findViewById(R.id.txtPassword);

		lblStatus = (TextView) findViewById(R.id.lblStatus);

		readConfig();
		
		btnConnect = (Button) findViewById(R.id.btnConnect);
		btnConnect.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				setGUIAccess(false);
				EasyDialog.startProgressDialog(ReSAIDroid.this,
						"Connecting to Server");

				writeConfig();
				readConfig();

				Log.i(TAG, "RECEIPIENT: " + ServerConfig.RECIPIENT_FULL);
				
				try {
					com.connect(txtServerIp.getText().toString(), Integer
									.parseInt(txtServerPort.getText()
											.toString()));

					Log.i(TAG, "Connected...");
					
					com.login(txtLogin.getText().toString(), // + "@" + txtServerHostName.getText().toString(),
							txtPassword.getText().toString());
					
					Log.i(TAG, "Logged in with " +  txtLogin.getText().toString());
					
					ServerConfig.RECIPIENT_FULL = txtServerName.getText() + "@" + txtServerHostName.getText();

					if (com.isConnected()
							&& com.isLoggedIn()) {
						addStatusMessage("Connected to XMPP Server.");
						EasyDialog
								.changeProgressDialogMessage("Creating PacketHandler");

						createPacketHandler();
						addStatusMessage("PacketHandler created.");

						connectToReSAI();
						addStatusMessage("Connecting to ReSAI.");
						EasyDialog
								.changeProgressDialogMessage("Connecting to ReSAI");

					} else {
						addStatusMessage("Not connected to XMPP Server.");
						EasyDialog.dismissProgressDialog();
						setGUIAccess(true);
					}

				} catch (NumberFormatException e) {
					addStatusMessage("NumberFormatException: " + e.getMessage());
					EasyDialog.dismissProgressDialog();
					setGUIAccess(true);
				}
			}
		});

	}

	@Override
	protected void onResume() {
		super.onResume();
		
		if (com.isConnectedToReSAI()) {
			com.startBeacon();
			Intent intent = new Intent(getApplicationContext(),
					TabManager.class);
			startActivityForResult(intent, 1);
		} else {
			setGUIAccess(true);
		}
		getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
	}
	
	

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		removePacketHandler();
	}

	@Override
	public void onBackPressed() {
		super.onBackPressed();

		if (com.isConnected()) {
			com.disconnect();
		}

		finish();
	}

	/**
	 * Handle return from tab activities.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {

		switch (resultCode) {
		case ReturnCodes.NOT_CONNECTED:
			addStatusMessage("Client seems to be disconnected.");
			EasyDialog.showInfoDialog(this, "Client seems to be disconnected.");
			setGUIAccess(true);
			break;
		case ReturnCodes.BACK_PRESSED:
			EasyDialog.showInfoDialog(this, "Back pressed, disconnecting.");
			addStatusMessage("Back pressed, disconnecting.");
			setGUIAccess(true);
			break;
		case Activity.RESULT_OK:
			addStatusMessage("Disconnected");
			EasyDialog.showInfoDialog(this, "Successfully disconnected.");
			setGUIAccess(true);
			break;
		case ReturnCodes.SERVER_NOT_RESPONDING:
			addStatusMessage("Disconnected");
			EasyDialog.showInfoDialog(this, "Server is not responding.");
			setGUIAccess(true);
			break;		
		default:
		}
	}

	/**
	 * Writes configuration parameters to the configuration file
	 * 
	 */
	private void writeConfig() {
		Log.i(TAG, "WRITING CONFIG...");
		try {
			fos = openFileOutput(ServerConfig.CONFIGFILE, Context.MODE_PRIVATE);
			fos.write((Properties.SERVER_IP.name() + "="
					+ txtServerIp.getText().toString() + "\n").getBytes());
			fos.write((Properties.SERVER_HOSTNAME.name() + "="
					+ txtServerHostName.getText().toString() + "\n").getBytes());
			fos.write((Properties.SERVER_NAME.name() + "="
					+ txtServerName.getText().toString() + "\n").getBytes());			
			fos.write((Properties.SERVER_PORT.name() + "="
					+ txtServerPort.getText().toString() + "\n").getBytes());
			fos.write((Properties.ACCOUNT.name() + "="
					+ txtLogin.getText().toString() + "\n").getBytes());
			fos.write((Properties.PASSWORD.name() + "="
					+ txtPassword.getText().toString() + "\n").getBytes());
			fos.close();
		} catch (IOException e) {
			addStatusMessage("IOException: " + e.getMessage());
		}
		Log.i(TAG, "WRITING CONFIG...done");
	}

	/**
	 * Reads the configuration file and fills the corresponding text boxes
	 * 
	 */
	private void readConfig() {
		Log.i(TAG, "read configuration from file...");
		try {
			fis = openFileInput(ServerConfig.CONFIGFILE);
			byte[] byteArray = new byte[102400];
			int bytesRead = 0;
			while ((bytesRead = fis.read(byteArray)) != -1) {
				String configLine = new String(byteArray, 0, bytesRead);
				String[] configLines = configLine.split("\n");
				for (String singleLine : configLines) {
					String[] config = singleLine.split("=");
					if (config.length != 0) {
						if (config[0].equals(Properties.SERVER_IP.name()))
							txtServerIp.setText(config[1]);
						if (config[0].equals(Properties.SERVER_HOSTNAME.name()))
							txtServerHostName.setText(config[1]);
						if (config[0].equals(Properties.SERVER_NAME.name()))
							txtServerName.setText(config[1]);
						if (config[0].equals(Properties.SERVER_PORT.name()))
							txtServerPort.setText(config[1]);
						if (config[0].equals(Properties.ACCOUNT.name()))
							txtLogin.setText(config[1]);
						if (config[0].equals(Properties.PASSWORD.name()))
							txtPassword.setText(config[1]);
					}
				}
				
				
				ServerConfig.RECIPIENT = txtServerName.getText().toString();
				ServerConfig.RECIPIENT_FULL = ServerConfig.RECIPIENT + "@" + ServerConfig.HOSTNAME;
				Log.i(TAG, "Created RECIPIENT_FULL: " + ServerConfig.RECIPIENT_FULL);
				return;

			}
		} catch (IOException e) {
			addStatusMessage("IOException: " + e.getMessage());
		}

		Log.i(TAG, "SETTING DEFAULT VALUES...");
		// SETTING DEFAULT VALUES
		txtServerIp.setText(ServerConfig.SERVERIP);
		txtServerHostName.setText(ServerConfig.HOSTNAME);
		txtServerName.setText(ServerConfig.RECIPIENT);
		txtServerPort.setText(String.valueOf(ServerConfig.SERVERPORT));
		txtLogin.setText(ServerConfig.CLIENTNAME);
		txtPassword.setText(ServerConfig.CLIENTPASSWORD);
		ServerConfig.RECIPIENT_FULL = ServerConfig.RECIPIENT + "@" + ServerConfig.HOSTNAME;
	}

	/**
	 * Send connect message to ReSAI server.
	 */
	private void connectToReSAI() {
		if (com.isConnected()) {
			Log.i(TAG, "SENDING SERVER REQUEST");
			HashMap<String, String> propertiesToSend = new HashMap<String, String>();
			propertiesToSend.put(Properties.CMD.name(), Commands.connect.name());
			//TODO SERIALIZABLE
			propertiesToSend.put("TAG","ReSAIServerThread");

			com.sendMessage(ServerConfig.RECIPIENT_FULL, propertiesToSend,"Calling ReSAI Server...");
			Log.i(TAG, "SENDING SERVER REQUEST ...DONE");
			messageHandler.removeCallbacks(ConnectionChecker);
			messageHandler.postDelayed(ConnectionChecker, 10000);
		} else {
			addStatusMessage("Not Connected to XMPP Server");
		}
	}

	private void removePacketHandler() {
		com.removeListener(packetListener);
	}
	
	/**
	 * Create a PacketHandler for receiving packets from ReSAI server.
	 */
	private void createPacketHandler() {

		PacketFilter filter = new PacketTypeFilter(Message.class);
		XmppConnection.addListener(packetListener, filter);
	}

	/**
	 * Add a status message with timestamp.
	 * 
	 * @param message
	 *            message to be added to lblStatus.
	 */

	private void addStatusMessage(String message) {
		if (message != null) {
			lblStatus.append("\n"
					+ TimeConverter.toTime(System.currentTimeMillis()) + ": "
					+ message);
		}
	}

	/**
	 * Runnable that checks if ReSAI server answers to connection attempt.
	 */
	private Runnable ConnectionChecker = new Runnable() {
		public void run() {
			if (!com.isConnectedToReSAI()) {
				addStatusMessage("ReSAI not answering.");
				EasyDialog.showInfoDialog(ReSAIDroid.this,
						"ReSAI seems unreachable.");
			}
			EasyDialog.dismissProgressDialog();
			setGUIAccess(true);
		}
	};

	/**
	 * Activate / Deactivate GUI elements on connecting
	 * 
	 * @param access
	 *            true if elements can be changed
	 */
	private void setGUIAccess(boolean access) {
		btnConnect.setEnabled(access);
		txtServerIp.setEnabled(access);
		txtServerPort.setEnabled(access);
		txtLogin.setEnabled(access);
		txtPassword.setEnabled(access);
		txtServerHostName.setEnabled(access);
		txtServerName.setEnabled(access);
	}
	
	/**
	 * Private class for implementing own PacketListener.
	 * Only processes messages for a given TAG.
	 * @author akipp
	 *
	 */
	private class MyPacketListener implements PacketListener {
		public void processPacket(Packet packet) {
			if (packet instanceof Message) {
				
				Log.i(TAG,"PackageListener is RECEIVING Message");
				
				mIn = (Message) packet;
				if (mIn.getProperty(Properties.CONNECTED.name()) != null) {
					if (mIn.getProperty(Properties.CONNECTED.name())
							.equals("true")) {
						
						messageHandler.post(new Runnable() {
							public void run() {
								Log.i(TAG,"#### CONNECTED");
								addStatusMessage("ReSAI connected");
								com.setConnectedToReSAI(true);
								messageHandler
										.removeCallbacks(ConnectionChecker);
								EasyDialog.dismissProgressDialog();
								Intent intent = new Intent(
										getApplicationContext(),
										TabManager.class);
								com.startBeacon();
								startActivityForResult(intent, 1);
							}
						});
					} else {
						Log.i(TAG,"### WRONG VALUE");
					}
					
					
				} else {
					Log.i(TAG,"### NOT CONNECTED");
				}
			}
		}
	}
	
}