Source: routers/exercise.js

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;