/*
 * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
 *
 * SPDX-FileContributor: Authored By: Gustav Hartvigsson
 */

/*
 * All comments are copid from the GJS source code, but changed to work with
 * valadoc.
 */

/**
 * JavaScript bindings for GNOME
 *
 * Use the GNOME platform libraries in your JavaScript programs.
 * GJS powers GNOME Shell, Polari, GNOME Documents, and many other apps.
 * Under the hood it uses SpiderMonkey, Mozilla's JavaScript engine
 * originally developed for Firefox.
 */
[CCode (cheader_filename = "gjs/gjs.h",
        cprefix = "Gjs",
        lower_case_cprefix = "gjs_")]
namespace Gjs {
  
  
  [CCode (cname = "GjsError", 
          cprefix = "GJS_ERROR_",
          lower_case_cprefix = "gjs_error_")]
  public errordomain Error {
    FAILED,
    EXIT,
  }
  
  [CCode (cname = "GjsJSError",
          cprefix = "GJS_JS_ERROR_",
          lower_case_cprefix = "gjs_js_error_")]
  public errordomain JSError {
    ERROR,
    EVAL_ERROR,
    INTERNAL_ERROR,
    RANGE_ERROR,
    REFERENCE_ERROR,
    STOP_ITERATION,
    SYNTAX_ERROR,
    TYPE_ERROR,
    URI_ERROR,
  }
  
  [CCode (cname = "GjsContext",
          type_id = "GJS_TYPE_CONTEXT")]
  public class Context : GLib.Object {
    
    /*
     * The properties here are based on what I can read from the C++ source
     * code.
     */
    
    /**
     * Path where modules to import should reside.
     */
    
    public string[] search_path {construct;}
    
    /**
     * The filename of the launched JS program
     */
    public string program_name {get {
      unowned string ret_val = null;
      this.@get ("program-name", ref ret_val);
      return ret_val;
    } construct;}
    
    /**
     * The full path of the launched file or NULL if GJS was launched from
     * the C API or interactive console.
     */
    public string program_path {get {
      unowned string ret_val = null;
      this.@get ("program-path", ref ret_val);
      return ret_val;
    } construct;}
    /**
     * Set this property to profile any JS code run by this context. By
     * default, the profiler is started and stopped when you call
     * {@link Gjs.Context.eval}.
     *
     * The value of this property is superseded by the GJS_ENABLE_PROFILER
     * environment variable.
     *
     * You may only have one context with the profiler enabled at a time.
     */
    [NoAccessorMethod]
    public bool profiler_enabled {construct;}
    
    /**
     * Set this property to install a SIGUSR2 signal handler that starts and
     * stops the profiler. This property also implies that
     * {@link Gjs.Context.profiler_enabled} is set.
     */
    [NoAccessorMethod]
    public bool profiler_sigusr2 {construct;}
    
    /**
     * Whether to execute the file as a module
     */
    [NoAccessorMethod]
    public bool exec_as_module {construct;}
    
    
    [CCode (cname = "gjs_context_new")]
    public Context ();
    
    [CCode (cname = "gjs_context_new_with_search_path")]
    public Context.with_search_path ([CCode (array_length = false)]
                                     string[] search_path);
    
    [CCode (cname = "gjs_context_eval_file")]
    public bool eval_file (string filename,
                      out int exit_status_p)
                      throws GLib.Error;
    
    [CCode (cname = "gjs_context_eval_module_file")]
    public bool eval_module_file (string filename,
                                  out uint8 exit_status_p)
                                  throws GLib.Error;
    
    
    [CCode (cname = "gjs_context_eval")]
    public bool eval (string script,
                      string filename,
                      out int exit_status_p)
                      throws GLib.Error;
    
    [CCode (cname = "gjs_context_register_module")]
    public bool register_module (string identifier,
                                 string uri)
                                 throws GLib.Error;
    
