package de.duehl.basics.start;

import de.duehl.basics.debug.DebugHelper;
import de.duehl.basics.retry.Retry;

public class RetryCascade {

    private static final int NUMBER_OF_OUTER_TRIES = 3;
    private static final int NUMBER_OF_INNER_TRIES = 2;

    private static final long MILLIS_TO_SLEEP_OUTER = 1000;
    private static final long MILLIS_TO_SLEEP_INNER = 10;

    public static void main(String[] args) {
        new RetryCascade().retryCascade();
    }

    private final boolean throwExceptionInInnerLoopStep;
    private int outer;
    private int inner;

    public RetryCascade() {
        throwExceptionInInnerLoopStep = true;
    }

    public void retryCascade() {
        log("Start");

        outer = 0;
        inner = 0;
        outerLoop();

        log("Ende");
    }

    private void outerLoop() {
        log("Start");

        Retry retry = new Retry(this::outerLoopStep, NUMBER_OF_OUTER_TRIES, MILLIS_TO_SLEEP_OUTER);
        retry.tryAndTry();
        if (!retry.isSucessfullyDone()) {
            log("Outer: Ganz und gar kein Erfolg in allen Versuchen.");
        }

        log("Ende");
    }

    private void outerLoopStep() {
        ++outer;
        log("Start outer Loop Step " + outer);

        innerLoop();

        log("Ende outer Loop Step " + outer);
    }

    /** Der innere Loop probiert bei Misserfolg alle Proxies einmal durch. */
    private void innerLoop() {
        log("Start");

        Retry retry = new Retry(this::innerLoopStep, NUMBER_OF_INNER_TRIES, MILLIS_TO_SLEEP_INNER);
        retry.tryAndTry();
        if (!retry.isSucessfullyDone()) {
            log("Inner: Ganz und gar kein Erfolg in allen Versuchen.");
            throw new RuntimeException("Inner loop not successfull!");
        }

        log("Ende");
    }

    private void innerLoopStep() {
        ++inner;
        log("Start inner Loop Step " + inner);

        if (throwExceptionInInnerLoopStep) {
            log("Hier geht nun was schief!");
            throw new RuntimeException("Padauz!");
        }

        log("Ende inner Loop Step " + inner);
    }

    /** Loggt die übergebene Nachricht. */
    private void log(String message) {
        DebugHelper.sayWithClassAndMethodAndTime(message);
    }

}
