/**
 * 
 */
package info.guardianproject.otr.app.im.app;

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

import info.guardianproject.otr.app.im.IImConnection;
import info.guardianproject.otr.app.im.engine.ImConnection;
import info.guardianproject.otr.app.im.provider.Imps;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class AccountAdapter extends CursorAdapter {
    private LayoutInflater mInflater;
    private int mResId;
    private Cursor mStashCursor;
    private AsyncTask<Void, Void, List<AccountSetting>> mBindTask;
    private List<AccountSetting> mAccountSettingList;
    private Listener mListener;

    public AccountAdapter(Activity context,
            LayoutInflater.Factory factory, int resId) {
        super(context, null, 0);
        mInflater = LayoutInflater.from(context).cloneInContext(context);
        mInflater.setFactory(factory);
        mResId = resId;
    }
    
    public void setListener(Listener listener) {
        this.mListener = listener;
    }
    
    @Override
    public Cursor swapCursor(Cursor newCursor) {
        if(mBindTask != null) {
            mBindTask.cancel(false);
            mBindTask = null ;
        }
        mStashCursor = newCursor;
        
        if (mStashCursor != null) {
            // Delay swapping in the cursor until we get the extra info
            List<AccountInfo> accountInfoList = getAccountInfoList(mStashCursor) ;
            runBindTask((Activity)mContext, accountInfoList);
        }
        return super.swapCursor(mStashCursor);
    };
    
    /**
     * @param mStashCursor
     * @return
     */
    private List<AccountInfo> getAccountInfoList(Cursor cursor) {
        List<AccountInfo> aiList = new ArrayList<AccountInfo>();
        cursor.moveToPosition(-1);
        while( cursor.moveToNext() ) {
            aiList.add( getAccountInfo(cursor));
        }
        return aiList;
    }

    static class AccountInfo {
        int providerId;
        String activeUserName;
        int dbConnectionStatus;
        int presenceStatus;
    }
    
    static class AccountSetting {
        String mProviderNameText;
        String mSecondRowText;
        boolean mSwitchOn;
        String activeUserName;
        int connectionStatus ;
        
        String domain;
        String host;
        int port;
        boolean isTor;
        
    }
    
    AccountInfo getAccountInfo( Cursor cursor ) {
        AccountInfo accountInfo = new AccountInfo();
        accountInfo.providerId = cursor.getInt(cursor.getColumnIndexOrThrow(Imps.Provider._ID));
        if (!cursor.isNull(cursor.getColumnIndexOrThrow(Imps.Provider.ACTIVE_ACCOUNT_ID))) {
            accountInfo.activeUserName = cursor.getString(cursor.getColumnIndexOrThrow(Imps.Provider.ACTIVE_ACCOUNT_USERNAME));
            accountInfo.dbConnectionStatus = cursor.getInt(cursor.getColumnIndexOrThrow(Imps.Provider.ACCOUNT_PRESENCE_STATUS));
            accountInfo.presenceStatus = cursor.getInt(cursor.getColumnIndexOrThrow(Imps.Provider.ACCOUNT_CONNECTION_STATUS));
        }
        return accountInfo;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        // create a custom view, so we can manage it ourselves. Mainly, we want to
        // initialize the widget views (by calling getViewById()) in newView() instead of in
        // bindView(), which can be called more often.
        ProviderListItem view = (ProviderListItem) mInflater.inflate(mResId, parent, false);
        view.init(cursor, true);
        return view;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ((ProviderListItem) view).bindView(cursor);
        
        if (mAccountSettingList != null && mAccountSettingList.size() > cursor.getPosition())
            ((ProviderListItem) view).applyView(mAccountSettingList.get(cursor.getPosition()));
    }

    private void runBindTask( final Activity context, final List<AccountInfo> accountInfoList ) {
        final Resources resources = context.getResources();
        final ContentResolver resolver = context.getContentResolver();
        final ImApp mApp = (ImApp)context.getApplication();
        
        // if called multiple times
        if (mBindTask != null)
            mBindTask.cancel(false);
        // 
        mBindTask = new AsyncTask<Void, Void, List<AccountSetting>>() {
            
            @Override
            protected List<AccountSetting> doInBackground(Void... params) {
                List<AccountSetting> accountSettingList = new ArrayList<AccountSetting>();
                for( AccountInfo ai : accountInfoList ) {
                    accountSettingList.add( getAccountSettings(ai) );
                }
                return accountSettingList;
            }
            
            private AccountSetting getAccountSettings(AccountInfo ai) {
                AccountSetting as = new AccountSetting();
                
                final Imps.ProviderSettings.QueryMap settings =
                        new Imps.ProviderSettings.QueryMap(resolver, ai.providerId, false , null);
                
                as.connectionStatus = ai.dbConnectionStatus;
                as.activeUserName = ai.activeUserName;
                as.domain = settings.getDomain();
                as.host = settings.getServer();
                as.port = settings.getPort();
                as.isTor = settings.getUseTor();
                
                IImConnection conn = mApp.getConnection(ai.providerId);
                if (conn == null) {
                    as.connectionStatus = ImConnection.DISCONNECTED;
                } else {
                    try {
                        as.connectionStatus = conn.getState();
                    } catch (RemoteException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                settings.close();
                return as;
            }
            
            @Override
            protected void onPostExecute(List<AccountSetting> result) {
                // store 
                mAccountSettingList = result ;
                mBindTask = null;
                // swap
                AccountAdapter.super.swapCursor(mStashCursor);
                if (mListener != null)
                    mListener.onPopulate();
            }
        };
        mBindTask.execute();
    }
    
    public interface Listener {
        void onPopulate();
    }
}
@@ -4628,16 +4628,70 @@
     // %0A
+        %0A        mAccountSettingList = null;%0A        %0A
         

set mAccountList data to null before async fetch to ensure not stale