package com.fsck.k9.cache;

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

import com.fsck.k9.provider.EmailProvider.MessageColumns;
import com.fsck.k9.provider.EmailProvider.ThreadColumns;

import android.content.Context;
import android.database.Cursor;
import android.database.CursorWrapper;

/**
 * A {@link CursorWrapper} that utilizes {@link EmailProviderCache}.
 */
public class EmailProviderCacheCursor extends CursorWrapper {
    private EmailProviderCache mCache;
    private List<Integer> mHiddenRows = new ArrayList<Integer>();
    private int mMessageIdColumn;
    private int mFolderIdColumn;
    private int mThreadRootColumn;

    /**
     * The cursor's current position.
     *
     * Note: This is only used when {@link #mHiddenRows} isn't empty.
     */
    private int mPosition;


    public EmailProviderCacheCursor(String accountUuid, Cursor cursor, Context context) {
        super(cursor);

        mCache = EmailProviderCache.getCache(accountUuid, context);

        mMessageIdColumn = cursor.getColumnIndex(MessageColumns.ID);
        mFolderIdColumn = cursor.getColumnIndex(MessageColumns.FOLDER_ID);
        mThreadRootColumn = cursor.getColumnIndex(ThreadColumns.ROOT);

        if (mMessageIdColumn == -1 || mFolderIdColumn == -1 || mThreadRootColumn == -1) {
            throw new IllegalArgumentException("The supplied cursor needs to contain the " +
                    "following columns: " + MessageColumns.ID + ", " + MessageColumns.FOLDER_ID +
                    ", " + ThreadColumns.ROOT);
        }

        while (cursor.moveToNext()) {
            long messageId = cursor.getLong(mMessageIdColumn);
            long folderId = cursor.getLong(mFolderIdColumn);
            if (mCache.isMessageHidden(messageId, folderId)) {
                mHiddenRows.add(cursor.getPosition());
            }
        }

        // Reset the cursor position
        cursor.moveToFirst();
        cursor.moveToPrevious();
    }

    @Override
    public int getInt(int columnIndex) {
        long messageId = getLong(mMessageIdColumn);
        long threadRootId = getLong(mThreadRootColumn);

        String columnName = getColumnName(columnIndex);
        String value = mCache.getValueForMessage(messageId, columnName);

        if (value != null) {
            return Integer.valueOf(value);
        }

        value = mCache.getValueForThread(threadRootId, columnName);
        if (value != null) {
            return Integer.valueOf(value);
        }

        return super.getInt(columnIndex);
    }

    @Override
    public int getCount() {
        return super.getCount() - mHiddenRows.size();
    }

    @Override
    public boolean moveToFirst() {
        return moveToPosition(0);
    }

    @Override
    public boolean moveToLast() {
        return moveToPosition(getCount());
    }

    @Override
    public boolean moveToNext() {
        return moveToPosition(getPosition() + 1);
    }

    @Override
    public boolean moveToPrevious() {
        return moveToPosition(getPosition() - 1);
    }

    @Override
    public boolean move(int offset) {
        return moveToPosition(getPosition() + offset);
    }

    @Override
    public boolean moveToPosition(int position) {
        if (mHiddenRows.size() == 0) {
            return super.moveToPosition(position);
        }

        mPosition = position;
        int newPosition = position;
        for (int hiddenRow : mHiddenRows) {
            if (hiddenRow > newPosition) {
                break;
            }
            newPosition++;
        }

        return super.moveToPosition(newPosition);
    }

    @Override
    public int getPosition() {
        if (mHiddenRows.size() == 0) {
            return super.getPosition();
        }

        return mPosition;
    }

    @Override
    public boolean isLast() {
        if (mHiddenRows.isEmpty()) {
            return super.isLast();
        }

        return (mPosition == getCount() - 1);
    }
}
