package com.beem.project.beem.ui;

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

import org.jivesoftware.smack.util.StringUtils;

import android.app.ExpandableListActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
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.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;

import com.beem.project.beem.BeemApplication;
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;

public class ContactList extends ExpandableListActivity {

    private static final String TAG = "CONTACTLIST_ACT";
    private static final int PREFERENCECHANGED = 0;
    private static final String DEFAULT_GROUP = "Default";
    private IXmppFacade mService = null;
    private MyExpandableListAdapter mAdapter;
    private BeemApplication mBeemApplication;
    private BeemRosterListener mRosterListener;
    private SharedPreferences mSettings;
    private IRoster mRoster;
    private Map<String, List<Contact>> groupMap;
    private List<String> groupName;
    private List<Contact> mListContact;
    private Handler mHandler;

    @Override
    protected void onCreate(Bundle saveBundle) {
	super.onCreate(saveBundle);
	mHandler = new Handler();
	mRosterListener = new BeemRosterListener();
	mSettings = getSharedPreferences(getString(R.string.PreferenceFileName), MODE_PRIVATE);
	mBeemApplication = BeemApplication.getApplication(this);
	if (mSettings.getString(getString(R.string.PreferenceHostKey), "").equals(""))
	    startActivityForResult(new Intent(this, ContactListSettings.class), PREFERENCECHANGED);
    }

    @Override
    protected void onResume() {
	super.onResume();
	
	mBeemApplication.callWhenConnectedToServer(mHandler, new Runnable() {
	    @Override
	    public void run() {
		mService = mBeemApplication.getXmppFacade();
		try {
		    mRoster = mService.getRoster();
		} catch (RemoteException e1) {
		    Log.e(TAG, "Get roster failed", e1);
		}
		if (mRoster != null) {
		    try {
			mRoster.addConnectionListener(mRosterListener);
		    } catch (RemoteException e) {
			e.printStackTrace();
		    }
		}
		if (mAdapter == null)
		    callbackShowContactList();
	    }
	});
	if (!mBeemApplication.isConnected()) {
	    mBeemApplication = BeemApplication.getApplication(this);
	    mBeemApplication.startBeemService();
	}
    }

    @Override
    protected void onDestroy() {
	mBeemApplication.unbindBeemService();
	super.onDestroy();	
    }

    private void callbackShowContactList() {
	/*
	 * @TODO: A ameliorer apres listener de nikita
	 */
	if (mRoster != null)
	    try {
		buildContactList(mRoster.getContactList());
	    } catch (RemoteException e) {
		e.printStackTrace();
	    }
    }

