import { getBits, toBitArray } from '../utils/functions';

export default function parse(sysex) {
  const patch = build_patch(sysex.slice(0, 38));
  switch (patch.voice_mode) {
    default:
    case 0:
      return [
        { ...patch },
        { ...build_timbre(1, sysex.slice(38, 146)) },
        null,
        null,
      ];

    case 2:
      return [
        { ...patch },
        { ...build_timbre(1, sysex.slice(38, 146)) },
        { ...build_timbre(2, sysex.slice(146, 254)) },
        null,
      ];
    case 3:
      return [
        { ...patch },
        null,
        null,
        { ...build_vocoder(sysex.slice(38, 142)) },
      ];
  }
}

function build_patch(patch) {
  return {
    /* BYTES 0, 11 NOT 0, 12 */
    program_name: String.fromCharCode(...patch.slice(0, 12)),
    /* BYTES 12 / 13 SKIPPED */
    arp_trigger_length: patch[14],
    arp_trigger_pattern: toBitArray(patch[15]),
    voice_mode: getBits(patch[16], 4, 5),
    scale_key: getBits(patch[17], 4, 7),
    scale_type: getBits(patch[17], 0, 3),
    /* BYTE 18 SKIPPED */
    delay_sync: (patch[19] & (1 << 7)) !== 0,
    delay_timebase: getBits(patch[19], 0, 3),
    delay_time: patch[20],
    delay_depth: patch[21],
    delay_type: patch[22],
    mod_lfo_speed: patch[23],
    mod_depth: patch[24],
    mod_type: patch[25],
    eq_hi_freq: patch[26],
    eq_hi_gain: patch[27],
    eq_low_freq: patch[28],
    eq_low_gain: patch[29],
    arp_tempo: (patch[30] << 8) + patch[31],
    arp_on_off: (patch[32] & (1 << 7)) !== 0,
    arp_latch: (patch[32] & (1 << 6)) !== 0,
    arp_target: getBits(patch[32], 4, 5),
    arp_key_sync: (patch[32] & (1 << 0)) !== 0,
    arp_type: getBits(patch[33], 0, 3),
    arp_range: getBits(patch[33], 4, 7),
    arp_gate_time: patch[34],
    arp_resolution: patch[35],
    arp_swing: patch[36],
    keyboard_octave: patch[37],
  };
}

function build_timbre(num, timbre) {
  return {
    [`t${num}_midi_channel`]: timbre[0],
    [`t${num}_assign_mode`]: getBits(timbre[1], 6, 7),
    [`t${num}_eg_2_reset`]: (timbre[1] & (1 << 5)) !== 0,
    [`t${num}_eg_1_reset`]: (timbre[1] & (1 << 4)) !== 0,
    [`t${num}_trigger_mode`]: (timbre[1] & (1 << 3)) !== 0,
    [`t${num}_key_priority`]: getBits(timbre[1], 0, 1),
    [`t${num}_unison_detune`]: timbre[2],
    [`t${num}_tune`]: timbre[3],
    [`t${num}_bend_range`]: timbre[4],
    [`t${num}_transpose`]: timbre[5],
    [`t${num}_vibrato_int`]: timbre[6],
    [`t${num}_osc_1_wave`]: timbre[7],
    [`t${num}_osc_1_ctrl_1`]: timbre[8],
    [`t${num}_osc_1_ctrl_2`]: timbre[9],
    [`t${num}_osc_1_dgws`]: timbre[10],
    /* SKIP BYTE 11 */
    [`t${num}_osc_2_mod_select`]: getBits(timbre[12], 4, 5),
    [`t${num}_osc_2_wave`]: getBits(timbre[12], 0, 1),
    [`t${num}_osc_2_semitone`]: timbre[13],
    [`t${num}_osc_2_tune`]: timbre[14],
    [`t${num}_portamento`]: getBits(timbre[15], 0, 6),
    [`t${num}_osc_1_level`]: timbre[16],
    [`t${num}_osc_2_level`]: timbre[17],
    [`t${num}_noise_level`]: timbre[18],
    [`t${num}_filter_type`]: timbre[19],
    [`t${num}_filter_cutoff`]: timbre[20],
    [`t${num}_filter_resonance`]: timbre[21],
    [`t${num}_filter_eg_intensity`]: timbre[22],
    [`t${num}_filter_vel_sense`]: timbre[23],
    [`t${num}_filter_key_track`]: timbre[24],
    [`t${num}_amp_level`]: timbre[25],
    [`t${num}_amp_panpot`]: timbre[26],
    [`t${num}_amp_switch`]: (timbre[27] & (1 << 6)) !== 0,
    [`t${num}_amp_distortion`]: (timbre[27] & (1 << 0)) !== 0,
    [`t${num}_amp_vel_sense`]: timbre[28],
    [`t${num}_amp_key_track`]: timbre[29],
    [`t${num}_eg_1_attack`]: timbre[30],
    [`t${num}_eg_1_decay`]: timbre[31],
    [`t${num}_eg_1_sustain`]: timbre[32],
    [`t${num}_eg_1_release`]: timbre[33],
    [`t${num}_eg_2_attack`]: timbre[34],
    [`t${num}_eg_2_decay`]: timbre[35],
    [`t${num}_eg_2_sustain`]: timbre[36],
    [`t${num}_eg_2_release`]: timbre[37],
    [`t${num}_lfo_1_key_sync`]: getBits(timbre[38], 4, 5),
    [`t${num}_lfo_1_wave`]: getBits(timbre[38], 0, 1),
    [`t${num}_lfo_1_frequency`]: timbre[39],
    [`t${num}_lfo_1_tempo_sync`]: (timbre[40] & (1 << 7)) !== 0,
    [`t${num}_lfo_1_sync_note`]: getBits(timbre[40], 0, 4),
    [`t${num}_lfo_2_key_sync`]: getBits(timbre[41], 4, 5),
    [`t${num}_lfo_2_wave`]: getBits(timbre[41], 0, 1),
    [`t${num}_lfo_2_frequency`]: timbre[42],
    [`t${num}_lfo_2_tempo_sync`]: (timbre[43] & (1 << 7)) !== 0,
    [`t${num}_lfo_2_sync_note`]: getBits(timbre[43], 0, 4),
    [`t${num}_patch_1_dest`]: getBits(timbre[44], 4, 6),
    [`t${num}_patch_1_src`]: getBits(timbre[44], 0, 2),
    [`t${num}_patch_1_intensity`]: timbre[45],
    [`t${num}_patch_2_dest`]: getBits(timbre[46], 4, 6),
    [`t${num}_patch_2_src`]: getBits(timbre[46], 0, 2),
    [`t${num}_patch_2_intensity`]: timbre[47],
    [`t${num}_patch_3_dest`]: getBits(timbre[48], 4, 6),
    [`t${num}_patch_3_src`]: getBits(timbre[48], 0, 2),
    [`t${num}_patch_3_intensity`]: timbre[49],
    [`t${num}_patch_4_dest`]: getBits(timbre[50], 4, 6),
    [`t${num}_patch_4_src`]: getBits(timbre[50], 0, 2),
    [`t${num}_patch_4_intensity`]: timbre[51],
  };
}

