package com.beem.project.beem.ui;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.jivesoftware.smack.util.StringUtils;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;

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.PresenceAdapter;
import com.beem.project.beem.service.aidl.IBeemRosterListener;
import com.beem.project.beem.service.aidl.IRoster;
import com.beem.project.beem.service.aidl.IXmppFacade;
import com.beem.project.beem.utils.Status;

/**
 * The contact list activity displays the roster of the user.
 */
public class ContactList extends Activity {

    private static final String TAG = "CONTACTLIST_ACT";
    private static final int REQUEST_CODE = 1;
    private BeemContactList mAdapter;
    private IRoster mRoster;
    private List<Contact> mListContact;
    private List<String> mListGroup;
    private int mPosCurGroup = -1;
    private Handler mHandler;
    private IXmppFacade mXmppFacade;
    private final ServiceConnection mServConn = new BeemServiceConnection();

    /**
     * Constructor.
     */
    public ContactList() {

    }

    /**
     * Callback for menu creation.
     * @param menu the menu created
     * @return true on success, false otherwise
     */
    @Override
    public final boolean onCreateOptionsMenu(Menu menu) {
	super.onCreateOptionsMenu(menu);
	MenuInflater inflater = getMenuInflater();
	inflater.inflate(R.menu.contact_list, menu);
	return true;
    }

    /**
     * Callback for menu item selected.
     * @param item the item selected
     * @return true on success, false otherwise
     */
    @Override
    public final boolean onOptionsItemSelected(MenuItem item) {
	switch (item.getItemId()) {
	    case R.id.contact_list_menu_settings:
		startActivityForResult(new Intent(this, EditSettings.class), REQUEST_CODE);
		return true;
	    case R.id.contact_list_menu_add_contact:
		startActivity(new Intent(ContactList.this, AddContact.class));
		return true;
	    default:
		return false;
	}
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	if (requestCode == REQUEST_CODE) {
	    if (resultCode == 69) {
		finish();
		stopService(new Intent(this, BeemService.class));
		startActivity(new Intent(this, Login.class));
	    }
	}
    }

    @Override
    protected void onCreate(Bundle saveBundle) {
	super.onCreate(saveBundle);
	setContentView(R.layout.contactlist);
	mAdapter = new BeemContactList(this);
	Button b = (Button) findViewById(R.id.contactlist_group);
	b.setOnClickListener(new OnClickGroupName());
	b = (Button) findViewById(R.id.contactlist_left);
	b.setOnClickListener(new OnClickLeft());
	b = (Button) findViewById(R.id.contactlist_right);
	b.setOnClickListener(new OnClickRight());
	mHandler = new Handler();

    }

    /**
     * Event on middle groupe name.
     */
    private class OnClickGroupName implements View.OnClickListener {
	/**
	 * Constructor.
	 */
	public OnClickGroupName() {

	}

	@Override
	public void onClick(View arg0) {

	}
    }

    /**
     * Event on left groupe name.
     */
    private class OnClickLeft implements View.OnClickListener {
	/**
	 * Constructor.
	 */
	public OnClickLeft() {

	}

	@Override
	public void onClick(View arg0) {
	    mPosCurGroup--;
	    if (mPosCurGroup < -1)
		mPosCurGroup = mListGroup.size() - 1;
	    Button b = (Button) findViewById(R.id.contactlist_group);
	    if (mPosCurGroup == -1)
		b.setText(R.string.contact_list_all_contact);
	    else
		b.setText(mListGroup.get(mPosCurGroup));
	    try {
		buildContactList(mRoster.getContactList(), mRoster.getGroupsNames());
	    } catch (RemoteException e) {
		e.printStackTrace();
	    }
	    mAdapter.notifyDataSetChanged();
	    mAdapter.notifyDataSetChanged();
	}
    }

    /**
     * Event on right groupe name.
     */
    private class OnClickRight implements View.OnClickListener {

