package nova;

import java.util.*;
import java.util.concurrent.*;

/**
 * Warranty & Liability
 * To the extent permitted by applicable law and unless explicitly
 * otherwise agreed upon, XLOG Technologies AG makes no warranties
 * regarding the provided information. XLOG Technologies AG assumes
 * no liability that any problems might be solved with the information
 * provided by XLOG Technologies AG.
 *
 * Rights & License
 * All industrial property rights regarding the information - copyright
 * and patent rights in particular - are the sole property of XLOG
 * Technologies AG. If the company was not the originator of some
 * excerpts, XLOG Technologies AG has at least obtained the right to
 * reproduce, change and translate the information.
 *
 * Reproduction is restricted to the whole unaltered document. Reproduction
 * of the information is only allowed for non-commercial uses. Selling,
 * giving away or letting of the execution of the library is prohibited.
 * The library can be distributed as part of your applications and libraries
 * for execution provided this comment remains unchanged.
 *
 * Restrictions
 * Only to be distributed with programs that add significant and primary
 * functionality to the library. Not to be distributed with additional
 * software intended to replace any components of the library.
 *
 * Trademarks
 * Jekejeke is a registered trademark of XLOG Technologies AG.
 */
public final class Handler {

    /**
     * make_special(), flags=MASK_PRED_SPECIAL
     */
    public static interface Builtin {
        public abstract Object run(Object[] args);
    }

    /**
     * make_check(), flags=MASK_PRED_TEST
     */
    public static interface Check {
        public abstract boolean run(Object[] args);
    }

    /**
     * make_arithmetic(), flags=MASK_PRED_ARITH
     * Use german spelling to distinguish from Function
     */
    public static interface Funktion {
        public abstract Number eval(Object[] obj);
    }

    /**
     * Choice point callback.
     */
    public static interface Callback {
        public abstract Object run(Object rope, int at, Machine.Choice choice);
    }

    /**
     * A runtime exception with a Prolog term.
     */
    public static class Problem extends RuntimeException {
        public Object term;

        public Problem(Object term) {
            this.term = term;
        }
    }

    /**
     * An array list which exposes removeRange.
     */
    public static class Rope extends ArrayList {

        public void removeRange(int f, int t) {
            super.removeRange(f, t);
        }

    }

    /******************************************************************/
    /* Synchronous Streams                                            */
    /******************************************************************/

    public static interface Sender {
        public abstract Object eval(Object data, String buf);
    }

    public static interface Receiver {
        public abstract String eval(Object data);
    }

    public static interface Notifier {
        public abstract void run(Object data);
    }

    public static interface Releaser {
        public abstract void run(Object data);
    }

    /******************************************************************/
    /* Surrogate async/await                                          */
    /******************************************************************/

    public static Semaphore bouncer = new Semaphore(0, true);

    public static class Promise {
        Runnable proc;

        public Promise(Runnable proc) {
            this.proc = proc;
        }

        public void await() {
            bouncer.release();
            try {
                proc.run();
            } finally {
                bouncer.acquireUninterruptibly();
            }
        }

    }

    public static class Coroutine {
        Runnable proc;

        public Coroutine(Runnable proc) {
            this.proc = proc;
        }

        public void async() {
            new Thread(() -> {
                bouncer.acquireUninterruptibly();
                try {
                    proc.run();
                } finally {
                    bouncer.release();
                }
            }).start();
        }
    }

    /******************************************************************/
    /* Asynchronous Streams                                           */
    /******************************************************************/

    public static interface Factory {
        public abstract Promise eval(Object buf, runtime.Source stream);
    }

    /******************************************************************/
    /* Contour Walk                                                   */
    /******************************************************************/

    public static interface Acceptor {
        public abstract boolean run(Object node);
    }

    public static class RangeException extends RuntimeException {
        private final Object obj;

        public RangeException(String s, Object o) {
            super(s);
            obj = o;
        }

        public Object getCulprit() {
            return obj;
        }

    }

}