    [CCode (cname = "gjs_context_eval_module")]
    public bool eval_module (string identifier,
                             out uint8 exit_code)
                             throws GLib.Error;
    
    [CCode (cname = "gjs_context_define_string_array")]
    public bool define_string_array (string array_name,
                                     [CCode (array_length_pos = 1.1)]
                                     string[] array_values)
                                     throws GLib.Error;
    
    [CCode (cname = "gjs_context_set_argv")]
    public void set_argv ([CCode (array_length_pos = 0.1,
                                  type = "const char**")]
                          string[] array_values);
    
    /**
     * Returns a newly-allocated list containing all known instances of 
     * {@link Gjs.Context}. This is useful for operating on the contexts from a
     * process-global situation such as a debugger.
     *
     * @return Known {@link Gjs.Context} instances
     */
    [CCode (cname = "gjs_context_get_all")]
    public GLib.List<Context> get_all ();
    
    [CCode (cname = "gjs_context_get_current")]
    public static Context get_current ();
    
    [CCode (cname = "gjs_context_make_current")]
    public void make_current ();
    
    /**
     * Returns a pointer to the underlying native context. For SpiderMonkey,
     * this is a JSContext *
     */
    [CCode (cname = "gjs_context_get_native_context")]
    public GLib.pointer get_native_context ();
    
    [CCode (cname = "gjs_context_print_stack_stderr")]
    public void print_stack_stderr ();
    
    /**
     * Similar to the Spidermonkey JS_MaybeGC() call which
     * heuristically looks at JS runtime memory usage and
     * may initiate a garbage collection.
     *
     * This function always unconditionally invokes JS_MaybeGC(), but
     * additionally looks at memory usage from the system malloc()
     * when available, and if the delta has grown since the last run
     * significantly, also initiates a full JavaScript garbage
     * collection.  The idea is that since GJS is a bridge between
     * JavaScript and system libraries, and JS objects act as proxies
     * for these system memory objects, GJS consumers need a way to
     * hint to the runtime that it may be a good idea to try a
     * collection.
     *
     * A good time to call this function is when your application
     * transitions to an idle state.
     */
    [CCode (cname = "gjs_context_maybe_gc")]
    public void maybe_gc ();
    
    /**
     * Initiate a full GC; may or may not block until complete. This
     * function just calls Spidermonkey JS_GC().
     */
    [CCode (cname = "gjs_context_gc")]
    public void gc ();
    
    /*
     * Returns the profiler's internal instance of {@link Gjs.Profiler}
     * for you to customize, or %NULL if profiling is not enabled on this
     * {@link Gjs.Context}.
     *
     * @returns {@link Gjs.Profiler}
     */
    [CCode (cname = "gjs_context_get_profiler")]
    public Profiler get_profiler ();
    
    [CCode (cname = "gjs_context_setup_debugger_console")]
    public void setup_debugger_console ();
  }
  
  [CCode (cheader_filename = "gjs/context.h",
          cname = "gjs_dumpstack")]
  public void dump_stack ();
  
  /**
   * Returns the underlying version of the JS engine.
   *
   * Returns: a string
   */
  [CCode (cheader_filename = "gjs/context.h",
          cname = "gjs_get_js_version")]
  public string get_js_version ();
  
  /*
   * This class has no visible _new function, can only be created from
   * context.
   */
  [CCode (cheader_filename = "gjs/profiler.h",
          cname = "GjsProfiler",
          type_id = "GJS_TYPE_PROFILER")]
  public class Profiler : GLib.Object {
    /**
     * Set the capture writer to which profiling data is written when the
     * ''this'' is stopped.
     * 
     * @param capture A {SysprofCaptureWriter}
     */
    [CCode (cname = "gjs_profiler_set_capture_writer")]
    public void set_capture_writer (GLib.pointer capture);
    
