// @ts-ignore
import { gui } from "./reporter_job_control_gui.jsi";
import { ReporterVariablesFile } from "../shared/reporter_variables_transfer.mjs";
import { find_lsdyna_files } from "../shared/file_helper.mjs";
/**
* GUI to allow user to specify keyword file, results directory and output directory for
* REPORTER template "job".
* @param {string} keyword_file Keyword file
* @param {string} results_dir Directory containing LS-DYNA results (can be different from keyword file directory)
* @param {string} output_dir Directory where images and other output files will be written
* @param {string} reporter_temp REPORTER's temporary directory, used for exchanging REPORTER variables
* @param {string} job_control Overall job control
*/
export function reporter_job_control(keyword_file, results_dir, output_dir, reporter_temp, job_control) {
//@ts-ignore
if (!JobControl.GetAll().includes(job_control)) {
ErrorMessage(`Unexpected value of <job_control = "${job_control}"> in function reporter_job_control.`);
Exit();
}
if (job_control == JobControl.ABORT) {
Message(`Generation aborted (job control).`);
return;
}
if (gui) {
/* Set callback functions here (we can't set them in GUI builder because it doesn't like
* when they're defined when gui is imported from within a module). */
gui.w.T_keyword_file.onChange = check_valid;
gui.w.T_results_dir.onChange = check_valid;
gui.w.T_output_dir.onChange = check_valid;
gui.w.B_keyword_file.onClick = browse_keyword_file;
gui.w.B_results_dir.onClick = browse_results_dir;
gui.w.B_output_dir.onClick = browse_output_dir;
gui.w.B_run.onClick = run_clicked;
gui.w.B_cancel.onClick = cancel_clicked;
/* Browse icons */
gui.w.B_keyword_file.DirectoryIcon(Widget.BLACK, Widget.YELLOW);
gui.w.B_results_dir.DirectoryIcon(Widget.BLACK, Widget.YELLOW);
gui.w.B_output_dir.DirectoryIcon(Widget.BLACK, Widget.YELLOW);
/* Populate textboxes */
gui.w.T_keyword_file.text = keyword_file;
gui.w.T_results_dir.text = results_dir;
gui.w.T_output_dir.text = output_dir;
/* Add reporter_temp directory to <gui> object to make it accessible in callback functions. */
if (!File.IsDirectory(reporter_temp)) {
ErrorMessage(`Invalid REPORTER temporary directory for file exchange: ${reporter_temp}`);
Exit();
}
gui._reporter_temp = reporter_temp;
/* Check whether current selections are valid */
check_valid();
gui.w.Show();
} else {
ErrorMessage(`Unable to open job control GUI.`);
Exit();
}
}
/**
* Checks whether the textbox entries for KEYWORD_FILE, RESULTS_DIR, and OUTPUT_DIR are valid.
* Controls whether `Run` button is active.
*/
function check_valid() {
let all_valid = true;
if (File.Exists(gui.w.T_keyword_file.text)) {
gui.w.T_keyword_file.category = Widget.CATEGORY_TEXT_BOX;
} else {
gui.w.T_keyword_file.category = Widget.CATEGORY_WARNING_ACTION;
all_valid = false;
}
if (File.IsDirectory(gui.w.T_results_dir.text)) {
gui.w.T_results_dir.category = Widget.CATEGORY_TEXT_BOX;
} else {
gui.w.T_results_dir.category = Widget.CATEGORY_WARNING_ACTION;
all_valid = false;
}
if (File.IsDirectory(gui.w.T_output_dir.text)) {
gui.w.T_output_dir.category = Widget.CATEGORY_TEXT_BOX;
} else {
gui.w.T_output_dir.category = Widget.CATEGORY_WARNING_ACTION;
all_valid = false;
}
if (all_valid) {
gui.w.B_run.active = true;
} else {
gui.w.B_run.active = false;
}
/* Redraw window to force widget category changes to refresh */
gui.w.Redraw();
}
/**
* Allows user to browse for a keyword file
*/
function browse_keyword_file() {
/* If there is already a keyword file entry, use its location as the starting point for the
* file selector. */
let path_index = Math.max(gui.w.T_keyword_file.text.lastIndexOf("/"), gui.w.T_keyword_file.text.lastIndexOf("\\"));
let start_dir = gui.w.T_keyword_file.text.substring(0, path_index);
let keyword_file;
if (File.IsDirectory(start_dir)) {
keyword_file = Window.GetFile(`*.k*`, false, start_dir);
} else {
keyword_file = Window.GetFile(`*.k*`);
}
if (keyword_file != null) {
gui.w.T_keyword_file.text = keyword_file;
}
check_valid();
}
/**
* Allows user to browse for a results directory
*/
function browse_results_dir() {
browse_dir(gui.w.T_results_dir);
}
/**
* Allows user to browse for an output directory
*/
function browse_output_dir() {
browse_dir(gui.w.T_output_dir);
}
/**
* Allows the user to browse for a directory. Updates the appropriate textbox.
* @param {Widget} textbox The directory textbox associated with this browse button
*/
function browse_dir(textbox) {
/* If the textbox already contains a valid directory, use it as the starting point for the
* directory selector. */
let new_dir;
if (File.IsDirectory(textbox.text)) {
new_dir = Window.GetDirectory(textbox.text);
} else {
new_dir = Window.GetDirectory();
}
if (new_dir != null) {
textbox.text = new_dir;
}
check_valid();
}
/**
* When user clicks `Run`, write KEYWORD_FILE, RESULTS_DIR, and OUTPUT_DIR to a temporary CSV
* file that can be picked up by REPORTER in the subsequent `#AAW REPORTER read variables from
* PRIMER job control` item.
* Set JOB_CONTROL to "Check", ready for `#AAW T/HIS check and do assessment` item.
*/
function run_clicked() {
let keyword_file = gui.w.T_keyword_file.text;
let results_dir = gui.w.T_results_dir.text;
let output_dir = gui.w.T_output_dir.text;
/* Determine RESULTS_FILE_THIS */
let path_index = Math.max(keyword_file.lastIndexOf("/"), keyword_file.lastIndexOf("\\"));
let filename = keyword_file.substring(path_index + 1);
let job_name = filename.substring(0, filename.lastIndexOf("."));
let results_file_this = find_lsdyna_files(results_dir, job_name, "T/HIS");
/* Write variables file */
let file = new ReporterVariablesFile(gui._reporter_temp, ReporterVariablesFile.JOB_CONTROL);
file.WriteVariable(`KEYWORD_FILE`, keyword_file, `Keyword file`, `File(absolute)`);
file.WriteVariable(`RESULTS_DIR`, results_dir, `Directory containing LS-DYNA results`, `Directory`);
file.WriteVariable(`OUTPUT_DIR`, output_dir, `Directory for output files`, `Directory`);
file.WriteVariable(`RESULTS_FILE_THIS`, results_file_this, `T/HIS results filename`, `String`);
file.WriteVariable(`JOB_CONTROL`, JobControl.CHECK, `"Check"/"Run"/"Skip"/"Abort" for #AAW items`, `String`);
file.Close();
Exit();
}
/**
* If user clicks `Cancel`, set JOB_CONTROL to "Abort" so that template generation is aborted ASAP.
*/
function cancel_clicked() {
let file = new ReporterVariablesFile(gui._reporter_temp, ReporterVariablesFile.JOB_CONTROL);
/* We are aborting template generation so just write a blank filename for results file: */
file.WriteVariable(`RESULTS_FILE_THIS`, ``, `T/HIS results filename`, `String`);
file.WriteVariable(`JOB_CONTROL`, JobControl.ABORT, `"Check"/"Run"/"Skip"/"Abort" for #AAW items`, `String`);
file.Close();
Exit();
}
export class JobControl {
/**
* This class holds constants used for REPORTER job control i.e. controlling whether various
* items in REPORTER templates are run or skipped, or whether the entire template generation
* is aborted.
*/
/** Abort constant (used to indicate that the entire template generation should be aborted)
* @type {string} */
static get ABORT() {
return "Abort";
}
/** Check constant (used to indicate that the check in this item should be performed)
* @type {string} */
static get CHECK() {
return "Check";
}
/** Run constant (used to indicate that the item should be run)
* @type {string} */
static get RUN() {
return "Run";
}
/** Skip constant (used to indicate that the item should be skipped)
* @type {string} */
static get SKIP() {
return "Skip";
}
/* Class methods */
/**
* Return an array of all the available job control constants
* @returns {string[]}
* @example
* let job_controls = JobControl.GetAll();
*/
static GetAll() {
return [JobControl.ABORT, JobControl.CHECK, JobControl.RUN, JobControl.SKIP];
}
}