package cc.hughes.droidchatty;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

public abstract class LoadingAdapter<T> extends ArrayAdapter<T>
{
    protected abstract View createView(int position, View convertView, ViewGroup parent);
    protected abstract ArrayList<T> loadData() throws Exception;
    protected void afterDisplay() { }
    
    private List<T> _items;
    private int _normalResource;
    private int _loadingResource;
    private View _loadingView;
    private boolean _moreToLoad = true;
    
    LayoutInflater _inflater;
    
    public LoadingAdapter(Context context, int resource, int loadingResource, List<T> objects)
    {
        super(context, 0, 0, objects);
        _inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        _normalResource = resource;
        _loadingResource = loadingResource;
        _items = objects;
    }
    
    public List<T> getItems()
    {
        return _items;
    }
    
    @Override
    public T getItem(int position)
    {
        if (position == super.getCount())
            return null;
        return super.getItem(position);
    }

    @Override
    public int getItemViewType(int position)
    {
        if (position == super.getCount())
            return IGNORE_ITEM_VIEW_TYPE;
        
        return super.getItemViewType(position);
    }

    @Override
    public int getViewTypeCount()
    {
        // regular view + loading view
        return super.getViewTypeCount() + 1;
    }
    
    @Override
    public int getCount()
    {
        if (_moreToLoad && getMoreToLoad())
            return super.getCount() + 1;
        return super.getCount();
    }
    
    @Override
    public void add(T item)
    {
        _items.add(item);
    }
    
    @Override
    public void clear()
    {
        _items.clear();
        super.clear();
        _moreToLoad = true;
        _loadingView = null;
    }
    
    protected boolean getMoreToLoad()
    {
        return _moreToLoad;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        if (position == super.getCount())
        {
            if (_loadingView == null)
            {
                _loadingView = getLoadingView(parent);
                new LoadAndAppendTask().execute();
            }
            return _loadingView;
        }
        
        if (convertView == null)
            convertView = _inflater.inflate(_normalResource, null);
        
        return createView(position, convertView, parent);
    }
    
    private View getLoadingView(ViewGroup parent)
    {
        return _inflater.inflate(_loadingResource, parent, false);
    }
    
    class LoadAndAppendTask extends AsyncTask<Void, Void, ArrayList<T>>
    {
        Exception _exception;
        
        @Override
        protected ArrayList<T> doInBackground(Void... arg0)
        {
            try
            {
                return loadData();
            }
            catch (Exception e)
            {
                Log.e("DroidChatty", "Error loading data.", e);
                _exception = e;
            }
            
            return null;
        }

        @Override
        protected void onPostExecute(ArrayList<T> result)
        {
            if (_exception != null)
            {
               _moreToLoad = false;
               ErrorDialog.display(getContext(), "Error", "Error loading data."); 
            }
            else if (result != null)
            {
                if (result.size() == 0)
                {
                    _moreToLoad = false;
                }
                else
                {
                    for (T item : result)
                        add(item);
                }
            }
            
            // dataset changed, either there are new items, or the count went down (no more "Loading")
            notifyDataSetChanged();
            _loadingView = null;
            
            // if there wasn't an error, run the after process
            if (_moreToLoad)
                afterDisplay();
        }
    }
    
}

@@ -75,16 +75,39 @@
 il.List;
+%0Aimport java.util.UUID;
 %0A%0Aimport
@@ -742,24 +742,52 @@
 oad = true;%0A
+    private UUID _uniqueId;%0A
     %0A    Lay
@@ -1160,16 +1160,55 @@
 bjects;%0A
+        _uniqueId = UUID.randomUUID();%0A
     %7D%0A  
@@ -2215,24 +2215,63 @@
 iew = null;%0A
+        _uniqueId = UUID.randomUUID();%0A
     %7D%0A    %0A 
@@ -2649,16 +2649,25 @@
 execute(
+_uniqueId
 );%0A     
@@ -3086,20 +3086,20 @@
 yncTask%3C
-Void
+UUID
 , Void, 
@@ -3144,24 +3144,49 @@
 _exception;%0A
+        UUID _loadingId;%0A
         %0A   
@@ -3246,20 +3246,20 @@
 kground(
-Void
+UUID
 ... arg0
@@ -3262,32 +3262,66 @@
 arg0)%0A        %7B%0A
+            _loadingId = arg0%5B0%5D;%0A
             try%0A
@@ -3666,32 +3666,298 @@
 sult)%0A        %7B%0A
+            // user did something to invalidate the previous request%0A            if (!_loadingId.equals(_uniqueId))%0A            %7B%0A                Log.i(%22DroidChatty%22, %22Stale unique ID, discarding loaded results.%22);%0A                return;%0A            %7D%0A            %0A
             if (

Discard results of requests that have been abandoned.