    /**
     * Set the file to which profiling data is written when the ''this'' is
     * stopped. By default, this is `gjs-$PID.syscap` in the current directory.
     */
    [CCode (cname = "gjs_profiler_set_filename")]
    public void set_filename (string filename);
    
    
    [CCode (cname = "gjs_profiler_set_fd")]
    public void set_fd (int fd);
    
    /**
     * As expected, this starts the {@link Gjs.Profiler}.
     *
     * This will enable the underlying JS profiler and register a POSIX timer to
     * deliver SIGPROF on the configured sampling frequency.
     *
     * To reduce sampling overhead, Gjs.Profiler stashes information
     * about the profile to be calculated once the profiler has been disabled.
     * Calling Gjs.Profiler.stop() will result in that delayed work to be
     * completed.
     *
     * You should call Gjs.Profiler.stop() when the profiler is no longer
     * needed.
     */
    [CCode (cname = "gjs_profiler_start")]
    public void start ();
    
    /**
     * Stops a currently running {@link Gjs.Profiler}. If the profiler is not 
     * running, this function will do nothing.
     *
     * Some work may be delayed until the end of the capture. Such delayed work
     * includes flushing the resulting samples and file location information to
     * disk.
     *
     * This may block while writing to disk. Generally, the writes are delivered
     * to a tmpfs device, and are therefore negligible.
     */
    [CCode (cname = "gjs_profiler_stop")]
    public void stop ();
    
    /**
     * Use this to pass a signal info caught by another signal handler to a
     * {@link Gjs.Profiler}. This might be needed if you have your own complex
     * signal handling system for which Gjs.Profiler cannot simply add a SIGUSR2
     * handler.
     *
     * This function should only be called from the JS thread.
     *
     * @return true if the signal was handled.
     */
    [CCode (cname = "gjs_profiler_chain_signal")]
    public static bool chain_signal (Context ctx,
                                     Posix.siginfo_t info);
  }
  
  [CCode (cheader_filename = "gjs/mem.h",
          cname = "gjs_memory_report")]
  public void memory_report (string where,
                 bool die_if_fail);
  
  [CCode (cheader_filename = "gjs/coverage.h",
          cname = "GjsProfiler",
          type_id = "GJS_TYPE_COVERAGE")]
  public class Coverage : GLib.Object {
    
    /**
     * Prefixes of files on which to perform coverage analysis
     */
    public string prefixes {construct;}
    
    /**
     * A context to gather coverage stats for
     */
    public Context context {construct;}
    
    /**
     * Directory handle at which to output coverage statistics
     */
    public GLib.File output_directory {construct;}
    
    /**
     * Creates a new {@link Gjs.Coverage} object that collects coverage
     * information for any scripts run in context.
     *
     * Scripts which were provided as part of {@link prefixes} will be written
     * out to {@link output_dir}, in the same directory structure relative to
     * the source dir where the tests were run.
     *
     * @param coverage_prefixes A null-terminated strv of prefixes of files on
     * which to record code coverage
     *
     * @param coverage_context A {@link Gjs.Context} object
     *
     * @param output_dir A {@link GLib.File} handle to a directory in which to
     * write coverage information
     */
    [CCode (cname = "gjs_coverage_new")]
    public Coverage (string coverage_prefixes,
                     Context coverage_context,
                     GLib.File output_dir);
    
    /**
     * Scripts which were provided as part of the {@link Gjs.Coverage.prefixes}
     * construction property will be written out to {output_directory}, in the
     * same directory structure relative to the source dir where the tests were
     * run.
     *
     * This function takes all available statistics and writes them out to
     * either the file provided or to files of the pattern (filename).info in
     * the same directory as the scanned files. It will provide coverage data
     * for all files ending with ".js" in the coverage directories.
     */
    [CCode (cname = "gjs_coverage_write_statistics")]
    public void write_statistics ();
    
    /**
     * This function must be called before creating any {@link Gjs.Context}, 
     * if you intend to use any {@link Gjs.Coverage} APIs.
     */
    [CCode (cname = "gjs_coverage_enable")]
    public static void enable ();
  }
}
