/**
 *
 */
package com.beem.project.beem.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;

import com.beem.project.beem.service.aidl.IBeemConnectionListener;
import com.beem.project.beem.service.aidl.IBeemRosterListener;

import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

/**
 * This class implement a Roster adapter for BEEM.
 * @author darisk
 */
public class RosterAdapter extends com.beem.project.beem.service.aidl.IRoster.Stub {

	private static final String TAG = "RosterAdapter";
	private Roster mAdaptee;
	private RemoteCallbackList<IBeemRosterListener> mRemoteRosListeners = 
		new RemoteCallbackList<IBeemRosterListener>();
	private Map<String, Contact> mContacts = new HashMap<String, Contact>();
	private RosterListener mRosterListener = new RosterListener() {
		@Override
		public void presenceChanged(Presence presence) {
			String user = presence.getFrom();
			Presence bestPresence = mAdaptee.getPresence(user);
			Contact c = mContacts.get(user);
			if (c == null) {
				c = new Contact(user);
				mContacts.put(user, c);
			}
			int status;
			if (bestPresence.getType().equals(Presence.Type.unavailable))
				status = Contact.CONTACT_STATUS_DISCONNECT;
			else {
				switch (bestPresence.getMode()) {
				case available:
					status = Contact.CONTACT_STATUS_AVAILABLE;
					break;
				case away:
					status = Contact.CONTACT_STATUS_AWAY;
					break;
				case chat:
					status = Contact.CONTACT_STATUS_AVAILABLE_FOR_CHAT;
					break;
				case dnd:
					status = Contact.CONTACT_STATUS_BUSY;
					break;
				case xa:
					status = Contact.CONTACT_STATUS_UNAVAILABLE;
					break;
				default:
					Log.e("RosterAdapter", "Status mode non gere");
				status = Contact.CONTACT_STATUS_DISCONNECT;
				break;
				}
			}
			c.setStatus(status);
		}

		@Override
		public void entriesUpdated(Collection<String> arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void entriesDeleted(Collection<String> arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void entriesAdded(Collection<String> arg0) {
			// TODO Auto-generated method stub

		}
	};

	/**
	 * Constructor.
	 * @param roster the roster to adapt
	 */
	public RosterAdapter(final Roster roster) {
		mAdaptee = roster;
		roster.addRosterListener(mRosterListener);
		for (RosterEntry entry : roster.getEntries()) {
			String user = entry.getUser();
			if ( !mContacts.containsKey(user))
				mContacts.put(user, new Contact(user));
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void createGroup(String groupname) throws RemoteException {
		// TODO Auto-generated method stub
		mAdaptee.createGroup(groupname);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Contact addContact(String user, String name, String[] groups) throws RemoteException {
		try {
			mAdaptee.createEntry(user, name, groups);
			Contact res = new Contact(user);
			mContacts.put(user, res);
			return res;
		} catch (XMPPException e) {
			return null;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void deleteContact(Contact contact) throws RemoteException {
		// TODO Auto-generated method stub

	}
	@Override
	public void addConnectionListener(IBeemRosterListener listen) throws RemoteException {
		if (listen != null)
			mRemoteRosListeners.register(listen);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeConnectionListener(IBeemRosterListener listen) throws RemoteException {
		if (listen != null)
			mRemoteRosListeners.unregister(listen);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Contact getContact(String jid) throws RemoteException {
		return mContacts.get(jid);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<Contact> getContactList() throws RemoteException {
		List<Contact> res = new ArrayList<Contact>();
		res.addAll(mContacts.values());
		return res;
	}

	private class RosterListenerAdapter implements RosterListener {

		@Override
		public void entriesAdded(Collection<String> addresses) {
			final int n = mRemoteRosListeners.beginBroadcast();

			List<String> tab = null;
			for (int i = 0; i < n; i++) {
				IBeemRosterListener listener = mRemoteRosListeners.getBroadcastItem(i);
				try {
					tab.addAll(addresses);
					listener.onEntriesAdded(tab);
				} catch (RemoteException e) {
					// The RemoteCallbackList will take care of removing the
					// dead listeners.
					Log.w(TAG, "Error while adding roster entries", e);
				}
			}
			mRemoteRosListeners.finishBroadcast();

		}

		@Override
		public void entriesDeleted(Collection<String> addresses) {
			final int n = mRemoteRosListeners.beginBroadcast();

			List<String> tab = null;
			for (int i = 0; i < n; i++) {
				IBeemRosterListener listener = mRemoteRosListeners.getBroadcastItem(i);
				try {
					tab.addAll(addresses);
					listener.onEntriesDeleted(tab);
				} catch (RemoteException e) {
					// The RemoteCallbackList will take care of removing the
					// dead listeners.
					Log.w(TAG, "Error while deleting roster entries", e);
				}
			}
			mRemoteRosListeners.finishBroadcast();			
		}

		@Override
		public void entriesUpdated(Collection<String> addresses) {
			final int n = mRemoteRosListeners.beginBroadcast();

			List<String> tab = null;
			for (int i = 0; i < n; i++) {
				IBeemRosterListener listener = mRemoteRosListeners.getBroadcastItem(i);
				try {
					tab.addAll(addresses);
					listener.onEntriesUpdated(tab);
				} catch (RemoteException e) {
					// The RemoteCallbackList will take care of removing the
					// dead listeners.
					Log.w(TAG, "Error while updating roster entries", e);
				}
			}
			mRemoteRosListeners.finishBroadcast();			
		}

		@Override
		public void presenceChanged(Presence presence) {
			final int n = mRemoteRosListeners.beginBroadcast();

			List<String> tab = null;
			for (int i = 0; i < n; i++) {
				IBeemRosterListener listener = mRemoteRosListeners.getBroadcastItem(i);
				try {
					listener.onPresenceChanged(new PresenceAdapter(presence));
				} catch (RemoteException e) {
					// The RemoteCallbackList will take care of removing the
					// dead listeners.
					Log.w(TAG, "Error while updating roster entries", e);
				}
			}
			mRemoteRosListeners.finishBroadcast();			
		}    	

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<String> getGroupsNames() throws RemoteException {
		Collection<RosterGroup> groups = mAdaptee.getGroups();
		ArrayList<String> result = new ArrayList<String>(groups.size());
		for (RosterGroup rosterGroup : groups) {
			result.add(rosterGroup.getName());
		}
		return result;
	}

}
