/*
    BEEM is a videoconference application on the Android Platform.

    Copyright (C) 2009 by Frederic-Charles Barthelery,
                          Jean-Manuel Da Silva,
                          Nikita Kozlov,
                          Philippe Lago,
                          Jean Baptiste Vergely,
                          Vincent Veronis.

    This file is part of BEEM.

    BEEM is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    BEEM is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.

    Please send bug reports with examples or suggestions to
    contact@beem-project.com or http://dev.beem-project.com/

 */

package com.beem.project.beem;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.beem.project.beem.ui.Notification.BeemNotification;
import com.beem.project.beem.utils.Status;

/**
 * Class for managing intent receive.
 * @author marseille
 */
public class BeemServiceHandler extends Handler {

    private static final String TAG = BeemServiceHandler.class.getName();

    private enum IMESSAGE {
	CONNECT, DISCONNECT, IS_CONNECTED, SEND_MSG, SYNC, ADD_CONTACT, CHANGE_STATUS, MUC_JOIN, MUC_SEND_MSG, ADD_MUC
    };

    private Map<String, BeemConnection> mBeemConnection = new HashMap<String, BeemConnection>();

    private final Context mContext;

    public BeemServiceHandler(Looper looper, Context context) {
	super(looper);
	mContext = context;
    }

