package com.ghostflying.portalwaitinglist.loader;

import android.content.AsyncTaskLoader;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;

import com.ghostflying.portalwaitinglist.dao.datahelper.PortalEventHelper;
import com.ghostflying.portalwaitinglist.dao.dbinfo.PortalEventDbInfo;
import com.ghostflying.portalwaitinglist.model.PortalDetail;
import com.ghostflying.portalwaitinglist.model.PortalEvent;
import com.ghostflying.portalwaitinglist.util.MailProcessUtil;
import com.ghostflying.portalwaitinglist.util.SettingUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

/**
 * Created by ghostflying on 1/20/15.
 */
public class PortalListLoader extends AsyncTaskLoader<PortalListLoader.PortalListViewModel> {
    private long rowId = -1;
    private List<PortalDetail> totalPortals;
    private PortalListViewModel mViewModel;
    private Action mAction;
    private PortalEventHelper mHelper;
    private ContentObserver mContentObserver;
    private Observer mSettingObserver;
    private boolean isObserved;

    public PortalListLoader(Context context){
        super(context);
        totalPortals = new ArrayList<>();
        mAction = Action.GET_DATA;
        isObserved = false;
        mContentObserver = new PartUpdateContentObserver();
    }

    @Override
    public PortalListViewModel loadInBackground() {
        if (mHelper == null){
            mHelper = new PortalEventHelper(getContext());
            mSettingObserver = new SettingObserver();
        }
        setObserver();
        PortalListViewModel viewModel = new PortalListViewModel();
        if (mViewModel != null)
            viewModel.counts = mViewModel.counts;
        switch (mAction){
            case GET_DATA:
                doGetData(viewModel);
                break;
            case SORT:
                doSort(viewModel);
                break;
            case FILTER:
            default:
                doFilter(viewModel);
                break;
        }
        mAction = Action.DONE;
        return viewModel;
    }

    private void setObserver() {
        if (!isObserved){
            mHelper.setContentObserver(mContentObserver);
            SettingUtil.registerObserver(mSettingObserver);
            isObserved = true;
        }
    }

    private void doGetData(PortalListViewModel viewModel){
        MailProcessUtil mProcessUtil = MailProcessUtil.getInstance();
        Cursor mCursor = mHelper.getAll(rowId);
        try {
            List<PortalEvent> portalEvents = mHelper.fromCursor(mCursor);
            if (portalEvents.size() != 0){
                mCursor.moveToLast();
                rowId = mCursor.getLong(mCursor.getColumnIndex(PortalEventDbInfo._ID));
                mProcessUtil.mergeEvents(totalPortals, portalEvents);
            }
        }
        finally {
            mCursor.close();
        }
        viewModel.counts = mProcessUtil.getCounts(totalPortals);
        viewModel.totalPortals = totalPortals;
        doFilter(viewModel);
        viewModel.mAction = Action.GET_DATA;
    }

    private void doFilter(PortalListViewModel viewModel){
        MailProcessUtil mProcessUtil = MailProcessUtil.getInstance();
        mProcessUtil.filterAndSort(
                SettingUtil.getTypeFilterMethod(),
                SettingUtil.getResultFilterMethod(),
                SettingUtil.getSortOrder(),
                totalPortals,
                viewModel.mPortals
        );
        viewModel.totalPortals = totalPortals;
        viewModel.mAction = Action.FILTER;
    }

    private void doSort(PortalListViewModel viewModel){
        MailProcessUtil mProcessUtil = MailProcessUtil.getInstance();
        viewModel.mPortals = mViewModel.mPortals;
        mProcessUtil.sortPortalDetails(
                SettingUtil.getSortOrder(),
                viewModel.mPortals
        );
        viewModel.totalPortals = totalPortals;
        viewModel.mAction = Action.SORT;
    }

    @Override
    public void deliverResult(PortalListViewModel viewModel){
        mViewModel = viewModel;
        if (isStarted()){
            super.deliverResult(viewModel);
        }
    }

    @Override
    protected void onStartLoading(){
        if (mViewModel != null){
            deliverResult(mViewModel);
        }

        if (mHelper != null){
            setObserver();
        }

        if (takeContentChanged() || mViewModel == null){
            forceLoad();
        }
    }

    @Override
    protected void onStopLoading(){
        cancelLoad();
        SettingUtil.unregisterObserver();
        if (mHelper != null)
            mHelper.unregisterContentObserver(mContentObserver);
        isObserved = false;
    }

    @Override
    protected void onReset(){
        super.onReset();

        onStopLoading();
        mViewModel = null;
    }

    public enum Action{
        GET_DATA, FILTER, SORT, DONE
    }

    public class PortalListViewModel{
        public List<PortalDetail> mPortals;
        public List<PortalDetail> totalPortals;
        public int[] counts;
        public Action mAction;

        public PortalListViewModel(){
            mPortals = new ArrayList<>();
        }
    }

    public class PartUpdateContentObserver extends ContentObserver{

        public PartUpdateContentObserver() {
            super(new Handler());
        }

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

        @Override
        public void onChange(boolean selfChange) {
            mAction = Action.GET_DATA;
            onContentChanged();
        }
    }

    public class SettingObserver implements Observer{

        @Override
        public void update(Observable observable, Object data) {
            if (data instanceof SettingUtil.SortOrder){
                mAction = Action.SORT;
            }
            else {
                mAction = Action.FILTER;
            }
            onContentChanged();
        }
    }
}
