package com.beem.project.beem.ui;

import java.util.List;

import org.jivesoftware.smack.util.StringUtils;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.util.Linkify;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;

import com.beem.project.beem.BeemService;
import com.beem.project.beem.R;
import com.beem.project.beem.service.Contact;
import com.beem.project.beem.service.Message;
import com.beem.project.beem.service.PresenceAdapter;
import com.beem.project.beem.service.aidl.IBeemRosterListener;
import com.beem.project.beem.service.aidl.IChat;
import com.beem.project.beem.service.aidl.IChatManager;
import com.beem.project.beem.service.aidl.IChatManagerListener;
import com.beem.project.beem.service.aidl.IMessageListener;
import com.beem.project.beem.service.aidl.IRoster;
import com.beem.project.beem.service.aidl.IXmppFacade;

/**
 * This activity class provides the view for instant messaging after selecting a correspondant.
 * @author barbu
 */

public class SendIM extends Activity implements OnClickListener, OnKeyListener {

	private static final String TAG = "SEND_IM";
	private EditText mToSend;
	private SendIMDialogSmiley mSmyDialog;
	private SharedPreferences mSet;
	private Handler mHandler;
	private Contact mContact;
	private IChatManager mChatManager;
	private IChatManagerListener mChatManagerListener;
	private IMessageListener mMessageListener;
	private IChat mChat;
	private TextView mText;
	private TextView mLogin;
	private ScrollView mScrolling;
	private char mSpeak;

	private final ServiceConnection mServConn = new BeemServiceConnection();
	private IXmppFacade xmppFacade;
	public IRoster mRoster;
	private TextView mStatusText;

