/**
 * 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 {add, make_check, exec_unify, fs,
    exec_build, check_atom, make_error, Compound
} from "../../nova/core.mjs";

/*********************************************************************/
/* File Access                                                       */
/*********************************************************************/

/**
 * directory_files(F, L):
 * The predicate succeeds in L with the entries of the directory F.
 * Barks if path F doesn't exist or if path F doesn't point to directory.
 */
function test_directory_files(args) {
    let url = exec_build(args[0]);
    check_atom(url);
    if (fs === undefined)
        throw make_error(new Compound("permission_error", ["access", "source_sink", url]));

    let entries;
    try {
        entries = fs.readdirSync(url !== "" ? url : process.cwd());
    } catch (err) {
        if (err.code === "ENOENT") {
            throw make_error(new Compound("existence_error", ["source_sink", url]));
        } else {
            throw make_error(new Compound("resource_error", ["io_exception"]));
        }
    }

    let res = "[]";
    for (let i = entries.length - 1; i >= 0; i--) {
        let val = entries[i];
        res = new Compound(".", [val, res]);
    }
    return exec_unify(args[1], res);
}

/**
 * file_exists(F):
 * The predicate succeeds if the file F exists, otherwise fails.
 */
function test_file_exists(args) {
    let url = exec_build(args[0]);
    check_atom(url);
    if (fs === undefined)
        throw make_error(new Compound("permission_error", ["access", "source_sink", url]));

    return fs.existsSync(url);
}

/**
 * make_directory(F):
 * The predicate succeeds. As a side effect a directory F is created.
 * Barks if the parent of F doesn't exist or if F already exists.
 */
function test_make_directory(args) {
    let url = exec_build(args[0]);
    check_atom(url);
    if (fs === undefined)
        throw make_error(new Compound("permission_error", ["access", "source_sink", url]));

    try {
        fs.mkdirSync(url);
    } catch (err) {
        if (err.code === "ENOENT") {
            throw make_error(new Compound("existence_error", ["source_sink", url]));
        } else {
            throw make_error(new Compound("resource_error", ["io_exception"]));
        }
    }
    return true;
}

/**
 * delete_file(F):
 * The predicate succeeds. As a side effect the file F is deleted.
 * Barks if the file F doesn't exist or if its a directory.
 */
function test_delete_file(args) {
    let url = exec_build(args[0]);
    check_atom(url);
    if (fs === undefined)
        throw make_error(new Compound("permission_error", ["access", "source_sink", url]));

    try {
        fs.unlinkSync(url);
    } catch (err) {
        if (err.code === "ENOENT") {
            throw make_error(new Compound("existence_error", ["source_sink", url]));
        } else {
            throw make_error(new Compound("resource_error", ["io_exception"]));
        }
    }
    return true;
}

/*********************************************************************/
/* Os Lib Init                                                       */
/*********************************************************************/

export function main() {
    add("directory_files", 2, make_check(test_directory_files));
    add("file_exists", 1, make_check(test_file_exists));
    add("make_directory", 1, make_check(test_make_directory));
    add("delete_file", 1, make_check(test_delete_file));
}