    public void handleIntent(Intent intent) {
	Message msg = null;
	String action = intent.getAction();
	if (BeemIntent.ACTION_CONNECT.equals(action)) {
	    msg = obtainMessage(IMESSAGE.CONNECT.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_DISCONNECT.equals(action)) {
	    msg = obtainMessage(IMESSAGE.DISCONNECT.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_ISCONNECTED.equals(action)) {
	    msg = obtainMessage(IMESSAGE.IS_CONNECTED.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_SEND_MESSAGE.equals(action)) {
	    msg = obtainMessage(IMESSAGE.SEND_MSG.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_SYNC.equals(action)) {
	    msg = obtainMessage(IMESSAGE.SYNC.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_ADD_CONTACT.equals(action)) {
	    msg = obtainMessage(IMESSAGE.ADD_CONTACT.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_CHANGE_STATUS.equals(action)) {
	    msg = obtainMessage(IMESSAGE.CHANGE_STATUS.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_MUC_JOIN.equals(action)) {
	    msg = obtainMessage(IMESSAGE.MUC_JOIN.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_MUC_SEND_MESSAGE.equals(action)) {
	    msg = obtainMessage(IMESSAGE.MUC_SEND_MSG.ordinal(), intent.getExtras());
	} else if (BeemIntent.ACTION_ADD_MUC.equals(action)) {
	    msg = obtainMessage(IMESSAGE.ADD_MUC.ordinal(), intent.getExtras());
	} else {
	    Log.w(TAG, "Unknown intent " + intent);
	}
	if (msg != null)
	    sendMessage(msg);
    }

    @Override
    public void handleMessage(Message msg) {
	String accountName = null;
	BeemConnection connection = null;
	Bundle b = (Bundle) msg.obj;
	if (b.containsKey(BeemIntent.EXTRA_ACCOUNT)) {
	    accountName = b.getString(BeemIntent.EXTRA_ACCOUNT);
	    connection = mBeemConnection.get(accountName);
	}
	if (connection == null && msg.what != IMESSAGE.CONNECT.ordinal() && msg.what != IMESSAGE.SYNC.ordinal()
	    && msg.what != IMESSAGE.IS_CONNECTED.ordinal() && msg.what != IMESSAGE.CHANGE_STATUS.ordinal()) {
	    Toast.makeText(mContext, mContext.getString(R.string.BeemServiceNotConnected, accountName),
		Toast.LENGTH_LONG).show();
	    return;
	}

	if (msg.what == IMESSAGE.CONNECT.ordinal()) {
	    handleConnect(accountName);
	} else if (msg.what == IMESSAGE.DISCONNECT.ordinal()) {
	    handleDisconnect(accountName);
	} else if (msg.what == IMESSAGE.IS_CONNECTED.ordinal()) {
	    Intent res = new Intent(BeemIntent.ACTION_DISCONNECTED);
	    res.putExtra(BeemIntent.EXTRA_MESSAGE, R.string.contact_status_msg_offline);
	    res.putExtra(BeemIntent.EXTRA_ACCOUNT, accountName);
	    if (mBeemConnection.containsKey(accountName))
		res.setAction(BeemIntent.ACTION_CONNECTED);
	    mContext.sendBroadcast(res);
	} else if (msg.what == IMESSAGE.SEND_MSG.ordinal()) {
	    connection.handleXMPPMessage(accountName, msg);
	} else if (msg.what == IMESSAGE.SYNC.ordinal()) {
	    BeemNotification.StartSyncNotification(mContext);
	    //TODO: Connect with option to not show status
	    handleConnect(accountName);
	    connection = mBeemConnection.get(accountName);
	    if (connection != null)
		connection.syncRoster();
	    BeemNotification.StopSyncNotification(mContext);
	} else if (msg.what == IMESSAGE.ADD_CONTACT.ordinal()) {
	    String jid = b.getString(BeemIntent.EXTRA_JID);
	    if (connection.addContact(jid) == false) {
		Toast.makeText(mContext, connection.getErrorMessage(), Toast.LENGTH_LONG).show();
	    }
	} else if (msg.what == IMESSAGE.CHANGE_STATUS.ordinal()) {
	    Bundle extraBundle = b.getBundle(BeemIntent.EXTRA_MESSAGE);
	    int status = extraBundle.getInt(BeemApplication.STATUS_KEY);
	    if (status == Status.CONTACT_STATUS_DISCONNECT) {
		handleDisconnect(accountName);
	    } else {
		handleConnect(accountName);
		connection = mBeemConnection.get(accountName);
		if (connection != null) {
		    String sStatus = extraBundle.getString(BeemApplication.STATUS_TEXT_KEY);		   
		    connection.changeStatus(status, sStatus, 0);
		    Toast.makeText(mContext, R.string.ChangeStatusOk, Toast.LENGTH_LONG).show();
		}
	    }
	} else if (msg.what == IMESSAGE.MUC_JOIN.ordinal()) {
	    String mucjid = b.getString(BeemIntent.EXTRA_JID);
	    if (connection.mucJoin(mucjid) == false) {
		Toast.makeText(mContext, connection.getErrorMessage(), Toast.LENGTH_LONG).show();
	    }
	} else if (msg.what == IMESSAGE.MUC_SEND_MSG.ordinal()) {
	    String mucjid = b.getString(BeemIntent.EXTRA_JID);
	    String mucmsg = b.getString(BeemIntent.EXTRA_MESSAGE);
	    connection.mucSendMsg(mucjid, mucmsg);

	} else if (msg.what == IMESSAGE.ADD_MUC.ordinal()) {
	    String mucjid = b.getString(BeemIntent.EXTRA_JID);
	    Bundle extra = b.getBundle(BeemIntent.EXTRA_MESSAGE);
	    connection.mucAdd(mucjid, extra);
	} else {
	    Log.w(TAG, "Unknown message " + msg);
	}
    }

    private void handleConnect(String accountName) {
	Intent res = new Intent(BeemIntent.ACTION_DISCONNECTED);
	res.putExtra(BeemIntent.EXTRA_MESSAGE, R.string.contact_status_msg_offline);
	res.putExtra(BeemIntent.EXTRA_ACCOUNT, accountName);

	if (mBeemConnection.containsKey(accountName)) {
	    res.setAction(BeemIntent.ACTION_CONNECTED);
	} else {
	    if (accountName == null) {
		;//connect all
	    } else {
		BeemConnection connection = new BeemConnection(mContext, accountName);
		if (connection.connect()) {
		    mBeemConnection.put(accountName, connection);
		    res.setAction(BeemIntent.ACTION_CONNECTED);
		    Log.i(TAG, "Account connection : " + accountName + " DONE");
		} else {
		    Log.w(TAG, "Unable to connect " + accountName);
		    res.putExtra(BeemIntent.EXTRA_MESSAGE, connection.getErrorMessage());
		}

	    }

	}
	//Bookmark : Muc
	//	if (mConnection.containsKey(accountName)) {
	//	    //TODO AutoConnect
	//	}
	//TODO: ADD MESSAGE || TOAST TO CONFIRM CONNECTION OF THE ACCOUNT
	mContext.sendBroadcast(res);
    }

    private void handleDisconnect(String accountName) {
	Intent res = new Intent(BeemIntent.ACTION_DISCONNECTED);
	res.putExtra(BeemIntent.EXTRA_ACCOUNT, accountName);
	//TODO: ADD MESSAGE TO CONFIRM DECONNECTION OF THE ACCOUNT
	mBeemConnection.get(accountName).finalize();
	mBeemConnection.remove(accountName);
	mContext.sendBroadcast(res);
    }

}