import nova.*;
import nova.runtime;
import jdk.internal.misc.Signal;

import java.io.*;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.function.BiFunction;

/**
 * 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 Dogelog {

    /**
     * Setup the Prolog interpreter.
     */
    public static void init() {
        Store.set_stage(0);
        Store.set_partition("user");
    }

    /**************************************************************/
    /* Plain Console                                              */
    /**************************************************************/

    private static Object plain_out(Object data, String buf) {
        try {
            ((Writer) data).write(buf);
            return data;
        } catch (IOException err) {
            throw Machine.make_error(runtime.map_stream_error(err));
        }
    }

    private static void plain_flush(Object data) {
        try {
            ((Writer) data).flush();
        } catch (IOException err) {
            throw Machine.make_error(runtime.map_stream_error(err));
        }
    }

    /**************************************************************/
    /* When Main                                                  */
    /**************************************************************/

    private static void ctrlc_abort(Signal sig) {
        theatre.post(new Store.Compound("system_error",
                new Object[]{"user_abort"}));
    }

    private static void dogelog_async(Object[] args) {
        Signal.Handler back = Signal.handle(new Signal("INT"), Dogelog::ctrlc_abort);
        try {
            init();
            theatre.perform("sys_baseline");
            if (args.length > 0) {
                theatre.perform_async("sys_launch");
            } else {
                runtime.Sink dst = Store.engine.text_output;
                dst.flags |= nova.runtime.MASK_DST_FEAT;

                dst = Store.engine.text_error;
                dst.flags |= nova.runtime.MASK_DST_FEAT;

                theatre.perform_async("sys_launch");
            }
        } finally {
            Signal.handle(new Signal("INT"), back);
        }
    }

    public static void main(String[] args) throws IOException, URISyntaxException {
        theatre.core(args);

        runtime.Sink dst = new runtime.Sink();
        dst.data = new OutputStreamWriter(System.out, StandardCharsets.UTF_8);
        dst.send = Dogelog::plain_out;
        dst.notify = Dogelog::plain_flush;
        dst.flags |= runtime.MASK_DST_LINE;
        Store.engine.text_output = dst;

        dst = new runtime.Sink();
        dst.data = new OutputStreamWriter(System.err, StandardCharsets.UTF_8);
        dst.send = Dogelog::plain_out;
        dst.notify = Dogelog::plain_flush;
        dst.flags |= runtime.MASK_DST_LINE;
        Store.engine.text_error = dst;

        runtime.Source src = new runtime.Source();
        src.data = new InputStreamReader(System.in, StandardCharsets.UTF_8);
        src.receive = (BiFunction<Object, runtime.Source, Handler.Promise>) runtime::file_read_promise;
        src.flags |= runtime.MASK_SRC_AREAD;
        Store.engine.text_input = src;

        try {
            dogelog_async(args);
        } catch (Handler.Problem err) {
            theatre.perform(new Store.Compound("sys_print_error", new Object[]{err.term}));
            System.exit(1);
        }
    }

}
