% Script to convert APE toolbox [1] (MATLAB) .mat output files to WAET 
% toolbox [2] (HTML5/JavaScript) XML output files. 
%
% [1] B. De Man and Joshua D. Reiss, ?APE: Audio Perceptual Evaluation 
% toolbox for MATLAB,? 136th Convention of the Audio Engineering Society, 
% 2014.
%
% [2] Nicholas Jillings, Brecht De Man, David Moffat and Joshua D. Reiss, 
% "Web Audio Evaluation Tool: A Browser-Based Listening Test Environment," 
% 12th Sound and Music Computing Conference, July 2015.

% CONFIGURATION: 
location = 'CIRMMT Critical Listening Lab'; 
day = 5;
month = 2;
year = 2015;

% IMPORT FILES
sourcefolder = ... %'.';
    '/Users/Brecht/Google Drive/Writings/Mixing experiments/McGill/results/2015spring/mat';
outputfolder = [sourcefolder '/../xml'];
list = dir([sourcefolder '/*.mat']); % find all '.mat' files in this folder

% remove hidden files from list
% see http://www.mathworks.co.uk/matlabcentral/newsreader/view_thread/258220
for k = length(list):-1:1
    fname = list(k).name;
    if fname(1) == '.'
        list(k) = [ ];
    end
end

aliastable = {{'JohnSmith', 'anon1'};
			  {'JaneDoe', 'anon2'}};
        
% TODO: create output folder if doesn't exist yet

