package org.academiadecodigo.bootcamp11.integerrange;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class IntegerRange implements Iterable<Integer> {
    private Integer min;
    private Integer max;
    private Integer interval;
    private LinkedList<Integer> removed = new LinkedList<>();

    public IntegerRange(Integer max) {
        this.min = 0;
        this.interval = 1;

        this.max = max;
        showInfo();
    }

    public IntegerRange(Integer min, Integer max) {
        this.interval = 1;

        this.min = min;
        this.max = max;
        showInfo();
    }

    public IntegerRange(Integer min, Integer max, Integer interval) {
        this.min = min;
        this.max = max;
        this.interval = interval;
        showInfo();
    }

    private void showInfo() {
        System.out.printf("==== min: %d; max: %d; interval: %d ===\n",
                min, max, interval);
    }

    public void reverse() {
        this.interval *= -1;
    }

    public void setInterval(int newInterval) {
        this.interval = newInterval;
        System.out.println("changing interval to " + newInterval);
    }

    public void setAscending() {
        interval = Math.abs(interval);
    }

    public void setDescending() {
        interval = -Math.abs(interval);
    }

    public Iterator<Integer> iterator() {
        // BiDirectionalIterator
        if (min < max && interval < 0 ||
                min > max && interval > 0) {
            int temp = min;
            min = max;
            max = temp;
            System.out.println(min + " " + max);
        }

        return new Iterator<Integer>() {
            private int itMin = min;
            private int itMax = max;
            private int itInterval = interval;
            private Integer lastNext = itMin - itInterval;

            @Override
            public boolean hasNext() {
                while (removed.contains(lastNext + itInterval)) {
                    System.out.println("skipping " + (lastNext+itInterval));
                    lastNext += itInterval;
                }

                return (itInterval > 0) ?
                        lastNext + itInterval < itMax :
                        lastNext + itInterval > itMax;
            }

            @Override
            public Integer next() {
                if (!hasNext()) {
                    throw new NoSuchElementException("there's no next element");
                }
                return lastNext += itInterval;
            }

            @Override
            public void remove() {

                if (lastNext > itMax) {
                    throw new IllegalStateException("you need to run next() once");
                }

                if (removed.contains(lastNext)) {
                    throw new IllegalStateException("remove method has already been called");
                }

                removed.add(lastNext);
            }
        };
    }
}
