package com.team5.aLife.BaseStation;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;

import org.json.JSONArray;

import android.app.AlertDialog;
import android.app.Service;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import com.google.gson.Gson;
import com.ibm.mqtt.MqttException;
import com.team5.aLife.BaseStation.DBHandler.DB_Devices;
import com.team5.aLife.BaseStation.DBHandler.DB_Notifications_Setup;
import com.team5.aLife.BaseStation.DBHandler.DB_Users;
import com.team5.aLife.BaseStation.SerialCommunication.SerialPort;

public class BackgroundServices extends Service{
	
	private final static int MESSAGE_BUFFER_SIZE = 12;
	
	//  Used for serial communication
	protected Application mApplication;
	protected SerialPort mSerialPort;
	protected static OutputStream mOutputStream;
	protected static InputStream mInputStream;
	//private ReadThread mReadThread;
	
	static byte[] messageBuffer = new byte[MESSAGE_BUFFER_SIZE];
	private int messageBufferIterator = 0;
	
	//  For testing of message received
	
	private int lastReceived = 99;
	private int justReceived = 99;
	
	private boolean readThreadHasBeenRun = false;
	protected static boolean garageDoorNotificationAlreadySetup = false;
	protected static boolean powerSwitchNotificationAlreadySetup = false;
	protected static boolean userIgnoredGarageNotification = false;
	protected static boolean userIgnoredPowerNotification = false;
	protected static boolean garageDoorStateChangedToOn = false;
	protected static boolean powerSwitchStateChangedToOn = false;

	static boolean bufferReadyToRead = false;
	
	private ArrayList<ALifeNotificationSetup> notificationList = null;		// holds our device list
	
	//  For sending notifications
	private MQTTConnection mc;

	private final String TAG = "BackgroundSerivces:  ";
	
	// default ip to listen to
    public static String SERVERIP = "10.0.2.15";

    // designate a port
    public static final int SERVERPORT = 8640;
    
    public static final int TWENTY_FOUR_HOURS_IN_SECONDS = 86400;
    public static final int ONE_HOUR_IN_SECONDS = 3600;
    public static final int SECONDS_TO_ADD_TO_CONVERT_TO_GMT_TIME = 7 * ONE_HOUR_IN_SECONDS;

    private final String delimiter = "[&]+";
    
    private Handler handler = new Handler();
    
    private String line;
    
    private boolean serviceIsRunning;

    private ServerSocket serverSocket;
    
    private PrintWriter out;
    
    private BufferedReader in;
    
    private DBHandler db = new DBHandler(this);
    
    Gson gson = new Gson();
    
    Timer testingTimer;
    Timer clearPowerHistorTimer;
	Timer clearNotiifcationHistoryTimer;
	Timer pollZigbeeDevicesTimer;
	Timer garageDoorTimer;
	Timer powerSwitchTimer;
    
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
    public void onCreate() {
        super.onCreate();
        
        notificationList = new ArrayList<ALifeNotificationSetup>();
        
        clearPowerHistorTimer = new Timer();
		clearNotiifcationHistoryTimer = new Timer();
		pollZigbeeDevicesTimer = new Timer();
		
        clearPowerHistorTimer.schedule(new ClearPowerHistorTask(), 0, TWENTY_FOUR_HOURS_IN_SECONDS * 1000);
        clearNotiifcationHistoryTimer.schedule(new ClearNotificationHistorTask(), 0, TWENTY_FOUR_HOURS_IN_SECONDS * 1000);
        pollZigbeeDevicesTimer.schedule(new PollZigbeeDevicesTask(), 0, TWENTY_FOUR_HOURS_IN_SECONDS * 1000);
		
		serviceIsRunning = true;
        SERVERIP = getLocalIpAddress();
        Log.d("BackgroundServices: onStart","Service created ..." + SERVERIP);
        Runnable serverThread = new ServerThread();
        new Thread(serverThread).start();
        
    }
	
//	class testingTask extends TimerTask {
//	    public void run() {
//	    //  TODO "Implement method to clear power history"
//	    	//  To be implemented
//	    	
//	    	try {
////				mOutputStream.write((char)'A');
////				mOutputStream.flush();
////				mOutputStream.write((char)'T');
////				mOutputStream.flush();
////				mOutputStream.write((char)'I');
////				mOutputStream.flush();
////				mOutputStream.write((char)'S');
////				mOutputStream.flush();
////				mOutputStream.write((char)'\r');
////				mOutputStream.flush();
//				//mOutputStream.write((char)'\n');
//				mOutputStream.write(new String("ATIS"+'\r').getBytes());
//				Log.i("Sending:  ", "Ouput buffer: " + new String("ATIS + '\r'"));
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//	    }
//	  }

    public void onStart(Intent intent, int startId){
        super.onStart(intent, startId);
        
        Log.i(TAG+"onStart", "onStart is being called");
         
        cancelAllNotificationListeners();
        initiateNotificationListener();
        
        String value = "";
    	
    	Bundle extras = intent.getExtras();
    	if(extras != null)
    	{
    		value = extras.getString("STOPSERIAL");
    	}
        
    	if(value.equals("stop"))
    	{
    		//  Kill thread in charge of serial communication
//            if (mReadThread != null)
//    			mReadThread.interrupt();
    		mApplication.closeSerialPort();
    		mSerialPort = null;
    	}
    	else if (PreferenceHandler.isSerialCommunicationEnabled() && !readThreadHasBeenRun)
        {
    		readThreadHasBeenRun = true;
    		Log.i(TAG+"onStart", "I am starting mReadThread");
	        mApplication = (Application) getApplication();
			try {
				mSerialPort = mApplication.getSerialPort();
				mOutputStream = mSerialPort.getOutputStream();
				mInputStream = mSerialPort.getInputStream();
	
				/* Create a receiving thread */
//				mReadThread = new ReadThread();
//				mReadThread.start();
			} catch (SecurityException e) {
				DisplayError(R.string.error_security);
			} catch (IOException e) {
				DisplayError(R.string.error_unknown);
			} catch (InvalidParameterException e) {
				DisplayError(R.string.error_configuration);
			}
			
//			try {
//				//mOutputStream.write(new String("About to start sending you stuff").getBytes());
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
			
			//  TODO "Need to delete this later, just for testing purposes"
	        //testingTimer = new Timer();
			Log.i("Sending:  ", "Ouput buffer: " + new String("+++"));
	        //testingTimer.schedule(new testingTask(), 1400, 1400);
        }
    }

    private void cancelAllNotificationListeners() {
    	
    	Log.i(TAG+"cancelAllNotificationListeners", "cancelAllNotificationListeners is being called");
    	
    	garageDoorNotificationAlreadySetup = false;
    	powerSwitchNotificationAlreadySetup = false;
    	
    	if (garageDoorTimer != null)
    		garageDoorTimer.cancel();
    	if (powerSwitchTimer != null)
    		powerSwitchTimer.cancel();
	}

