import { ModificationBase, NoteDetails } from './ModificationBase.mjs';
import * as WebAudioApiErrors from '../modules/Errors.mjs';

/**
 * Class representing a Velocity modification.
 * 
 * A Velocity modification causes a note to be played at an absolute velocity between [0.0, 1.0].
 * 
 * @extends ModificationBase
 */
export class Velocity extends ModificationBase {

   /**
    * Constructs a new {@link Velocity} modification object.
    */
   constructor(tempo, key, details) {
      super(tempo, key, details);
   }

   /**
    * Returns a list of all parameters available for use in this modification, including whether
    * the parameter is required or optional when playing back either a "sequence" or just a
    * single "note".
    * 
    * @returns {Object<string,Object<string,string[]>>} List of modification-specific parameter keys and when they are required
    */
   static getParameters() {
      return {
         required: {
            singleNote: ['velocity'],
            sequence: []
         },
         optional: {
            singleNote: [],
            sequence: []
         }
      };
   }

   /**
    * Returns whether this modification can be used to modify a sequence of notes.
    * 
    * @returns {boolean} Whether this modification can be used to modify a sequence of notes
    */
   static canModifySequence() {
      return false;
   }

   static inferParametersFromSequence() {
      throw new WebAudioApiErrors.WebAudioValueError('The "Velocity" modification cannot infer any parameters from a sequence of notes');
   }

   /**
    * Returns a list of all modified notes, durations, and velocities as generated by the
    * corresponding modification class.
    * 
    * The `details` variable must contain the following key:
    * 
    * `velocity`:  Intensity at which to play the note between [0.0, 1.0]
    * 
    * @param {Object<string, number>} details - Information about the intensity of the note
    * @returns {NoteDetails[]} List of {@link NoteDetails} to replace the original note
    */
   getModifiedNoteDetails(details) {
      if (!('velocity' in details)) {
         if (!('implicit' in details))
            throw new WebAudioApiErrors.WebAudioValueError('The "details" variable must contain the following keys: velocity');
         details.velocity = details.implicit;
      }
      if ((Number(details.velocity) < 0.0) || (Number(details.velocity) > 1.0))
         throw new WebAudioApiErrors.WebAudioValueError(`The target velocity value (${details.velocity}) is outside of the available range: [0.0, 1.0]`);
      return [new NoteDetails(
         this.unmodifiedDetails.note,
         Number(details.velocity),
         this.unmodifiedDetails.duration
      )];
   }
}