for i = 1:length(list) % for every file in the list
    matfile = load([sourcefolder '/' list(i).name]);
    name = fieldnames(matfile);
    test = matfile.(char(name)); % store loaded file in 'test'

    docNode = com.mathworks.xml.XMLUtils.createDocument('browserevaluationresult');
    docRootNode = docNode.getDocumentElement;

    % DATE AND TIME
    datetime = docNode.createElement('datetime');   % create 'datetime' child
    docRootNode.appendChild(datetime);
    date = docNode.createElement('date');           % create 'date' child
    datetime.appendChild(date); 
    date.setAttribute('year', num2str(year));       % add 'year' as attribute
    date.setAttribute('month', num2str(month));     % add 'month' as attribute
    date.setAttribute('day', num2str(day));         % add 'day' as attribute
    datestr = sprintf('%i/%i/%i', year, month, day);
    date.appendChild(docNode.createTextNode(datestr));

    % PRETEST
    pretest = docNode.createElement('pretest');
    docRootNode.appendChild(pretest);
        sessionID_comment = docNode.createElement('comment');
        pretest.appendChild(sessionID_comment);
        
        % Session ID: entered id or file name
        sessionID_comment.setAttribute('id', 'SessionID');
        %sessionID_comment.appendChild(docNode.createTextNode(test.id));
        str = anonymise(list(i).name(1:end-4), aliastable);
        sessionID_comment.appendChild(docNode.createTextNode(str));
        
        location_comment = docNode.createElement('comment');
        pretest.appendChild(location_comment);
        location_comment.setAttribute('id', 'location');
        location_comment.appendChild(docNode.createTextNode(location));


    % AUDIOHOLDER
    % for each song in the test:
    for song = 1:length(test.tstDat)/2 % 2 structs for every song
        song_id = song*2; % every second field corresponds with a song
        
        % only add song if 'rsl' present
        if isfield(test.tstDat{1,song_id}, 'rsl')
            % create audioholder
            audioholder = docNode.createElement('audioholder');
            docRootNode.appendChild(audioholder);
            % save song name
            songname = test.tstDat{1,song_id-1}.tstFile(2:end-4); % chop off '_*.txt'
            audioholder.setAttribute('id', songname);
            % add pretest (empty)
            pretest = docNode.createElement('pretest');
            audioholder.appendChild(pretest);
            % add posttest (empty)
            posttest = docNode.createElement('posttest');
            audioholder.appendChild(posttest);
            % add metric
            metric = docNode.createElement('metric');
            audioholder.appendChild(metric);
            metricresult = docNode.createElement('metricresult');
                metric.appendChild(metricresult);
                metricresult.setAttribute('id', 'testTime');
                testduration = 60*test.tstDat{1,song_id}.rsl.duration; % minutes to seconds
                metricresult.appendChild(docNode.createTextNode(num2str(testduration)));

            % go over audio files in the order they were presented
            permVec = test.tstDat{1,song_id}.rsl.permVec;
            Naudioelements = length(permVec); 
            invPermVec(permVec(1:Naudioelements)) = 1:Naudioelements;
            for index=1:length(permVec) % ('index' is presented id)
                actualID = invPermVec(index);
                % create audioelement and attach to audioholder
                audioelement = docNode.createElement('audioelement');
                audioholder.appendChild(audioelement);
                % save mix name
                mixname = ...
                    anonymise(test.tstDat{1,song_id-1}.rsl.sounds(actualID).name, ...
                    aliastable);
                % distinguish between pro1 and pro2 (Spring 2014)
                if strcmp(mixname, 'McG-pro')
                    if strcmp(songname, 'PouringRoom')
                        mixname = [mixname '1'];
                    else if strcmp(songname, 'InTheMeantime')
                            mixname = [mixname '2'];
                        end
                    end
                end
                audioelement.setAttribute('id', mixname);
                    %...strcat('McG-', mixname)); % Prefix 'McG-'
                % add presented id
                audioelement.setAttribute('presentedid', num2str(index));
                % add comment
                comment = docNode.createElement('comment');
                audioelement.appendChild(comment);
                    % add comment question and response
                    question = docNode.createElement('question');
                    comment.appendChild(question);
                    str = sprintf('Comment on track %i', index);
                    question.appendChild(docNode.createTextNode(str));
                    response = docNode.createElement('response');
                    comment.appendChild(response);
                    % comment order as shown
                    str = char(test.tstDat{1,song_id}.rsl.hcom(index));
                    % avoid errors due to multiline strings: 
                    str_t = str'; % transpose str
                    str = str_t(:)'; % concatenate columns and transpose again
                    if length(str)<4% get rid of shot, meaningless comments
                        if length(str)>1
                            if strncmp(str(2), ':', 1) % if a number and a column
                                str = ''; % omit entirely
                            end
                        else % if just a number
                            str = ''; % omit
                        end
                    else % strip numbers off comments
                        if strncmp(str(2:3), ': ', 2)
                            str = str(4:end); % strip '1: ' off string
                        else if strncmp(str(2), ':', 1)
                                str = str(3:end); % strip '1:' off string
                            else if strncmp(str(3:4), ': ', 2) % strip '10: ' off string
                                    str = str(5:end);
                                else if strncmp(str(3), ':', 1) % strip '10:' off string
                                    str = str(4:end);
                                    end
                                end
                            end
                        end
                    end
                    response.appendChild(docNode.createTextNode(str));
                % add rating
                value = docNode.createElement('value');
                audioelement.appendChild(value);
                % divide by 100 to be within 0-1
                rating = test.tstDat{1,song_id}.rsl.mat(actualID)/100;
                value.appendChild(docNode.createTextNode(num2str(rating)));
                % add metric (only 'has been played')
                metric = docNode.createElement('metric');
                audioelement.appendChild(metric);
                metricresult = docNode.createElement('metricresult');
                metric.appendChild(metricresult);
                hasbeenplayed = test.tstDat{1,song_id}.rsl.playVec(actualID); % I guess?
                if hasbeenplayed
                    metricresult.appendChild(docNode.createTextNode('true'));
                else
                    metricresult.appendChild(docNode.createTextNode('false'));
                end
            end
        end
    end

    xmlFileName = [outputfolder '/' anonymise(list(i).name(1:end-4), aliastable) '.xml'];
    xmlwrite(xmlFileName,docNode);
    % type(xmlFileName); % display XML in CLI
end