package foreign.util;

import nova.Machine;
import nova.runtime;
import nova.special;
import nova.Store;

import java.io.*;

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

    /****************************************************************/
    /* 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.
     */
    private static boolean test_directory_files(Object[] args) {
        Object url = Machine.exec_build(args[0]);
        special.check_atom(url);

        File file = runtime.findWrite(runtime.codebase, (String) url);

        String[] entries = file.list();
        if (entries == null) {
            if (!file.exists()) {
                throw Machine.make_error(new Store.Compound("existence_error",
                        new Object[]{"source_sink", url}));
            } else {
                throw Machine.make_error(new Store.Compound("resource_error",
                        new Object[]{"io_exception"}));
            }
        }

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

    /**
     * file_exists(F):
     * The predicate succeeds if the file F exists, otherwise fails.
     */
    private static boolean test_file_exists(Object[] args) {
        Object url = Machine.exec_build(args[0]);
        special.check_atom(url);

        File file = runtime.findWrite(runtime.codebase, (String) url);
        return file.exists();
    }

    /**
     * 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.
     */
    private static boolean test_make_directory(Object[] args) {
        Object url = Machine.exec_build(args[0]);
        special.check_atom(url);

        File file = runtime.findWrite(runtime.codebase, (String) url);
        if (!file.mkdir()) {
            if (!file.exists()) {
                throw Machine.make_error(new Store.Compound("existence_error",
                        new Object[]{"source_sink", url}));
            } else {
                throw Machine.make_error(new Store.Compound("resource_error",
                        new Object[]{"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.
     */
    private static boolean test_delete_file(Object[] args) {
        Object url = Machine.exec_build(args[0]);
        special.check_atom(url);

        File file = runtime.findWrite(runtime.codebase, (String) url);
        if (file.isDirectory() || !file.delete()) {
            if (!file.exists()) {
                throw Machine.make_error(new Store.Compound("existence_error",
                        new Object[]{"source_sink", url}));
            } else {
                throw Machine.make_error(new Store.Compound("resource_error",
                        new Object[]{"io_exception"}));
            }
        }
        return true;
    }

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

    public static void main() {
        Store.add("directory_files", 2, special.make_check(oslib::test_directory_files));
        Store.add("file_exists", 1, special.make_check(oslib::test_file_exists));
        Store.add("make_directory", 1, special.make_check(oslib::test_make_directory));
        Store.add("delete_file", 1, special.make_check(oslib::test_delete_file));
    }

}