    /**
     * 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.contactlistmenu, 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.account_edit:
		startActivityForResult(new Intent(this, ContactListSettings.class), PREFERENCECHANGED);
		return true;
	    case R.id.account_about:
		Intent t = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.beem-project.com"));
		startActivity(t);
		return true;
	    case R.id.account_create:
		startActivity(new Intent(this, AccountCreation.class));
		return true;
	    case R.id.add_contact:
		startActivity(new Intent(this, AddContact.class));
		return true;
	    default:
		return false;
	}
    }

    @Override
    public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
	Intent i = new Intent(this, SendIM.class);
	try {
	    i.putExtra("contact", groupMap.get(groupName.get(groupPosition)).get(childPosition));
	    startActivity(i);
	    return true;
	} catch (NullPointerException e) {
	    Log.e(TAG, "Child not found", e);
	    return false;
	}
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	//TODO:marche pas
	if (requestCode == PREFERENCECHANGED) {
	    if (resultCode == RESULT_OK) {
		mAdapter = null;
		setListAdapter(mAdapter);
		mBeemApplication.stopBeemService();
	    }
	}
    }

    private void buildContactList(List<Contact> listContact) {
	mListContact = listContact;
	groupMap = new HashMap<String, List<Contact>>();
	groupName = new ArrayList<String>();
	for (Contact contact : listContact) {
	    for (String group: contact.getGroups()) {
		if (!groupMap.containsKey(group)) {
		    groupMap.put(group, new ArrayList<Contact>());
		    groupName.add(group);
		}
		try {
		    groupMap.get(group).add(contact);
		} catch (NullPointerException e) {
		    Log.e(TAG, "Failed to find group in groupMap", e);
		}
	    }
	    if (contact.getGroups().isEmpty()) {
		if (!groupMap.containsKey(DEFAULT_GROUP)) {
		    groupMap.put(DEFAULT_GROUP, new ArrayList<Contact>());
		    groupName.add(DEFAULT_GROUP);
		}
		groupMap.get(DEFAULT_GROUP).add(contact);
	    }
	}
	mAdapter = new MyExpandableListAdapter();
	setListAdapter(mAdapter);
    }

    private class MyExpandableListAdapter implements ExpandableListAdapter {

	private List<DataSetObserver> observers; 
	
	public MyExpandableListAdapter() {
	    observers = new ArrayList<DataSetObserver>();
	}
	
	public void changed() {
	    for (DataSetObserver obs : observers) {
		obs.onChanged();
	    }
	}
	
	
	@Override
	public boolean areAllItemsEnabled() {
	    return true;
	}

	@Override
	public Object getChild(int groupPosition, int childPosition) {
	    try {
		return groupMap.get(groupName.get(groupPosition)).get(childPosition);
	    } catch (NullPointerException e) {
		Log.e(TAG, "Child not found", e);
		return null;
	    }
	}

	@Override
	public long getChildId(int groupPosition, int childPosition) {
	    try {
		groupMap.get(groupName.get(groupPosition)).get(childPosition);
	    } catch (NullPointerException e) {
		Log.e(TAG, "Child not found", e);
		return 0;
	    }
	    return childPosition;
	}

	@Override
	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
	    ViewGroup parent) {
	    View v;
	    if (convertView == null) {
		v  = LayoutInflater.from(ContactList.this).inflate(R.layout.contactlistcontact, null);
		Log.d(TAG, "Convert view est vide sur un getChildView");
	    } else {
		v = convertView;
	    }
	    bindView(v, groupMap.get(groupName.get(groupPosition)).get(childPosition));
	    return v;
	}

	@Override
	public int getChildrenCount(int groupPosition) {
	    try {
		return groupMap.get(groupName.get(groupPosition)).size();
	    } catch (NullPointerException e) {
		Log.e(TAG, "Child not found", e);
		return 0;
	    }
	}

	@Override
	public long getCombinedChildId(long groupId, long childId) {
	    return 1000 * groupId + childId;
	}

	@Override
	public long getCombinedGroupId(long groupId) {
	    return 1000 * groupId;
	}

	@Override
	public Object getGroup(int groupPosition) {
	    try {
		return groupMap.get(groupName.get(groupPosition));
	    } catch (NullPointerException e) {
		Log.e(TAG, "Group not found", e);
		return null;
	    }
	}

	@Override
	public int getGroupCount() {
	    return groupMap.size();
	}

	@Override
	public long getGroupId(int groupPosition) {
	    return groupPosition;
	}

	@Override
	public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
	    Log.d(TAG, "View getGroupView");
	    View holder = LayoutInflater.from(ContactList.this).inflate(R.layout.contactlistgroup, null);
	    TextView groupTextView = (TextView) holder.findViewById(R.id.textgroup);
	    groupTextView.setText(groupName.get(groupPosition));
	    return holder;
	}

	@Override
	public boolean hasStableIds() {
	    Log.d(TAG, "boolean hasStableIds");
	    return false;
	}

	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
	    Log.d(TAG, "boolean isChildSelectable");
	    return !false;
	}

	@Override
	public boolean isEmpty() {
	    return groupMap.isEmpty();
	}

	@Override
	public void onGroupCollapsed(int groupPosition) {
	    // TODO A voir
	}

	@Override
	public void onGroupExpanded(int groupPosition) {
	    // TODO A voir

	}

	@Override
	public void registerDataSetObserver(DataSetObserver observer) {
	    Log.d(TAG, "registerDataSetObserver");
	    observers.add(observer);
	}

	@Override
	public void unregisterDataSetObserver(DataSetObserver observer) {
	    Log.d(TAG, "unregisterDataSetObserver");
	    observers.remove(observer);
	}

	private void bindView(View view, Contact curContact) {

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

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

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

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

    }

    private class BeemRosterListener extends IBeemRosterListener.Stub {

	@Override
	public void onEntriesAdded(List<String> addresses) throws RemoteException {
	    Log.i(TAG, "ENTRIES ADDED");

	}

	@Override
	public void onEntriesDeleted(List<String> addresses) throws RemoteException {
	    Log.i(TAG, "ENTRIES DEL");

	}

	@Override
	public void onEntriesUpdated(List<String> addresses) throws RemoteException {
	    Log.i(TAG, "ENTRIES UPD");

	}

	@Override
	public void onPresenceChanged(PresenceAdapter presence) throws RemoteException {
	    for (Contact curContact :mListContact) {
		if (curContact.getJID().equals(StringUtils.parseBareAddress(presence.getFrom()))) {
		    curContact.setStatus(presence);
		    mHandler.post(new Runnable() {
			@Override
			public void run() {
			    mAdapter.changed();
			}
		    });
		    return ;
		}
	    }
	}

    }
}
