/*
    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.ui;

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

import android.app.Activity;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.ContextMenu;
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.view.ViewStub;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Filterable;
import android.widget.Gallery;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

import com.beem.project.beem.BeemIntent;
import com.beem.project.beem.R;
import com.beem.project.beem.service.Contact;
import com.beem.project.beem.service.aidl.IChatManager;
import com.beem.project.beem.service.aidl.IRoster;
import com.beem.project.beem.service.aidl.IXmppFacade;
import com.beem.project.beem.ui.dialogs.builders.Alias;
import com.beem.project.beem.ui.dialogs.builders.ChatList;
import com.beem.project.beem.ui.dialogs.builders.DeleteContact;
import com.beem.project.beem.ui.dialogs.builders.ResendSubscription;

/**
 * The contact list activity displays the roster of the user.
 * @author Vincent V. <marseille@beem-project.com>
 */
public class ContactList extends Activity {

    private static final Intent SERVICE_INTENT = new Intent();
    static {
	SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
    }

    private static final String SETTINGS_HIDDEN_CONTACT = "settings_key_hidden_contact";
    private static final String TAG = "ContactList";

    /**
     * Map containing a list of the different contacts of a given group. Each list is a @{link SortedList} so there is
     * no need to sort it again.
     */

    private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick();

    private final ComparatorContactListByStatusAndName<Contact> mComparator = new ComparatorContactListByStatusAndName<Contact>();
    private IRoster mRoster;
    private Contact mSelectedContact;
    private IXmppFacade mXmppFacade;
    private IChatManager mChatManager;
    private SharedPreferences mSettings;
    private BeemBanner mAdapterBanner;
    private BeemContactList mAdapterContactList;

    private String mAccountName;

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

    @Override
    protected void onCreate(Bundle saveBundle) {
	super.onCreate(saveBundle);
	mSettings = PreferenceManager.getDefaultSharedPreferences(this);
	setContentView(R.layout.contactlist);

	mAccountName = getIntent().getExtras().getString(BeemIntent.EXTRA_ACCOUNT);

	// Get Groups list
	final Cursor cursorGroup = getContentResolver().query(ContactsContract.Groups.CONTENT_URI,
	    new String[] { ContactsContract.Groups._ID, ContactsContract.Groups.TITLE },
	    ContactsContract.Groups.ACCOUNT_NAME + "=?", new String[] { mAccountName }, null);
	mAdapterBanner = new BeemBanner(this, R.layout.contactlist_group, cursorGroup,
	    new String[] { ContactsContract.Groups.TITLE }, new int[] { R.id.contactlist_group });
	cursorGroup.registerContentObserver(new BeemGroupObserver(new Handler()));
	// Get Contacts list
	// TODO: Get contact list by account  -> Create Sqlite View or join
	final Cursor cursorContact = getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI,
	    new String[] { ContactsContract.RawContacts._ID, ContactsContract.RawContacts.SOURCE_ID },
	    ContactsContract.RawContacts.ACCOUNT_NAME + "=?", new String[] { mAccountName }, null);
	// TODO: GetAvatar + Presence
	mAdapterContactList = new BeemContactList(this, R.layout.contactlistcontact, cursorContact, new String[] {
	    ContactsContract.RawContacts._ID, ContactsContract.RawContacts.SOURCE_ID }, new int[] { R.id.avatar,
	    R.id.contactlistpseudo, R.id.contactlistmsgperso });