	/**
	 * Constructor.
	 */
	public SendIM() {
		super();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onClick(View view) {
		sendText();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onCreate(Bundle saveBundle) {
		super.onCreate(saveBundle);
		mHandler = new Handler();
		mChatManagerListener = new OnChatListener();
		mMessageListener = new OnMessageListener();
		setContentView(R.layout.sendim);
		mToSend = (EditText) findViewById(R.id.userText);
		mSet = getSharedPreferences("lol", MODE_PRIVATE);
		mSmyDialog = new SendIMDialogSmiley(this, mSet);
		mToSend.setOnClickListener(this);
		mToSend.setOnKeyListener(this);
		mLogin = (TextView) findViewById(R.id.sendimlogin);
		mContact = new Contact(getIntent().getData());
		mText = (TextView) findViewById(R.id.sendimlist);
		mScrolling = (ScrollView) findViewById(R.id.sendimscroll);
		mStatusText = (TextView) findViewById(R.id.sendimstatus);
		setViewHeader();
	}

	/**
	 * Set the header information in the window.
	 */
	private void setViewHeader() {
		Drawable avatar = getResources().getDrawable(R.drawable.avatar);
		ImageView imgV = (ImageView) findViewById(R.id.sendimavatar);
		imgV.setImageDrawable(avatar);		
		mStatusText.setTextSize(12);
		mLogin.setText(mContact.getJID());
		mLogin.setTextColor(getResources().getColor(R.color.white));
	}

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

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (mChatManager != null) {
			try {
				mChatManager.removeChatCreationListener(mChatManagerListener);
				// TODO trouver quand detruire le chat
				// mChatManager.destroyChat(mChat);
			} catch (RemoteException e) {
				Log.e(TAG, "mchat manager and SendIM destroy", e);
			}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onKey(View v, int keyCode, KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_DOWN) {
			switch (keyCode) {
			case KeyEvent.KEYCODE_DPAD_CENTER:
			case KeyEvent.KEYCODE_ENTER:
				sendText();
				return true;
			default:
				return false;
			}
		}
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
		mContact = new Contact(intent.getData());
		setViewHeader();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.sendim_smiley:
			mSmyDialog.show();
			return true;
		default:
			return false;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onPause() {
		super.onPause();
		try {
			mChat.setOpen(false);
		} catch (RemoteException e) {
			Log.d(TAG, "Error while closing chat", e);
		}
		unbindService(mServConn);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onResume() {
		super.onResume();
		bindService(new Intent(this, BeemService.class), mServConn, BIND_AUTO_CREATE);
		mScrolling.fullScroll(ScrollView.FOCUS_DOWN);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onStart() {
		super.onStart();
		// TODO cancel the notification if any
		if (mContact == null)
			mContact = getIntent().getParcelableExtra("contact");
		setViewHeader();

	}

	private class BeemServiceConnection implements ServiceConnection {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			xmppFacade = IXmppFacade.Stub.asInterface(service);
			try {
				if (mChatManager == null) {
					mChatManager = xmppFacade.getChatManager();
					mChatManager.addChatCreationListener(mChatManagerListener);
				}
				switchChat(mContact);
			} catch (RemoteException e) {
				Log.e(TAG, "Error during chat manager creation", e);
			}
			try {
				mRoster = xmppFacade.getRoster();
				if (mRoster != null) {
					mRoster.addRosterListener(new BeemRosterListener());
					mContact.setStatus(mRoster.getPresence(mContact.getJID()));
					mStatusText.setText(mContact.getMsgState());
					Linkify.addLinks(mStatusText, Linkify.WEB_URLS);
				}
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			xmppFacade = null;
		}
	}

	/**
	 * Send a message to the contact over the XMPP connection. Also display it on activity view. TODO : Gerer
	 * l'exception si la connexion se coupe pendant la conversation
	 */
	private void sendText() {
		String text = mToSend.getText().toString();
		if (!text.equals("")) {
			Message msg = new Message(mContact.getJID(), Message.MSG_TYPE_CHAT);
			msg.setBody(text);
			try {
				// TODO: PAs connecter au serveur BING grosse Error ! INTERDICTION !
				mChat.sendMessage(msg);
				if (mSpeak != 1)
					mText.append(getString(R.string.SendIMYouSay) + text + '\n');
				else
					mText.append(text + "\n");
				mToSend.setText(null);
				mScrolling.fullScroll(ScrollView.FOCUS_DOWN);
				mToSend.requestFocus();
				mSpeak = 1;
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}	

	/**
	 * Show the message history.
	 * @param messages list of message to display
	 */
	private void showMessageList(List<Message> messages) {
		mText.setText("");
		mSpeak = 0;
		for (Message message : messages) {
			String from = message.getFrom();
			if (from == null) {
				if (mSpeak != 1)
					mText.append(getString(R.string.SendIMYouSay));
				mSpeak = 1;
			} else {
				if (mSpeak != 2) {
					String str = String.format(getString(R.string.SendIMSays), from);
					mText.append(str);
				}
				mSpeak = 2;
			}
			mText.append(message.getBody() + '\n');
		}
		mScrolling.fullScroll(ScrollView.FOCUS_DOWN);
	}

	/**
	 * Change the correspondant of the chat.
	 * @param newContact New contact to chat with
	 * @throws RemoteException if an errors occurs in the connection with the service
	 */
	private void switchChat(Contact newContact) throws RemoteException {
		if (mChat != null)
			mChat.setOpen(false);
		mChat = mChatManager.createChat(newContact, mMessageListener);
		showMessageList(mChat.getMessages());
		mChat.setOpen(true);
		mContact = newContact;
		mToSend.requestFocus();
	}

	/**
	 * Listener for chat creation. (maybe not necessary)
	 * @author darisk
	 */
	private class OnChatListener extends IChatManagerListener.Stub {
		/**
		 * {@inheritDoc}
		 */
		@Override
		public void chatCreated(IChat chat, boolean locally) throws RemoteException {
			Log.i("LOG", "chatCreated");
		}

	}
	private class BeemRosterListener extends IBeemRosterListener.Stub {

		@Override
		public void onEntriesAdded(List<String> addresses)
		throws RemoteException {
			// TODO Auto-generated method stub

		}

		@Override
		public void onEntriesDeleted(List<String> addresses)
		throws RemoteException {
			// TODO Auto-generated method stub

		}

		@Override
		public void onEntriesUpdated(List<String> addresses)
		throws RemoteException {
			// TODO Auto-generated method stub

		}

		@Override
		public void onPresenceChanged(PresenceAdapter presence)
		throws RemoteException {
			if (mContact.getJID().equals(StringUtils.parseBareAddress(presence.getFrom()))) {
				mContact.setStatus(mRoster.getPresence(StringUtils.parseBareAddress(presence.getFrom())));
				mHandler.post(new RunnableChange());
			}
		}

		private class RunnableChange implements Runnable {
			@Override
			public void run() {
				mStatusText.setText(mContact.getMsgState());
				Linkify.addLinks(mStatusText, Linkify.WEB_URLS);
			}
		}

	}

	/**
	 * Listener for new chat messages.
	 * @author darisk
	 */
	private class OnMessageListener extends IMessageListener.Stub {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void processMessage(IChat chat, Message msg) throws RemoteException {

			if (chat != mChat)
				return;
			final Message m = msg;
			mHandler.post(new Runnable() {

				@Override
				public void run() {
					if (m.getBody() != null) {
						if (mSpeak == 2)
							mText.append(m.getBody() + "\n");
						else {
							String str = String.format(getString(R.string.SendIMSays), m.getFrom());
							mText.append(str);
							mText.append(m.getBody() + "\n");
						}
						mScrolling.fullScroll(ScrollView.FOCUS_DOWN);
						mToSend.requestFocus();
						mSpeak = 2;
					}
				}
			});
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void stateChanged(IChat chat) throws RemoteException {
			// TODO: a integrer dans l'ui
			// Log.d(TAG, "state changed");
		}
	}

}
