package de.sebse.fuplanner.tools;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Iterator;

public abstract class DateSortedList<T> extends ArrayList<T> {
    private int split = -1;
    private boolean mSorting = false;

    public T getPast(int index) {
        if (split < 0)
            sort();
        if (index >= this.sizePast())
            throw new ArrayIndexOutOfBoundsException(String.format("Index %d out of bounds! Only %d past events found!", index, split));
        if (reversed())
            index += sizeUpcoming();
        return this.get(index);
    }

    public T getUpcoming(int index) {
        if (split < 0)
            sort();
        if (index >= this.sizeUpcoming())
            throw new ArrayIndexOutOfBoundsException(String.format("Index %d out of bounds! Only %d upcoming events found!", index-split, this.size()-split));
        if (!reversed())
            index += this.sizePast();
        return this.get(index);
    }

    @Override
    public T get(int index) {
        if (mSorting) return super.get(index);
        if (split < 0)
            sort();
        if (reversed())
            index = size() - 1 - index;
        return super.get(index);
    }

    public int sizePast() {
        if (split < 0)
            sort();
        return split;
    }

    public int sizeUpcoming() {
        if (split < 0)
            sort();
        return this.size()-split;
    }

    public boolean add(T event) {
        split = -1;
        return super.add(event);
    }

    public void sort() {
        mSorting = true;
        Collections.sort(this, ((e1, e2) -> Long.compare(getDateByItem(e1), getDateByItem(e2))));
        long now = System.currentTimeMillis();
        split = 0;
        for (T event: this) {
            if (getDateByItem(event) < now)
                split++;
            else
                break;
        }
        mSorting = false;
    }

    public Iterator<T> getEventsOfMonth(int year, int month) {
        if (split < 0)
            sort();
        final int[] i = {0};
        Calendar minC = Calendar.getInstance();
        minC.set(year, month-1, 1, 0, 0);
        Calendar maxC = Calendar.getInstance();
        maxC.set(year, month, 1, 0, 0);
        for (; i[0] < this.size(); i[0]++) {
            if (getDateByItem(this.get(i[0])) > minC.getTimeInMillis()) {
                break;
            }
        }
        return new Iterator<T>() {
            @Override
            public boolean hasNext() {
                return i[0] < DateSortedList.this.size() && getDateByItem(DateSortedList.this.get(i[0])) < maxC.getTimeInMillis();
            }

            @Override
            public T next() {
                if (hasNext()) {
                    return DateSortedList.this.get(i[0]++);
                } else {
                    return null;
                }
            }
        };
    }

    protected boolean reversed() {
        return false;
    }

    protected abstract long getDateByItem(T item);
}