	ListView listView = (ListView) findViewById(R.id.contactlist);
	listView.setOnItemClickListener(mOnContactClick);
	registerForContextMenu(listView);
	listView.setAdapter(mAdapterContactList);
    }

    @Override
    protected void onResume() {
	super.onResume();
	if (!mSettings.getBoolean("settings_key_hide_groups", false))
	    showGroups();
	else
	    hideGroups();
    }

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

    @Override
    public final boolean onOptionsItemSelected(MenuItem item) {
	switch (item.getItemId()) {
	    case R.id.contact_list_menu_settings:
		Intent i = new Intent(this, Settings.class);
		i.putExtra("account_name", mAccountName);
		startActivity(i);
		return true;
	    case R.id.contact_list_menu_add_contact:
		startActivity(new Intent(ContactList.this, AddContact.class));
		return true;
	    case R.id.menu_change_status:
		startActivity(new Intent(ContactList.this, ChangeStatus.class));
		return true;
	    case R.id.contact_list_menu_chatlist:
		List<Contact> openedChats;
		try {
		    openedChats = mChatManager.getOpenedChatList();
		    Log.d(TAG, "opened chats = " + openedChats);
		    Dialog chatList = new ChatList(ContactList.this, openedChats).create();
		    chatList.show();
		} catch (RemoteException e) {
		    e.printStackTrace();
		}
		return true;
	    case R.id.contact_list_menu_sync:
		Intent intent = new Intent(BeemIntent.ACTION_SYNC);
		intent.putExtra(BeemIntent.EXTRA_ACCOUNT, mAccountName);
		startService(intent);
		return true;
	    case R.id.menu_disconnect:
		stopService(SERVICE_INTENT);
		return true;
	    default:
		return false;
	}
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
	super.onCreateContextMenu(menu, v, menuInfo);
	MenuInflater inflater = getMenuInflater();
	inflater.inflate(R.menu.contactlist_context, menu);
	AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
	// Contact c = new Contact();
	// try {
	// mSelectedContact = mRoster.getContact(c.getJID());
	// } catch (RemoteException e) {
	// e.printStackTrace();
	// }
	// menu.setHeaderTitle(mSelectedContact.getJID());
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
	Intent in;
	boolean result;
	if (mSelectedContact != null) {
	    switch (item.getItemId()) {
		case R.id.contact_list_context_menu_chat_item:
		    List<String> res = mSelectedContact.getMRes();
		    if (res.isEmpty()) {
			result = false;
			break;
		    }
		    for (String resv : res) {
			in = new Intent(this, Chat.class);
			in.setData(mSelectedContact.toUri(resv));
			item.getSubMenu().add(resv).setIntent(in);
		    }
		    result = true;
		    break;
		case R.id.contact_list_context_menu_call_item:
		    try {
			mXmppFacade.call(mSelectedContact.getJID() + "/psi");
			result = true;
		    } catch (RemoteException e) {
			e.printStackTrace();
		    }
		    result = true;
		    break;
		case R.id.contact_list_context_menu_user_info:
		    item.getSubMenu().setHeaderTitle(mSelectedContact.getJID());
		    result = true;
		    break;
		case R.id.contact_list_context_menu_userinfo_alias:
		    Dialog alias = new Alias(ContactList.this, mRoster, mSelectedContact).create();
		    alias.show();
		    result = true;
		    break;
		case R.id.contact_list_context_menu_userinfo_group:
		    in = new Intent(this, GroupList.class);
		    in.putExtra("contact", mSelectedContact);
		    startActivity(in);
		    result = true;
		    break;
		case R.id.contact_list_context_menu_userinfo_subscription:
		    Dialog subscription = new ResendSubscription(ContactList.this, mXmppFacade, mSelectedContact)
			.create();
		    subscription.show();
		    result = true;
		    break;
		case R.id.contact_list_context_menu_userinfo_block:
		    result = true;
		    break;
		case R.id.contact_list_context_menu_userinfo_delete:
		    Dialog delete = new DeleteContact(ContactList.this, mRoster, mSelectedContact).create();
		    delete.show();
		    result = true;
		    break;
		default:
		    result = super.onContextItemSelected(item);
		    break;
	    }
	    return result;
	}
	return super.onContextItemSelected(item);
    }

    /**
     * Show the groups view.
     */
    private void showGroups() {
	ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub);
	if (stub != null) {
	    View v = stub.inflate();
	    Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner);
	    g.setOnItemClickListener(new OnItemClickGroupName());
	    g.setAdapter(mAdapterBanner);
	    if (mAdapterBanner.getCount() == 0)
		v.setVisibility(View.GONE);
	    else
		v.setVisibility(View.VISIBLE);
	}
    }

    /**
     * Hide the groups view.
     */
    private void hideGroups() {
	View v = findViewById(R.id.contactlist_groupstub);
	if (v != null)
	    v.setVisibility(View.GONE);
    }

    /**
     * Adapter contact list.
     */
    private static class BeemContactList extends SimpleCursorAdapter implements Filterable {

	private Context mContext;
	private int mLayout;

	public BeemContactList(Context context, int layout, Cursor c, String[] from, int[] to) {
	    super(context, layout, c, from, to);
	    mContext = context;
	    mLayout = layout;
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
	    final LayoutInflater inflater = LayoutInflater.from(mContext);
	    return inflater.inflate(mLayout, parent, false);
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor) {
	    String name = cursor.getString(cursor.getColumnIndex(ContactsContract.RawContacts.SOURCE_ID));
	    String jid = cursor.getString(cursor.getColumnIndex(ContactsContract.RawContacts.SOURCE_ID));
	    TextView nameText = (TextView) view.findViewById(R.id.contactlistpseudo);
	    if (nameText != null) {
		nameText.setText(name);
	    }

	    // String msgStatus = cursor.getString(cursor
	    // .getColumnIndex(ContactsContract.Contacts.CONTACT_STATUS));
	    // TextView msgStatusText = (TextView) view
	    // .findViewById(R.id.contactlistmsgperso);
	    // if (msgStatusText != null) {
	    // msgStatusText.setText(msgStatus);
	    // }

	    view.setTag(jid);

	    // ImageView img = (ImageView) view.findViewById(R.id.avatar);
	    // String avatarId = curContact.getAvatarId();
	    // int contactStatus = curContact.getStatus();
	    // Drawable avatar = getAvatarStatusDrawable(avatarId);
	    // img.setImageDrawable(avatar);
	    // img.setImageLevel(contactStatus);
	}

	// @Override
	// public Filter getFilter() {
	// return mFilter;
	// }

	/**
	 * Get a LayerDrawable containing the avatar and the status icon. The status icon will change with the level of
	 * the drawable.
	 * @param avatarId the avatar id to retrieve or null to get default
	 * @return a LayerDrawable
	 */
	// private Drawable getAvatarStatusDrawable(String avatarId) {
	// Drawable avatarDrawable = null;
	// if (avatarId != null) {
	// Uri uri =
	// AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
	// InputStream in = null;
	// try {
	// try {
	// in = getContentResolver().openInputStream(uri);
	// avatarDrawable = Drawable.createFromStream(in, avatarId);
	// } finally {
	// if (in != null)
	// in.close();
	// }
	// } catch (IOException e) {
	// Log.w(TAG, "Error while setting the avatar", e);
	// }
	// }
	// if (avatarDrawable == null)
	// avatarDrawable =
	// getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
	// LayerDrawable ld = (LayerDrawable)
	// getResources().getDrawable(R.drawable.avatar_status);
	// ld.setLayerInset(1, 36, 36, 0, 0);
	// ld.setDrawableByLayerId(R.id.avatar, avatarDrawable);
	// return ld;
	// }

	/**
	 * A Filter which select Contact to display by searching in ther Jid.
	 */
	// private class ContactFilter extends Filter {
	//
	// /**
	// * Create a ContactFilter.
	// */
	// public ContactFilter() {
	// }
	//
	// @Override
	// protected Filter.FilterResults performFiltering(CharSequence
	// constraint) {
	// Log.d(TAG, "performFiltering");
	// List<Contact> result = mListContact;
	// if (constraint.length() > 0) {
	// result = new LinkedList<Contact>();
	// for (Contact c : mContactOnGroup.get(mSelectedGroup)) {
	// if (c.getJID().contains(constraint))
	// result.add(c);
	// }
	// }
	// Filter.FilterResults fr = new Filter.FilterResults();
	// fr.values = result;
	// fr.count = result.size();
	// return fr;
	// }
	//
	// @Override
	// protected void publishResults(CharSequence constraint,
	// Filter.FilterResults results) {
	// Log.d(TAG, "publishResults");
	// List<Contact> contacts = (List<Contact>) results.values;
	// mListContact = contacts;
	// notifyDataSetChanged();
	// }
	// }
    }

    /**
     * Adapter banner group list.
     */
    private static class BeemBanner extends SimpleCursorAdapter {

	private Context mContext;
	private int mLayout;

	public BeemBanner(Context context, int layout, Cursor c, String[] from, int[] to) {
	    super(context, layout, c, from, to);
	    mContext = context;
	    mLayout = layout;
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
	    final LayoutInflater inflater = LayoutInflater.from(mContext);
	    return inflater.inflate(mLayout, parent, false);
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor) {
	    String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Groups.TITLE));
	    TextView nameText = (TextView) view.findViewById(R.id.contactlist_group);
	    if (nameText != null) {
		nameText.setText(name);
	    }
	}
    }

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

	@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());
	}
    }

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

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onItemClick(AdapterView<?> arg0, View v, int pos, long lpos) {
	    String jid = (String) v.getTag();
	    Log.i(TAG, "OnClick Jid :" + jid);
	    Intent i = new Intent(ContactList.this, Chat.class);
	    i.setData(Uri.parse("imto://jabber/" + jid));
	    startActivity(i);
	}
    }

    /**
     * Event simple click on middle group name.
     */
    private class OnItemClickGroupName implements OnItemClickListener {

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

	@Override
	public void onItemClick(AdapterView<?> arg0, View v, int i, long l) {
	    // String group = mListGroup.get(i);
	    // buildContactList(group);
	}
    }

    private class BeemGroupObserver extends ContentObserver {

	public BeemGroupObserver(Handler handler) {
	    super(handler);
	}

	@Override
	public boolean deliverSelfNotifications() {
	    return true;
	}

	@Override
	public void onChange(boolean selfChange) {
	    super.onChange(selfChange);
	    View v = findViewById(R.id.contactlist_groupstub);
	    if (v != null) {
		if (mAdapterBanner.getCount() > 0) {
		    v.setVisibility(View.VISIBLE);
		} else {
		    v.setVisibility(View.GONE);
		}
	    }
	}

    }

}
