/**
 * Modern Albufeira Prolog Interpreter
 *
 * 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.
 */

import {
    get_engine, Compound, set_stage, set_partition, stream_flush,
    stream_close, fiddle_out, html_send, fiddle_flush
} from "./nova/core.mjs";
import {
    fs, url, make_error
} from "./nova/core.mjs";
import {
    get_bootbase, Source, set_bootbase, Sink, set_codebase,
    MASK_SRC_AREAD, map_stream_error, file_read_promise,
    MASK_DST_FEAT, MASK_DST_LINE
} from "./nova/core.mjs";
import {
    post, perform, perform_async, instrument_document_async
} from "./nova/core.mjs";

/**
 * Setup the Prolog interpreter.
 */
export function init() {
    set_stage(0);
    set_partition("user");
}

/**
 * Setup the Prolog interpreter and do the document instrumentation.
 */
export async function notebook_async() {
    let spec = new Compound("library",["misc/react"]);
    await perform_async(new Compound("ensure_loaded", [spec]));
    spec = new Compound("library",["tester/session"]);
    await perform_async(new Compound("ensure_loaded", [spec]));
    init();
    await instrument_document_async();
}

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

function plain_out(data, buf) {
    try {
        fs.writeSync(data, buf);
        return data;
    } catch (err) {
        throw make_error(map_stream_error(err));
    }
}

/**************************************************************/
/* When Main or Browser                                       */
/**************************************************************/

function ctrlc_abort() {
    post(new Compound("system_error", ["user_abort"]));
}

/**
 * Simply colored process standard input/output.
 */
async function dogelog_async() {
    process.on("SIGINT", ctrlc_abort);
    try {
        init();
        perform("sys_baseline");
        if (process.argv.length > 2) {
            await perform_async("sys_launch");
        } else {
            let dst = get_engine().text_output;
            dst.flags |= MASK_DST_FEAT;

            dst = get_engine().text_error;
            dst.flags |= MASK_DST_FEAT;

            await perform_async("sys_launch");
        }
    } finally {
        process.off("SIGINT", ctrlc_abort);
        if (fs !== undefined)
            delete globalThis.navigator.gpu;
    }
}

if (fs !== undefined) {
    set_bootbase(url.fileURLToPath(import.meta.url));

    let dst = new Sink();
    dst.buf = "";
    dst.data = process.stdout.fd;
    dst.send = plain_out;
    dst.flags |= MASK_DST_LINE;
    get_engine().text_output = dst;

    dst = new Sink();
    dst.buf = "";
    dst.data = process.stderr.fd;
    dst.send = plain_out;
    dst.flags |= MASK_DST_LINE;
    get_engine().text_error = dst;

    let src = new Source();
    src.data = 0;
    src.receive = (buf, stream) => file_read_promise("utf8", buf, stream);
    src.partial = Buffer.alloc(0);
    src.flags |= MASK_SRC_AREAD;
    get_engine().text_input = src;

    if (get_bootbase() === process.argv[1])
        (async () => {
            try {
                await dogelog_async()
            } catch (err) {
                perform(new Compound("sys_print_error", [err]));
                process.exit(1);
            }
        })();
} else {
    set_bootbase(import.meta.url);

    let dom = new Sink();
    dom.buf = "";
    dom.data = document.body;
    dom.send = fiddle_out;
    dom.notify = fiddle_flush;

    let dst = new Sink();
    dst.data = dom;
    dst.send = html_send;
    dst.notify = stream_flush;
    dst.release = stream_close;
    dst.flags |= MASK_DST_LINE;
    get_engine().text_output = dst;

    dom = new Sink();
    dom.buf = "";
    dom.data = document.body;
    dom.send = fiddle_out;
    dom.notify = fiddle_flush;

    dst = new Sink();
    dst.data = dom;
    dst.send = html_send;
    dst.notify = stream_flush;
    dst.release = stream_close;
    dst.flags |= MASK_DST_LINE;
    get_engine().text_error = dst;

    let src = new Source();
    get_engine().text_input = src;

    if (self.document !== undefined)
        set_codebase(document.URL);
}