	/**
	 * Constructor.
	 */
	public OnClickRight() {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onClick(View v) {
	    mPosCurGroup++;
	    if (mPosCurGroup == mListGroup.size())
		mPosCurGroup = -1;
	    Button b = (Button) findViewById(R.id.contactlist_group);
	    if (mPosCurGroup == -1)
		b.setText(R.string.contact_list_all_contact);
	    else
		b.setText(mListGroup.get(mPosCurGroup));
	    try {
		buildContactList(mRoster.getContactList(), mRoster.getGroupsNames());
	    } catch (RemoteException e) {
		e.printStackTrace();
	    }
	    mAdapter.notifyDataSetChanged();
	}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onStart() {
	super.onStart();
	bindService(new Intent(this, BeemService.class), mServConn, BIND_AUTO_CREATE);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onStop() {
	Log.e(TAG, "UNBINSERVICE");
	super.onStop();
	unbindService(mServConn);
    }

    /**
     * Comparator Contact by Name.
     */
    class ComparatorContactListByName<T> implements Comparator<T> {
	/**
	 * Constructor.
	 */
	public ComparatorContactListByName() {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int compare(T c1, T c2) {
	    return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
	}
    }

    /**
     * Comparator Contact by status and name.
     */
    class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
	/**
	 * Constructor.
	 */
	public ComparatorContactListByStatusAndName() {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int compare(T c1, T c2) {
	    if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) {
		return 1;
	    } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) {
		return -1;
	    } else
		return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
	}
    }

    /**
     * Contact List construction.
     * @param listContact Contact list.
     * @param listGroup Group list.
     */
    private void buildContactList(List<Contact> listContact, List<String> listGroup) {
	mListGroup = listGroup;
	Collections.sort(mListGroup);
	if (mListContact != null)
	    mListContact.clear();
	if (mPosCurGroup == -1)
	    mListContact = listContact;
	else {
	    String curGroup = mListGroup.get(mPosCurGroup);
	    for (Contact c : listContact) {
		if (c.getGroups().contains(curGroup)) {
		    mListContact.add(c);
		}
	    }
	}

	sortBeemContactList();

	ListView listView = (ListView) findViewById(R.id.contactlist);
	listView.setOnItemClickListener(new BeemContactListOnClick());
	listView.setOnItemLongClickListener(new BeemContactListOnLongClick());
	listView.setAdapter(mAdapter);
    }

    /**
     * Event simple click on item of the contact list.
     */
    public class BeemContactListOnClick implements OnItemClickListener {
	/**
	 * Constructor.
	 */
	public BeemContactListOnClick() {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onItemClick(AdapterView<?> arg0, View v, int pos, long lpos) {
	    Contact c = mListContact.get(pos);
	    Intent i = new Intent(ContactList.this, SendIM.class);
	    i.setData(c.toUri());
	    startActivity(i);
	}
    }

    /**
     * Event long click on item of the contact list.
     */
    public class BeemContactListOnLongClick implements OnItemLongClickListener {
	/**
	 * Constructor.
	 */
	public BeemContactListOnLongClick() {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onItemLongClick(AdapterView<?> arg0, View v, int pos, long lpos) {
	    Contact c = mListContact.get(pos);
	    ContactDialog dialogContact = new ContactDialog(ContactList.this, c, "MYSTATICGROUP");
	    dialogContact.setOwnerActivity(ContactList.this);
	    dialogContact.show();
	    return true;
	}
    }

    /**
     * Sort the contact list.
     */
    private void sortBeemContactList() {
	Collections.sort(mListContact, new ComparatorContactListByStatusAndName<Contact>());
    }

    /**
     * Listener on service event.
     */
    private class BeemRosterListener extends IBeemRosterListener.Stub {
	/**
	 * Constructor.
	 */
	public BeemRosterListener() {

	}

	/**
	 * Refresh the contact list.
	 */
	private class RunnableChange implements Runnable {
	    /**
	     * Constructor.
	     */
	    public RunnableChange() {

	    }

	    /**
	     * {@inheritDoc}
	     */
	    @Override
	    public void run() {
		sortBeemContactList();
		mAdapter.notifyDataSetChanged();
	    }
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onEntriesAdded(List<String> addresses) throws RemoteException {
	    for (String newName : addresses) {
		Contact c = new Contact(newName);
		mListContact.add(c);
	    }
	    mHandler.post(new RunnableChange());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onEntriesDeleted(List<String> addresses) throws RemoteException {
	    for (String cToDelete : addresses) {
		for (Contact c : mListContact) {
		    if (c.getJID().equals(cToDelete)) {
			mListContact.remove(c);
			break;
		    }
		}
	    }
	    mHandler.post(new RunnableChange());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onEntriesUpdated(List<String> addresses) throws RemoteException {
	    mHandler.post(new RunnableChange());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onPresenceChanged(PresenceAdapter presence) throws RemoteException {
	    for (Contact curContact : mListContact) {
		if (curContact.getJID().equals(StringUtils.parseBareAddress(presence.getFrom()))) {
		    curContact.setStatus(mRoster.getPresence(StringUtils.parseBareAddress(presence.getFrom())));
		    mHandler.post(new RunnableChange());
		    return;
		}
	    }
	}
    }

    /**
     * Adapter contact list.
     */
    private class BeemContactList extends BaseAdapter {
	private LayoutInflater mInflater;

	/**
	 * Constructor.
	 * @param context context activity.
	 */
	public BeemContactList(final Context context) {
	    mInflater = LayoutInflater.from(context);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getCount() {
	    return mListContact.size();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Object getItem(int position) {
	    return position;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public long getItemId(int position) {
	    return position;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
	    View v = convertView;
	    if (convertView == null) {
		v = mInflater.inflate(R.layout.contactlistcontact, null);
	    }

	    Contact c = mListContact.get(position);
	    bindView(v, c);
	    return v;
	}

	/**
	 * Adapte curContact to the view.
	 * @param view the row view.
	 * @param curContact the current contact.
	 */
	private void bindView(View view, Contact curContact) {

	    if (curContact != null) {
		ImageView imgV = (ImageView) view.findViewById(R.id.contactliststatus);
		TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
		Drawable imageDrawable = null;
		switch (curContact.getStatus()) {
		    case Status.CONTACT_STATUS_AVAILABLE:
			imageDrawable = getResources().getDrawable(R.drawable.online);
			v.setTextColor(getResources().getColor(R.color.white));
			break;
		    case Status.CONTACT_STATUS_AVAILABLE_FOR_CHAT:
			imageDrawable = getResources().getDrawable(R.drawable.chat);
			break;
		    case Status.CONTACT_STATUS_AWAY:
			imageDrawable = getResources().getDrawable(R.drawable.away);
			break;
		    case Status.CONTACT_STATUS_BUSY:
			imageDrawable = getResources().getDrawable(R.drawable.dnd);
			break;
		    case Status.CONTACT_STATUS_DISCONNECT:
			imageDrawable = getResources().getDrawable(R.drawable.offline);
			break;
		    case Status.CONTACT_STATUS_UNAVAILABLE:
			imageDrawable = getResources().getDrawable(R.drawable.requested);
			break;
		    default:
			imageDrawable = getResources().getDrawable(R.drawable.error);
			break;
		}
		imgV.setImageDrawable(imageDrawable);

		String mContactName = curContact.getName();
		if ("".equals(mContactName)) {
		    mContactName = curContact.getJID();
		    mContactName = StringUtils.parseName(mContactName);
		    if ("".equals(mContactName))
			mContactName = curContact.getJID();
		}
		v.setText(mContactName);

		v = (TextView) view.findViewById(R.id.contactlistmsgperso);
		if (v != null) {
		    v.setText(curContact.getMsgState());
		}

		/*
		 * Rajouter l'avatar du contact getAvatar() dans la classe imgV = (ImageView)
		 * view.findViewById(R.id.contactlistavatar); if (imgV != null) { imageDrawable =
		 * getResources().getDrawable(R.drawable.avatar); imgV.setImageDrawable(imageDrawable); }
		 */
	    }
	}
    }

    /**
     * The service connection used to connect to the Beem service.
     */
    private class BeemServiceConnection implements ServiceConnection {
	private BeemRosterListener mBeemRosterListener = new BeemRosterListener();

	/**
	 * Constructor.
	 */
	public BeemServiceConnection() {
	}

	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
	    mXmppFacade = IXmppFacade.Stub.asInterface(service);
	    try {
		mRoster = mXmppFacade.getRoster();
		if (mRoster != null) {
		    mRoster.addRosterListener(mBeemRosterListener);
		    buildContactList(mRoster.getContactList(), mRoster.getGroupsNames());
		}
	    } catch (RemoteException e) {
		e.printStackTrace();
	    }
	}

	@Override
	public void onServiceDisconnected(ComponentName name) {
	    try {
		mRoster.removeRosterListener(mBeemRosterListener);
	    } catch (RemoteException e) {
		e.printStackTrace();
	    }
	    mXmppFacade = null;
	    mRoster = null;
	}
    }
}
