
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;

import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodType.methodType;

/**
 * @author Anastasiya Solodkaya.
 */
public class PossibleProblems {

    private static boolean printTrace = true;

    public static void main(String[] args) throws Throwable {
        run(1, -10);
        run(1, 0);
        run(Integer.MAX_VALUE - 1, Integer.MIN_VALUE + 10);
        run(Integer.MIN_VALUE, Integer.MIN_VALUE + 4, 4);
        run(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1, 1);
        run(Integer.MAX_VALUE - 1, 0, 0);
        run(Integer.MAX_VALUE - 1, 10, 0);
        run(Integer.MAX_VALUE - 1, -10, 0);
        run(Integer.MAX_VALUE, Integer.MIN_VALUE + 10);
        run(Integer.MAX_VALUE - 1, Integer.MAX_VALUE, 1);
        run(Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
    }

    private static void run(int start, int end) {
        run(start, end, 0);
    }

    private static void run(int start, int end, int expectedIterations) {
        try {
            System.out.printf("Run with values %d ... %d:%n", start, end);
            MethodHandle loop = MethodHandles.countedLoop(
                    MethodHandles.constant(int.class, start), MethodHandles.constant(int.class, end),
                    MethodSets.mh("init", void.class), MethodSets.mh("body", void.class, int.class));
            loop.invoke();
            System.out.printf(String.format("%s. Itearated %d times. Expected %d iterations. %n", MethodSets.count == expectedIterations ? "OK: " : "FAIL: ", MethodSets.count, expectedIterations));
            System.out.printf("---------------- %n%n");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }


    static class MethodSets {
        static long count = 0;

        static void body(int s) {
            count++;
            if (printTrace) {
                System.out.println(s);
            }
        }

        static void init() {
            count = 0;
        }

        protected static MethodHandle mh(String methodName, Class returnType, Class... params) {
            try {
                return lookup().findStatic((Class) MethodSets.class, methodName, methodType(returnType, params));
            } catch (NoSuchMethodException | IllegalAccessException e) {
                throw new RuntimeException("Unexpected exception: " + e.getMessage());
            }
        }

    }
}
