package shapes77.util;
/* Saved in UTF-8 codepage: Příliš žluťoučký kůň úpěl ďábelské ódy. ÷ × ¤ */



/*******************************************************************************
 * Instance třídy {@code Repeater} umožňují opakování zadaných akcí
 * na pozadí, tj. bez čekání na jejich dokončení.
 *
 * @author  Rudolf PECINOVSKÝ
 * @version 2021-Winter
 */
public class Repeater
{
//== CONSTANT CLASS ATTRIBUTES =================================================

    /** Hodnota reprezentující nekonečné opakování. */
    private static final int NONSTOP = -2;



//== VARIABLE CLASS ATTRIBUTES =================================================



//##############################################################################
//== STATIC INITIALIZER (CLASS CONSTRUCTOR) ====================================
//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================
//== PRIVATE AND AUXILIARY CLASS METHODS =======================================



//##############################################################################
//== CONSTANT INSTANCE ATTRIBUTES ==============================================
//== VARIABLE INSTANCE ATTRIBUTES ==============================================

    /** Opakovač je zrovna zaměstnán. */
    private volatile boolean running = false;

    /** Byl vydán požadavek k zastavení. */
    private volatile boolean stop = false;



//##############################################################################
//== CONSTRUCTORS AND FACTORY METHODS ==========================================

    /***************************************************************************
     *
     */
    public Repeater()
    {
    }



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================
//== OTHER NON-PRIVATE INSTANCE METHODS ========================================

    /***************************************************************************
     * Opakuje metodu parametru akce přičemž počet opakování je zadán
     * v parametru počet.
     *
     * @param  times    Požadovaný počet opakování, 0=pořád
     * @param  action Instance, jejíž metoda run() bude opakována
     */
    public synchronized void repeat(final int times, final Runnable action)
    {
        repeat(times, action, () -> {});
    }


    /***************************************************************************
     * Opakuje metodu parametru akce přičemž počet opakování je zadán
     * v parametru počet.
     *
     * @param times    Požadovaný počet opakování, 0=pořád
     * @param action   Instance, jejíž metoda run() bude opakována
     * @param finished Metoda vyvolávaná po ukončení posledního opakování
     */
    public synchronized void repeat(final int times, final Runnable action,
                                    final Runnable finished)
    {
        if (running) {
            throw new RuntimeException(
                "\nDokud je opakovač zaměstnán, není možné jej použít znovu");
        }
        if (times < 0) {
            throw new IllegalArgumentException(
                    "\nNeplatný počet opakování: " + times);
        }
        running = true;
        stop    = false;
        new Thread(""+action) {
            int remains = ((times == 0) ?  NONSTOP  :  times);
            @Override
            public void run() {
                do {
                    action.run();
                }while (! stop  &&
                        ((remains == NONSTOP)  ||  (--remains > 0)));
                running = false;
                finished.run();
            }
        }.start();
    }


    /***************************************************************************
     * Zastaví opakování prováděná daným opakovačem.
     */
    public synchronized void stop()
    {
        stop = true;
    }



//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================



//##############################################################################
//== NESTED DATA TYPES =========================================================
}
