package com.github.tibolte.agendacalendarview.utils;

import com.github.tibolte.agendacalendarview.agenda.AgendaListView;

import android.util.SparseArray;
import android.view.View;

/**
 * Helper class calculating the scrolling distance in the AgendaListView.
 */
public class ListViewScrollTracker {
    private AgendaListView mListView;
    private SparseArray<Integer> mPositions;
    private SparseArray<Integer> mListViewItemHeights = new SparseArray<>();
    private int mFirstVisiblePosition;
    private int mReferencePosition = -1; // Position of the current date in the Agenda listView

    // region Constructor and Accessor(s)

    public ListViewScrollTracker(AgendaListView listView) {
        mListView = listView;
    }

    public int getReferencePosition() {
        return mReferencePosition;
    }

    // endregion

    // region Public methods

    /**
     * Call from an AbsListView.OnScrollListener to calculate the incremental offset (change in
     * scroll offset
     * since the last calculation).
     *
     * @param firstVisiblePosition First visible item position in the list.
     * @param visibleItemCount     Number of visible items in the list.
     * @return The incremental offset, or 0 if it wasn't possible to calculate the offset.
     */
    public int calculateIncrementalOffset(int firstVisiblePosition, int visibleItemCount) {
        // Remember previous positions, if any
        SparseArray<Integer> previousPositions = mPositions;

        // Store new positions
        mPositions = new SparseArray<>();
        for (int i = 0; i < visibleItemCount; i++) {
            mPositions.put(firstVisiblePosition + i, mListView.getListChildAt(i).getTop());
        }

        if (previousPositions != null) {
            // Find position which exists in both mPositions and previousPositions, then return the difference
            // of the new and old Y values.
            for (int i = 0; i < previousPositions.size(); i++) {
                int previousPosition = previousPositions.keyAt(i);
                int previousTop = previousPositions.get(previousPosition);
                Integer newTop = mPositions.get(previousPosition);
                if (newTop != null) {
                    return newTop - previousTop;
                }
            }
        }

        return 0; // No view's position was in both previousPositions and mPositions
    }

    /**
     * Call from an AbsListView.OnScrollListener to calculate the scrollY (Here
     * we definite as the distance in pixels compared to the position representing the current
     * date).
     *
     * @param firstVisiblePosition First visible item position in the list.
     * @param visibleItemCount     Number of visible items in the list.
     * @return Distance in pixels compared to current day position (negative if firstVisiblePosition less than mReferencePosition)
     */
    public int calculateScrollY(int firstVisiblePosition, int visibleItemCount) {
        mFirstVisiblePosition = firstVisiblePosition;
        if (mReferencePosition < 0) {
            mReferencePosition = mFirstVisiblePosition;
        }

        if (visibleItemCount > 0) {
            View c = mListView.getListChildAt(0); // this is the first visible row
            int scrollY = -c.getTop();
            mListViewItemHeights.put(firstVisiblePosition, c.getMeasuredHeight());

            if (mFirstVisiblePosition >= mReferencePosition) {
                for (int i = mReferencePosition; i < firstVisiblePosition; ++i) {
                    if (mListViewItemHeights.get(i) == null) {
                        mListViewItemHeights.put(i, c.getMeasuredHeight());
                    }
                    scrollY += mListViewItemHeights.get(i); // add all heights of the views that are gone
                }
                return scrollY;
            } else {
                for (int i = mReferencePosition - 1; i >= firstVisiblePosition; --i) {
                    if (mListViewItemHeights.get(i) == null) {
                        mListViewItemHeights.put(i, c.getMeasuredHeight());
                    }
                    scrollY -= mListViewItemHeights.get(i);
                }
                return scrollY;
            }

        }
        return 0;
    }

    public void clear() {
        mPositions = null;
    }

    // endregion
}