	private void initiateNotificationListener() {

		Log.i(TAG+"initiateNotificationListener", "initiateNotificationListener is being called");
		
    	// reset the device list to empty
		notificationList.clear();
        
        // Holds all the devices
    	
        ALifeNotificationSetup tempNotification;
    	
    	db.open();
    	
    	Cursor c = db.getAllNotifications();
    	
    	/* Get the indices of the Columns we will need */
        int IDCol = c.getColumnIndex(DB_Notifications_Setup._ID);
        int deviceIDCol = c.getColumnIndex(DB_Notifications_Setup.DEVICE_ID);
        int userIDCol = c.getColumnIndex(DB_Notifications_Setup.USER_ID);
        int notificationTypeCol = c.getColumnIndex(DB_Notifications_Setup.NOTIFICATION_TYPE);
        int triggerConditionCol = c.getColumnIndex(DB_Notifications_Setup.TRIGGERING_CONDITION);
        
        if (c != null)
	    	if (c.moveToFirst())
	    	{	
	    		do {
	    		//  Retrieve the values of the Entry the Cursor is pointing to. 
	            int ID = c.getInt(IDCol);
	            int deviceID = c.getInt(deviceIDCol);
	            int userID = c.getInt(userIDCol);
	            int notificationType = c.getInt(notificationTypeCol);
	            String triggeringCondition = c.getString(triggerConditionCol);
	            
	            tempNotification = new ALifeNotificationSetup(ID, deviceID, userID, notificationType, 
	            										  triggeringCondition);
	            
	            notificationList.add(tempNotification);
	            
	    		}while (c.moveToNext());
	    		
	            c.close();
	    		
	    	}
        
    	db.close(); 
    	
    	
    	for (int i = 0; i < notificationList.size(); i++)
    	{
    		ALifeNotificationSetup selectedNotification = notificationList.get(i);
    		
    		String tokens[] = selectedNotification.getTriggeringCondition().split(delimiter);
    		
    		//  Gives you the current time in milliseconds since January 1, 1970 00:00:00 UTC.
    		//  We then modulus it by 24 hours to only get the amount of milliseconds have passed
    		//  relative to a "standard" day.  Does not take into consideration daylight savings
    		//  days.
    		long currentTime = (System.currentTimeMillis()/1000) % TWENTY_FOUR_HOURS_IN_SECONDS;
    		
    		Log.i(TAG+"initiateNotificationListener", "CurrentTime = " + currentTime);
    		
    		long startTime = (Integer.parseInt(tokens[0]) * ONE_HOUR_IN_SECONDS + SECONDS_TO_ADD_TO_CONVERT_TO_GMT_TIME) % TWENTY_FOUR_HOURS_IN_SECONDS;
    		long endTime = (Integer.parseInt(tokens[1]) * ONE_HOUR_IN_SECONDS + SECONDS_TO_ADD_TO_CONVERT_TO_GMT_TIME) % TWENTY_FOUR_HOURS_IN_SECONDS;
    		
    		Log.i(TAG+"initiateNotificationListener", "startTime = " + startTime);
    		Log.i(TAG+"initiateNotificationListener", "endTime = " + endTime);
    		Log.i(TAG+"initiateNotificationListener", "Power Notification setup = " + powerSwitchNotificationAlreadySetup);
    		Log.i(TAG+"initiateNotificationListener", "Garage Notification setup = " + garageDoorNotificationAlreadySetup);
    		
    		if (endTime < startTime)
    		{
    			Log.i(TAG+"initiateNotificationListener", "EndTime is less than StartTime");
    			
    			if ( (currentTime >= startTime && currentTime <= TWENTY_FOUR_HOURS_IN_SECONDS) ||
    				 (currentTime >= 0 && currentTime <endTime) )
        		{
    				Log.i(TAG+"initiateNotificationListener", "Condition meet to setup notification");
    				
    				int timeInterval = (int)((TWENTY_FOUR_HOURS_IN_SECONDS - startTime) + endTime);
    				
        			int deviceType = getDeviceType(selectedNotification.getDeviceID());
        	    	
            		if (deviceType == Device.DEVICE_TYPE_POWER_MONITOR_SWITCH && !powerSwitchNotificationAlreadySetup &&
            			!userIgnoredPowerNotification)
                	{
            			powerSwitchNotificationAlreadySetup = true;
            			powerSwitchTimer = new Timer();
            			powerSwitchTimer.schedule(new PowerSwitchNotificationStartTask(selectedNotification), 0, 10000);
            			powerSwitchTimer.schedule(new PowerSwitchNotificationEndTask(selectedNotification), timeInterval * 10000);
                	}
                	else if(deviceType == Device.DEVICE_TYPE_SWITCH && !garageDoorNotificationAlreadySetup &&
                			!userIgnoredGarageNotification)
                	{
                		garageDoorNotificationAlreadySetup = true;
                		garageDoorTimer = new Timer();
            			garageDoorTimer.schedule(new GarageDoorNotificationStartTask(selectedNotification), 0, 10000);
            			garageDoorTimer.schedule(new GarageDoorNotificationEndTask(selectedNotification), timeInterval * 10000);
                	}
                	else if(deviceType == Device.DEVICE_TYPE_WIRELESS_SENSOR && !garageDoorNotificationAlreadySetup &&
                			!userIgnoredGarageNotification)
                	{	
                		garageDoorNotificationAlreadySetup = true;
                		garageDoorTimer = new Timer();
            			garageDoorTimer.schedule(new GarageDoorNotificationStartTask(selectedNotification), 0, 10000);
            			garageDoorTimer.schedule(new GarageDoorNotificationEndTask(selectedNotification), timeInterval * 10000);
                	}
        		}
    		}
    		else if (currentTime >= startTime && currentTime <= endTime)
    		{
    			Log.i(TAG+"initiateNotificationListener", "Not bridging from one day to another");
    			Log.i(TAG+"initiateNotificationListener", "Condition meet to setup notification");
    			int deviceType = getDeviceType(selectedNotification.getDeviceID());
    	    	
        		if (deviceType == Device.DEVICE_TYPE_POWER_MONITOR_SWITCH && !powerSwitchNotificationAlreadySetup &&
            		!userIgnoredPowerNotification)
            	{
        			powerSwitchNotificationAlreadySetup = true;
        			powerSwitchTimer = new Timer();
        			powerSwitchTimer.schedule(new PowerSwitchNotificationStartTask(selectedNotification), 0, 1000);
        			powerSwitchTimer.schedule(new PowerSwitchNotificationEndTask(selectedNotification), (endTime - currentTime) * 1000);
            	}
            	else if(deviceType == Device.DEVICE_TYPE_SWITCH && !garageDoorNotificationAlreadySetup &&
            			!userIgnoredGarageNotification)
            	{
            		garageDoorNotificationAlreadySetup = true;
            		garageDoorTimer = new Timer();
        			garageDoorTimer.schedule(new GarageDoorNotificationStartTask(selectedNotification), 0, 1000);
        			garageDoorTimer.schedule(new GarageDoorNotificationEndTask(selectedNotification), (endTime - currentTime) * 1000);
            	}
            	else if(deviceType == Device.DEVICE_TYPE_WIRELESS_SENSOR && !garageDoorNotificationAlreadySetup &&
            			!userIgnoredGarageNotification)
            	{	
            		garageDoorNotificationAlreadySetup = true;
            		garageDoorTimer = new Timer();
        			garageDoorTimer.schedule(new GarageDoorNotificationStartTask(selectedNotification), 0, 1000);
        			garageDoorTimer.schedule(new GarageDoorNotificationEndTask(selectedNotification), (endTime - currentTime) * 1000);
            	}
    		}
    		 		
    	}
    	
	}
    
