/**
 * @title BLAST
 * @description The task is an adapted version of BLAST from Lachaux (2019). A short computerized test to measure the ability to stay on task.
 * @version 1.1.2 - modified for Sylvie
 *
 * @assets assets/
 */

$(document).ready(function () {
  $(document).on('keydown', function (e) {
    e = e || window.event;
    if (e.ctrlKey || e.metaKey) {
      let c = e.which || e.keyCode;
      if (c == 82) {
        e.preventDefault();
        e.stopPropagation();
      }
    }
  });
});

// prevent getting back or closing the window : https://stackoverflow.com/questions/12381563/how-can-i-stop-the-browser-back-button-using-javascript
window.onbeforeunload = function () { return `Your work will be lost.`; };

var blast = async() => {

  // ##########################
  // ### initialize jsPsych ###
  // ##########################
  var jsPsych = initJsPsych();

  // Task parameters 
  const blast_params = window.RG_BLAST_PARAMS; // rg-port: was injected from src/blast-params.json by code.php
  var repeat_practice = [];
  const present_practice = targetPresent(blast_params.target_practice, blast_params.array_practice);
  const sessionData = window.RG.session; // rg-port: was PHP $_SESSION

  // Timelines
  var welcome = [];
  var practice = [];
  var main = [];

  // ***************
  // *** WELCOME ***
  // ***************

  // Preload assets 
  welcome.push({
    type: jsPsychPreload,
    images: [
      blast_params.root_path + 'assets/img/blast.png',
      blast_params.root_path + 'assets/img/card.png',
      blast_params.root_path + 'assets/img/d.png',
      blast_params.root_path + 'assets/img/ltdz.png',
      blast_params.root_path + 'assets/img/ltdzG.png',
      blast_params.root_path + 'assets/img/pltbR.png'
    ],
    data: {
      trial_name: "preload",
      block: "welcome"
    },
    on_finish: function () {
      jsPsych.data.addProperties({
        log_start: logCurrentDateTime(),
      });
    }
  });

  // Switch to fullscreen
  welcome.push({
    type: jsPsychFullscreen,
    message: "<p>The experiment will switch to full screen mode when you press the button below</p>" +
      "<p>(Version 1.1, December 2024)</p>",
    data: {
      trial_name: "fullscreen",
      block: "welcome"
    },
    fullscreen_mode: true,
  });

  // Browser check
  const get_subject_id = sessionData['token'];
  const get_study_id = 'rg-study-2';
  const get_session_id = sessionData['stage'];
  welcome.push({
    type: jsPsychBrowserCheck,
    skip_features: ['width', 'height', 'webaudio', 'webcam', 'microphone'],
    data: {
      trial_name: "browser_check",
      block: "welcome"
    },
    on_finish: function() {
      jsPsych.data.addProperties({
        subject_id: get_subject_id,
        study_id: get_study_id,
        session_id: get_session_id,
      });
    }
  })

  // Virtual chinrest
  const get_monitor_size_inch = sessionData['monitorsize'];
  welcome.push({
    type: jsPsychVirtualChinrest,
    data: {
      trial_name: "virtual_chinrest",
      block: "welcome"
    },
    blindspot_reps: 2,
    resize_units: "none",
    item_path: "assets/img/card.png",
    // Add data on all trials
    on_finish: function () {
      const px2deg = jsPsych.data.get().last(1).values()[0].px2deg;
      const view_dist_cm = jsPsych.data.get().last(1).values()[0].view_dist_mm * 0.1;
      jsPsych.data.addProperties({
        _px2deg: round3deci(px2deg),
        _view_dist_cm: round3deci(view_dist_cm),
        _letter_width_va: round3deci(blast_params.letter_width_va),
        _letter_width_cm: round3deci(vaToCm(blast_params.letter_width_va, view_dist_cm)),
        _letter_dist_from_center_va: round3deci(blast_params.letter_dist_from_center_va),
        _letter_dist_from_center_cm: round3deci(vaToCm(blast_params.letter_dist_from_center_va, view_dist_cm)),
        _monitor_width_px: window.outerWidth,
        _monitor_height_px: window.outerHeight,
        monitor_size_inch: get_monitor_size_inch,
      });
      document.getElementsByClassName("jspsych-content-wrapper")[0].remove();
    }
  });

  // Run welcome
  await jsPsych.run(welcome);

  // ****************  
  // *** PRACTICE ***
  // ****************  

  // Practice Instructions
  practice.push({
    type: jsPsychInstructions,
    data: {
      trial_name: "instructions",
      block: "practice"
    },
    pages: [
      `Welcome to our task.`,
      `This task is easy. You will first see a letter on the screen (target) <img src="assets/img/d.png" style="width:` + getLetterDistFromCenterPx(jsPsych, blast_params) * 2 + `px; vertical-align: middle;"></img><br><br>` +
      `Followed by 4 letters <img src="assets/img/ltdz.png" style="width:` + getLetterDistFromCenterPx(jsPsych, blast_params) * 2 + `px; vertical-align: middle;"></img><br><br>` +
      `If the target letter is` + ` <span style="color:MediumSeaGreen;">present</span>` + `, press the ` + `<span style="color:MediumSeaGreen;"><b style="font-size:xx-large;">F</b>` + ` key with your left finger</span> ` + `<img src="assets/img/ltdzG.png" style="width:` + getLetterDistFromCenterPx(jsPsych, blast_params) * 2 + `px; vertical-align: middle"></img><br><br>` +
      `If the target letter is ` + `<span style="color:Tomato;">NOT present</span>` + `, press the ` + `<span style="color:Tomato;"><b style="font-size:xx-large;">J</b>` + ` key with your right finger</span>` + ` <img src="assets/img/pltbR.png" style="width:` + getLetterDistFromCenterPx(jsPsych, blast_params) * 2 + `px; vertical-align: middle"></img><br><br>`,
      `The goal is to be as FAST AND ACCURATE as you can.<br> It is like driving a car, you want to drive as fast as you can, AND avoid making an accident.<br>` +
      `If you do not give any response, the next trial will automatically start after a short period<br>`,
      `Let's start with some practice. Remember, the goal is to be as fast as you can AND make as less errors as you can.`,
    ],
    show_clickable_nav: true,
    on_finish: function () {
      // Hide cursor
      document.body.style.cursor = "none";
    }
  })

  // Getting Ready: 5 sec mask5 followed by .8 sec mask1
  const waitmask5 = {
    type: jsPsychHtmlKeyboardResponse,
    stimulus: getMask5(jsPsych, blast_params, 0),
    choices: `NO_KEYS`,
    trial_duration: blast_params.pres_time_mask5_intro,
    data: {
      trial_duration: blast_params.pres_time_mask5_intro,
      trial_name: "mask5_intro",
      real_trial_index: '',
      block: "practice"
    },
    on_finish: function (data) {
      data.real_trial_index = jsPsych.data.get().last(2).values()[0].real_trial_index;
    },
  };

  const waitmask1 = {
    type: jsPsychHtmlKeyboardResponse,
    stimulus: getMask1(jsPsych, blast_params),
    choices: `NO_KEYS`,
    trial_duration: blast_params.pres_time_mask1_intro,
    data: {
      trial_duration: blast_params.pres_time_mask1_intro,
      trial_name: "mask1_intro",
      real_trial_index: '',
      block: "practice"
    },
    on_finish: function (data) {
      data.real_trial_index = jsPsych.data.get().last(2).values()[0].real_trial_index;
    },
  };

  // Timeline variables and timeline
  const block_practice = {
    timeline_variables: createBlastTimelineVariables(
      blast_params.target_practice,
      blast_params.array_practice,
      present_practice,
      jsPsych,
      blast_params
    ),
    timeline: createBlastTimeline("practice", jsPsych, blast_params),
    on_timeline_finish: function () {
      // Show cursor
      document.body.style.cursor = "auto";
    }
  };

  const repeat_prac_message = { // https://www.youtube.com/watch?v=LP7o0iAALik
    type: jsPsychHtmlKeyboardResponse,
    data: {
      trial_name: "instructions",
      block: "practice",
      real_trial_index: '',
    },
    choices: [' '],
    stimulus: `
                <p>You will go through another practice block. Please be as accurate as possible.</p>
                <p>If the `+ ` <span style="color:MediumSeaGreen;">target letter is present</span>` + `, press the ` + `<span style="color:MediumSeaGreen;"><b>F</b>` + ` key with your left finger</span></p>
                <p>If the `+ `<span style="color:Tomato;">target letter is NOT present</span>` + `, press the ` + `<span style="color:Tomato;"><b>J</b>` + ` key with your right finger</span></p>
                <p>Press the spacebar to continue.<p>
                `,
    on_start: function () {
      document.body.style.cursor = 'auto'; // display cursor during instructions
    },
    on_finish: function (data) {
      document.body.style.cursor = 'none'; // hide cursor during task
      data.real_trial_index = jsPsych.data.get().last(2).values()[0].real_trial_index;
    }
  };

  const repeat_prac_conditional = {
    timeline: [repeat_prac_message],
    conditional_function: function () {
      const trials_practice = jsPsych.data.get().filter({ block: 'practice', trial_name: 'array' }).last(blast_params.target_practice.length); // get last practice.length trials
      const n_correct_trials_practice = trials_practice.filter({ correct: 1 }).count(); // count only the true last 4 practice trials
      if (n_correct_trials_practice <= blast_params.target_practice.length / 2 && repeat_practice.length < blast_params.repeat_practice_times) {// if not more than half correct trials and we allow repeat_practice_times (normally 2) repetitions meaning practice is repeated.
        repeat_practice.push(true);
        return true;
      } else {
        repeat_practice.push(false);
        document.getElementsByClassName("jspsych-content-wrapper")[0].remove();
        return false;
      }
    }
  };

  practice.push({
    timeline: [waitmask5, waitmask1, block_practice, repeat_prac_conditional],
    loop_function: function (data) {
      if (repeat_practice[repeat_practice.length - 1] === true) { // if last practice is true, redo practice
        return true;
      } else {
        document.body.style.cursor = 'auto'; // display cursor during instructions
        return false;
      }
    },
  });

  await jsPsych.run(practice);

  // ************
  // *** MAIN ***
  // ************

  const testmode = window.RG.testmode == 1; // rg-port: was URL param via code.php
  const arrays = testmode == false ? // if testmode == true AND participant answered 0, testonly should be true and task would only show 4 trials
    generateArrays(blast_params.letter_array, blast_params.n_trials) :
    generateArrays(blast_params.letter_array, blast_params.n_test_trials);
  const target_main = arrays.target_main;
  const array_main = arrays.array_main;
  const present_main = arrays.trial_type;

  // Main Instructions
  main.push({
    type: jsPsychInstructions,
    data: {
      trial_name: "instructions",
      block: "main"
    },
    pages: [
      `Remember, you need to find the target letter within an array of 4 letters.<br>` +
      `If the ` + ` <span style="color:MediumSeaGreen;">target letter is present</span>` + `, press the ` + `<span style="color:MediumSeaGreen;"><b style="font-size:xx-large;">F</b>` + ` key with your left finger</span> ` +
      `If the ` + `<span style="color:Tomato;">target letter is NOT present</span>` + `, press the ` + `<span style="color:Tomato;"><b style="font-size:xx-large;">J</b>` + ` key with your right finger</span>`,
      `Be as FAST AND ACCURATE as you can.`
    ],
    show_clickable_nav: true,
    on_finish: function () {
      // Hide cursor
      document.body.style.cursor = "none";
    }
  })

  // Getting Ready: 5 sec mask5 followed by .8 sec mask1
  main.push({
    type: jsPsychHtmlKeyboardResponse,
    stimulus: getMask5(jsPsych, blast_params, 0),
    choices: `NO_KEYS`,
    trial_duration: blast_params.pres_time_mask5_intro,
    data: {
      trial_duration: blast_params.pres_time_mask5_intro,
      trial_name: "mask5_intro",
      real_trial_index: '',
      block: "main"
    },
    on_finish: function (data) {
      data.real_trial_index = 0;
    },
  });
  main.push({
    type: jsPsychHtmlKeyboardResponse,
    stimulus: getMask1(jsPsych, blast_params),
    choices: `NO_KEYS`,
    trial_duration: blast_params.pres_time_mask1_intro,
    data: {
      trial_duration: blast_params.pres_time_mask1_intro,
      trial_name: "mask1_intro",
      real_trial_index: '',
      block: "main"
    },
    on_finish: function (data) {
      data.real_trial_index = 0;
    },
  });

  // Timeline variables and timeline
  main.push({
    timeline_variables: createBlastTimelineVariables(
      target_main,
      array_main,
      present_main,
      jsPsych,
      blast_params
    ),
    timeline: createBlastTimeline("main", jsPsych, blast_params),
    on_timeline_finish: function (data) {
      // Show cursor
      document.body.style.cursor = "auto";
    }
  })

// Control questionnaires
  let survey_elements_end_p1 = [
    {
      type: 'boolean',
      title: 'Did you do the task in good conditions (e.g. without being disturbed)?',
      name: 'conditiongood',
      isRequired: true,
      labelTrue: "Yes",
      labelFalse: "No",
      valueTrue: "yes",
      valueFalse: "no",
    },
    {
      type: 'comment',
      title: 'Please give a short explanation.',
      name: 'conditioncomment',
      visibleIf: '{conditiongood} = "no"',
      isRequired: true,
    }
  ];
  let survey_elements_end_p2 = [
    {
      type: 'html',
      html: '<span class="sv-string-viewer sv-string-viewer--multiline">Please indicate your preferences in the use of hands in the following activities or objects. If you use both, select the one that you use the most.</span>',
    },
    {
      type: 'boolean',
      title: '✍️ Writing',
      name: 'writing',
      isRequired: true,
      labelTrue: "Right",
      labelFalse: "Left",
      valueTrue: "right",
      valueFalse: "left",
    },
    {
      type: 'boolean',
      title: '🤽 Throwing',
      name: 'throwing',
      isRequired: true,
      labelTrue: "Right",
      labelFalse: "Left",
      valueTrue: "right",
      valueFalse: "left",
    },
    {
      type: 'boolean',
      title: '🪥 Brushing your teeth',
      name: 'teeth',
      isRequired: true,
      labelTrue: "Right",
      labelFalse: "Left",
      valueTrue: "right",
      valueFalse: "left",
    },
    {
      type: 'boolean',
      title: '🥄 Using a spoon',
      name: 'spoon',
      isRequired: true,
      labelTrue: "Right",
      labelFalse: "Left",
      valueTrue: "right",
      valueFalse: "left",
    }
  ];

  main.push({
    type: jsPsychSurvey,
    data: {
      trial_name: "survey",
      block: "end-questionnaire"
    },
    survey_json: {
      showQuestionNumbers: false,
      pages: [
        {
          name: 'page1',
          elements: {
            type: 'html',
            html: '<span class="sv-string-viewer sv-string-viewer--multiline">The task is now over, we would like you to answer few questions before completing the session.<br>Please click on the "Next" button.</span>',
          },
        },
        {
          name: 'page2',
          elements: survey_elements_end_p1
        },
        {
          name: 'page3',
          elements: survey_elements_end_p2
        }
      ],
    },
    on_finish: function (data) {
      // add variables to data
      jsPsych.data.addProperties({
        condition_good: data.response.conditiongood,
        condition_comment: data.response.conditioncomment ? data.response.conditioncomment.replace(/\s/, ' ').replace(/[\W_]+/g," ") : "",
        writing: data.response.writing,
        throwing: data.response.throwing,
        teeth: data.response.teeth,
        spoon: data.response.spoon,
      });

      // Exit fullscreen
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.webkitExitFullscreen) { /* Safari */
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) { /* IE11 */
        document.msExitFullscreen();
      }

      data.response = '';
    }
  });

  // Save to db
  const ignoreCols = [ // This is the list of ignored columns from final data
    'success',
    'timeout',
    'failed_images',
    'failed_audio',
    'failed_video',
    'trial_type',
    'trial_index',
    'internal_node_id',
    'item_width_mm',
    'item_height_mm',
    'item_width_px',
    'px2mm',
    'view_dist_mm',
    'item_width_deg',
    'px2deg',
    'win_width_deg',
    'win_height_deg',
    'view_history',
    'stimulus',
    'plugin_version',
  ];
  if (blast_params.savedb) {
    main.push({
      type: jsPsychCallFunction,
      async: true,
      func: function (done) {
        // Log finish time
        jsPsych.data.addProperties({
          log_end: logCurrentDateTime(),
        });
        // Get and clean final data
        let final = jsPsych.data.get().ignore(ignoreCols);
        // Filter data to get only the relevant data
        final.trials = final.trials.filter(
          trial => trial.trial_name !== 'mask5_intro'
            && trial.trial_name !== 'mask1_intro'
            && trial.trial_name !== 'target'
            && trial.trial_name !== 'mask1'
            && trial.trial_name !== 'mask5'
            // if you want the time spend on the different instructions and survey, you can comment the lines below
            && trial.trial_name !== 'preload'
            && trial.trial_name !== 'fullscreen'
            && trial.trial_name !== 'virtual_chinrest'
            && trial.trial_name !== 'instructions'
            && trial.trial_name !== 'survey'
        );
        // rg-port: was a POST to src/save.php — download the data as JSON instead
        RG.saveJSON('rg-blast-data.json', JSON.parse(final.json()));
        done(); // invoking done() causes experiment to progress to next trial.
      }
    });
  }

  // End message
  main.push({
    type: jsPsychInstructions,
    data: {
      trial_name: "instructions",
      block: "main"
    },
    pages: [
      `Congratulations! You completed the task. We thank you for your participation.`
    ],
    show_clickable_nav: true,
    allow_backward: false,
    button_label_next: "Finish Experiment",
    on_finish: function () {
      // rg-port: the original redirected to the rg-study dashboard here
      // (blast_params.redirect); the library port stays on the end page.
    }
  })

  await jsPsych.run(main);
}

blast();