function build_vocoder(vocoder) {
  return {
    v_midi_channel: vocoder[0],
    v_assign_mode: getBits(vocoder[1], 6, 7),
    v_eg_2_reset: (vocoder[1] & (1 << 5)) !== 0,
    v_eg_1_reset: (vocoder[1] & (1 << 4)) !== 0,
    v_trigger_mode: (vocoder[1] & (1 << 3)) !== 0,
    v_key_priority: getBits(vocoder[1], 0, 1),
    v_unison_detune: vocoder[2],
    v_tune: vocoder[3],
    v_bend_range: vocoder[4],
    v_transpose: vocoder[5],
    v_vibrato_int: vocoder[6],
    v_osc_wave: vocoder[7],
    v_osc_ctrl_1: vocoder[8],
    v_osc_ctrl_2: vocoder[9],
    v_osc_dgws: vocoder[10],
    /* BYTE 11 SKIPPED */
    v_audio_in_hpf_gate: (vocoder[12] & (1 << 0)) !== 0,
    /* BYTE 13 SKIPPED */
    v_portamento_time: getBits(vocoder[14], 0, 6),
    v_osc_level: vocoder[15],
    v_ext_level: vocoder[16],
    v_noise_level: vocoder[17],
    v_audio_in_hpf_level: vocoder[18],
    v_audio_in_gate_sense: vocoder[19],
    v_audio_in_threshold: vocoder[20],
    v_filter_shift: vocoder[21],
    v_filter_cutoff: vocoder[22],
    v_filter_resonance: vocoder[23],
    v_filter_mod_source: vocoder[24],
    v_filter_intensity: vocoder[25],
    v_filter_e_f_sense: vocoder[26],
    v_amp_level: vocoder[27],
    v_amp_direct_level: vocoder[28],
    v_amp_distortion: (vocoder[29] & (1 << 0)) !== 0,
    v_amp_vel_sense: vocoder[30],
    v_amp_key_track: vocoder[31],
    v_eg_1_attack: vocoder[32],
    v_eg_1_decay: vocoder[33],
    v_eg_1_sustain: vocoder[34],
    v_eg_1_release: vocoder[35],
    v_eg_2_attack: vocoder[36],
    v_eg_2_decay: vocoder[37],
    v_eg_2_sustain: vocoder[38],
    v_eg_2_release: vocoder[39],
    v_lfo_1_key_sync: getBits(vocoder[40], 4, 5),
    v_lfo_1_wave: getBits(vocoder[40], 0, 1),
    v_lfo_1_frequency: vocoder[41],
    v_lfo_1_tempo_sync: (vocoder[42] & (1 << 7)) !== 0,
    v_lfo_1_sync_note: getBits(vocoder[42], 0, 4),
    v_lfo_2_key_sync: getBits(vocoder[43], 4, 5),
    v_lfo_2_wave: getBits(vocoder[43], 0, 1),
    v_lfo_2_frequency: vocoder[44],
    v_lfo_2_tempo_sync: (vocoder[45] & (1 << 7)) !== 0,
    v_lfo_2_sync_note: getBits(vocoder[45], 0, 4),
    v_level_1: vocoder[46],
    v_level_2: vocoder[47],
    v_level_3: vocoder[48],
    v_level_4: vocoder[49],
    v_level_5: vocoder[50],
    v_level_6: vocoder[51],
    v_level_7: vocoder[52],
    v_level_8: vocoder[53],
    v_pan_1: vocoder[62],
    v_pan_2: vocoder[63],
    v_pan_3: vocoder[64],
    v_pan_4: vocoder[65],
    v_pan_5: vocoder[66],
    v_pan_6: vocoder[67],
    v_pan_7: vocoder[68],
    v_pan_8: vocoder[69],
  };
}