    private int getDeviceType(int deviceID) {
		
		int deviceType = 0;
		
		db.open();
		
		Cursor c = db.getDevice(deviceID);
		
		/* Get the indices of the Columns we will need */
        int deviceTypeCol = c.getColumnIndex(DB_Devices.DEVICE_TYPE);
        
        // Check if our result was valid. 
        if (c != null) {
        	
                // Check if at least one Result was returned. 
                if (c.moveToFirst()) 
                {	
                	
                    //  Retrieve the values of the Entry the Cursor is pointing to. 
                    deviceType = c.getInt(deviceTypeCol);
                    
                }
        }
		
		c.close();
		db.close();
		
		return deviceType;
	}

	@Override
    public void onDestroy() {
        super.onDestroy();
        
        serviceIsRunning = false;
        try {
            // make sure you close the socket upon exiting
        	if (serverSocket != null)
        		serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        serverSocket = null;
        
        
        //  Kill thread in charge of serial communication
        if (readThreadHasBeenRun )
        {
        	Log.i(TAG+"onStart", "I am destroying mReadThread");
//	        if (mReadThread != null)
//				mReadThread.interrupt();
	        mApplication.closeSerialPort();
			mSerialPort = null;
        }
        
        //  Kill all timers
        if (testingTimer != null)
        	testingTimer.cancel();
        if (clearPowerHistorTimer != null)
        	clearPowerHistorTimer.cancel();
    	if (clearNotiifcationHistoryTimer != null)
    		clearNotiifcationHistoryTimer.cancel();
    	if (pollZigbeeDevicesTimer != null)
    		pollZigbeeDevicesTimer.cancel();
    	if (garageDoorTimer != null)
    		garageDoorTimer.cancel();
    	if (powerSwitchTimer != null)
    		powerSwitchTimer.cancel();
    }
    
    class ClearPowerHistorTask extends TimerTask {
	    public void run() {
	    //  TODO "Implement method to clear power history"
	    	//  To be implemented
	    	
	    	
	    }
	  }
	
	class ClearNotificationHistorTask extends TimerTask {
	    public void run() {
	    	//  TODO "Implement method to clear notifications"
	    	//  To be implemented
	    	
	    }
	  }
	
	class PollZigbeeDevicesTask extends TimerTask {
	    public void run() {
	    	//  TODO "Implement method to poll zigbee devices"
	    	//  To be implemented
	    	
	    }
	  }
	
	class PowerSwitchNotificationStartTask extends TimerTask {
	    
		private ALifeNotificationSetup selectedNotification;
		
		public PowerSwitchNotificationStartTask(ALifeNotificationSetup selectedNotification)
		{
			this.selectedNotification = selectedNotification;
		}
		
		public void run() {
	    	//  TODO "Implement method to poll zigbee devices"
	    	//  To be implemented
	    	
			if (powerSwitchStateChangedToOn)
			{
				powerSwitchStateChangedToOn = false;
				sendNotification(getUserName(selectedNotification.getUserID()), 2 +"&" +"The power device is on");
		    	Log.i(TAG+"PowerSwitchNotificationStartTask", "I am checking Power Device");
			}
	    }
	  }
	
	class PowerSwitchNotificationEndTask extends TimerTask {
		
		private ALifeNotificationSetup selectedNotification;
		
		public PowerSwitchNotificationEndTask(ALifeNotificationSetup selectedNotification)
		{
			this.selectedNotification = selectedNotification;
		}
		
	    public void run() {
	    	
	    	powerSwitchNotificationAlreadySetup = false;
	    	powerSwitchTimer.cancel();
	    	
	    }
	  }
	
	class GarageDoorNotificationStartTask extends TimerTask {
	    
		private ALifeNotificationSetup selectedNotification;
		
		public GarageDoorNotificationStartTask(ALifeNotificationSetup selectedNotification)
		{
			this.selectedNotification = selectedNotification;
		}	
		
		public void run() {
	    	//  TODO "Implement method to poll zigbee devices"
	    	//  To be implemented
	    	
			if (garageDoorStateChangedToOn)
			{
				garageDoorStateChangedToOn = false;
				sendNotification(getUserName(selectedNotification.getUserID()), 1 +"&" +"The Garage Door is Open");
	    		Log.i(TAG+"GarageDoorNotificationStartTask", "I am checking Garage Door Device");
			}
	    }

		
	  }
	
	private String getUserName(int targetUserID) {
		// TODO Auto-generated method stub
		
		String tempUserName ="";
		
		db.open();
    	
    	Cursor c = db.getAllUsers();
    	
    	/* Get the indices of the Columns we will need */
        int userIDCol = c.getColumnIndex(DB_Users._ID);
        int userNameCol = c.getColumnIndex(DB_Users.USER_NAME);
        int passwordCol = c.getColumnIndex(DB_Users.PASSWORD);
        int permissionCol = c.getColumnIndex(DB_Users.PERMISSION);
        int failedLoginCol = c.getColumnIndex(DB_Users.FAILED_LOGIN_NUM);
        int timeoutCol = c.getColumnIndex(DB_Users.TIMEOUT);
        int timeoutTimeCol = c.getColumnIndex(DB_Users.TIMEOUT_TIME);
        
        // Check if our result was valid. 
        if (c != null) {
        	
                // Check if at least one Result was returned. 
                if (c.moveToFirst()) 
                {	
                	do {
                		//  Retrieve the values of the Entry the Cursor is pointing to. 
                        int userID = c.getInt(userIDCol);
                        String userName = c.getString(userNameCol);
                        
                        if(userID == targetUserID )
                        	tempUserName = userName;
                        
                	} while (c.moveToNext());
                	
                }
        }
    	
    	db.close(); 
		
		return tempUserName;
	}
	
	class GarageDoorNotificationEndTask extends TimerTask {
	    
		private ALifeNotificationSetup selectedNotification;
		
		public GarageDoorNotificationEndTask(ALifeNotificationSetup selectedNotification)
		{
			this.selectedNotification = selectedNotification;
		}
		
		public void run() {
	    	
	    	garageDoorNotificationAlreadySetup = false;
	    	garageDoorTimer.cancel();
	    	
	    }
	  }
	
	public void sendNotification(String userName, String message)
	{
		
		Log.i("Notification; ", "Sending to " + userName);
		try {
			mc = new  MQTTConnection("rsmb.sidewalktech.com", "aLifeClient");
			mc.publishToTopic("aLifeClient"+ "/" + userName, message);  //mc.publishToTopic("aLifeClient/" + UserName, "From Java");
			mc.disconnect();
			mc = null;
		} catch (MqttException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
    
//    private class ReadThread extends Thread {
//
//		@Override
//		public void run() {
//			super.run();
//			while(!isInterrupted()) {
//				int size;
//				try {
//					byte[] buffer = new byte[64];
//					if (mInputStream == null) return;
//					size = mInputStream.read(buffer);
//					if (size > 0) {
//						onDataReceived(buffer, size);
//					}
//				} catch (IOException e) {
//					e.printStackTrace();
//					return;
//				}
//			}
//		}
//	}
    
//    synchronized protected void onDataReceived(final byte[] buffer, final int size) {
//		
//    	Log.i(TAG+"onDataReceived", "On Data Received was called");
//    	
//    	if(new String(buffer, 0, buffer.length).equals("OK"))
//    	{
//    		Log.i(TAG+"onDataReceived", "Just got the OK!!");
//    	}
//    	else
//    	{
//	    	//  Because we are dealing with serial ports we can have several calls to this method
//	    	//  before one message is received.  For that reason we must keep track of an message
//	    	//  iterator to make sure we have filled our buffer before taking action.
//	    	for (int i = messageBufferIterator; i < messageBufferIterator + buffer.length; i += buffer.length)
//	    	{
//	    		System.arraycopy( buffer, i, messageBuffer, i, buffer.length);
//	    	}
//	    	
//	    	messageBufferIterator += buffer.length;
//	    	
//	    	//  Our buffer is full
//	    	if (messageBufferIterator >= MESSAGE_BUFFER_SIZE)
//	    	{
//	    		//  Reset the value of the iterator
//	    		messageBufferIterator = 0;
//	    		
//	    		lastReceived = justReceived;
//	    		justReceived = new Integer(messageBuffer.toString());
//	    		
//	    		if (justReceived == 01003000002 && lastReceived != 01003000002)
//	    		{
//	    			Log.i(TAG+"onDataReceived", "About to send out a notification");
//	    			sendNotification("Tim", "Rippin and Tearin");
//	    		}
//	    		
//	    		Log.i(TAG+"onDataReceived", "The message is complete:  " + new String(messageBuffer, 0, messageBuffer.length));
//	    		    	
//	    	}
//    	}
//    	
//    	
//	}
    
    private void DisplayError(int resourceId) {
		AlertDialog.Builder b = new AlertDialog.Builder(this);
		b.setTitle("Error");
		b.setMessage(resourceId);
		b.setPositiveButton("OK", new OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				//SerialPortActivity.this.finish();
			}
		});
		b.show();
	}
    
    public class ServerThread implements Runnable {

        public void run() {
            while(serviceIsRunning){ 	
	        	try {
	                if (SERVERIP != null) 
	                {
	                    InetAddress localAddr = InetAddress.getByName(SERVERIP);
	                    serverSocket = new ServerSocket(SERVERPORT, 5, localAddr);
	                    while (true) 
	                    {
	                        // listen for incoming clients
	                    	Log.i("BackgroundServices: run()","S:  Listening for incoming clients");
	                        Socket client = serverSocket.accept();
	                        Log.i("BackgroundServices: run()","S:  Accepted a clients message");
	                        Log.i("BackgroundServices: run()", "REMOTE IP: " + client.getRemoteSocketAddress().toString());
	                        
	                        in = new BufferedReader(new InputStreamReader(client.getInputStream()));
	                        out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
	                        
	                        line = in.readLine();
	                        
	                        processIncomingRequest(line);
	                    
	                    	out.close();
	                        in.close();
	                        
	                     } 
	                    } else {
	                        
	                        
	                    	//  Status:  Couldn't detect internet connection
	                            
	                    }
	                } catch (Exception e) {
	                //  Error
	                Log.e(TAG+"run()", "Had an exception, closing server socket and attempting to reconnect");
	                try {
	                	if (serverSocket != null)
	                		serverSocket.close();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					serverSocket = null;
	                e.printStackTrace();
	            }
            }
        }
        
        void processIncomingRequest(String request){
        	
        	String[] tokens = line.split(delimiter);
            
            int messageType = Integer.parseInt(tokens[0]);
            String jsonString = null;
            
            if (tokens.length > 1)
            	jsonString = tokens[1];
            
            switch (messageType) 
            {
	        	case AbstractRequest.LOGIN_REQUEST:  
	        		processLoginRequest(jsonString); 
	        		break;
		        case AbstractRequest.GET_ALL_DEVICES_REQUEST:  //Toast.makeText(this,"You Sent Message 2", Toast.LENGTH_LONG).show(); 
		        	processGetAllDevicesRequest();
		        	break;
		        case AbstractRequest.ADD_DEVICE_REQUEST:  
		        	processAddDeviceRequest(jsonString);
		        	break;
		        case AbstractRequest.GET_ALL_USERS_REQUEST:  
		        	processGetAllUsersRequest();
		        	break;
		        case AbstractRequest.DELETE_USER_REQUEST:
		        	processDeleteUserRequest(jsonString);
		        	break;
		        case AbstractRequest.ADD_USER_REQUEST:
		        	processAddUserRequest(jsonString);
		        	break;
		        case AbstractRequest.GET_USER_REQUEST:
		        	processGetUserRequest(jsonString);
		        	break;
		        case AbstractRequest.UPDATE_USER_REQUEST:  
		        	processUpdateUserRequest(jsonString);
		        	break;
		        case AbstractRequest.UPDATE_DEVICE_REQUEST:
		        	processUpdateDeviceRequest(jsonString);
		        	break;
		        case AbstractRequest.DELETE_DEVICE_REQUEST:
		        	processDeleteDeviceRequest(jsonString);
		        	break;
		        case AbstractRequest.BACKGROUND_SERVICE_ON_START_REQUEST:
		        	processBackgroundServicesOnStartRequest();
		        	break;
		        case AbstractRequest.GET_ALL_NOTIFICATIONS_REQUEST: 
		        	processGetAllNotificationsRequest();
		        	break;
		        case AbstractRequest.DELETE_NOTIFICATION_REQUEST:
		        	processDeleteNotificationRequest(jsonString);
		        	break;
		        case AbstractRequest.GET_DEVICE_REQUEST: 
		        	processGetDeviceRequest(jsonString);
		        	break;
		        case AbstractRequest.GET_DEVICE_STATE: 
		        	processGetDeviceStateRequest(jsonString);
		        	break;
		        case AbstractRequest.UPDATE_DEVICE_STATE:
		        	processUpdateDeviceState(jsonString);
		        	break;
		        case AbstractRequest.GET_USERS_NOTIFICATION_REQUEST:
		        	processGetUsersNotificationRequest(jsonString);
		        	break;
		        case AbstractRequest.UPDATE_NOTIFICATION_REQUEST:
		        	processUpdateNotificationRequest(jsonString);
		        	break;
		        case AbstractRequest.INSERT_NOTIFICATION_REQUEST:
		        	processInsertNotificationRequest(jsonString);
		        	break;
		        default: //System.out.println("Invalid month.");
		        	break;
	    	}
        	
        }

		private void processInsertNotificationRequest(String jsonString) {
			
			InsertNotificationRequest insertNotificationRequest = (InsertNotificationRequest) gson.fromJson(jsonString, InsertNotificationRequest.class);
			
			db.open();
    		
    		long result = db.insertNotification(insertNotificationRequest.getNotification());
    		
    		db.close();
    		
    		if (result > 0)
        	{
        		TransactionReply insertNotificationReply = new TransactionReply(true);
            	
            	out.write(insertNotificationReply.encodeToReplyString());
        	}
        	{
        		TransactionReply insertNotificationReply = new TransactionReply(false);
            	
            	out.write(insertNotificationReply.encodeToReplyString());
        	}
    		
    		
			
		}

		private void processUpdateNotificationRequest(String jsonString) {
			
			UpdateNotificationRequest updateNotificationRequest = (UpdateNotificationRequest)gson.fromJson(jsonString, UpdateNotificationRequest.class);
			
			db.open();
    		
    		boolean result = db.updateNotification(updateNotificationRequest.getNotification());
    		
    		db.close();
    		
    		TransactionReply addDeviceReply = new TransactionReply(result);
	     	
	     	out.write(addDeviceReply.encodeToReplyString());
			
		}

		private void processGetUsersNotificationRequest(String jsonString) {
			
			GetUsersNotificationRequest getUsersNotificationRequest = (GetUsersNotificationRequest) gson.fromJson(jsonString, GetUsersNotificationRequest.class);
			
			db.open();
	    	
	    	Cursor c = db.getNotification(getUsersNotificationRequest.getDevice().getDeviceID(),
	    								  getUsersNotificationRequest.getUser().getUserID());
	    	
	    	ALifeNotificationSetup notification = new ALifeNotificationSetup();
	    	boolean result = false;
	    	
	    	/* Get the indices of the Columns we will need */
	        int IDCol = c.getColumnIndex(DB_Notifications_Setup._ID);
	        int deviceIDCol = c.getColumnIndex(DB_Notifications_Setup.DEVICE_ID);
	        int userIDCol = c.getColumnIndex(DB_Notifications_Setup.USER_ID);
	        int notificationTypeCol = c.getColumnIndex(DB_Notifications_Setup.NOTIFICATION_TYPE);
	        int triggerConditionCol = c.getColumnIndex(DB_Notifications_Setup.TRIGGERING_CONDITION);
	        
	        if (c != null)
		    	if (c.moveToFirst())
		    	{
		    		result = true;
		    		
		    		//  Retrieve the values of the Entry the Cursor is pointing to. 
		            int ID = c.getInt(IDCol);
		            int deviceID = c.getInt(deviceIDCol);
		            int userID = c.getInt(userIDCol);
		            int notificationType = c.getInt(notificationTypeCol);
		            String triggeringCondition = c.getString(triggerConditionCol);
		            
		            notification = new ALifeNotificationSetup(ID, deviceID, userID, notificationType, 
		            										  triggeringCondition);
		            
		            c.close();
		    		
		    	}
		    	else
		    	{
		    		result = false;
		    	}
	    	
	    	
	    	db.close();

	    	GetUserNotificiationReply getUsersNotificationReply = new GetUserNotificiationReply(result, notification);
	    	
	    	out.write(getUsersNotificationReply.encodeToReplyString());
	    	
		}

		private void processUpdateDeviceState(String jsonString) {
			
			UpdateDeviceStateRequest updateDeviceStateRequest = (UpdateDeviceStateRequest) gson.fromJson(jsonString, UpdateDeviceStateRequest.class);
			
			boolean wasTransactionSuccessful;
			
			switch (updateDeviceStateRequest.getAction()){
			
			case ACTIVATE:
				wasTransactionSuccessful = SerialCommunicatonHandler.activateDevice(updateDeviceStateRequest.getDevice());
				TransactionReply activateReply = new TransactionReply(wasTransactionSuccessful);
		     	out.write(activateReply.encodeToReplyString());
				break;
			case DEACTIVATE:
				wasTransactionSuccessful = SerialCommunicatonHandler.deactivateDevice(updateDeviceStateRequest.getDevice());
				TransactionReply deactivateReply = new TransactionReply(wasTransactionSuccessful);
		     	out.write(deactivateReply.encodeToReplyString());
				break;
			case UPDATE_PARAMS:
				wasTransactionSuccessful = SerialCommunicatonHandler.setThermostat((Thermostat)updateDeviceStateRequest.getDevice());
				TransactionReply setThermostatReply = new TransactionReply(wasTransactionSuccessful);
		     	out.write(setThermostatReply.encodeToReplyString());
				break;
			default:
				break;
			
			}
			
		}

		private void processGetDeviceStateRequest(String jsonString) {
			
			GetDeviceStateRequest getDeviceStateRequest = (GetDeviceStateRequest) gson.fromJson(jsonString, GetDeviceStateRequest.class);
			
			GetDeviceReply getDeviceReply;
			
			if (getDeviceStateRequest.getDevice().getDeviceType() == Device.DEVICE_TYPE_THERMOSTAT)
			{
				Thermostat returnedDevice = (Thermostat)SerialCommunicatonHandler.getDeviceState(getDeviceStateRequest.getDevice());
				getDeviceReply = new GetDeviceReply(returnedDevice);
			}
			else if (getDeviceStateRequest.getDevice().getDeviceType() == Device.DEVICE_TYPE_POWER_MONITOR_SWITCH)
			{
				PowerSwitchDevice returnedDevice = (PowerSwitchDevice)SerialCommunicatonHandler.getDeviceState(getDeviceStateRequest.getDevice());
				getDeviceReply = new GetDeviceReply(returnedDevice);
			}
			else
			{
				Device returnedDevice = SerialCommunicatonHandler.getDeviceState(getDeviceStateRequest.getDevice());
				getDeviceReply = new GetDeviceReply(returnedDevice);
			}
        	
			Log.i(TAG+"processGetDeviceStateRequest", "Attempting to send Device State Reply:  " + getDeviceReply.encodeToReplyString());
        	out.write(getDeviceReply.encodeToReplyString());
			
		}

		private void processGetDeviceRequest(String jsonString) {
			
			GetDeviceRequest getDeviceRequest = (GetDeviceRequest) gson.fromJson(jsonString, GetDeviceRequest.class);
			
			Device device = null;
			
			db.open();
        	
        	Cursor c = db.getDevice(getDeviceRequest.getDeviceID());
        	
        	/* Get the indices of the Columns we will need */
            int IDCol = c.getColumnIndex(DB_Devices._ID);
            int deviceTypeCol = c.getColumnIndex(DB_Devices.DEVICE_TYPE);
            int nameCol = c.getColumnIndex(DB_Devices.NAME);
            int addressCol = c.getColumnIndex(DB_Devices.ADDRESS);
            int zigbeeStatusCol = c.getColumnIndex(DB_Devices.ZIGBEE_STATUS);
            int statusCol = c.getColumnIndex(DB_Devices.STATUS);
            int updatedTimeCol = c.getColumnIndex(DB_Devices.UPDATED_TIME);
            
            // Check if our result was valid. 
            if (c != null) {
            	
                    // Check if at least one Result was returned. 
                    if (c.moveToFirst()) 
                    {	
                    	
                        //  Retrieve the values of the Entry the Cursor is pointing to. 
                        int ID = c.getInt(IDCol);
                        int deviceType = c.getInt(deviceTypeCol);
                        String name = c.getString(nameCol);
                        String address = c.getString(addressCol);
                        int zigbeeStatus = c.getInt(zigbeeStatusCol);
                        int status = c.getInt(statusCol);
                        int updatedTime = c.getInt(updatedTimeCol);
                        
                        device = new Device(ID, deviceType, name, address,
                        							   zigbeeStatus, status);
                        
                        device.setUpdatedTime(updatedTime);
	                        
                    	GetDeviceReply getDeviceReply = new GetDeviceReply(device);
                    	
                    	out.write(getDeviceReply.encodeToReplyString());
                    	//Log.i(TAG+"processGetAllDevicesRequest", getAllDevicesReply.encodeToReplyString());
                    	
                    }
            }
        	
        	db.close();
			
		}

		private void processDeleteNotificationRequest(String jsonString) {
			
			DeleteNotificationRequest deleteNotificationRequest = (DeleteNotificationRequest) gson.fromJson(jsonString, DeleteNotificationRequest.class);
			
			db.open();
          	 
	       	boolean result = db.deleteNotification(deleteNotificationRequest.getNotification().getID());
	          
	       	db.close();
			
	       	onStart(new Intent(), 0);
	   	    
	   	    TransactionReply addDeviceReply = new TransactionReply(result);
	     	
	     	out.write(addDeviceReply.encodeToReplyString());
	       	
		}

		private void processGetAllNotificationsRequest() {
			
			// Holds all the devices
    		JSONArray notifications = new JSONArray();;
        	ALifeNotificationSetup tempNotification = new ALifeNotificationSetup();
        	
        	db.open();
        	
        	Cursor c = db.getAllNotificationsForUser(LoginActivity.activeUser.getUserID());
        	
        	/* Get the indices of the Columns we will need */
            int IDCol = c.getColumnIndex(DB_Notifications_Setup._ID);
            int deviceIDCol = c.getColumnIndex(DB_Notifications_Setup.DEVICE_ID);
            int userIDCol = c.getColumnIndex(DB_Notifications_Setup.USER_ID);
            int notificationTypeCol = c.getColumnIndex(DB_Notifications_Setup.NOTIFICATION_TYPE);
            int triggerConditionCol = c.getColumnIndex(DB_Notifications_Setup.TRIGGERING_CONDITION);
            
            if (c != null)
            {
    	    	if (c.moveToFirst())
    	    	{	
    	    		do {
    	    		//  Retrieve the values of the Entry the Cursor is pointing to. 
    	            int ID = c.getInt(IDCol);
    	            int deviceID = c.getInt(deviceIDCol);
    	            int userID = c.getInt(userIDCol);
    	            int notificationType = c.getInt(notificationTypeCol);
    	            String triggeringCondition = c.getString(triggerConditionCol);
    	            
    	            tempNotification = new ALifeNotificationSetup(ID, deviceID, userID, notificationType, 
    	            										  triggeringCondition);
    	            
    	            notifications.put(tempNotification);
    	            
    	    		}while (c.moveToNext());
    	    		
    	            c.close();
    	            
    	            GetAllNotificationsReply getAllNotificaitonsReply = new GetAllNotificationsReply(notifications);
                	
                	out.write(getAllNotificaitonsReply.encodeToReplyString());
    	    		
    	    	}
    	    	else
                {
                	//  Cursor was empty, no rows in database
    	    		GetAllNotificationsReply getAllNotificationsReply = new GetAllNotificationsReply(null);
                	
                	out.write(getAllNotificationsReply.encodeToReplyString());
                }
        }
        else
        {	
        	//  Cursor is equal to null
        	GetAllNotificationsReply getAllNotificationsReply = new GetAllNotificationsReply(null);
        	
        	out.write(getAllNotificationsReply.encodeToReplyString());
        	
        }
            
        	db.close();
        	
        	
			
		}

		private void processBackgroundServicesOnStartRequest() {
			
			startService(new Intent(BackgroundServices.this, BackgroundServices.class));
			
		}

		private void processDeleteDeviceRequest(String jsonString) {
			
			DeleteDeviceRequest deleteDeviceRequest = (DeleteDeviceRequest) gson.fromJson(jsonString, DeleteDeviceRequest.class);
			
			SerialCommunicatonHandler.removeDeviceFromNetwork(Integer.parseInt(deleteDeviceRequest.getDevice().getDeviceAddress()));
			
			db.open();
   	        
     	   	db.deleteNotificationByDeviceID(deleteDeviceRequest.getDevice().getDeviceID());
	   	    boolean result = db.deleteDevice(deleteDeviceRequest.getDevice().getDeviceID());
	   	        
	   	    db.close();
	   	    
	   	    onStart(new Intent(), 0);
	   	    
	   	    TransactionReply addDeviceReply = new TransactionReply(result);
	     	
	     	out.write(addDeviceReply.encodeToReplyString());				
		}

		private void processUpdateDeviceRequest(String jsonString) {
			
			UpdateDeviceRequest updateDeviceRequest = (UpdateDeviceRequest) gson.fromJson(jsonString, UpdateDeviceRequest.class);
			
			db.open();
   	        
   	        boolean result = db.updateDevice(updateDeviceRequest.getDevice());
   	        
   	        db.close();
   	        
	   	    TransactionReply addDeviceReply = new TransactionReply(result);
	     	
	     	out.write(addDeviceReply.encodeToReplyString());
			
		}

		private void processUpdateUserRequest(String jsonString) {
			
			UpdateUserRequest updateUserRequest = (UpdateUserRequest) gson.fromJson(jsonString, UpdateUserRequest.class);
			
			User user = updateUserRequest.getUser();
			
			db.open();
        	
        	boolean result = db.updateUser(user.getUserID(),
        				  user.getUserName(), 
        				  user.getPassword(), 
        				  user.getPermission(), 
        				  user.getFailedLogin(), 
        				  user.getTimeout(), 
        				  user.getTimeoutTime());
        	
        	db.close();
        	
			TransactionReply addDeviceReply = new TransactionReply(result);
        	
        	out.write(addDeviceReply.encodeToReplyString());
		
        	
			
		}

		private void processGetUserRequest(String jsonString) {
			
			GetUserRequest getUserRequest = (GetUserRequest) gson.fromJson(jsonString, GetUserRequest.class);
			
			User user = null;
				
			db.open();
	    	
	    	Cursor c = db.getUser(getUserRequest.getUserName());
	    	
	    	/* Get the indices of the Columns we will need */
	        int userIDCol = c.getColumnIndex(DB_Users._ID);
	        int userNameCol = c.getColumnIndex(DB_Users.USER_NAME);
	        int passwordCol = c.getColumnIndex(DB_Users.PASSWORD);
	        int permissionCol = c.getColumnIndex(DB_Users.PERMISSION);
	        int failedLoginCol = c.getColumnIndex(DB_Users.FAILED_LOGIN_NUM);
	        int timeoutCol = c.getColumnIndex(DB_Users.TIMEOUT);
	        int timeoutTimeCol = c.getColumnIndex(DB_Users.TIMEOUT_TIME);
	       
	        // Check if our result was valid. 
	        if (c != null) {
	        	
	                // Check if at least one Result was returned. 
	                if (c.moveToFirst()) {
	                	
	                    //  Retrieve the values of the Entry the Cursor is pointing to. 
	                    int userID = c.getInt(userIDCol);
	                    String userName = c.getString(userNameCol);
	                    String password = c.getString(passwordCol);
	                    String permission = c.getString(permissionCol);
	                    int failedLogin = c.getInt(failedLoginCol);
	                    int timeout = c.getInt(timeoutCol);
	                    int timeoutTime = c.getInt(timeoutTimeCol);
	                    
	                	user = new User(userID, userName, password, 
	                						  permission, failedLogin, timeout, timeoutTime);
	                    	
	                    	  
	                }
	        }
	    	
	        db.close();
			
	        LoginReply loginReply = new LoginReply(true, user);
	        
	        out.write(loginReply.encodeToReplyString());
			
		}

		private void processAddUserRequest(String jsonString) {
			
			AddUserRequest addUserRequest = (AddUserRequest) gson.fromJson(jsonString, AddUserRequest.class);
			
			if (isUserNameUnavailable(addUserRequest.getUser().getUserName()))
        	{
				AddUserReply addUserReply = new AddUserReply(false, "User name already in use");
				
				out.write(addUserReply.encodeToReplyString());
				
        	}
        	else
        	{
	        		
        		db.open();
        		
 
    			long result = db.insertUser(addUserRequest.getUser().getUserName(), 
    						  addUserRequest.getUser().getPassword(), 
    						  addUserRequest.getUser().getPermission(), 0, 0, 0);      		
        		
        		db.close();
        		
        		if (result > 0)
        		{
        			AddUserReply addUserReply = new AddUserReply(true, "Transaction Successful");
    				
    				out.write(addUserReply.encodeToReplyString());	
        		}
        		else
        		{
        			AddUserReply addUserReply = new AddUserReply(false, "");
    				
    				out.write(addUserReply.encodeToReplyString());	
        		}
	        	
        	}
			
		}
		
		private boolean isUserNameUnavailable(String userName)
	    {
	    	boolean result;
	    	
	    	db.open();
	    	
	    	Cursor c = db.getUser(userName);
	    	
	    	if (c.moveToFirst())
	    		result = true;
	    	else
	    		result = false;
	    	
	    	c.close();
	    	db.close();
	    	
	    	Log.i(TAG+"IsUserNameUnavailable", "Is the user name unavailable?  " + result);
	    	return result;
	    		
	    }

		private void processDeleteUserRequest(String jsonString) {
			
			DeleteUserRequest deleteUserRequest = gson.fromJson(jsonString, DeleteUserRequest.class);
			
			db.open();
			
			if(db.deleteUser(deleteUserRequest.getUser().getUserName()))
			{
				db.close();
				TransactionReply addDeviceReply = new TransactionReply(true);
            	
            	out.write(addDeviceReply.encodeToReplyString());
			}
			else
			{
				db.close();
				TransactionReply addDeviceReply = new TransactionReply(false);
            	
            	out.write(addDeviceReply.encodeToReplyString());
			}
				
			
		}

		private void processGetAllUsersRequest() {
			
			// Holds all the devices
    		JSONArray users = new JSONArray();;
        	User tempUser;
        	
        	db.open();
        	
        	Cursor c = db.getAllUsers();
        	
        	/* Get the indices of the Columns we will need */
            int userIDCol = c.getColumnIndex(DB_Users._ID);
            int userNameCol = c.getColumnIndex(DB_Users.USER_NAME);
            int passwordCol = c.getColumnIndex(DB_Users.PASSWORD);
            int permissionCol = c.getColumnIndex(DB_Users.PERMISSION);
            int failedLoginCol = c.getColumnIndex(DB_Users.FAILED_LOGIN_NUM);
            int timeoutCol = c.getColumnIndex(DB_Users.TIMEOUT);
            int timeoutTimeCol = c.getColumnIndex(DB_Users.TIMEOUT_TIME);
            
            // Check if our result was valid. 
            if (c != null) {
            	
                    // Check if at least one Result was returned. 
                    if (c.moveToFirst()) 
                    {	
                    	do {
                    		//  Retrieve the values of the Entry the Cursor is pointing to. 
                            int userID = c.getInt(userIDCol);
                            String userName = c.getString(userNameCol);
                            String password = c.getString(passwordCol);
                            String permission = c.getString(permissionCol);
                            int failedLogin = c.getInt(failedLoginCol);
                            int timeout = c.getInt(timeoutCol);
                            int timeoutTime = c.getInt(timeoutTimeCol);
                            
                            tempUser = new User(userID, userName, password, permission,
                            							   failedLogin, timeout, timeoutTime);
                          
                            users.put(tempUser);
                            
                    	} while (c.moveToNext());
                    	
                    	GetAllUsersReply getAllUsersReply = new GetAllUsersReply(users);
                    	
                    	out.write(getAllUsersReply.encodeToReplyString());
                    	
                    }
            }
        	
        	db.close();
			
		}

		void processLoginRequest(String request)
        {
        	Log.i(TAG + "processLoginRequest", request);
        	
        	LoginRequest loginRequest = gson.fromJson(request, LoginRequest.class);
        	
        	db.open();
        	
        	Cursor c = db.getUser(loginRequest.getUserName());
        	
        	/* Get the indices of the Columns we will need */
            int userIDCol = c.getColumnIndex(DB_Users._ID);
            int userNameCol = c.getColumnIndex(DB_Users.USER_NAME);
            int passwordCol = c.getColumnIndex(DB_Users.PASSWORD);
            int permissionCol = c.getColumnIndex(DB_Users.PERMISSION);
            int failedLoginCol = c.getColumnIndex(DB_Users.FAILED_LOGIN_NUM);
            int timeoutCol = c.getColumnIndex(DB_Users.TIMEOUT);
            int timeoutTimeCol = c.getColumnIndex(DB_Users.TIMEOUT_TIME);
           
            // Check if our result was valid. 
            if (c != null) {
            	
                    // Check if at least one Result was returned. 
                    if (c.moveToFirst()) {
                    	
                        //  Retrieve the values of the Entry the Cursor is pointing to. 
                        int userID = c.getInt(userIDCol);
                        String userName = c.getString(userNameCol);
                        String password = c.getString(passwordCol);
                        String permission = c.getString(permissionCol);
                        int failedLogin = c.getInt(failedLoginCol);
                        int timeout = c.getInt(timeoutCol);
                        int timeoutTime = c.getInt(timeoutTimeCol);
                        
                        if (loginRequest.getPassword().equals(password))
                        {

                        	User activeUser = new User(userID, userName, password, 
                        						  permission, failedLogin, timeout, timeoutTime);
                        	
                        	db.close();
                        	
                        	LoginReply loginReply = new LoginReply(true, activeUser);
                        	
                        	String replyString = loginReply.encodeToReplyString();
                        	
                        	Log.i(TAG + "processLoginRequest", replyString);
                    		
                        	//loginReply.getReplyType() + delimiter + gson.toJson(loginReply);
                        	
                        	out.write(replyString);
                        	
                        }
                        else
                        {
	                        //  Alert the user the Password field is incorrect                        	
                        	LoginReply loginReply = new LoginReply(false, null);
                        	
                        	String replyString = loginReply.encodeToReplyString();
                        	
                        	out.write(replyString);
                        	
                        	db.close();
	                    	
	                    	db.close();
                        }   
                    }
                    else
                    {
                    	//  Alert the user the User Name field is incorrect
                    	LoginReply loginReply = new LoginReply(false, null);
                    	
                    	String replyString = loginReply.encodeToReplyString();
                    	
                    	out.write(replyString);
                    	
                    	db.close();
 	
                    	db.close();
                    }
            }
            else
            {	
            	//  Alert the user the User Name field is incorrect
            	
            	LoginReply loginReply = new LoginReply(false, null);
            	
            	String replyString = loginReply.encodeToReplyString();
            	
            	out.write(replyString);
            	
            	db.close();
            }
        }
        
        void processGetAllDevicesRequest()
        {
        	// Holds all the devices
    		JSONArray devices = new JSONArray();;
        	Device tempDevice;
        	
        	db.open();
        	
        	Cursor c = db.getAllDevices();
        	
        	/* Get the indices of the Columns we will need */
            int IDCol = c.getColumnIndex(DB_Devices._ID);
            int deviceTypeCol = c.getColumnIndex(DB_Devices.DEVICE_TYPE);
            int nameCol = c.getColumnIndex(DB_Devices.NAME);
            int addressCol = c.getColumnIndex(DB_Devices.ADDRESS);
            int zigbeeStatusCol = c.getColumnIndex(DB_Devices.ZIGBEE_STATUS);
            int statusCol = c.getColumnIndex(DB_Devices.STATUS);
            int updatedTimeCol = c.getColumnIndex(DB_Devices.UPDATED_TIME);
            
            // Check if our result was valid. 
            if (c != null) {
            	
                    // Check if at least one Result was returned. 
                    if (c.moveToFirst()) 
                    {	
                    	do {
	                        //  Retrieve the values of the Entry the Cursor is pointing to. 
	                        int ID = c.getInt(IDCol);
	                        int deviceType = c.getInt(deviceTypeCol);
	                        String name = c.getString(nameCol);
	                        String address = c.getString(addressCol);
	                        int zigbeeStatus = c.getInt(zigbeeStatusCol);
	                        int status = c.getInt(statusCol);
	                        int updatedTime = c.getInt(updatedTimeCol);
	                        
	                        tempDevice = new Device(ID, deviceType, name, address,
	                        							   zigbeeStatus, status);
	                        
	                        tempDevice.setUpdatedTime(updatedTime);
	                        
	                        devices.put(tempDevice);
	                        
                    	} while (c.moveToNext());
                    	
                    	GetAllDevicesReply getAllDevicesReply = new GetAllDevicesReply(devices);
                    	
                    	out.write(getAllDevicesReply.encodeToReplyString());
                    	//Log.i(TAG+"processGetAllDevicesRequest", getAllDevicesReply.encodeToReplyString());
                    	
                    }
                    else
                    {
                    	//  Cursor was empty, no rows in database
                    	GetAllDevicesReply getAllDevicesReply = new GetAllDevicesReply(null);
                    	
                    	out.write(getAllDevicesReply.encodeToReplyString());
                    }
            }
            else
            {	
            	//  Cursor is equal to null
            	GetAllDevicesReply getAllDevicesReply = new GetAllDevicesReply(null);
            	
            	out.write(getAllDevicesReply.encodeToReplyString());
            	
            }
        	
        	
        	db.close();
        	
        }
        
        private void processAddDeviceRequest(String request) {
			
        	AddDeviceRequest addDeviceRequest = gson.fromJson(request, AddDeviceRequest.class);
        	
        	int zigbeeAddress = SerialCommunicatonHandler.pollForNewDevice();
        	
        	if (zigbeeAddress > 0)
        	{
	        	Device newDevice = addDeviceRequest.getDevice();
	        	
	        	newDevice.setDeviceAddress("" +zigbeeAddress);
	        	
	        	db.open();
	        	
	        	long result = db.insertDevice(newDevice);
	        	
	        	db.close();
				
	        	if (result > 0)
	        	{
	        		TransactionReply addDeviceReply = new TransactionReply(true);
	            	
	            	out.write(addDeviceReply.encodeToReplyString());
	        	}
	        	{
	        		TransactionReply addDeviceReply = new TransactionReply(false);
	            	
	            	out.write(addDeviceReply.encodeToReplyString());
	        	}
        	}
        	
		}
        
        
        
    }

    // gets the ip address of your phone's network
    private String getLocalIpAddress() {
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); }
                }
            }
        } catch (SocketException ex) {
            Log.e("ServerActivity", ex.toString());
        }
        return null;
    }
    

}