const express = require('express');
const auth = require('../middleware/authenticator.js');
const verify = require("../middleware/verifier.js");
const mysql = require("../db/mysql.js");
const alphaProcesser = require('../AlphaTab/ProcessAlphaTab.js');
const ParserMeasures = require("../Parser/ParserMeasures.js");
const ParserPData = require("../Parser/ParserPerformanceData.js");
const Manipulator = require("../Parser/ParsedOutputManipulator.js");
const updateExerciseTable = require("../util/updateExercise.js");
const router = express.Router();
/**
* @typedef {object} ExerciseGetPackage
* @property {string} sheet_music The Tex for the exercise
* @property {string[]} part_list A list of the part names of the AlphaTex
* @property {string[]} clefs A list of clefs per staff
* @property {number[]} performance_expectation A 1D array of even size with the ith index as the midi value and the i+1 index as the duration of that note for i%2==0
* @property {number[]} lower_upper A 1D two valued array with the lower and upper midi values
* @property {number[]} measure_lengths A collection of the lengths of each Measure. The ith index contains the length in seconds of the i+1 Measure
* @property {string} part The name of the main exercise to be rendered
*/
/**
* Route for getting an exercise within the given parameters if the user is a member of the choir attached to the given sheet music
* @name exercise/get
* @function
* @inner
* @param {*} req
* @param {string} req.query.sheetMusicId The sheet music ID to be accessed.
* @param {number} req.query.trackNumber The track number to be accessed
* @param {number} req.query.staffNumber The staff number to be accessed
* @param {number} req.query.measureStart The start measure number for the exercise
* @param {number} req.query.measureEnd The end measure number for the exercise
* @param {boolean} req.query.isDurationExercise Whether the exercise should be a duration exercise or not
* @param {*} res
* @returns {ExerciseGetPackage|string} On success, a collection of information about the exercise. Otherwise, an error message.
* @async
*/
router.get('/', auth.token, async (req,res) => {
verify.memberOfSheetMusic(req, res).then((choirId) => {
if (choirId === null) {
res.status(403).send('Unauthorized');
} else {
let sheetMusicId = req.query.sheetMusicId;
let trackNumber = parseInt(req.query.trackNumber,10);
let staffNumber = parseInt(req.query.staffNumber,10);
let measureStart = parseInt(req.query.measureStart,10);
let measureEnd = parseInt(req.query.measureEnd,10);
let isDurationExercise = req.query.isDurationExercise;
const errorMessage = "Unable to get exercise";
if (sheetMusicId && trackNumber && staffNumber && measureStart && measureEnd && isDurationExercise !== undefined) {
mysql.getClient().then((client) => {
client.query("SELECT performance_data FROM tma.sheet_music WHERE sheet_music_id = unhex(?)", [sheetMusicId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
isDurationExercise = req.query.isDurationExercise === 'true' ? true : false;
let performanceData = JSON.parse(results[0]['performance_data']);
let measureParser = new ParserMeasures(performanceData);
let texAndLyrics = measureParser.measuresToAlphaTex([measureStart, measureEnd], trackNumber, staffNumber, isDurationExercise);
let tex = texAndLyrics.alphaTex;
let exercisePerformanceData = alphaProcesser.process(tex, {0:texAndLyrics.lyricText});
let partNames = ParserPData.getPartNames(exercisePerformanceData.mainObj);
let clefs = ParserPData.getClefs(exercisePerformanceData.mainObj);
let partName = partNames[0];
let noteStream = ParserPData.getNoteStream(exercisePerformanceData.mainObj, partName);
let lowerAndUpper = ParserPData.getLowerAndUpper(noteStream);
let manipulator = new Manipulator(exercisePerformanceData.mainObj);
let measureLengths = manipulator.getMeasureTimeLength(partName);
let retObj = {
"sheet_music": tex,
"part_list": partNames,
clefs,
"performance_expectation": noteStream,
"lower_upper": lowerAndUpper,
"measure_lengths": measureLengths,
"part": partNames[0]
};
updateExerciseTable(sheetMusicId, trackNumber, staffNumber, measureStart, measureEnd, isDurationExercise).then((exerciseId) => {
retObj.exerciseId = exerciseId;
res.status(200).json(retObj);
});
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
module.exports = router;