package com.beem.project.beem.ui;

import java.io.IOException;
import java.io.InputStream;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

import com.beem.project.beem.R;
import com.beem.project.beem.providers.AvatarProvider;
import com.beem.project.beem.service.Contact;
import com.beem.project.beem.utils.SortedList;
import com.beem.project.beem.utils.Status;

public class ContactListAdapter extends BaseAdapter implements Filterable {
	 private static final String TAG = ContactListAdapter.class.getSimpleName();
	private final ComparatorContactListByStatusAndName<Contact> mComparator =
				new ComparatorContactListByStatusAndName<Contact>();
    private List<Contact> mCurrentList;
    private final List<Contact> allContacts = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
    private final List<Contact> onlineContacts = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
	private final Filter mFilter = new ContactFilter();
    private final Context context;
    private LayoutInflater mInflater;


    private boolean showOnlineOnly;
    
    public ContactListAdapter(Context c) {
    	mCurrentList = allContacts;
    	context = c;
    	mInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    
    @Override
	public int getCount() {
	    return mCurrentList.size();
	}


	@Override
	public Object getItem(int position) {
	    return mCurrentList.get(position);
	}


	@Override
	public long getItemId(int position) {
	    return mCurrentList.get(position).hashCode();
	}

	@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 = mCurrentList.get(position);
	    bindView(v, c);
	    return v;
	}
	
	public void put(Contact c) {
		put(c, allContacts);
		if (Status.statusOnline(c.getStatus()))
			put(c, onlineContacts);
		notifyDataSetChanged();
	}
	
	public void remove(Contact c) {
		allContacts.remove(c);
		onlineContacts.remove(c);
		notifyDataSetChanged();
	}
	
	
	public void clear() {
		allContacts.clear();
		onlineContacts.clear();
		notifyDataSetChanged();
	}
	
	@Override
	public Filter getFilter() {
	    return mFilter;
	}
	
	/**
	 * 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) {
		TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
		v.setText(curContact.getName());
		v = (TextView) view.findViewById(R.id.contactlistmsgperso);
		v.setText(curContact.getMsgState());
		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);
	    }
	}

	/**
	 * 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 = context.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 " + avatarId, e);
		}
	    }
	    if (avatarDrawable == null)
		avatarDrawable = context.getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
	    LayerDrawable ld = (LayerDrawable) context.getResources().getDrawable(R.drawable.avatar_status);
	    ld.setLayerInset(1, 36, 36, 0, 0);
	    ld.setDrawableByLayerId(R.id.avatar, avatarDrawable);
	    return ld;
	}
	
	private void put(Contact c, List<Contact> list) {
			list.remove(c);
			list.add(c);
	}

	public boolean isOnlineOnly() {
		return showOnlineOnly;
	}
	
	public void setOnlineOnly(boolean online) {
		if (online != showOnlineOnly) {
			showOnlineOnly = online;
			mCurrentList = showOnlineOnly ? onlineContacts : allContacts;
			notifyDataSetChanged();
		}
	}
	
	
	  /**
     * 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());
	}
    }

	
	/**
	 * 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 = mCurrentList;
		if (constraint.length() > 0) {
		    result = new LinkedList<Contact>();
		    for (Contact c : mCurrentList) {
			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;
		mCurrentList = contacts;
		notifyDataSetChanged();
	    }
	}
    
	

}
