Source: supervision_shifts.js

(
/**
* Contains the functionalities related to the supervision shifts page.
*
* @module supervision_shifts
* @author Joonas Konki
* @author Anu Koskela
* @author Mikko Kuhno
* @author Henrik Paananen
* @author Atte Räty
* @license BSD 3-clause, see LICENSE for more details.
* @copyright 2015 Kepler project authors
*/
function(){
var timeslots = null;
var ownTimeSlots = null;
var allTimeSlots = null;
var currentTime = null;
var showOwnTimeSlots = true;
var cal = null;

/**
* Creates a table which displays all the supervision shifts, and a toggleable
* area for each shift, which includes the information of the reserved unit
* groups and of the participants. Adds a "cancel shift" button (and a listener
* for it) for each upcoming shift.
* @memberof module:supervision_shifts
*/
function initTable(data) {
//TODO (Anu) Editing the time slot

    timeslots = data.time_slots;
    var tsList = $('#timeSlotList');

    for (var i = 0; i < timeslots.length; i++) {
        var ts = timeslots[i];
        var tsDiv = $('<li>').addClass('timeSlot').attr('id',"li" + i);
        var hasReservations = ts.reservations.length !== 0;

        var listRow = $('<div>').addClass("list-group-item");
        listRow.attr("id", "header" + i);

        var noOfExperiments = getNumberOfReservations(ts);
        if(ts.status == 'canceled_id'){
            listRow.append($("<span>").addClass("badge").text(
              noOfExperiments).css("background", "#a94442").css(
                                   "display", "inline-block"));
            listRow.addClass("list-group-item-danger");
            listRow.attr("data-toggle", "collapse").attr("data-target",
                         "#row" + i).css("cursor","pointer");
            listRow.append($("<span>").addClass(
              "glyphicon glyphicon-chevron-down").css("float","left").css(
                                                      "cursor","pointer"));
        }
        else if(hasReservations){
            listRow.append($("<span>").addClass("badge").text(
              noOfExperiments).css("display", "inline-block"));
            listRow.addClass("list-group-item-info");
            listRow.attr("data-toggle","collapse").attr(
              "data-target","#row"+i).css("cursor","pointer");
            listRow.append($("<span>").addClass(
              "glyphicon glyphicon-chevron-down").css("float","left").css(
                                                      "cursor","pointer"));
        }
        else {
            listRow.append($("<span>").addClass("badge").text(
              noOfExperiments).css("background",
              "lightgray").css("display", "inline-block"));
            listRow.addClass("list-group-item-default").attr("disabled", true);
            listRow.append($("<span>").addClass(
              "glyphicon glyphicon-chevron-down").css("color", "lightgray").css(
                                                      "float","left"));
        }

        var tsTime = kepler.datetimeIntervalString(ts.start_time, ts.end_time);

        var tm_span = $("<div>").text(tsTime);
        tm_span.css("display", "inline-block").css("min-width", "12em");
        tm_span.css("margin-left", "1em");
        listRow.append(tm_span);


        var tsName = ts.unit_type_name;
        var instructors = "";
        for (var k = 0; k < ts.supervisors.length; k++){
            if (k > 0) instructors += ",";
            if(ts.supervisors[k].call_name !== null) {
              instructors += " " + ts.supervisors[k].call_name;
            }
            else {
              instructors += " " + ts.supervisors[k].first_names;
            }
            instructors += " " + ts.supervisors[k].last_name;
        }
        tsName += ", " + instructors;
        listRow.append($("<div>").text(tsName).css("display", "inline-block"));

        if (ts.status == 'canceled_id'){
            var cancelledSpan = $("<div>").text(
              kepler.translate('content.reservations_cancelled_time_slot'));
            cancelledSpan.css("display","inline-block").css("min-width","12em");
            cancelledSpan.css("margin-left", "1em");
            listRow.append(cancelledSpan);
        }

        tsDiv.append(listRow);

        var collapseRow = $('<div>').addClass('collapse').attr('id',"row" + i);
        for (var j = 0; j < ts.reservations.length; j++){
            var colUnitGroup = "";
            var listItem = $("<li>").addClass("list-group-item");
            var helpDiv = $("<div>").addClass("row");
            var listDivInfo = $("<div>").addClass("col-sm-6");

            addExperimentsInfo(ts, j, listDivInfo);
            helpDiv.append(listDivInfo);


            if(ts.reservations[j].notes.length !== 0){
                var infoDiv = $("<div>").append($("<b>").text(kepler.translate(
                  'content.reservations_extra_info') + ":"));
                for (var l = 0; l < ts.reservations[j].notes.length; l++) {

                    infoDiv.append($("<br>")).append($("<i>").text(
                      ts.reservations[j].notes[l].note));
                }
                helpDiv.append(infoDiv);
            }

            listItem.append(helpDiv);
            collapseRow.append(listItem);
        }

        var buttonClass = '';
        buttonClass = "class='btn btn-default'";
        var editButton = $("<button id=" + ts.id + " " + buttonClass +
                           ">" + kepler.translate('button.edit') +"</button>");
        if (ts.start_time > currentTime) editButton.hide();
        if (noOfExperiments === 0) editButton.attr("disabled", true);
        editButton.click(function(){
            notImplementedMsg();
        });
        var buttonDiv = $("<div>").attr("align", "right");
        buttonDiv.append(editButton);
        collapseRow.append(buttonDiv);
        tsDiv.append(collapseRow);
        tsList.append(tsDiv);
    }
}

/**
* Initialises and updates the calendar.
* @memberof module:supervision_shifts
*/
function updateCalendar() {
    if (cal === null) {
        initCalendar();
    }
    cal.fullCalendar('refetchEvents');
}

/**
* Selects the event clicked on the calendar.
* @memberof module:supervision_shifts
* @param event - Contains the event information.
* @param element - Contains information what kind of
* element the clicked event is.
* @param view - Contains the viewmode in which the element is shown.
*/
function calendarClick (event, element, view) {
    if (event.eventTimeslot !== undefined) {
        selectCalendarTimeslot(event);
    }
}

/**
* Renders the events to the calendar using a default renderer.
* @memberof module:supervision_shifts
* @param event - Contains the event information.
* @param element - Contains information what kind of
* element the clicked event is.
* @param view - Contains the viewmode in which the element is shown.
*/
function calendarEventRender(event, element, view) {
    calUtil.defaultEventRender(event, element, view);
}

/**
* Initialises the calendar.
* @memberof module:supervision_shifts
* @param calendarClick - The click function to be added to the calendar events.
* @param calendarEventRender - The render options to be added to
*                              the calendar events.
*/
function initCalendar() {
    cal = calUtil.initCal(calendarClick, calendarEventRender);

     cal.fullCalendar('addEventSource', {
         events: function(start, end, timezone, callback) {

            var params = {
                'start_time': start.toISOString(),
                'end_time': end.toISOString()
            };

            if(showOwnTimeSlots) {
                params.current_user = true;
            }


            kepler.getCalendarEvents(params, function(data) {
                 var events = [];
                 for (var i = 0; i < data.events.length; i++) {

                    var event = data.events[i];
                    var color = calUtil.colorPalette.reservedGrey;

                    var pointer = false;
                    var res_id = null;
                    if(event.type === 'reservation'){
                        color = calUtil.colorPalette.lightBlue;
                        res_id = event.reservation.id;
                        pointer = true;
                    }

                    calEvent = calUtil.makeCalendarEvent(event);
                    calEvent.color = color;
                    calEvent.borderColor = calUtil.colorPalette.borderBlue;
                    calEvent.textColor = 'black';
                    calEvent.reservation_id = res_id;
                    calEvent.pointer = pointer;

                    events.push(calEvent);
                }
                callback(events);
            });
        }
    });

}



/**
* Gets the number of reservations for the specific time slot.
*
* @memberof module:supervision_shifts
* @param timeslot - The time slot for which the information is fetched for.
*/
function getNumberOfReservations(timeslot){
    return timeslot.reservations.length;
}

/**
* Creates a list element that includes the information of the reserved
* unit, the extra information it may have and its participants.
* @memberof module:supervision_shifts
* @param {object} timeslot - The selected time slot.
* @param {number} index - The index of the wanted unit.
* @param {object} parent - The element where the information is added.
*/
function addExperimentsInfo(timeslot, index, parent){
    var studentList = $("<ul>").css("list-style","none");
    var experiment = timeslot.reservations[index];

    parent.append($("<div>").text(experiment.unit_group_name + "/" +
        experiment.unit_qualifier + ", " + experiment.unit_name));
    for (var k = 0; k < experiment.user_group.members.length; k++){
        var listItem = $("<li>");

        var button = $("<button>");
        button.addClass("btn btn-xs btn-default").attr("type", "button");
        button.attr("data-placement", "bottom");
        button.attr("data-toggle", "popover").attr("title",
                    kepler.translate('label.contactInfo'));

        var emailText = "";
        if (experiment.user_group.members[k].email === ""){
            emailText = kepler.translate('label.noContactInfo');
        }
        else {
            emailText = experiment.user_group.members[k].email;
        }
        button.attr("data-content",emailText);

        button.append($("<span>").addClass("glyphicon glyphicon-info-sign"));
        button.popover();

        listItem.append(button);
        listItem.append($("<span>").text(
          " " + experiment.user_group.members[k].name +  " "));

        studentList.append(listItem);
    }
    parent.append(studentList);
}


/**
* Shows the wanted time slots based on which options (past, present, future)
* are checked and hides the rest. If no time slots match the selected time
* frame, shows a notification.
* @memberof module:supervision_shifts
*/
function updateTable(){
    var tsList = $('#timeSlotList');
    var howManyDisplayed = 0;
    var showPast = $('#selectionPast').is(':checked');
    var showCurrent = $('#selectionCurrent').is(':checked');
    var showFuture =$('#selectionFuture').is(':checked');

    function timeSlotVisible(timeSlot) {
        return (showPast && timeSlot.end_time < currentTime) ||
            (showCurrent && (timeSlot.start_time < currentTime &&
                timeSlot.end_time > currentTime) ) ||
            (showFuture && timeSlot.start_time > currentTime);
    }

    for (var i = 0; i < timeslots.length; i++) {
        if (timeSlotVisible(timeslots[i])) {
            $("#li" + i).show();
            howManyDisplayed++;
        }
        else $("#li" + i).hide();
    }

    if(howManyDisplayed === 0) {
        $("#noMatches").show();
        $("#timeSlotList").hide();
    }
    else {
      $("#noMatches").hide();
      $("#timeSlotList").show();
    }
}

/**
* Reloads the information of the time slots from the database, empties and
* updates the list of the time slots.
* @memberof module:supervision_shifts
*/
function reloadTimeSlots(){
    var tsTable = $("#timeSlotList");
    tsTable.empty();

    var params = null;
    if (showOwnTimeSlots){
        if(ownTimeSlots === null){
            params = {
                "current_user": true,
                "only_active": true,
            };
            kepler.getTimeSlots(params, function (data) {
                ownTimeSlots = data;
                currentTime = data.timestamp;
                initTable(ownTimeSlots);
                updateTable();

                $('#displayedSelection').change(function () {
                    updateTable();
                });
            });
        }
        else {
            initTable(ownTimeSlots);
            updateTable();
        }
    }
    else if (!showOwnTimeSlots){
        if(allTimeSlots === null){
            params = {
                "only_active": true,
            };
            kepler.getTimeSlots(params, function (data) {
                allTimeSlots = data;
                currentTime = data.timestamp;
                initTable(allTimeSlots);
                updateTable();
            });
        }
        else{
        initTable(allTimeSlots);
        updateTable();
        }
    }

}

/**
* This is executed after the HTML page has been loaded.
* This is a common procedure of all of the client-side modules to
* initialise the page content.
* @memberof module:supervision_shifts
*/
function doc_ready() {
    $("#navSupervisionShifts").addClass("active");
    reloadTimeSlots();

    $("#timeframeSelection").change(function(v){
        notImplementedMsg();
        //TODO (Anu)
    });

    /**
    * Updates the view to shows the supervision time slots of the selected
    * user.
    *
    * @function
    * @name supervisorSelection change
    * @inner
    * @memberof module:supervision_shifts
    */
    $("#supervisorSelection").change(function(v){
        if ($("#showOwn").is(':checked')) {
            showOwnTimeSlots = true;
            if($("#calendar").is(":visible")){
                updateCalendar();
            }else{
                reloadTimeSlots();
            }
        }
        else if ($("#showAll").is(':checked')){
            showOwnTimeSlots = false;
            if($("#calendar").is(":visible")){
                updateCalendar();
            }else{
                reloadTimeSlots();
            }
        }

    });

    /**
    * Toggles between the calendar and list views when the button is clicked.
    *
    * @function
    * @name toggleCalendarBtn click
    * @inner
    * @memberof module:supervision_shifts
    */
    $("#toggleCalendarBtn").click(function(v) {
        if($("#calendar").is(":visible")) {
            $("#timeSlotList").show();
            $("#calendar").hide();
            $("#toggleCalendarBtn").text(
                kepler.translate('content.reservation_frame_button_calendar'));
            reloadTimeSlots();
        } else {
            $("#timeSlotList").hide();
            $("#calendar").show();
            updateCalendar();
            $("#toggleCalendarBtn").text(
                kepler.translate('content.reservation_frame_button_list'));
        }
    });
}

$(document).ready(doc_ready);
}());