/* Minification failed. Returning unminified contents.
(556,17-22): run-time error JS1300: Strict-mode does not allow assignment to undefined variables: model
 */
'use strict';

// Angular

var wbApp = angular.module('wbApp', [
    'ngAnimate',
    'mgcrea.ngStrap',
    'pascalprecht.translate',
    'ngResource',
    'ngSanitize',
    'wb.directives',
    'angulartics',
    'angulartics.google.analytics',
    'angulartics.facebook.pixel',
    'LocalStorageModule',
    'uiGmapgoogle-maps',
    'googlechart',
    'WBGrid',
    'nemLogging',
    'jkuri.gallery',
    'dx'
]);


//wbApp.config(['$tabProvider', function ($tabProvider) {
//    angular.extend($tabProvider.defaults, {
//        template: 'details-tabs-template.html'
//    });
//}]);

wbApp.config(['$locationProvider', function ($locationProvider) {
    $locationProvider.html5Mode({ enabled: true, requireBase: false, rewriteLinks: false });
}]);

wbApp.config(['$modalProvider', function ($modalProvider) {
    angular.extend($modalProvider.defaults, {
        animation: 'am-fade-and-slide-top',
    });
}]);

wbApp.config(['$datepickerProvider', function ($datepickerProvider) {
    angular.extend($datepickerProvider.defaults, {
        startWeek: 1,
        autoclose: true,
        container: 'body',
        useNative: true,
        dateFormat: 'd.M.yyyy'
    });
}]);

wbApp.config(['$timepickerProvider', function ($timepicketProvider) {
    angular.extend($timepicketProvider.defaults, {
        autoclose: true,
        //container: 'body',
        useNative: true,
        timeFormat: 'H:mm'
    });
}]);

wbApp.config(['localStorageServiceProvider', function (localStorageServiceProvider) {
    localStorageServiceProvider.setPrefix('wbAppNgAdmin');
    localStorageServiceProvider.setStorageType('localStorage');
    localStorageServiceProvider.setNotify(true, true);
}]);

function convertDateStringsToDates(input) {
    // Ignore things that aren't objects.
    if (typeof input !== "object") return input;

    for (var key in input) {
        if (!input.hasOwnProperty(key)) continue;

        var value = input[key];
        var match;
        // Check for string properties which look like dates.
        if (typeof value === "string" && isNaN(value)) {
            var date = moment(value, moment.ISO_8601);
            if (date.isValid()) {
                input[key] = date.toDate();
            }
        } else if (typeof value === "object") {
            // Recurse into object
            convertDateStringsToDates(value);
        }
    }
}

//var regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})(Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/;
//var regexIso8601 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|([\-+])(\d{2}):(\d{2}))?$/;

wbApp.config(["$httpProvider", function ($httpProvider) {
    $httpProvider.defaults.transformResponse.push(function (data, headerGetter) {
        convertDateStringsToDates(data);
        return data;
    });

    $httpProvider.defaults.transformRequest.push(function (data, header) {
        return data;
    });
}]);


// Strip the timezone
Date.prototype.toISOString = function () {
    return moment(this).format('YYYY-MM-DDTHH:mm:ss');
};

wbApp.constant('currentUser', loggedInUser);
wbApp.constant('preferredLanguage', preferredLanguage);
wbApp.constant('securityFeatures', securityFeatures);
wbApp.constant('tenantInfo', tenantInfo);

moment.locale(preferredLanguage);
moment.duration().locale(preferredLanguage);

if (tenantInfo.isFranchiseCentral) {
    wbApp.config(['uiGmapGoogleMapApiProvider', function (uiGmapGoogleMapApiProvider) {
        uiGmapGoogleMapApiProvider.configure({
            key: 'AIzaSyDgac1ahn5_WNYnb1b0TgRf7Q_JhM3ZRQc',
            v: '3.20', //defaults to latest 3.X anyhow
            libraries: 'weather,geometry,visualization'
        });
    }]);
}



;
'use strict';

wbApp.controller('ActionRegistrationCtrl', ['$scope', '$translate', '$modal', 'securitySvc', 'tenantSettingSvc', 'actionDetailSvc', 'notificationSvc', 'onlinePaymentsSvc', 'urlUtils',
    'studentSvc', 'employeeSvc', 'courseSvc', 'classroomSvc', '$filter', 'courseRegistrationSvc', 'messageBoxSvc',
    function ($scope, $translate, $modal, securitySvc, tenantSettingSvc, actionDetailSvc, notificationSvc, onlinePaymentsSvc, urlUtils,
        studentSvc, employeeSvc, courseSvc, classroomSvc, $filter, courseRegistrationSvc, messageBoxSvc) {

        var courseID = urlUtils.getLastUrlPart();

        //var actionDetail = actionDetailSvc.getActionDetail();
        //actionDetail.$promise.then(function (result) {
        //    actionDetailSvc.setUpActionPrices(result.action, result.students);
        //    $scope.students = result.students;
        //    $scope.origStudents = angular.copy(result.students);
        //    validateConditionForBooking(result.students);
        //    prepareTabs();
        //    $scope.images = _.map(result.action.pictures, function (p) {
        //        return {
        //            thumb: p.imageUrl,
        //            img: p.imageUrl
        //        };
        //    });
        //});

        $scope.actionScheduleDesc = '';
        $scope.actionIsLoading = true;
        $scope.supportsOnlinePayment = false;
        $scope.userStudents = null;
        $scope.students = null;
        $scope.studentsAreLoading = true;
        $scope.employeeIsLoading = true;
        $scope.employee = {};
        $scope.classroom = { address: { location: {} } };
        $scope.isSaving = false;

        function validateConditionForBooking(students) {
            if (!securitySvc.isAuthenticated()) {
                $scope.serverError = { errors: [{ message: $translate.instant('TXT_ERROR_NOT_LOGGED_IN') }] };
            } else {
                if (!students.length) {
                    $scope.serverError = { errors: [{ message: $translate.instant('TXT_ERROR_NO_STUDENTS') }] };
                }
            }
        }


        function setUpScope(students) {

            $scope.origStudents = angular.copy(students);

            // Preselect student if only one is defined
            if (!!students && students.length == 1) {
                var student = students[0];
                if (student.isNew) {
                    student.attend = true;
                }
            }
        }

        function loadStudentRegs(refresh, registrationsLoadedCallback) {
            if ($scope.userStudents.length && (!$scope.students || refresh)) {
                $scope.students = courseRegistrationSvc.getAllForCourseAndUser(
                    securitySvc.loggedInUser().userID,
                    $scope.action,
                    $scope.userStudents,
                    true,
                    tenantSettingSvc.settings.courseInterestsSupport,
                    $scope.showLessonSelection);

                $scope.students.$promise.then(function () {
                    $scope.studentsAreLoading = false;
                    setUpScope($scope.students);
                    if (!!registrationsLoadedCallback) {
                        registrationsLoadedCallback($scope.students);
                    }
                });
            }
        }

        function loadData(registrationsLoadedCallback) {
            $scope.action = courseSvc.getByCourseID(courseID);
            $scope.action.$promise.then(function (action) {

                $scope.supportsOnlinePayment = action.supportsOnlinePayment;

                $scope.employee = employeeSvc.getBriefByEmployeeID(action.employeeID);
                $scope.employee.$promise.then(function () {
                    $scope.employeeIsLoading = false;
                });

                $scope.actionScheduleDesc = !!action.firstLesson
                    ? $filter('date')(action.firstLesson, 'd. M. y EEE HH:mm').toUpperCase() + 
                      ' - ' +
                      $filter('date')(action.firstLessonEndDate, 'HH:mm')
                    : '';

                $scope.images = _.map(action.pictures, function (p) {
                    return {
                        thumb: p.imageUrl,
                        img: p.imageUrl
                    };
                });

                if (securitySvc.isAuthenticated()) {
                    studentSvc.getCurrentAsync().$promise.then(function (students) {

                        $scope.userStudents = students;

                        validateConditionForBooking(students);

                        if (!students.length) {
                            $scope.students = [];
                            $scope.studentsAreLoading = false;
                        } else {
                            prepareTabs();
                            if (!!$scope.students) {
                                loadStudentRegs(true, registrationsLoadedCallback);
                            }
                        }
                    });
                } else {
                    $scope.students = [];
                    $scope.studentsAreLoading = false;

                    validateConditionForBooking(null); 
                }

                if ($scope.action.classroomID) {
                    classroomSvc.getAsync($scope.action.classroomID).then(function (data) {
                        angular.extend($scope.classroom, data);
                    });
                }

                $scope.actionIsLoading = false;
            });
        }


        $scope.allowShareOnFBForActions = tenantSettingSvc.settings.allowShareOnFBForActions;

      //  $scope.action = actionDetail.action;

        $scope.tabs = [{
            title: 'TXT_TAB_ACTION_DETAIL',
            template: 'actions/action-detail-tab.html',
            name: 'detail'
        }];

        $scope.tabs.activeTab = 0;

        var preparedTabsCalled = false;

        $scope.$watch('tabs.activeTab', function (newValue, oldValue) {

            if (preparedTabsCalled || !urlUtils.getQueryParams()['tabName']) {
                var tabName = $scope.tabs[newValue].name;
                urlUtils.setUrlParam("tabName", tabName);
            }

            if (newValue !== 0) {
                loadStudentRegs(false);
            }
        });

        function showOnlinePaymentResultsIfNeeded() {
            var onlinePaymentIDStr = urlUtils.getQueryParams()['onlinePaymentID'];
            if (!!onlinePaymentIDStr) {
                var onlinePaymentID = Number(onlinePaymentIDStr);

                onlinePaymentsSvc.getTransactionState(onlinePaymentID).$promise.then(
                    function (data) {
                        messageBoxSvc.showMessageDlg({
                            title: 'TXT_PAYMENT_RESULT',
                            message: onlinePaymentsSvc.getOnlinePaymentResultMessage(data),
                            buttons: [{
                                text: 'TXT_BTN_OK',
                                callback: function () {
                                    urlUtils.removeUrlParam('onlinePaymentID');
                                }
                            }]
                        });
                    });
            }
        }

        function switchToCorrectTab() {
            var tabName = urlUtils.getQueryParams()['tabName'];
            if (!!tabName) {
                // find correct tab
                var tabIndexToActivate = _.findIndex($scope.tabs, { name: tabName });
                if (tabIndexToActivate !== -1) {
                    if ($scope.tabs.activeTab !== tabIndexToActivate) {
                        $scope.tabs.activeTab = tabIndexToActivate;
                    }
                    showOnlinePaymentResultsIfNeeded();
                    return;
                }

            }

            $scope.tabs.activeTab = 0;
            urlUtils.setUrlParam("tabName", $scope.tabs[$scope.tabs.activeTab].name);
            showOnlinePaymentResultsIfNeeded();
        }

        function prepareTabs() {
            if (!$scope.serverError) {
                var idx = _.findIndex($scope.tabs, { name: 'book-event' });
                if (idx === -1) {
                    $scope.tabs.push({
                        title: 'TXT_TAB_BOOKING',
                        template: 'actions/book-action-tab.html',
                        name: 'book-event'
                    });
                }

                switchToCorrectTab();
            }

            preparedTabsCalled = true;
        }

        //$scope.onAttendanceCountChange = function (student) {
        //    actionDetailSvc.setUpActionPrices(actionDetail.action, $scope.students);
        //}

        $scope.shouldShowSaveButton = function () {
            if (!tenantSettingSvc.settings.allowClientActionRegistration) {
                return false;
            }

            if (!!$scope.serverError) {
                return false;
            }

            return $scope.tabs.activeTab === 1;
        }

        $scope.shouldEnableSaveButton = function () {
            if (!$scope.tabs.activeTab)
                return true;

            return !angular.equals($scope.origStudents, $scope.students);
        }

        $scope.onPrevBtnClick = function (returnUrl) {
            if ($scope.tabs.activeTab === 0) {
                window.location = returnUrl;
            } else {
                $scope.tabs.activeTab = 0;
            }
        }

        $scope.onNextClick = function () {

            if (!securitySvc.isAuthenticated()) {
                notificationSvc.advertiseLogin();
                return;
            }

            if ($scope.tabs.activeTab === 0) {
                $scope.tabs.activeTab = 1;
            }
        }

        $scope.confirmRegistration = { students: [] };

        $scope.onRegisterClick = function (returnUrl) {

            if (!$scope.tabs.activeTab) {
                $scope.tabs.activeTab += 1;
                return;
            }

            $scope.action.$promise.then(function (action) {
                if ($scope.students && $scope.students.$promise) {
                    $scope.students.$promise.then(function () {
                        $scope.confirmRegistration.students = _.filter($scope.students, { isNew: true, attend: true });
                        $scope.confirmRegistration.courseID = $scope.action.courseID;
                        $scope.confirmRegistration.description = actionDetailSvc.getConfirmRegistrationDescription(
                            $scope.students,
                            $scope.origStudents,
                            $scope.action);

                        confirmRegistrationDlg.$promise.then(function () {
                            confirmRegistrationDlg.show();
                        });
                    });
                }
            });
        }

        $scope.onPromoBuyClick = function (student) {
            actionDetailSvc.updatePriceDetails($scope.action, student);
        }

        $scope.onRegistrationConfirmClick = function (courseID, students, hideFn) {

            $scope.isSaving = true;

            var notificationConfig = {
                sendEmailNotification: true,
                sendSmsNotification: false
            };

            // Clear all errors
            _.forEach(students, function (student) {
                student.markErrorAttendance.call(student, []);
            });

            courseRegistrationSvc.insertAll(
                _.filter($scope.students, { attend: true }),
                courseID,
                notificationConfig,
                2,
                function () {
                    $scope.bookCourseTabContent = 'courses/book-course-tab-confirmation-content.html';
                    hideFn();
                    loadData(function (registrations) {

                        if ($scope.supportsOnlinePayment) {

                            var newRegistrations = _.intersectionBy(registrations, students, 'studentID');
                            var invoiceIDs = _.map(newRegistrations, 'invoiceID');
                            var price = _.sumBy(newRegistrations, 'price');

                            messageBoxSvc.showMessageDlg({
                                title: 'TXT_TITLE_CONFIRM_ONLINE_PAYMENT',
                                message: '<i class="fa fa-3x fa-credit-card text-success pull-right" aria-hidden="true"></i>' +
                                    $translate.instant('TXT_CONFIRM_CONFIRM_START_ONLINE_PAYMENT'),
                                buttons: [{
                                    text: 'TXT_BTN_NO'
                                }, {
                                    text: 'TXT_BTN_YES',
                                    callback: function () { return onlinePaymentsSvc.startOnlinePayment(invoiceIDs, price).$promise; }
                                }]
                            });
                        }
                    });
                    $scope.isSaving = false;
                }, function (errorResult) {
                    $scope.isSaving = false;
                }
            );


            //actionDetailSvc.registerOnAction(
            //    courseID,
            //    students,
            //    success,
            //    error);

            //function success(result) {
            //    actionDetailSvc.setUpActionPrices(result.action, result.students);
            //    $scope.students = result.students;
            //    $scope.origStudents = angular.copy(result.students);
            //    validateConditionForBooking(result.students);
            //}

            //function error(result) {
            //    $scope.students = angular.copy($scope.origStudents);
            //}
        }

        var confirmRegistrationDlg = $modal({
            template: 'actions/confirm-registration.html',
            show: false,
            scope: $scope
        });


        loadData();

    }
]);;
'use strict';

wbApp.controller('ActionsCtrl', ['$scope', 'tenantSettingSvc',
function ($scope, tenantSettingSvc) {
    var data = actionList;

    $scope.tenantSettings = tenantSettingSvc.settings;

    $scope.actions = data;

    $scope.startDate = moment().toDate();
    $scope.endDate = moment().add('days', $scope.tenantSettings.noOfDaysToShowAction).toDate()

    $scope.setSelectedAction = function (action) {
        if (action.freeCapacity !== 0) {
            $scope.selectedAction = action;
            window.location = "/Actions/Register/" + action.id + "?returnUrl=Actions";
        }
    }

    $scope.tabs = [
        {
            title: $scope.tenantSettings.eventsMenuName
                ? $scope.tenantSettings.eventsMenuName
                : 'TXT_TITLE_ACTIONS',
            template: 'actions/actions-list-tab.html'
        }
    ];

    $scope.tabs.activeTab = 0;
}]);;
'use strict';

wbApp.factory('actionDetailSvc', [
    '$http', 'notificationSvc', '$translate', 'courseRegistrationCommonSvc',
    function ($http, notificationSvc, $translate, courseRegistrationCommonSvc) {

        //var model = courseRegistrationCommonSvc.prepareModelAsync(action, true); // external dependency
        //// model : { action: ..., studetns: [] }

        //function getActionDetail() {
        //    return model;
        //}

        function registerOnAction(courseID, students, onSuccess, onError) {
            $http({
                method: 'POST',
                url: '/Actions/Register',
                data: { courseID: courseID, students: students }
            })
            .success(function (actionDetail, status, headers, config) {

                model = courseRegistrationCommonSvc.prepareModelAsync(actionDetail, true);
                model.$promise.then(function (result) {
                    if (onSuccess) {
                        onSuccess(model);
                    }

                    notificationSvc.notifyInfo(
                        $translate.instant('TXT_ALERT_TITLE_ACTION_REGISTRATION_SUCCESS'));
                });
            })
            .error(function (errorResult, status, headers, config) {
                if (onError) {
                    onError(errorResult);
                }

                notificationSvc.notifyError(
                    $translate.instant('TXT_ALERT_TITLE_ACTION_REGISTRATION_FAILURE'),
                    notificationSvc.translateError(errorResult));
            });
        }

        function setUpActionPrices(action, students) {
            return courseRegistrationCommonSvc.setUpCoursePrices(action, students);
        }

        function getConfirmRegistrationStudents(students, origStudents) {
            return courseRegistrationCommonSvc.getConfirmRegistrationStudents(students, origStudents, true);
        }

        function getConfirmRegistrationDescription(students, origStudents, action) {
            return courseRegistrationCommonSvc.getConfirmRegistrationDescription(students, origStudents, action, true);
        }

        function updatePriceDetails(action, student) {
            courseRegistrationCommonSvc.updatePriceDetails(action, student);
        }

        return {
           // getActionDetail: getActionDetail,
            registerOnAction: registerOnAction,
            setUpActionPrices: setUpActionPrices,
            updatePriceDetails: updatePriceDetails,
            getConfirmRegistrationStudents: getConfirmRegistrationStudents,
            getConfirmRegistrationDescription: getConfirmRegistrationDescription
        }
    }]);
;
'use strict';

wbApp.controller('ActivitiesCtrl', ['$scope', '$translate', '$analytics', 'tenantSettingSvc', 'securitySvc', 'activitySvc', 'notificationSvc',
function ($scope, $translate, $analytics, tenantSettingSvc, securitySvc, activitySvc, notificationSvc) {
    $scope.tenantSettings = tenantSettingSvc.settings;

    $scope.semesters = activitySvc.getAllOpenForRegistration();

    $scope.tabs = [];
    $scope.tabs.activeTab = 0;

    function PrepareTabs(data) {
        for (var i = 0; i < data.length; i++) {
            var semester = data[i];
            $scope.tabs.push({
                title: semester.semesterName,
                template: "activities/activity-list-tab.html",
                activities: semester.activities
            });
        }
        $scope.tabs.activeTab = 0;
    }

    $scope.onInterestClick = function (semesterID) {

        if (!securitySvc.isAuthenticated()) {
            notificationSvc.advertiseLogin();
            return;
        }

        $analytics.eventTrack('Lead');

        activitySvc.registerActivityInterest(semesterID, success);

        function success() {
            notificationSvc.notifyInfo($translate.instant('TXT_ALERT_TITLE_ACTIVITY_INTEREST_REQUESTED'));
        }
    }

    $scope.semesters.$promise.then(function (data) {
        PrepareTabs(data);
    });
}]);;
'use strict';

wbApp.controller('ActivityAttendanceCtrl', ['$scope', '$filter', '$modal', '$translate', '$q' ,'activityAttendanceSvc',
function ($scope, $filter, $modal, $translate, $q, activityAttendanceSvc) {
    

    $scope.tabs = [
        {
            title: 'TXT_TAB_ACTIVITY_SELECTION',
            template: 'activity-attendance/activity-selection-tab.html'
        },
        {
            title: 'TXT_TAB_DAY_SELECTION',
            template: 'activity-attendance/day-selection-tab.html'
        },
        {
            title: 'TXT_TAB_ATTENDANCE',
            template: 'activity-attendance/attendance-edit-tab.html'
        }]

    $scope.tabs.activeTab = 0;


    $scope.activities = activities;
    $scope.activitySchedules = activitySchedules;
    $scope.scheduleMonths = [];
    $scope.selectedMonth = null;
    $scope.semesterID = semesterID;
    $scope.attendanceChanged = false;

    function setSelectedActivityImpl(activity) {
        $scope.scheduleMonths = activityAttendanceSvc.filterAndBreakByMonth($scope.activitySchedules, activity.activityID);
        selectToday($scope.scheduleMonths);
        $scope.selectedActivity = activity;
    }

    $scope.setSelectedActivity = function (activity) {
        setSelectedActivityImpl(activity);
        $scope.tabs.activeTab += 1;
    }

    $scope.setSelectedSchedule = function (schedule) {
        $scope.selectedSchedule = schedule;
        $scope.attendances = activityAttendanceSvc.getAttendancesBySchedule(schedule);
        $scope.tabs.activeTab += 1;
    }

    // TODO: $index is wrong
    $scope.onAttendaceConfirmClicked = function (attendance) {
        var oldConfirmed = !attendance.confirmed;

        var index = _.findIndex($scope.attendances, { 'studentID': attendance.studentID });

        activityAttendanceSvc.saveAttendanceAsync(attendance, false).$promise
            .then(function (data) {
                // success
                $scope.attendanceChanged = true;                
                $scope.attendances[index] = data[0];
            }, function (error) {
                // revert to previous state
                attendance.confirmed = oldConfirmed;
            });

    }

    $scope.$watch('tabs.activeTab', function (newValue, oldValue) {
        switch (newValue) {
            case 1:
                onDaySelectionTabShow();
                break;
        }
    });

    function selectToday(months) {
        if (!months || !months.length) {
            $scope.selectedMonth = null;
            $scope.selectedSchedule = null;
            return;
        }

        var month = null;
        var schedule = null;
        var today = moment();
        for (var m = 0; m < months.length; m++) {
            month = months[m];
            var mStartDay = moment(month.startDate);
            if (mStartDay.year() >= today.year() &&
                mStartDay.month() >= today.month()) {
                for (var s = 0; s < month.schedules.length; s++) {
                    schedule = month.schedules[s];
                    var sStartDate = moment(schedule.startDate);
                    if (sStartDate.date() >= today.date()) {
                        $scope.selectedMonth = month;
                        month.expanded = true;
                        $scope.selectedSchedule = schedule;
                        $scope.attendances = activityAttendanceSvc.getAttendancesBySchedule(schedule);
                        return;
                    }
                }
            }
        }

        month = months[months.length - 1];
        if (!month.schedules.length) {
            return;
        }
        month.expanded = true;
        schedule = month.schedules[month.schedules.length - 1];

        $scope.selectedMonth = month;
        $scope.selectedSchedule = schedule;
        $scope.attendances = activityAttendanceSvc.getAttendancesBySchedule(schedule);
    }

    function setSelectedActivityByNewActivities(activities, oldSelectedActivity) {

        if (!oldSelectedActivity) {
            return;
        }

        for (var i = 0; i < activities.length; i++) {
            var activity = activities[i];
            if (activity.activityID === oldSelectedActivity.activityID) {
                $scope.selectedActivity = activity;
            }
        }
    }

    function setSelectedActivityScheduleByNewSchedules(schedules, oldSelectedSchedule) {
        if (!oldSelectedSchedule) {
            return;
        }

        for (var i = 0; i < schedules.length; i++) {
            var schedule = schedules[i];
            if (schedule.activityScheduleID === oldSelectedSchedule.activityScheduleID) {
                $scope.selectedSchedule = schedule;
            }
        }
    }

    function setSelectedMonthBynewActivities(months, selectedMonth) {
        if (!selectedMonth) {
            return;
        }

        for (var i = 0; i < months.length; i++) {
            var month = months[i];
            if (moment(month.startDate).isSame(moment(selectedMonth.startDate))) {
                $scope.selectedMonth = month;
                month.expanded = true;
            }
        }
    }

    function onDaySelectionTabShow() {
        if ($scope.attendanceChanged) {
            
            var a = activityAttendanceSvc.getActivitySchedules($scope.semesterID);
            a.$promise.then(function (data) {
                $scope.activities = data.activities;
                $scope.activitySchedules = data.activitySchedules;

                var months = activityAttendanceSvc.filterAndBreakByMonth($scope.activitySchedules, $scope.selectedActivity.activityID);

                if (months.length === $scope.scheduleMonths.length) {
                    for (var m = 0; m < months.length; m++) {
                        var newMonth = months[m];
                        var oldMonth = $scope.scheduleMonths[m];

                        oldMonth.schedules.length = 0;
                        oldMonth.schedules.push.apply(oldMonth.schedules, newMonth.schedules);
                    }
                } else {
                    $scope.scheduleMonths = months;
                }
                
                setSelectedActivityByNewActivities($scope.activities, $scope.selectedActivity);
                setSelectedMonthBynewActivities(months, $scope.selectedMonth);
                setSelectedActivityScheduleByNewSchedules($scope.activitySchedules, $scope.selectedSchedule);

            });
            $scope.attendanceChanged = false;
        }
    }

    $scope.setSelectedMonth = function (month) {
        $scope.selectedMonth = month;
        month.expanded = !month.expanded;
    }

    $scope.noteChangeModal = { title: "", saved: false };

    $scope.editDayNote = function (schedule) {
        $scope.noteChangeModal.schedule = schedule;
        $scope.noteChangeModal.lessonNote = schedule.notes;

        noteChangeModalPromise.$promise.then(function () {
            noteChangeModalPromise.show();
        });
    }

    $scope.showWaitQueue = function (schedule, activity) {
        waitQueueModalPromise.$promise.then(function () {
            waitQueueModalPromise.$scope.schedule = schedule;
            waitQueueModalPromise.$scope.activity = activity;
            waitQueueModalPromise.show();
        });
        
    }

    $scope.onLessonNoteChange = function (schedule, lessonNote, sendNotification) {
        var res = activityAttendanceSvc.updateScheduleNotesAsync(schedule.activityScheduleID, lessonNote, sendNotification);
        res.$promise.then(function () {
            schedule.notes = lessonNote;
        });
    }

    $scope.onAddBtnClick = function () {
        $scope.addStudentModal = { studentID: null };

        addStudentModalPromise.$promise.then(function () {
            addStudentModalPromise.show();
        });
    }

    $scope.onAddStudent = function (studentID) {
        if ($scope.selectedSchedule) {
            activityAttendanceSvc.addNewStudent($scope.attendances, $scope.selectedSchedule, studentID);
        }
    }

    $scope.onPrevBtnClick = function () {
        if ($scope.tabs.activeTab > 0) {
            $scope.tabs.activeTab--;
        } else {
            $scope.tabs.activeTab = 0;
        }
    }

    $scope.onDoneBtnClick = function () {

        var promisses = [];

        for (var i = 0; i < $scope.attendances.length; i++) {
            var a = $scope.attendances[i];

            if (a.isDirty) {
                var p = activityAttendanceSvc.saveAttendanceAsync(a, false).$promise;
                promisses.push(p);

                p.then(function (data) {
                    // success
                    $scope.attendanceChanged = true;
                    $scope.attendances[i] = data;
                });
            }
        }

        $q.all(promisses).then(function () {
            $scope.onPrevBtnClick();
        });
    }

    $scope.onNextBtnClick = function () {
        if ($scope.tabs.activeTab < ($scope.tabs.length - 1)) {
            $scope.tabs.activeTab++;
        } else {
            $scope.tabs.activeTab = ($scope.tabs.length - 1);
        }
    }

    $scope.onDeleteAttendanceClick = function (attendance) {
        if (!attendance.canBeDeletedWithoutConfirmation) {            
            confirmDeletePromise.$promise.then(function () {
                $scope.attendanceToBeDeleted = attendance;
                $scope.attendanceToBeDeletedMessage = 
                    $translate.instant('TXT_CONFIRM_DELETE_STUDENT_ATTENDANCE').f(attendance.studentFullName);
                confirmDeletePromise.show();
            });
        } else {
            activityAttendanceSvc.deleteAttendanceAsync($scope.attendances, attendance);

        }
    }


    $scope.onConfirmAttendanceDeleteClick = function (attendance) {
        activityAttendanceSvc.deleteAttendanceAsync($scope.attendances, attendance);
        $scope.attendanceChanged = true;
    }

    var noteChangeModalPromise = $modal({
        template: 'activity-attendance/edit-lesson-note.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    var addStudentModalPromise = $modal({
        template: 'activity-attendance/add-student-detail.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    var confirmDeletePromise = $modal({
        template: 'activity-attendance/attendance-confirm-delete.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    var waitQueueModalPromise = $modal({
        template: 'activity-attendance/wait-queue-detail.html',
        show: false,
        backdrop: true,
        scope: $scope.$new()
    });

    // pre-select first activity
    if ($scope.activities.length > 0) {
        var filtered = $filter('orderBy')($scope.activities, 'name');
        setSelectedActivityImpl(filtered[0]);
    }

}]);;
var webooker_acivity_models = webooker_acivity_models || {};

(function (ns) {

    // #region ActivityAttendance - Ctor 
    ns.ActivityAttendance = function ActivityAttendance(
        schedule,
        reservation,
        attendance,
        activityStudentSetting,
        activity,
        tenantSetting,
        numberOfExcuses,
        studentID,
        momentNow) {

        this.schedule = schedule;
        this.reservation = reservation;
        this.attendance = attendance;

        this.activityStudentSetting = activityStudentSetting;
        this.activity = activity;
        this.tenantSetting = tenantSetting;
        
        this.momentNow = momentNow || function () { return moment(); }

        this.calculateProperties(studentID, numberOfExcuses);

        this.origAttendance = this.getServerAttendance();
    }

    // #endregion

    // #region ActivityAttendance - Methods

    ns.ActivityAttendance.prototype.clone = function () {
        var newObj = new ns.ActivityAttendance(
            this.schedule,
            this.reservation,
            !!this.attendance ? angular.copy(this.attendance) : this.attendance,
            this.activityStudentSetting,
            this.activity,
            this.tenantSetting,
            this.numberOfExcuses,
            this.studentID,
            this.momentNow
        );

        return newObj;
    }

    ns.ActivityAttendance.prototype.calculateProperties = function (studentID, numberOfExcuses, attendance, schedule) {
        if (attendance) {
            this.attendance = attendance;
        }

        if (schedule) {
            this.schedule = schedule;
        }

        this.numberOfExcuses = numberOfExcuses;

        var rdata = this.attendance || this.reservation;
        var data = rdata || this.schedule;        

        this.studentFullName = rdata ? rdata.studentFullName : null;
        this.studentID = rdata ? rdata.studentID : studentID;

        this.activityAttendanceID = data.activityAttendanceID || 0;
        this.activityScheduleID = data.activityScheduleID;
        this.activityID = data.activityID;

        this.firstPeriodStartDate = this.normalizeDate(data.firstPeriodStartDate);
        this.firstPeriodEndDate = this.normalizeDate(data.firstPeriodEndDate);
        this.secondPeriodStartDate = this.normalizeDate(data.secondPeriodStartDate);
        this.secondPeriodEndDate = this.normalizeDate(data.secondPeriodEndDate);
        this.lunch = data.lunch;
        this.firstSnack = data.firstSnack;
        this.secondSnack = data.secondSnack;
        this.notes = data.notes;
        this.scheduleNotes = this.schedule.notes;
        this.confirmed = this.activityAttendanceID !== 0 ? data.confirmed : false;
        this.firstPeriodFilled = this.schedule ? this.schedule.firstPeriodFilled : null;
        this.secondPeriodFilled = this.schedule ? this.schedule.secondPeriodFilled : null;
        this.firstPeriodCapacity = this.schedule ? this.schedule.firstPeriodCapacity : null;
        this.secondPeriodCapacity = this.schedule ? this.schedule.secondPeriodCapacity : null;

        this.firstPeriodWaitQueuePosition = !!this.attendance
            ? this.attendance.firstPeriodWaitQueuePosition
            : _.findIndex(this.schedule.firstPeriodWaitQueue, ['studentID', this.studentID]) + 1;

        this.secondPeriodWaitQueuePosition = !!this.attendance
            ? this.attendance.secondPeriodWaitQueuePosition
            : _.findIndex(this.schedule.secondPeriodWaitQueue, ['studentID', this.studentID]) + 1;

        if (this.attendance) {
            this._firstPeriodAttendanceStatusID = data.firstPeriodAttendanceStatusID;
            this.firstPeriodAttendanceTypeID = data.firstPeriodAttendanceTypeID;
            this._secondPeriodAttendanceStatusID = data.secondPeriodAttendanceStatusID;
            this.secondPeriodAttendanceTypeID = data.secondPeriodAttendanceTypeID;

        } else if (this.reservation) {
            this._firstPeriodAttendanceStatusID = !!this.reservation.firstPeriodStartDate ? 0 : 1;
            this.firstPeriodAttendanceTypeID = 0; // Registered
            this._secondPeriodAttendanceStatusID = !!this.reservation.secondPeriodStartDate ? 0 : 1;
            this.secondPeriodAttendanceTypeID = 0; // Registered
        } else {
            this._firstPeriodAttendanceStatusID = 1;
            this.firstPeriodAttendanceTypeID = 0;
            this._secondPeriodAttendanceStatusID = 1;
            this.secondPeriodAttendanceTypeID = 0;
        }
    }

    ns.ActivityAttendance.prototype.getServerAttendance = function () {

        var activityAttendance = {};

        activityAttendance.studentID = this.studentID;
        activityAttendance.activityAttendanceID = this.activityAttendanceID;
        activityAttendance.activityScheduleID = this.activityScheduleID;
        activityAttendance.activityID = this.activityID;

        if (!this.noReservationFirstPeriod) {
            activityAttendance.firstPeriodStartDate =
                this.deNormalizeDate(this.firstPeriodStartDate, this.schedule.firstPeriodStartDate);
            activityAttendance.firstPeriodEndDate =
                this.deNormalizeDate(this.firstPeriodEndDate, this.schedule.firstPeriodEndDate);

            activityAttendance.lunch = this.lunch;
            activityAttendance.firstSnack = this.firstSnack;
        } else {
            activityAttendance.lunch = false;
            activityAttendance.firstSnack = false;
        }

        if (!this.noReservationSecondPeriod) {
            activityAttendance.secondPeriodStartDate =
                this.deNormalizeDate(this.secondPeriodStartDate, this.schedule.secondPeriodStartDate);
            activityAttendance.secondPeriodEndDate =
                this.deNormalizeDate(this.secondPeriodEndDate, this.schedule.secondPeriodEndDate);
            activityAttendance.secondSnack = this.secondSnack;
        } else {
            activityAttendance.secondSnack = false;
        }

        activityAttendance.notes = this.notes;
        activityAttendance.confirmed = this.confirmed;

        activityAttendance.firstPeriodAttendanceTypeID = this.firstPeriodAttendanceTypeID;
        activityAttendance.firstPeriodAttendanceStatusID = this.firstPeriodAttendanceStatusID;
        activityAttendance.secondPeriodAttendanceTypeID = this.secondPeriodAttendanceTypeID;
        activityAttendance.secondPeriodAttendanceStatusID = this.secondPeriodAttendanceStatusID;

        activityAttendance.firstPeriodWaitQueuePosition = this.firstPeriodWaitQueuePosition;
        activityAttendance.secondPeriodWaitQueuePosition = this.secondPeriodWaitQueuePosition;

        return activityAttendance;
    }

    ns.ActivityAttendance.prototype.normalizeDate = function (date) {
        if (!date) {
            return date;
        }

        var mvalue = moment(date);
        return new Date(1970, 0, 1, mvalue.hours(), mvalue.minutes());
    }

    ns.ActivityAttendance.prototype.deNormalizeDate = function (date, scheduleDate) {
        if (!date) {
            return date;
        }

        var mvalue = moment(date);
        var mscheduleDate = moment(scheduleDate);
        return new Date(mscheduleDate.year(), mscheduleDate.month(), mscheduleDate.date(), mvalue.hours(), mvalue.minutes());
    }


     ns.ActivityAttendance.prototype.getExcuseType = function(periodStartDate, now) {
        if (this.isWithinActivityExcuseWithoutFoodTimeLimit(periodStartDate, now)) {
            return 2; // NotPresentExcused;
        }

        if (this.isWithinActivityExcuseTimeLimit(periodStartDate, now)) {
            return 4; // NotPresentExcusedWithoutFood;
        }

        return 3; //NotPresentExcusedNoCompensation;
     }

     ns.ActivityAttendance.prototype.isWithinActivityExcuseWithoutFoodTimeLimit = function (lessonStartDate, now) {
         return this.isWithinThresholdTimeLimit(
             this.tenantSetting.activityExcuseWithoutFoodThresholdType,
             this.tenantSetting.activityExcuseWithoutFoodThreshold,
             lessonStartDate,
             now);
     }

     ns.ActivityAttendance.prototype.isWithinActivityExcuseTimeLimit = function(lessonStartDate, now) {
         return this.isWithinThresholdTimeLimit(
             this.tenantSetting.activityExcuseThresholdType,
             this.tenantSetting.activityExcuseThreshold,
             lessonStartDate,
             now);
     }

     ns.ActivityAttendance.prototype.isWithinThresholdTimeLimit = function(thresholdType, threshold, lessonStartDate, now) {

         var mLessonStartDate = moment(lessonStartDate);
         var mNow = moment(now);

         switch (thresholdType) {
             case 0: // ExcuseThresholdType.NoOfHoursBeforeStart:
                 return moment.duration(mLessonStartDate.diff(mNow)).asHours() > threshold;
             case 1: // ExcuseThresholdType.AtSpecificTimeOnStartDate:
                 return mNow.isBefore(mLessonStartDate.startOf('day').add(threshold, 'hours'));
             case 2: // ExcuseThresholdType.AtSpecificTimeOnDateBeforeStartDate:
                 return mNow.isBefore(mLessonStartDate.startOf('day').add(threshold, 'hours').subtract(1, 'day'));
             case 3: // ExcuseThresholdType.AtSpecificTimeOnPrevBusinessDay:
                 return mNow.isBefore(mLessonStartDate.startOf('day').add(threshold, 'hours').subtract(
                     this.getNoOfDaysToPrevBusinessDay(mLessonStartDate), 'day'));
         }

         return false;
     }

     ns.ActivityAttendance.prototype.getNoOfDaysToPrevBusinessDay = function(pivot) {
         switch (pivot.isoWeekday()) {
             case 1: // Monday
                 return 3;
             case 7: // Sunday
                 return 2;
             default:
                 return 1;
         }
     }


     ns.ActivityAttendance.prototype.bookFirstPeriod = function (book /* boolean */, waitQueueOperation /* boolean */) {
         var shouldDisableFirstPeriodBooking = !this.schedule.firstPeriodStartDate;
         if (!shouldDisableFirstPeriodBooking) {
             if (!book) {
                 // Return to orig state
                 this._firstPeriodAttendanceStatusID = this.origAttendance.firstPeriodAttendanceStatusID;
                 this.firstPeriodAttendanceTypeID = this.origAttendance.firstPeriodAttendanceTypeID;
             } else {
                 if (this.origAttendance.firstPeriodAttendanceStatusID == 1 /* NotPresentNotExcused */ &&
                     this.origAttendance.firstPeriodAttendanceTypeID == 0 /* Registered */ &&
                     (!this.reservation || !this.reservation.firstPeriodStartDate)) {
                     switch (this.activityStudentSetting.activityCompensationTypeID) {
                         case 0: // ActivityCompensationType.OneExcuseForOneCompensation
                             if (this.numberOfExcuses > 0) {
                                 this.numberOfExcuses = waitQueueOperation
                                    ? this.numberOfExcuses
                                    : this.numberOfExcuses - 1;
                                 this.firstPeriodAttendanceStatusID = 0; /* Present */
                                 this.firstPeriodAttendanceTypeID = 2; /* Amend */
                             } else {
                                 this.firstPeriodAttendanceTypeID = 1; /* OneOff */
                                 this.firstPeriodAttendanceStatusID = 0; /* Present */
                             }
                             break;
                         case 1: // ActivityCompensationType.TwoExcusesForOneCompensation
                             if (this.numberOfExcuses > 1) {
                                 this.numberOfExcuses = waitQueueOperation
                                    ? this.numberOfExcuses
                                    : this.numberOfExcuses - 2;
                                 this.firstPeriodAttendanceStatusID = 0; /* Present */
                                 this.firstPeriodAttendanceTypeID = 2; /* Amend */
                             } else {
                                 this.firstPeriodAttendanceTypeID = 1; /* OneOff */
                                 this.firstPeriodAttendanceStatusID = 0; /* Present */
                             }
                             break;
                         case 2: // ActivityCompensationType.CompensationsDisabled
                             this.firstPeriodAttendanceTypeID = 1; /* OneOff */
                             this.firstPeriodAttendanceStatusID = 0; /* Present */
                             break;
                     }
                 } else {
                     this.firstPeriodAttendanceStatusID = 0; /* Present */;
                 }
             }
         }
     }

     ns.ActivityAttendance.prototype.bookSecondPeriod = function (book /* boolean */, waitQueueOperation /* boolean */) {
         var shouldDisableSecondPeriodBooking = !this.schedule.secondPeriodStartDate;
         if (!shouldDisableSecondPeriodBooking) {
             if (!book) {
                 // Return to orig state
                 this._secondPeriodAttendanceStatusID = this.origAttendance.secondPeriodAttendanceStatusID;
                 this.secondPeriodAttendanceTypeID = this.origAttendance.secondPeriodAttendanceTypeID;
             } else {
                 if (this.origAttendance.secondPeriodAttendanceStatusID == 1 /* NotPresentNotExcused */ &&
                     this.origAttendance.secondPeriodAttendanceTypeID == 0 /* Registered */ &&
                     (!this.reservation || !this.reservation.secondPeriodStartDate)) {
                     switch (this.activityStudentSetting.activityCompensationTypeID) {
                         case 0: // ActivityCompensationType.OneExcuseForOneCompensation
                             if (this.numberOfExcuses > 0) {
                                 this.numberOfExcuses = waitQueueOperation
                                    ? this.numberOfExcuses
                                    : this.numberOfExcuses - 1;
                                 this.secondPeriodAttendanceStatusID = 0; /* Present */
                                 this.secondPeriodAttendanceTypeID = 2; /* Amend */
                             } else {
                                 this.secondPeriodAttendanceTypeID = 1; /* OneOff */
                                 this.secondPeriodAttendanceStatusID = 0; /* Present */
                             }
                             break;
                         case 1: // ActivityCompensationType.TwoExcusesForOneCompensation
                             if (this.numberOfExcuses > 1) {
                                 this.numberOfExcuses = waitQueueOperation
                                    ? this.numberOfExcuses
                                    : this.numberOfExcuses - 2;
                                 this.secondPeriodAttendanceStatusID = 0; /* Present */
                                 this.secondPeriodAttendanceTypeID = 2; /* Amend */
                             } else {
                                 this.secondPeriodAttendanceTypeID = 1; /* OneOff */
                                 this.secondPeriodAttendanceStatusID = 0; /* Present */
                             }
                             break;
                         case 2: // ActivityCompensationType.CompensationsDisabled
                             this.secondPeriodAttendanceTypeID = 1; /* OneOff */
                             this.secondPeriodAttendanceStatusID = 0; /* Present */
                             break;
                     }
                 } else {
                     this.secondPeriodAttendanceStatusID = 0; /* Present */;
                 }
             }
         }
     }


     ns.ActivityAttendance.prototype.bookAttendanceByPeriod = function (activityAttendancePeriod) {

         this.bookFirstPeriod(activityAttendancePeriod.am);

         this.bookSecondPeriod(activityAttendancePeriod.pm);
     }


    // #endregion

    // #region ActivityAttendance - Properties




    // 0 - Present
    // 1 - Not present / not excused
    // 2 - Not present / excused
    // 3 - Not present / excused without compensation
    // 4 - Not present / excused without food

    Object.defineProperty(ns.ActivityAttendance.prototype, "firstPeriodAttendanceStatusID", {
        get: function () {
            return this._firstPeriodAttendanceStatusID;
        },
        set: function (value) {

            if (!this.schedule.firstPeriodStartDate) {
                value = 1;
            }

            var valid = true;
            var reserved = !!this.reservation && !!this.reservation.firstPeriodStartDate;

            switch (value) {
                case 0: // Present
                    break;
                case 1: // Not present / not excused
                    break;
                case 2: // Not present / excused
                    valid = reserved || this.firstPeriodAttendanceTypeID == 2;
                    break;
            }

            if (!valid) {
                this.firstPeriodAttendanceTypeID = 0;
                value = 1;
            }

            if (value !== 0) {
                this.firstPeriodStartDate = null;
                this.firstPeriodEndDate = null;
                if (value == 2) {  // Not present / excused
                    this.lunch = false;
                    this.firstSnack = false;

                    if (this.firstPeriodAttendanceTypeID == 2 || // Amend 
                       (!this.reservation || !this.reservation.firstPeriodStartDate && this.firstPeriodAttendanceTypeID == 0)) {
                        value = 1;
                        this.firstPeriodAttendanceTypeID = 0;
                    }
                } else {
                    if (!reserved) {
                        this.lunch = !!(this.attendance && this.attendance.lunch);
                        this.firstSnack = !!(this.attendance && this.attendance.firstSnack);
                    } else {
                        this.lunch = !!this.reservation.lunch;
                        this.firstSnack = !!this.reservation.firstSnack;
                    }
                }
            } else {
                if ((!this.reservation || !this.reservation.firstPeriodStartDate) && this.firstPeriodAttendanceTypeID == 0) {
                    this.firstPeriodAttendanceTypeID = 2;
                }

                if (!this.firstPeriodStartDate || !this.firstPeriodEndDate) {
                    if (this.reservation && !!this.reservation.firstPeriodStartDate) {
                        this.firstPeriodStartDate = this.normalizeDate(this.reservation.firstPeriodStartDate);
                        this.firstPeriodEndDate = this.normalizeDate(this.reservation.firstPeriodEndDate);
                        this.lunch = this.reservation.lunch;
                        this.firstSnack = this.reservation.firstSnack;
                    }
                    if (this.schedule) {
                        this.firstPeriodStartDate = this.normalizeDate(this.schedule.firstPeriodStartDate);
                        this.firstPeriodEndDate = this.normalizeDate(this.schedule.firstPeriodEndDate);
                        this.lunch = this.schedule.lunch;
                        this.firstSnack = this.schedule.firstSnack;
                    }
                }
            }

            this._firstPeriodAttendanceStatusID = value;
        },
        enumerable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "secondPeriodAttendanceStatusID", {
        get: function () {
            return this._secondPeriodAttendanceStatusID;
        },
        set: function (value) {

            if (!this.schedule.secondPeriodStartDate) {
                value = 1;
            }

            var valid = true;
            var reserved = !!this.reservation && !!this.reservation.secondPeriodStartDate;

            switch (value) {
                case 0: // Present
                    break;
                case 1: // Not present / not excused
                    break;
                case 2: // Not present / excused
                    valid = reserved || this.secondPeriodAttendanceTypeID == 2;
                    break;
            }

            if (!valid) {
                this.secondPeriodAttendanceTypeID = 0;
                value = 1;
            }

            if (value > 0) {
                this.secondPeriodStartDate = null;
                this.secondPeriodEndDate = null;
                if (value == 2) {
                    this.secondSnack = false;

                    if (this.secondPeriodAttendanceTypeID == 2) { // Amend 
                        value = 1;
                        this.secondPeriodAttendanceTypeID = 0;
                    }
                } else { //if (value === 1) { 
                    if (!reserved) {
                        this.secondSnack = !!(this.attendance && this.attendance.secondSnack);
                    } else {
                        this.secondSnack = !!this.reservation.secondSnack;
                    }
                }
            } else {
                if ((!this.reservation || !this.reservation.secondPeriodStartDate) && this.secondPeriodAttendanceTypeID == 0) {
                    this.secondPeriodAttendanceTypeID = 2;
                }

                if (!this.secondPeriodStartDate || !this.secondPeriodEndDate) {
                    if (this.reservation && !!this.reservation.secondPeriodStartDate) {
                        this.secondPeriodStartDate = this.normalizeDate(this.reservation.secondPeriodStartDate);
                        this.secondPeriodEndDate = this.normalizeDate(this.reservation.secondPeriodEndDate);
                        this.secondSnack = this.reservation.secondSnack;
                    }
                    if (this.schedule) {
                        this.secondPeriodStartDate = this.normalizeDate(this.schedule.secondPeriodStartDate);
                        this.secondPeriodEndDate = this.normalizeDate(this.schedule.secondPeriodEndDate);
                        this.secondSnack = this.schedule.secondSnack;
                    }
                }
            } 

            this._secondPeriodAttendanceStatusID = value;
        },
        enumerable: true//,
        //configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "firstPeriodActive", {
        get: function () {
            return !!this.schedule.secondPeriodStartDate;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "secondPeriodActive", {
        get: function () {
            return !!this.schedule.secondPeriodStartDate;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "startDate", {
        get: function () {
            return moment(this.schedule.firstPeriodStartDate || this.schedule.secondPeriodStartDate).startOf('day').toDate();
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "weekNo", {
        get: function () {
            return moment(this.schedule.firstPeriodStartDate || this.schedule.secondPeriodStartDate).isoWeek()
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "attending", {
        get: function () {
            return ((!!this.reservation || !!this.attendance) &&
                !(!this.reservation && (
                    this.firstPeriodAttendanceStatusID === 1 &&
                    this.firstPeriodAttendanceTypeID === 0 &&
                    this.secondPeriodAttendanceStatusID === 1 &&
                    this.secondPeriodAttendanceTypeID === 0))) ||
                    (!!this.firstPeriodWaitQueuePosition || !!this.secondPeriodWaitQueuePosition);
        },
        enumerable: true,
        configurable: true
    });

    // 0 - Present
    // 1 - Not present / not excused
    // 2 - Not present / excused
    // 3 - Not present / excused without compensation
    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldShowFirstPeriodTypeIDEdit", {
        get: function () {
            return ((this.firstPeriodAttendanceStatusID == 0 &&
                (!this.reservation || !this.reservation.firstPeriodStartDate)) || (this.firstPeriodAttendanceTypeID != 0)) &&
                !this.firstPeriodWaitQueuePosition;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldShowSecondPeriodTypeIDEdit", {
        get: function () {
            return ((this.secondPeriodAttendanceStatusID == 0 &&
                (!this.reservation || !this.reservation.secondPeriodStartDate)) || (this.secondPeriodAttendanceTypeID != 0)) &&
                !this.secondPeriodWaitQueuePosition;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "canBeDeleted", {
        get: function () {
            return !this.reservation;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "canBeDeletedWithoutConfirmation", {
        get: function () {
            return !this.reservation && !this.activityAttendanceID;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "clientEditable", {
        get: function () {

            var now = this.momentNow().subtract(1, 'days').startOf('day');
            var startDate = moment(this.schedule.startDate).startOf('day');
            

            return !this.confirmed && now.isBefore(startDate);
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "clientExcusable", {
        get: function () {

            return this.clientEditable &&
                   ((this.firstPeriodAttendanceStatusID == 0 || this.firstPeriodWaitQueuePosition > 0) ||
                    (this.secondPeriodAttendanceStatusID == 0 || this.secondPeriodWaitQueuePosition > 0));
            
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "clientBookable", {
        get: function () {

            if (!this.clientEditable) {
                return false;
            }

            var excused =
                (this.firstPeriodAttendanceStatusID == 2 ||    // Not present / excused
                 this.firstPeriodAttendanceStatusID == 3 ||    // Not present / excused without compensation
                 this.firstPeriodAttendanceStatusID == 4) ||   // Not present / excused without food
                (this.secondPeriodAttendanceStatusID == 2 ||
                 this.secondPeriodAttendanceStatusID == 3 ||
                 this.secondPeriodAttendanceStatusID == 4);

            if (excused) {
                return true;
            }       

            return this.noReservationFirstPeriod || this.noReservationSecondPeriod;

        },
        enumerable: true,
        configurable: true
    });


    Object.defineProperty(ns.ActivityAttendance.prototype, "noReservationFirstPeriod", {
        get: function() {
            return (!this.reservation || (!!this.reservation && !this.reservation.firstPeriodStartDate)) &&
                !!this.schedule.firstPeriodStartDate &&
                this.firstPeriodAttendanceStatusID == 1  && // Not present / not excused
                this.firstPeriodAttendanceTypeID == 0;      // Registered
        }
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "noReservationSecondPeriod", {
        get: function () {
            return (!this.reservation || (!!this.reservation && !this.reservation.secondPeriodStartDate)) &&
                !!this.schedule.secondPeriodStartDate &&
                this.secondPeriodAttendanceStatusID == 1 && // Not present / not excused
                this.secondPeriodAttendanceTypeID == 0;      // Registered
        }
    });


    Object.defineProperty(ns.ActivityAttendance.prototype, "clientBookableCapacityCheck", {
        get: function () {
            return this.clientBookable &&
                ((this.firstPeriodFreeSpots > 0 && !this.shouldDisableFirstPeriodBooking) ||
                    (this.secondPeriodFreeSpots > 0 && !this.shouldDisableSecondPeriodBooking));

        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "firstPeriodFreeSpots", {
        get: function () {
            return Math.max(this.firstPeriodCapacity - this.firstPeriodFilled, 0);
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "showFirstPeriodFreeSpots", {
        get: function () {
            return this.clientBookable && !this.shouldDisableFirstPeriodBooking;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "secondPeriodFreeSpots", {
        get: function () {
            return Math.max(this.secondPeriodCapacity - this.secondPeriodFilled, 0);
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "showSecondPeriodFreeSpots", {
        get: function () {
            return this.clientBookable && !this.shouldDisableSecondPeriodBooking;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldShowFirstPeriodStatus", {
        get: function () {

            var b = !!this.schedule.firstPeriodStartDate &&
                   (
                       (!!this.reservation && !!this.reservation.firstPeriodStartDate) ||
                       (!!this.attendance &&
                          !(this.attendance.firstPeriodAttendanceTypeID == 0 &&
                            this.attendance.firstPeriodAttendanceStatusID == 1 &&
                           (!this.reservation || !this.reservation.firstPeriodStartDate)))
                   );
            return b;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldShowSecondPeriodStatus", {
        get: function () {
            var b = !!this.schedule.secondPeriodStartDate &&
                    (
                        (!!this.reservation && !!this.reservation.secondPeriodStartDate) ||
                        (!!this.attendance &&
                           !(this.attendance.secondPeriodAttendanceTypeID == 0 &&
                             this.attendance.secondPeriodAttendanceStatusID == 1 &&
                            (!this.reservation || !this.reservation.secondPeriodStartDate)))
                    );
            return b;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldDisableFirstPeriodBooking", {
        get: function () {
            return !this.schedule.firstPeriodStartDate || this.firstPeriodAttendanceStatusID == 0;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldDisableSecondPeriodBooking", {
        get: function () {
            return !this.schedule.secondPeriodStartDate || this.secondPeriodAttendanceStatusID == 0;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldDisableFirstPeriodExcuse", {
        get: function () {
            return !this.schedule.firstPeriodStartDate ||
                   (this.firstPeriodAttendanceStatusID != 0 && !this.firstPeriodWaitQueuePosition);
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "shouldDisableSecondPeriodExcuse", {
        get: function () {
            return !this.schedule.secondPeriodStartDate || 
                   (this.secondPeriodAttendanceStatusID != 0 && !this.secondPeriodWaitQueuePosition);
        },
        enumerable: true,
        configurable: true
    });
    
    Object.defineProperty(ns.ActivityAttendance.prototype, "isDirty", {
        set: function (value) {
            this.origAttendance = this.getServerAttendance();   // TODO: This looks suspicious !!!
        },
        get: function () {
            if (this.confirmed) {
                return false;
            }

            var attendance = this.getServerAttendance();
            return !angular.equals(attendance, this.origAttendance);
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "hasNewWaitQueue", {
        get: function () {
            var firstPeriodScheduleWaitQueue = this.schedule.firstPeriodWaitQueue || [];
            var secondPeriodScheduleWaitQueue = this.schedule.secondPeriodWaitQueue || [];

            return this.isDirty && (
                (!!this.firstPeriodWaitQueuePosition && !(_.findIndex(firstPeriodScheduleWaitQueue, ['studentID', this.studentID]) + 1)) ||
                (!!this.secondPeriodWaitQueuePosition && !(_.findIndex(secondPeriodScheduleWaitQueue, ['studentID', this.studentID]) + 1))
            );
        },
        enumerable: true,
        configurable: true
    });


    Object.defineProperty(ns.ActivityAttendance.prototype, "isNotRegularAttendance", {
        get: function () {
            return this.attending &&
                (((this.firstPeriodAttendanceStatusID !== 0 ||
                 this.firstPeriodAttendanceTypeID !== 0) &&
                !(this.firstPeriodAttendanceStatusID === 1 && this.firstPeriodAttendanceTypeID === 0 && this.reservation && !this.reservation.firstPeriodStartDate)) ||
                ((this.secondPeriodAttendanceStatusID !== 0 ||
                 this.secondPeriodAttendanceTypeID !== 0) &&
                !(this.secondPeriodAttendanceStatusID === 1 && this.secondPeriodAttendanceTypeID === 0 && this.reservation && !this.reservation.secondPeriodStartDate)))
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "firstPeriodAttending", {
        get: function () {
            return this.firstPeriodAttendanceStatusID == 0 || // Present
                   this.firstPeriodWaitQueuePosition > 0;
        },
        set: function (value) {
            if (value == this.firstPeriodAttending) {
                return;
            }

            if (!value) {

                var waitQueueOperation = this.firstPeriodWaitQueuePosition > 0;
                if (waitQueueOperation) {
                    this.firstPeriodWaitQueuePosition = 0;
                }

                if (this.firstPeriodAttendanceStatusID == 0 /* Present */) {
                    // Excuse
                    if (this.clientExcusable) {
                        var resetToOrig = this.origAttendance.firstPeriodAttendanceStatusID !== this.firstPeriodAttendanceStatusID ||
                            this.origAttendance.firstPeriodAttendanceTypeID !== this.firstPeriodAttendanceTypeID;

                        var excuseType = resetToOrig
                            ? this.origAttendance.firstPeriodAttendanceStatusID
                            : this.getExcuseType(
                                this.deNormalizeDate(this.firstPeriodStartDate, this.schedule.firstPeriodStartDate), this.momentNow().toDate())

                        if (!waitQueueOperation) {
                            if ((excuseType == 2 /* NotPresentExcused */ ||
                                 excuseType == 4 /* NotPresentExcusedWithoutFood */) &&
                                (this.firstPeriodAttendanceTypeID == 2 /* Amend */ ||
                                 this.firstPeriodAttendanceTypeID == 0 /* Registered */)) {

                                switch (this.activityStudentSetting.activityCompensationTypeID) {
                                    case 0: // OneExcuseForOneCompensation
                                        this.numberOfExcuses = this.numberOfExcuses + 1;
                                        break;
                                    case 1: // TwoExcusesForOneCompensation:
                                        this.numberOfExcuses = this.numberOfExcuses + 2;
                                        break;
                                    case 2: // CompensationsDisabled:
                                        break;
                                }
                            }
                        }
                        this.firstPeriodAttendanceStatusID = excuseType;
                        this.firstPeriodFilled = waitQueueOperation
                            ? this.firstPeriodFilled
                            : this.firstPeriodFilled - 1;
                        if (resetToOrig) {
                            this.firstPeriodAttendanceTypeID = this.origAttendance.firstPeriodAttendanceTypeID;
                        }
                    }
                }
            } else if (value) {
                if (this.clientBookable) {

                    var waitQueueOperation = this.schedule.firstPeriodCapacity <= this.firstPeriodFilled;
                    var resetToWqOrigState = false;

                    if (waitQueueOperation) {
                        var scheduleWaitQueue = this.schedule.firstPeriodWaitQueue || [];

                        resetToWqOrigState = _.findIndex(scheduleWaitQueue, ['studentID', this.studentID]) > -1;

                        this.firstPeriodWaitQueuePosition =
                            (_.findIndex(scheduleWaitQueue, ['studentID', this.studentID]) + 1) || scheduleWaitQueue.length + 1;
                    } else {
                        if ((this.firstPeriodAttendanceTypeID == 2 /* Amend */ ||
                            this.firstPeriodAttendanceTypeID == 0 /* Registered */) &&
                            (this.firstPeriodAttendanceStatusID == 2 /* NotPresentExcused */ ||
                                this.firstPeriodAttendanceStatusID == 4) /* NotPresentExcusedWithoutFood */) {

                            switch (this.activityStudentSetting.activityCompensationTypeID) {
                                case 0: // OneExcuseForOneCompensation:
                                    if (this.numberOfExcuses > 0) {
                                        this.numberOfExcuses = this.numberOfExcuses - 1;
                                    } else {
                                        return; // We do not have any excuses to reuse, so do not allow to change the attendance
                                    }
                                    break;
                                case 1: // TwoExcusesForOneCompensation:
                                    if (this.numberOfExcuses > 1) {
                                        this.numberOfExcuses = this.numberOfExcuses - 2;
                                    } else {
                                        return; // We do not have any excuses to reuse, so do not allow to change the attendance
                                    }
                                    break;
                                case 2: // CompensationsDisabled:
                                    return; // Compensations are disabled;
                            }
                        }
                    }

                    if (!resetToWqOrigState) {
                        this.bookFirstPeriod(true, waitQueueOperation);
                    } else {
                        this.firstPeriodAttendanceTypeID = this.origAttendance.firstPeriodAttendanceTypeID;
                        this.firstPeriodAttendanceStatusID = this.origAttendance.firstPeriodAttendanceStatusID;
                        this.firstPeriodStartDate = this.origAttendance.firstPeriodStartDate;
                        this.firstPeriodEndDate = this.origAttendance.firstPeriodEndDate;
                        this.lunch = this.origAttendance.lunch;
                        this.firstSnack = this.origAttendance.firstSnack;
                    }
                    if (!waitQueueOperation) {
                        this.firstPeriodFilled = this.firstPeriodFilled + 1;
                    }
                }
            }
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "secondPeriodAttending", {
        get: function () {
            return this.secondPeriodAttendanceStatusID == 0 ||  // Present;
                   this.secondPeriodWaitQueuePosition > 0;
        },
        set: function (value) {
            if (value == this.secondPeriodAttending) {
                return;
            }

            if (!value) { 
                
                var waitQueueOperation = this.secondPeriodWaitQueuePosition > 0;
                if (waitQueueOperation) {
                    this.secondPeriodWaitQueuePosition = 0;
                }

                if (this.secondPeriodAttendanceStatusID == 0 /* Present */) {
                    // Excuse
                    if (this.clientExcusable) {

                        var resetToOrig = this.origAttendance.secondPeriodAttendanceStatusID !== this.secondPeriodAttendanceStatusID ||
                            this.origAttendance.secondPeriodAttendanceTypeID !== this.secondPeriodAttendanceTypeID;

                        var excuseType = resetToOrig
                            ? this.origAttendance.secondPeriodAttendanceStatusID
                            : this.getExcuseType(
                                this.deNormalizeDate(this.secondPeriodStartDate, this.schedule.secondPeriodStartDate), this.momentNow().toDate())

                        if (!waitQueueOperation) {
                            if ((excuseType == 2 /* NotPresentExcused */ ||
                                 excuseType == 4 /* NotPresentExcusedWithoutFood */) &&
                                (this.secondPeriodAttendanceTypeID == 2 /* Amend */ ||
                                 this.secondPeriodAttendanceTypeID == 0 /* Registered */)) {

                                switch (this.activityStudentSetting.activityCompensationTypeID) {
                                    case 0: // ActivityCompensationType.OneExcuseForOneCompensation
                                        this.numberOfExcuses = this.numberOfExcuses + 1;
                                        break;
                                    case 1: // ActivityCompensationType.TwoExcusesForOneCompensation
                                        this.numberOfExcuses = this.numberOfExcuses + 2;
                                        break;
                                    case 2: // ActivityCompensationType.CompensationsDisabled
                                        break;
                                }
                            }
                        }
                        this.secondPeriodAttendanceStatusID = excuseType;
                        this.secondPeriodFilled = waitQueueOperation
                            ? this.secondPeriodFilled
                            : this.secondPeriodFilled - 1;
                        if (resetToOrig) {
                            this.secondPeriodAttendanceTypeID = this.origAttendance.secondPeriodAttendanceTypeID;
                        }
                    }
                }
            } else if (value) {
                if (this.clientBookable) {
                    var waitQueueOperation = this.schedule.secondPeriodCapacity <= this.secondPeriodFilled;
                    var resetToWqOrigState = false;
                    if (waitQueueOperation) {
                        var scheduleWaitQueue = this.schedule.secondPeriodWaitQueue || [];

                        resetToWqOrigState = _.findIndex(scheduleWaitQueue, ['studentID', this.studentID]) > -1;

                        this.secondPeriodWaitQueuePosition =
                            (_.findIndex(scheduleWaitQueue, ['studentID', this.studentID]) + 1) || scheduleWaitQueue.length + 1;
                    } else {
                        if ((this.secondPeriodAttendanceTypeID == 2 /* Amend */ ||
                            this.secondPeriodAttendanceTypeID == 0 /* Registered */) &&
                            (this.secondPeriodAttendanceStatusID == 2 /* NotPresentExcused */ ||
                                this.secondPeriodAttendanceStatusID == 4 /* NotPresentExcusedWithoutFood */)) {

                            switch (this.activityStudentSetting.activityCompensationTypeID) {
                                case 0: // ActivityCompensationType.OneExcuseForOneCompensation
                                    if (this.numberOfExcuses > 0) {
                                        this.numberOfExcuses = this.numberOfExcuses - 1;
                                    } else {
                                        return; // We do not have any excuses to reuse, so do not allow to change the attendance
                                    }
                                    break;
                                case 1: // ActivityCompensationType.TwoExcusesForOneCompensation
                                    if (this.numberOfExcuses > 1) {
                                        this.numberOfExcuses = this.numberOfExcuses - 2;
                                    } else {
                                        return; // We do not have any excuses to reuse, so do not allow to change the attendance
                                    }
                                    break;
                                case 2: // ActivityCompensationType.CompensationsDisabled
                                    return; // Compensations are disabled;
                            }
                        }
                    }
                    if (!resetToWqOrigState) {
                        this.bookSecondPeriod(true, waitQueueOperation);
                    } else {
                        this.secondPeriodAttendanceTypeID = this.origAttendance.secondPeriodAttendanceTypeID;
                        this.secondPeriodAttendanceStatusID = this.origAttendance.secondPeriodAttendanceStatusID;
                        this.secondPeriodStartDate = this.origAttendance.secondPeriodStartDate;
                        this.secondPeriodEndDate = this.origAttendance.secondPeriodEndDate;
                        this.secondSnack = this.origAttendance.secondSnack;
                    }
                    if (!waitQueueOperation) {
                        this.secondPeriodFilled = this.secondPeriodFilled + 1;
                    }
                }
            }
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "firstPeriodBookable", {
        get: function() {
            return this.firstPeriodClientEditable && this.origAttendance.firstPeriodAttendanceStatusID != 0; /* Present */
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "secondPeriodBookable", {
        get: function () {
            return this.secondPeriodClientEditable && this.origAttendance.secondPeriodAttendanceStatusID != 0 /* Present */;
        },
        enumerable: true,
        configurable: true
    });


    Object.defineProperty(ns.ActivityAttendance.prototype, "firstPeriodClientEditable", {
        get: function () {

            var reservationNotExcused = !!this.reservation &&
                !!this.reservation.firstPeriodStartDate &&
                !!this.attendance &&
                this.attendance.firstPeriodAttendanceStatusID == 1; /* NotPresentNotExcused */

            var attendanceNotExcused = !!this.attendance &&
                this.attendance.firstPeriodAttendanceStatusID == 1 /* NotPresentNotExcused */ &&
                this.attendance.firstPeriodAttendanceTypeID != 0; /* Registered */

            var ce = this.clientEditable && !reservationNotExcused && !attendanceNotExcused;

            var amendReturnPosibble = true;
            if ((this.firstPeriodAttendanceTypeID == 2 /* Amend */ || this.firstPeriodAttendanceTypeID == 0 /* Registered */) &&
                (this.firstPeriodAttendanceStatusID == 2 /* NotPresentExcused */ || this.firstPeriodAttendanceStatusID == 4 /* NotPresentExcusedWithoutFood */)) {
                switch (this.activityStudentSetting.activityCompensationTypeID) {
                    case 0: // ActivityCompensationType.OneExcuseForOneCompensation
                        amendReturnPosibble = this.numberOfExcuses > 0;
                        break;
                    case 1: // ActivityCompensationType.TwoExcusesForOneCompensation
                        amendReturnPosibble = this.numberOfExcuses > 1;
                        break;
                    case 2: // ActivityCompensationType.CompensationsDisabled
                        amendReturnPosibble = false;
                        break;
                }
            }

            var enableOneOffs = true;
            if (!this.activity.enableOneOffAttendance &&
                ((this.origAttendance.firstPeriodAttendanceStatusID === 1 /* NotPresentNotExcused */ &&
                    this.origAttendance.firstPeriodAttendanceTypeID === 0 /* Registered */ &&
                    (!this.reservation || !this.reservation.firstPeriodStartDate)))) {

                if (!this.firstPeriodWaitQueuePosition) {
                    switch (this.activityStudentSetting.activityCompensationTypeID) {
                        case 0: /* ActivityCompensationType.OneExcuseForOneCompensation */
                            enableOneOffs = this.numberOfExcuses > 0 || this.firstPeriodAttendanceStatusID === 0; /* Present */
                            break;
                        case 1: /* ActivityCompensationType.TwoExcusesForOneCompensation */
                            enableOneOffs = this.numberOfExcuses > 1 || this.firstPeriodAttendanceStatusID === 0; /* Present */
                            break;
                        case 2: /* ActivityCompensationType.CompensationsDisabled */
                            enableOneOffs = this.firstPeriodAttendanceStatusID === 0; /* Present */
                            break;
                    }
                }
            }

            var ret = ce && enableOneOffs && amendReturnPosibble;

            return ret;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "isOneOffAttendanceEnabled", {
        get: function () {
            return this.activity.enableOneOffAttendance;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "secondPeriodClientEditable", {
        get: function () {

            var reservationNotExcused = !!this.reservation &&
                !!this.reservation.secondPeriodStartDate &&
                !!this.attendance &&
                this.attendance.secondPeriodAttendanceStatusID == 1; /* NotPresentNotExcused */

            var attendanceNotExcused = !!this.attendance &&
                this.attendance.secondPeriodAttendanceStatusID == 1 /* NotPresentNotExcused */ &&
                this.attendance.secondPeriodAttendanceTypeID != 0 /* Registered */

            var ce = this.clientEditable && !reservationNotExcused && !attendanceNotExcused;

            var amendReturnPosibble = true;
            if ((this.secondPeriodAttendanceTypeID == 2 /* Amend */ || this.secondPeriodAttendanceTypeID == 0 /* Registered */) &&
                (this.secondPeriodAttendanceStatusID == 2 /* NotPresentExcused */ || this.secondPeriodAttendanceStatusID == 4 /* NotPresentExcusedWithoutFood */)) {
                switch (this.activityStudentSetting.activityCompensationTypeID) {
                    case 0: // ActivityCompensationType.OneExcuseForOneCompensation
                        amendReturnPosibble = this.numberOfExcuses > 0;
                        break;
                    case 1: // ActivityCompensationType.TwoExcusesForOneCompensation
                        amendReturnPosibble = this.numberOfExcuses > 1;
                        break;
                    case 2: // ActivityCompensationType.CompensationsDisabled
                        amendReturnPosibble = false;
                        break;
                }
            }

            var enableOneOffs = true;
            if (!this.activity.enableOneOffAttendance &&
                ((this.origAttendance.secondPeriodAttendanceStatusID === 1 /* NotPresentNotExcused */ &&
                    this.origAttendance.secondPeriodAttendanceTypeID === 0 /* Registered */ &&
                    (!this.reservation || !this.reservation.secondPeriodStartDate)))) {

                if (!this.secondPeriodWaitQueuePosition) {
                    switch (this.activityStudentSetting.activityCompensationTypeID) {
                        case 0: /* ActivityCompensationType.OneExcuseForOneCompensation */
                            enableOneOffs = this.numberOfExcuses > 0 || this.secondPeriodAttendanceStatusID === 0; /* Present */
                            break;
                        case 1: /* ActivityCompensationType.TwoExcusesForOneCompensation */
                            enableOneOffs = this.numberOfExcuses > 1 || this.secondPeriodAttendanceStatusID === 0; /* Present */
                            break;
                        case 2: /* ActivityCompensationType.CompensationsDisabled */
                            enableOneOffs = this.secondPeriodAttendanceStatusID === 0; /* Present */
                            break;
                    }
                }
            }

            return ce && enableOneOffs && amendReturnPosibble;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(ns.ActivityAttendance.prototype, "hasNewOneOff", {
        get: function () {
            return ((this.firstPeriodAttendanceStatusID == 0 /* Present */ && this.firstPeriodAttendanceTypeID == 1 /* OneOff */) &&
                (this.origAttendance.firstPeriodAttendanceStatusID != 0 /* Present */ || this.origAttendance.firstPeriodAttendanceTypeID != 1 /* OneOff */)) ||
                ((this.secondPeriodAttendanceStatusID == 0 /* Present */ && this.secondPeriodAttendanceTypeID == 1 /* OneOff */) &&
                    (this.origAttendance.secondPeriodAttendanceStatusID != 0 /* Present */ || this.origAttendance.secondPeriodAttendanceTypeID != 1 /* OneOff */));
        },
        enumerable: true,
        configurable: true
    });


    // #endregion

}(webooker_acivity_models));;
'use strict';

wbApp.factory('activityAttendanceSvc', ['$resource', '$q', '$translate', '$filter', 'repositorySvc',
    'notificationSvc', 'studentSvc', 'tenantSettingSvc', 'activitySvc',
function ($resource, $q, $translate, $filter, repositorySvc, notificationSvc, studentSvc, tenantSettingSvc, activitySvc) {

    var ActivityAtendances = $resource('/Api/ActivityAttendance/:id', {}, {
        'getAttendancesBySchedule': { method: 'GET', isArray: false, url: '/Api/ActivityAttendance/GetAttendancesBySchedule' },
        'getActivitySchedules': { method: 'GET', isArray: false, url: '/ActivityAttendance/GetActivitySchedules' },
        'updateScheduleNotes': { method: 'POST', url: '/ActivityAttendance/UpdateScheduleNotes' },
        'getStudentAttendanceDetail': { method: 'GET', isArray: false, url: '/Api/ActivityAttendance/GetAttendanceDetail' },
        'excuseStudent': { method: 'POST', isArray: false, url: '/Api/ActivityAttendance/ExcuseStudent' },
        'save': { method: 'POST', url: '/Api/ActivityAttendance/Save', isArray: false },
        'delete': { method: 'POST', url: '/Api/ActivityAttendance/Delete', isArray: false },
    });

    function filterAndBreakByMonth(schedules, activityID) {
        var months = {};

        var filtered = $filter('orderBy')(schedules, 'startDate');

        for (var s = 0; s < filtered.length; s++) {
            var schedule = filtered[s];
            if (schedule.activityID !== activityID) {
                continue;
            }

            var mStartDate = moment(schedule.startDate);
            var key = (mStartDate.year() << 16) | mStartDate.month();

            var mSchedules = months[key];
            if (!mSchedules) {
                mSchedules = [];
                months[key] = mSchedules;
            }

            mSchedules.push(schedule);
        }

        var ret = [];
        for (var key in months) {
            var month = months[key];
            ret.push({
                startDate: new Date(key >> 16, key & 0x0000FFFF, 1),
                schedules: month
            });
        }

        return $filter('orderBy')(ret, 'startDate');
    }

    function getExcusesAndAmendsOnly(schedules, activityID) {
        return $filter('orderBy')(_.filter(schedules, { activityID: activityID, isNotRegularAttendance: true }), 'startDate');
    }

    function findByProperty(collection, propertyName, value) {
        for (var i = 0; i < collection.length; i++) {
            var entity = collection[i];
            if (entity[propertyName] == value) {
                return entity;
            }
        }

        return null;

    }

    function findByStudentID(collection, studentID) {
        return findByProperty(collection, 'studentID', studentID);
    }

    function addNewStudent(attendances, schedule, studentID) {
        var deferred = $q.defer();

        var currentAttendance = findByStudentID(attendances, studentID);
        if (!!currentAttendance) {
            notificationSvc.notifyError($translate.instant('TXT_ALERT_TITLE_STUDENT_ALREADY_IN_ATTENDANCE'));

            deferred.resolve();
            return deferred.promise;
        }

        $q.all([
            activitySvc.getByActivityID(schedule.activityID).$promise,
            studentSvc.getByIDAsync(studentID).$promise]).then(function (data) {

                var activity = data[0];
                var student = data[1];

                var newAttendance = {
                    studentFullName: student.fullName,
                    studentID: studentID,
                    activityScheduleID: schedule.activityScheduleID,
                    activityID: schedule.activityID,
                    firstPeriodStartDate: null,
                    firstPeriodEndDate: null,
                    secondPeriodStartDate: null,
                    secondPeriodEndDate: null,
                    lunch: false,
                    firstSnack: false,
                    secondSnack: false,
                    notes: null,
                    confirmed: null,

                    firstPeriodAttendanceStatusID: 1,
                    secondPeriodAttendanceStatusID: 1,
                    firstPeriodAttendanceTypeID: 0,
                    secondPeriodAttendanceTypeID: 0,
                };

                var setting = {
                    activityCompensationTypeID: 0 /* ActivityCompensationType.OneExcuseForOneCompensatio */
                };

                var a = new webooker_acivity_models.ActivityAttendance(
                    schedule,
                    null,
                    newAttendance,
                    setting,
                    activity,
                    tenantSettingSvc.settings,
                    0,
                    studentID);

                attendances.push(a);


            }, function (errorResult) {
            deferred.reject(errorResult);
        });

        return deferred.promise;
    }

    function buildAttendanceModel(
        schedule, 
        reservations, 
        attendances,
        activityStudentSettings,
        activity,
        tenantSetting,
        numberOfExcusesByStudent)
    {
        var dict = {};

        var attendanceByStudentID = _.keyBy(attendances, 'studentID');
        var settingsByStudentID = _.keyBy(activityStudentSettings, 'studentID');
        var excusesByStudentID = _.mapValues(_.keyBy(numberOfExcusesByStudent, 'studentID'), 'noOfExcuses');

        _.forEach(reservations, function (reservation) {
            if (!!reservation) {
                dict[reservation.studentID] = (new webooker_acivity_models.ActivityAttendance(
                    schedule,
                    reservation,
                    attendanceByStudentID[reservation.studentID],
                    settingsByStudentID[reservation.studentID],
                    activity,
                    tenantSetting,
                    excusesByStudentID[reservation.studentID] || 0,
                    reservation.studentID));
            }
        });

        _.forEach(attendances, function (attendance) {
            if (!dict[attendance.studentID]) {
                dict[attendance.studentID] = new webooker_acivity_models.ActivityAttendance(
                    schedule,
                    null,
                    attendance,
                    settingsByStudentID[attendance.studentID],
                    activity,
                    tenantSetting,
                    excusesByStudentID[attendance.studentID] || 0,
                    attendance.studentID);
            }
        });

        return _.values(dict);
    }

    // studentID only if we are building model for single student
    function buildAttendanceModelBySchedules(
        schedules, 
        reservations, 
        attendances,
        activityStudentSetting,
        activity,
        tenantSetting,
        excusesByDate,
        studentID) {

        var rdict = _.keyBy(reservations, 'activityScheduleID');
        var adict = _.keyBy(attendances, 'activityScheduleID');
        var excusesDict = _.keyBy(excusesByDate, function (s) {return +moment(s.date).startOf('day') });
        var result = [];

        _.forEach(schedules, function (schedule) {
            var excuse = excusesDict[+moment(schedule.startDate).startOf('day')];

            result.push(new webooker_acivity_models.ActivityAttendance(
              schedule,
              rdict[schedule.activityScheduleID],
              adict[schedule.activityScheduleID],
              activityStudentSetting,
              activity,
              tenantSetting,
              excuse != null ? excuse.noOfExcuses : 0,
              studentID));
        });

        return result;
    }

    function getAttendancesBySchedule(schedule) {
        var deferred = $q.defer();
        var result = [];
        result.$promise = deferred.promise;

        repositorySvc.customGet('getAttendancesBySchedule', ActivityAtendances, {
            activityID: schedule.activityID,
            activityScheduleID: schedule.activityScheduleID
        }, success, error);

        function success(data) {
            result.push.apply(result, buildAttendanceModel(
                data.schedule,
                data.reservations,
                data.attendances,
                data.setting,
                data.activity,
                tenantSettingSvc.settings,
                data.excuses));
            deferred.resolve(result);
        }

        function error(errorResult) {
            deferred.reject(errorResult);
        }

        return result;
    }

    function getStudentAttendanceDetailAsync(activityID, studentID) 
    {
        var deferred = $q.defer();
        var result = [];

        result.$promise = deferred.promise;

        $q.all([
            activitySvc.getByActivityID(activityID).$promise,
            repositorySvc.customGet('getStudentAttendanceDetail', ActivityAtendances, {
                activityID: activityID,
                studentID: studentID
            }).$promise
        ]).then(function (data) {

            result.push.apply(result,
                buildAttendanceModelBySchedules(
                    data[1].schedules,
                    data[1].reservations,
                    data[1].attendances,
                    data[1].setting,
                    data[0],
                    tenantSettingSvc.settings,
                    data[1].excusesByDate,
                    studentID));
            deferred.resolve(result);

        }, function (error) {
            deferred.reject(error);
        });

        return result;
    }

    function excuseStudent(activityID, studentID, excuseFrom, excuseTo, firstPeriod, secondPeriod, notes) {
        var deferred = $q.defer();
        var result = [];
        result.$promise = deferred.promise;

        $q.all([
            activitySvc.getByActivityID(activityID).$promise,
            ActivityAtendances.excuseStudent({
                activityID: activityID,
                studentID: studentID,
                excuseFrom: excuseFrom,
                excuseTo: excuseTo,
                firstPeriod: firstPeriod,
                secondPeriod: secondPeriod,
                notes: notes
            }).$promise
        ]).then(function (data) {

            notificationSvc.notifyInfo($translate.instant('TXT_ALERT_TITLE_DATA_SAVED'));

            result.push.apply(result,
                buildAttendanceModelBySchedules(
                    data[1].schedules,
                    data[1].reservations,
                    data[1].attendances,
                    data[1].setting,
                    data[0],
                    tenantSettingSvc.settings,
                    data[1].excusesByDate,
                    studentID));
            deferred.resolve(result);
        }, function (error) {
            repositorySvc.defaultErrorHandler(error);
            deferred.reject(error);
        });

        return result;
    }

    function saveAttendanceAsync(attendance, checkCapacity) {

        var deferred = $q.defer();
        var result = [];
        result.$promise = deferred.promise;

        var studentID = attendance.origAttendance.studentID;

        $q.all([
            activitySvc.getByActivityID(attendance.activityID).$promise,
            ActivityAtendances.save({
                model: attendance.getServerAttendance(),
                checkCapacity: !!checkCapacity
            }).$promise
        ]).then(function (data) {
            notificationSvc.notifyInfo($translate.instant('TXT_ALERT_TITLE_DATA_SAVED'));

            if (!!checkCapacity) {
                // Called from MyActivities
                // Returns single student info for the whole semester
                result.push.apply(result,
                    buildAttendanceModelBySchedules(
                        data[1].schedules,
                        data[1].reservations,
                        data[1].attendances,
                        data[1].setting,
                        data[0],
                        tenantSettingSvc.settings,
                        data[1].excusesByDate,
                        studentID));
            } else {
                // Called from ActivityAttendance
                // Returns single student info for single day
                result.push.apply(result, buildAttendanceModel(
                    data[1].schedule,
                    data[1].reservations,
                    data[1].attendances,
                    data[1].setting,
                    data[0],
                    tenantSettingSvc.settings,
                    data[1].excuses));
            }

            deferred.resolve(result);
        }, function (error) {
            repositorySvc.defaultErrorHandler(error);
            deferred.reject(error);
        });

        return result;
    }

    function getActivitySchedules(semesterID) {
        return repositorySvc.customGet('getActivitySchedules', ActivityAtendances, {
            semesterID: semesterID
        });
    }

    function updateScheduleNotesAsync(activityScheduleID, notes, sendNotification) {
        var res = ActivityAtendances.updateScheduleNotes({
            activityScheduleID: activityScheduleID,
            notes: notes,
            sendNotification: sendNotification
        }, success, error);

        function success(data) {
            notificationSvc.notifyInfo($translate.instant('TXT_ALERT_TITLE_DATA_SAVED'));
        }

        function error(errorResult) {
            repositorySvc.defaultErrorHandler(errorResult);
        }

        return res;
    }

    function removeFromCollection(attendances, attendance) {
        var idxToRemove = attendances.indexOf(attendance);
        if (idxToRemove > -1) {
            attendances.splice(idxToRemove, 1);
        }
    }

    function deleteAttendanceAsync(attendances, attendance) {
        if (attendance.canBeDeletedWithoutConfirmation) {
            removeFromCollection(attendances, attendance);
        } else {
            ActivityAtendances.delete({
                activityAttendanceID: attendance.activityAttendanceID
            }, success, error);
        }

        function success(data) {
            removeFromCollection(attendances, attendance);
            notificationSvc.notifyInfo($translate.instant('TXT_ALERT_TITLE_DATA_SAVED'));
        }

        function error(errorResult) {
            repositorySvc.defaultErrorHandler(errorResult);
        }
    }

    function bookAttendanceByPeriod(attendance, origAttendance, period) {
        if (!origAttendance.shouldDisableFirstPeriodBooking) {
            if (!period.am) {
                // Return to orig state
                attendance.firstPeriodAttendanceStatusID = origAttendance.firstPeriodAttendanceStatusID;
                attendance.firstPeriodAttendanceTypeID = origAttendance.firstPeriodAttendanceTypeID;
            } else {
                if (origAttendance.firstPeriodAttendanceStatusID == 1 &&  // Not present / not excused
                    origAttendance.firstPeriodAttendanceTypeID == 0 &&    // Registered
                    (!origAttendance.reservation || !origAttendance.reservation.firstPeriodStartDate)) {

                    attendance.firstPeriodAttendanceStatusID = 0; // Present
                    attendance.firstPeriodAttendanceTypeID = 2;   // Amend
                } else {
                    attendance.firstPeriodAttendanceStatusID = 0; // Present
                }
            }
        }

        // Second attendance
        if (!origAttendance.shouldDisableSecondPeriodBooking) {
            if (!period.pm) {
                // Return to orig state
                attendance.secondPeriodAttendanceStatusID = origAttendance.secondPeriodAttendanceStatusID;
                attendance.secondPeriodAttendanceTypeID = origAttendance.secondPeriodAttendanceTypeID;
            } else {
                if (origAttendance.secondPeriodAttendanceStatusID === 1 &&  // Not present / not excused
                    origAttendance.secondPeriodAttendanceTypeID == 0 &&    // Registered
                    (!origAttendance.reservation || !origAttendance.reservation.secondPeriodStartDate)) {

                    attendance.secondPeriodAttendanceStatusID = 0; // Present
                    attendance.secondPeriodAttendanceTypeID = 2;   // Amend
                } else {
                    attendance.secondPeriodAttendanceStatusID = 0; // Present
                }
            }
        }
    }

    return {
        getAttendancesBySchedule: getAttendancesBySchedule,
        getActivitySchedules: getActivitySchedules,
        saveAttendanceAsync: saveAttendanceAsync,
        updateScheduleNotesAsync: updateScheduleNotesAsync,
        deleteAttendanceAsync: deleteAttendanceAsync,
        addNewStudent: addNewStudent,
        getStudentAttendanceDetailAsync: getStudentAttendanceDetailAsync,
        filterAndBreakByMonth: filterAndBreakByMonth,
        excuseStudent: excuseStudent,
        bookAttendanceByPeriod: bookAttendanceByPeriod,
        getExcusesAndAmendsOnly: getExcusesAndAmendsOnly
    }

}]);
;
'use strict';

wbApp.controller('AttendanceCtrl', ['$scope', '$http', '$window', 'notificationSvc', '$translate', '$timeout', '$modal', 'tenantSettingSvc', 'securitySvc', 'gridSortSvc',
function ($scope, $http, $window, notificationSvc, $translate, $timeout, $modal, tenantSettingSvc, securitySvc, gridSortSvc) {
    var data = courses;

    $scope.tabs = [
        {
            title: 'TXT_TAB_COURSE_SELECTION',
            template: 'attendance/course-selection-tab.html'
        },
        {
            title: 'TXT_TAB_LESSON_SELECTION',
            template: 'attendance/lesson-selection-tab.html'
        },
        {
            title: 'TXT_TAB_ATTENDANCE',
            template: 'attendance/attendance-selection-tab.html'
        },
        {
            title: 'TXT_TAB_STUDENT',
            template: 'attendance/student-detail-tab.html'
        }];

    $scope.tabs.activeTab = 0;

    $scope.courses = data;
    $scope.availableCourseTypes = _.keyBy(_.uniq(_.map($scope.courses, 'courseTypeID')));

    $scope.semesterID = semesterID;

    $scope.selectedStudent = { studentID: 0, isNew: true, attendanceCount: 1 };

    $scope.scrollPos = {};
    $scope.serverError = null;
    
    $scope.compensationGroupOverride = securitySvc.isInRole('CompensationGroupOverride');
    $scope.printLessonAttendanceVisible = securitySvc.isInRole('ClientAttendance.LessonAttendanceReport') && securitySvc.isInRole('Reports');

    $scope.tenantSettings = tenantSettingSvc.settings;

    $scope.setSelectedCourse = function (course) {
        $scope.selectedCourse = course;
        advanceTab($scope.tabs, $scope.scrollPos);
    }

    function selectNearestCourse(courses) {
        var now = moment();
        var nowDay = now.isoWeekday();
        for (var c = 0; c < courses.length; c++) {
            var course = courses[c];
            var firstDate = moment(course.firstDate);
            var day = firstDate.isoWeekday();

            if (day === nowDay) {
                $scope.selectedCourse = course;
                return;
            }                                 
        }
    }

    $scope.showCopyPhoneNumbersTooltip = false;

    $scope.copyPhoneNumbers = function(attendance)
    {
        var phones = _.reduce(attendance, function (sum, n) {
            if (!!n.phone1) {
                if (!!sum) {
                    return sum + '\n' + n.phone1;
                } else {
                    return n.phone1;
                }                 
            } else {
                return sum;
            }
        }, "");

        if (!!phones) {
            var $temp_input = $("<textarea>");
            $("body").append($temp_input);
            $temp_input.val(phones).select();
            document.execCommand("copy");
            $temp_input.remove();

            notificationSvc.notifyInfo($translate.instant('TXT_COPIED_TO_CLIPBOARD'));
        }
    }

    selectNearestCourse($scope.courses);

    $scope.setSelectedSchedule = function (schedule) {
        $scope.selectedSchedule = schedule;
        advanceTab($scope.tabs, $scope.scrollPos);
    }

    $scope.setSelectedStudent = function (student) {
        $scope.selectedStudent = student;
        advanceTab($scope.tabs, $scope.scrollPos);
    }

    $scope.editLessonNote = function (schedule) {
        $scope.noteChangeModal.schedule = schedule;
        $scope.noteChangeModal.lessonNote = schedule.lessonNote;

        noteChangeModalPromise.$promise.then(function () {
            noteChangeModalPromise.show();
        });
    }

    $scope.showRegistrationNote = function (student) {

        $http({
            method: 'GET',
            url: '/Attendance/GetRegistrationNote',
            params: {
                CourseID: $scope.selectedCourse.courseID,
                StudentID: student.studentID
            }
        }).success(function (data, status, headers, config) {
            registrationNotePromise.$promise.then(function () {
                if (data) {
                    registrationNotePromise.$scope.registrationNoteDetail = {
                        operatorFullName: data.operatorFullName,
                        note: student.registrationNote,
                        attendanceNote: student.note,
                        health: data.studentHealth,
                        attendantHealth: data.attendantHealth
                    };
                } else {
                    registrationNotePromise.$scope.registrationNoteDetail = {};
                }
                registrationNotePromise.show();
            });
        }).error(function (data, status, headers, config) {
            notificationSvc.notifyError(
                $translate.instant('TXT_ALERT_SERVER_ERROR'),
                notificationSvc.translateError(data));
        });
    }

    $scope.onStudentChange = function (selectedStudent) {
        $scope.selectedStudent.compensationCourseID = null;
        $scope.selectedStudent.attendanceCount = 1;
        $scope.serverError = null;
    }

    $scope.onAttendanceTypeChange = function () {
        $scope.serverError = null;
        $scope.selectedStudent.attendanceCount = 1;
    }

    $scope.isAttendanceTypeDisabled = function () {

        if (!$scope.selectedSchedule ||
               !$scope.selectedCourse ||
               !$scope.selectedStudent.studentID) {
            return true;
        } else {
            if (!$scope.selectedStudent.isNew) {
                if ($scope.selectedStudent.attendanceType === 0) {
                    return true;
                }
            }
            return false;
        }
    }

    $scope.isCompensationLookupDisabled = function () {
        return $scope.isAttendanceTypeDisabled();
    }

    $scope.onLessonNoteChange = function (schedule, lessonNote, sendNotification) {
        schedule.lessonNote = lessonNote;
        $http({
            method: 'POST',
            url: '/Attendance/UpdateScheduleNote',
            data: { CourseScheduleID: schedule.courseScheduleID, LessonNote: lessonNote, SendNotification: sendNotification }
        });
    }

    $scope.onPrevBtnClick = function () {
        regressTab($scope.tabs, $scope.scrollPos);
    }

    $scope.onNextBtnClick = function () {
        advanceTab($scope.tabs, $scope.scrollPos);
    }

    $scope.onSaveBtnClick = function (course, schedule, student) {
        if (student.isNew) {
            insertStudentAttendance(course, schedule, student);
        } else {
            uppdateStudentAttendanceImpl(schedule, student)
            .success(function (data, status, headers, config) {
                notificationSvc.notifyInfo(
                    $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_SUCCESS'));
                regressTab($scope.tabs, $scope.scrollPos);
            }).error(function (data, status, headers, config) {
                notificationSvc.notifyError(
                    $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_FAILURE'),
                    notificationSvc.translateError(data));
                $scope.serverError = data;
            });
        }
    }

    $scope.onAddBtnClick = function (schedule) {
        advanceTab($scope.tabs, $scope.scrollPos);

        $scope.selectedStudent = {
            isNew: true,
            attendanceStatus: 0,
            attendanceType: 2,
            compensationCourseID: -1,
            studentID: null,
            attendanceCount: 1,
        };
    }

    $scope.$watch('tabs.activeTab', function (newValue, oldValue) {
        switch (newValue) {
            case 1:
                onLessonSelectionTabShow();
                break;
            case 2:
                onStudentSelectionTabShow();
                break;
        }
    });

    $scope.noteChangeModal = { title: "", saved: false };

    var noteChangeModalPromise = $modal({
        template: 'attendance/edit-lesson-note.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    var registrationNotePromise = $modal({
        template: 'attendance/show-registration-note.html',
        show: false,
        backdrop: true,
        scope: $scope.$new()
    });

    function uppdateStudentAttendanceImpl(schedule, student) {
        return $http({
            method: 'POST',
            url: '/Attendance/UpdateStudentAttendance',
            data: {
                CourseScheduleID: schedule.courseScheduleID,
                StudentID: student.studentID,
                attendanceStatus: student.attendanceStatus,
                attendanceType: student.attendanceType,
                attendanceCount: student.attendanceCount,
                note: student.note,
                edited: student.modified,
                compensationCourseID: student.compensationCourseID
            }
        });
    }

    $scope.saveAttendanceConfirmation = function (schedule, student) {
        uppdateStudentAttendanceImpl(schedule, student)
        .success(function (data, status, headers, config) {
            notificationSvc.notifyInfo(
                $translate.instant('TXT_ALERT_ATTENDANCE_CONFIRM_SUCCESS').f(student.fullName));
        }).error(function (data, status, headers, config) {
            notificationSvc.notifyError(
                $translate.instant('TXT_ALERT_ATTENDANCE_CONFIRM_FAILURE').f(student.fullName),
                notificationSvc.translateError(data));
        });
    }

    function uppdateStudentAttendance(schedule, student) {
        $http({
            method: 'POST',
            url: '/Attendance/UpdateStudentAttendance',
            data: {
                CourseScheduleID: schedule.courseScheduleID,
                StudentID: student.studentID,
                attendanceStatus: student.attendanceStatus,
                attendanceType: student.attendanceType,
                attendanceCount: student.attendanceCount,
                note: student.note,
                edited: student.modified,
                compensationCourseID: student.compensationCourseID
            }
        }).success(function (data, status, headers, config) {
            notificationSvc.notifyInfo(
                $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_SUCCESS'));
            regressTab($scope.tabs, $scope.scrollPos);
        }).error(function (data, status, headers, config) {
            notificationSvc.notifyError(
                $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_FAILURE'),
                notificationSvc.translateError(data));
            $scope.serverError = data;
        });
    }

    function insertStudentAttendance(course, schedule, student) {
        $http({
            method: 'POST',
            url: '/Attendance/InsertStudentAttendance',
            data: {
                CourseID: course.courseID,
                CourseScheduleID: schedule.courseScheduleID,
                StudentID: student.studentID,
                attendanceStatus: student.attendanceStatus,
                attendanceType: student.attendanceType,
                attendanceCount: student.attendanceCount,
                note: student.note,
                compensationCourseID: student.compensationCourseID
            }
        }).success(function (data, status, headers, config) {
            notificationSvc.notifyInfo(
                $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_SUCCESS'));
            regressTab($scope.tabs, $scope.scrollPos);
        }).error(function (data, status, headers, config) {
            notificationSvc.notifyError(
                $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_FAILURE'),
                notificationSvc.translateError(data));
            $scope.serverError = data;
        });
    }

    function advanceTab(tabs, scrollPos) {
        $scope.serverError = null;
        scrollPos[tabs.activeTab] = $(window).scrollTop();
        tabs.activeTab += 1;
        if (scrollPos[tabs.activeTab]) {
            $timeout(function () {
                $(window).scrollTop(scrollPos[tabs.activeTab]);
            }, 200);
        }
    }

    function regressTab(tabs, scrollPos) {
        $scope.serverError = null;
        scrollPos[tabs.activeTab] = $(window).scrollTop();
        tabs.activeTab -= 1;
        if (scrollPos[tabs.activeTab]) {
            $timeout(function () {
                $(window).scrollTop(scrollPos[tabs.activeTab]);
            }, 200);
        }
    }

    function onLessonSelectionTabShow() {
        if (!$scope.selectedCourse) {
            $scope.lessonSelectionTabTitle = $translate.instant("TXT_TITLE_ATTENDANCE_SELECT_LESSON");
            $scope.schedules = {};
            $scope.selectedSchedule = null;
            $scope.selectedStudent = {};
            $scope.attendances = {};
        } else {
            $scope.lessonSelectionTabTitle =
                $translate.instant("TXT_TITLE_ATTENDANCE_SELECT_LESSON") + " " +
                ($scope.selectedCourse.courseAbbreviation ? $scope.selectedCourse.courseAbbreviation + " - " : "") +
                $scope.selectedCourse.subjectName + " - " +
                $scope.selectedCourse.courseName;

            $scope.schedules = {};

            getCourseSchedules($scope.selectedCourse.courseID)
                .success(function (data, status, headers, config) {
                    $scope.selectedSchedule = findSelectedSchedule($scope.selectedSchedule, data);
                    $scope.schedules = data;
                })
                .error(function (data, status, headers, config) {
                    $scope.selectedSchedule = null;
                    $scope.selectedStudent = {};
                    $scope.attendances = {};
                    notificationSvc.notifyError(
                        $translate.instant('TXT_ALERT_SERVER_ERROR'),
                        notificationSvc.translateError(data));
                });
        }
    }

    function findSelectedSchedule(oldVal, schedules) {
        if (oldVal) {
            for (var i = 0; i < schedules.length; i++) {
                var schedule = schedules[i];
                if (oldVal.courseScheduleID === schedule.courseScheduleID) {
                    return schedule;
                }
            };
        }

        var schedulesByDate = _.sortBy(schedules, 'startDate');
        var now = moment();
        return _.find(schedulesByDate, function (s) {            
            return moment(s.startDate).isSameOrAfter(now, 'day');
        });
    }

    function findSelectedStudent(oldVal, attendances) {
        if (oldVal) {
            for (var i in attendances) {
                if (oldVal.studentID === attendances[i].studentID) {
                    return attendances[i];
                }
            };
        }
        return { studentID: 0 };
    }


    function onStudentSelectionTabShow() {
        if (!$scope.selectedSchedule || !$scope.selectedCourse) {
            $scope.studentSelectionTabTitle = "";
            $scope.attendances = {};
            $scope.selectedStudent = {};
        } else {
            $scope.studentSelectionTabTitle =
                ($scope.selectedCourse.courseAbbreviation ? $scope.selectedCourse.courseAbbreviation + " - " : "") +
                $scope.selectedCourse.subjectName + " - " +
                $scope.selectedCourse.courseName + " - " +
                $scope.selectedSchedule.scheduleDate;

            $scope.attendances = {};

            getLessonAttendance($scope.selectedSchedule.courseScheduleID)
                .success(function (data, status, headers, config) {
                    $scope.selectedStudent = findSelectedStudent($scope.selectedStudent, data);
                    $scope.attendances = _.sortBy(data, function (a) { return gridSortSvc.sortHumanFullName2(a, 'fullName'); });
                }).error(function (data, status, headers, config) {
                    $scope.selectedStudent = {};
                    notificationSvc.notifyError(
                        $translate.instant('TXT_ALERT_SERVER_ERROR'),
                        notificationSvc.translateError(data));
                });
        }
    }

    $scope.onPrintBtnClick = function (schedule) {
        onPrintLessonAttendance(schedule.courseScheduleID);
    }

    function onPrintLessonAttendance(courseScheduleID) {
        $window.open('/Admin/Report/LessonAttendance?CourseScheduleID=' + courseScheduleID,
            '_blank', 'width=1000,height=500,toolbar=no,resizable=yes,location=no,directories=no,status=no,menubar=no,copyhistory=no');
    }

    function getCourseSchedules(courseID) {
        return $http({
            method: 'GET',
            url: '/Attendance/GetCourseSchedules',
            params: { CourseID: courseID }
        });
    }

    function getLessonAttendance(courseScheduleID) {

        return $http({
            method: 'GET',
            url: 'Api/Attendance/GetLessonAttendance',
            params: { CourseScheduleID: courseScheduleID }
        });
    }

}]);;
'use strict';

wbApp.directive('wbErrorAlert', ['errorTypeTranslateSvc',
    function (errorTypeTranslateSvc) {
        return {
            restrict: 'A',
            require: 'ngModel',
            priority: 1,
            scope: {
                serverError: '=ngModel',
                formErrors: '=formErrors'
            },
            replace: true,
            template:
                "<div class='bs-callout bs-callout-danger wb-server-alert' ng-show='showErrors()'>" +
                    "<h4>{{'TXT_TITLE_FIX_ERRORS' | translate}}</h4>" +
                    "<ul ng-show='!!serverError.data.title' class='list-unstyled'><li>{{serverError.data.title}}</li></ul>" +                    
                    "<ul class='list-unstyled' ng-show='serverError'>" +
                        "<li ng-repeat='error in serverError.errors'>{{error.message}}</li>" +
                    "</ul>" +
                    "<ul class='list-unstyled' ng-show='formErrors'>" +
                        "<li ng-repeat='(key, errors) in formErrors track by $index'>" +
                            "<ul>" +
                                "<li ng-repeat='e in errors'>{{ e.$name }} : <strong>{{ translateError(key) }}</strong>.</li>" +
                            "</ul>" +
                        "</li>" +
                    "</ul>" +
                "</div>",
            link: function (scope, elm, attrs, controller) {
                scope.translateError = function (error) {
                    return errorTypeTranslateSvc.translate(error, null, scope);
                };

                scope.showErrors = function() {
                    var result = scope.serverError || (scope.formErrors && Object.keys(scope.formErrors).length > 0);
                    return result;
                }

            }
        }
    }]);
;
'use strict';

wbApp.directive('wbActivityStatusLookup', ['$timeout',
    function ($timeout) {
        return {
            restrict: 'A',
            require: 'ngModel',
            replace: true,
            priority: 1,
            scope: {
                activity: '='
            },
            template: "<select class='form-control'>" +
                         "<option value='0'>{{'TXT_VAL_PRESENT' | translate}}</option>" +
                         "<option value='1'>{{'TXT_VAL_NOT_PRESENT' | translate}}</option>" +
                         "<option value='2'>{{'TXT_VAL_EXCUSED' | translate}}</option>" +
                         "<option value='3'>{{'TXT_VAL_EXCUSED_NO_COMP' | translate}}</option>" +
                         "<option value='4'>{{'TXT_VAL_EXCUSED_NO_FOOD' | translate}}</option>" +
                      "</select>",
            link: function (scope, elm, attrs, controller) {
                $timeout(function () {
                    $(elm).select2({
                        minimumResultsForSearch: -1
                    });

                    controller.$parsers.unshift(function (viewValue) {
                        if (!viewValue) {
                            return 0;
                        } else {
                            return parseInt(viewValue);
                        }
                    });

                    controller.$formatters.unshift(function (value) {
                        if (!value) {
                            return "0";
                        } else {
                            return value + "";
                        }
                    });

                    controller.$render = function () {
                        elm.select2('val', controller.$viewValue);
                    };

                    elm.on('change', function (e) {
                        scope.$apply(function () {
                            controller.$setViewValue(e.val);
                        });
                    });

                    attrs.$observe('readonly', function (value) {
                        elm.select2('readonly', !!value);
                    });

                    elm.bind("$destroy", function () {
                        elm.select2("destroy");
                    });
                }, 1);
            }
        }
    }]);
;
'use strict';

wbApp.directive('wbAlert', ['$timeout', '$alert', 'notificationSvc',
    function ($timeout, $alert, notificationSvc) {
        return {
            restrict: 'A',
            priority: 1,
            replace: true,
            scope: {},
            link: function (scope, elm, attrs, controller) {
            },
            controller: ['$scope', function ($scope) {
                $scope.queue = notificationSvc.getQueue();

                $scope.$watchCollection('queue', function (newCollection, oldCollection, scope) {
                    if (newCollection.length) {
                        var newMessage = newCollection[0];
                        newCollection.splice(0, 1);

                        var myAlert = $alert(
                        {
                            title: newMessage.title,
                            content: newMessage.content,
                            placement: 'top-right',
                            animation: 'am-fade-and-scale',
                            container: '#alertContainer',
                            type: newMessage.type,
                            show: true
                        });

                        $timeout(function () {
                            myAlert.hide();
                        }, 5000)
                    }
                });

            }]
        }
    }]);;
'use strict';

wbApp.directive('wbAttendanceStatusEdit',
    function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            priority: 1,
            scope: {
                status: '=ngModel',
                disabled: '=ngDisabled',
            },
            template:
                "<div class='radio wb-radio'><label><input wb-checkbox-edit ng-model='checkedArr[0]' ng-disabled='disabled' ng-change='onCheckboxClick(0)' ><span>&nbsp;{{'TXT_VAL_PRESENT' | translate}}</span></label></div>" +
                "<div class='radio wb-radio'><label><input wb-checkbox-edit ng-model='checkedArr[1]' ng-disabled='disabled' ng-change='onCheckboxClick(1)' ><span>&nbsp;{{'TXT_VAL_NOT_PRESENT' | translate}}</span></label></div>" +
                "<div class='radio wb-radio'><label><input wb-checkbox-edit ng-model='checkedArr[2]' ng-disabled='disabled' ng-change='onCheckboxClick(2)' ><span>&nbsp;{{'TXT_VAL_EXCUSED' | translate}}</span></label></div>" +
                "<div class='radio wb-radio'><label><input wb-checkbox-edit ng-model='checkedArr[3]' ng-disabled='disabled' ng-change='onCheckboxClick(3)' ><span>&nbsp;{{'TXT_VAL_EXCUSED_NO_COMP' | translate}}</span></label></div>",
            link: function (scope, element, attr, ctrl) {

                scope.checkedArr = [false, false, false, false];

                function fromViewValue(value) {
                    for (var i = 0; i < scope.checkedArr.length; i++) {
                        scope.checkedArr[i] = value === i;
                    }
                }

                function toViewValue() {
                    return scope.checkedArr.indexOf(true);
                }

                scope.onCheckboxClick = function (idx) {
                    for (var i = 0; i < scope.checkedArr.length; i++) {
                        scope.checkedArr[i] = idx === i;
                    }
                    ctrl.$setViewValue(idx);
                   // $event.preventDefault();
                }

                ctrl.$render = function () {
                    scope.spanChecked = fromViewValue(ctrl.$viewValue);
                };
            }
        }
    });
;
'use strict';

wbApp.directive('wbAttendanceTypeLookup', ['$timeout',
    function ($timeout) {
        return {
            restrict: 'A',
            require: 'ngModel',
            replace: true,
            priority: 1,
            template: "<select class='form-control'>" +
                         "<option value='0' disabled>{{'TXT_VAL_REGISTERED' | translate}}</option>" +
                         "<option value='1'>{{'TXT_VAL_ONEOFF' | translate}}</option>" +
                         "<option value='2'>{{'TXT_VAL_AMEND' | translate}}</option>" +
                         "<option value='3'>{{'TAX_VAL_PREVIEW' | translate}}</option>" +
                      "</select>",
            link: function (scope, elm, attrs, controller) {
                $timeout(function () {
                    $(elm).select2({
                        minimumResultsForSearch: -1
                    });

                    controller.$render = function () {
                        elm.select2('val', controller.$viewValue);
                    };

                    elm.on('change', function () {
                        scope.$apply(function () {
                            controller.$setViewValue(elm.select2('val'));
                        });
                    });

                    attrs.$observe('disabled', function (value) {
                        elm.select2('enable', !value);
                    });

                    attrs.$observe('readonly', function (value) {
                        elm.select2('readonly', !!value);
                    });

                    elm.bind("$destroy", function () {
                        elm.select2("destroy");
                    });
                }, 1);
            }
        }
    }]);
;
'use strict';

wbApp.directive('wbCompensationCourseLookup', ['$http', '$translate', '$timeout',
    function ($http, $translate, $timeout) {
        function formatResult(course, container) {
            if (!course) { return; }

            var compAllowed = course.compensationGroupID === compGroupID ||
                   (!!acceptingGroups && acceptingGroups.indexOf(course.compensationGroupID) !== -1);

            var html;
            if (!compAllowed && compOverride) {
                html  = "<div class='row' style='width:500px' disabled>";
                html += "<div class='col-md-10 text-danger' disabled>" + course.fullName + "</div>";
                html += "<div class='col-md-2 text-danger' disabled>" + course.amends + "</div>";
                html += "</div>";
            } else {
                html  = "<div class='row' style='width:500px'>";
                html +=   "<div class='col-md-10'>" + course.fullName + "</div>";
                html +=   "<div class='col-md-2'>" + course.amends + "</div>";
                html += "</div>";
            }

            return html;                    
        }

        function formatSelection(course) {
            if (!course || course.length === 0) {
                return null;
            }

            var compAllowed = course.compensationGroupID === compGroupID ||
                   (!!acceptingGroups && acceptingGroups.indexOf(course.compensationGroupID) !== -1);

            if (!compAllowed) {
                return "<span class='text-danger'>" + course.fullName + "</span>";
            } else {
                return course.fullName;
            }
        }

        var selection_data = [];
        var acceptingGroups = [];
        var compGroupID = -1;
        var compOverride = false;

        return {
            restrict: 'A',
            require: 'ngModel',
            scope: {
                ngModel: '=',
                studentId: '=',
                semesterId: '=',
                compGroupId: '=',
                compOverride: '=',
                acceptingGroups: '=',
                lessonEndDate: '='
            },
            priority: 1,
            replace: true,
            template: "<input class='form-control' />",
            link: function (scope, elm, attrs, controller) {
                $timeout(function () {
                    $(elm).select2({
                        placeholder: $translate.instant('TXT_PLACEHOLDER_SELECT_COURSE'),
                        formatResult: formatResult,
                        formatSelection: formatSelection,
                        dropdownAutoWidth: true,
                        minimumResultsForSearch: -1,
                        allowClear: false,
                        data: selection_data
                    });

                    controller.$render = function () {
                        elm.select2('val', controller.$viewValue);
                    };

                    scope.$watch('studentId', function (current, old) {
                        if (!current) {
                            $(elm).select2('data', []);
                        } else {
                            $http({
                                method: 'GET',
                                url: "Api/Courses/GetCompensationCourses",
                                params: {
                                    semesterID: scope.semesterId,
                                    studentID: current,
                                    courseID: controller.$viewValue,
                                    lessonEndDate: scope.lessonEndDate
                                }
                            })
                            .success(function (data, status, headers, config) {
                                selection_data.length = 0;
                                for (var i = 0; i < data.length; i++) {
                                    selection_data.push(data[i]);
                                }

                                if (!controller.$viewValue && scope.compGroupId) {
                                    for (var i = 0; i < data.length; i++) {
                                        var compAllowed = data[i].compensationGroupID === compGroupID ||
                                            (!!scope.acceptingGroups && scope.acceptingGroups.indexOf(data[i].compensationGroupID) !== -1);
                                        if (compAllowed) {
                                            controller.$setViewValue(data[i].id);
                                        } else {
                                            if (!scope.compOverride) {
                                                data[i].disabled = true;
                                            }
                                        }
                                    }
                                }

                                if (controller.$viewValue) {
                                    elm.select2('val', controller.$viewValue);
                                }
                            });
                        }
                    }, true);

                    scope.$watch('compGroupId', function (value) {
                        compGroupID = value;
                    });

                    scope.$watch('acceptingGroups', function (value) {
                        acceptingGroups = value;
                    });

                    scope.$watch('compOverride', function (value) {
                        compOverride = value;
                    })

                    elm.bind("$destroy", function () {
                        elm.select2("destroy");
                    });

                    attrs.$observe('disabled', function (value) {
                        elm.select2('enable', !value);
                    });

                    attrs.$observe('readonly', function (value) {
                        elm.select2('readonly', !!value);
                    });

                    elm.bind('select2-selecting', function (event) {
                        var compAllowed = event.object.compensationGroupID === compGroupID ||
                            (!!scope.acceptingGroups && scope.acceptingGroups.indexOf(event.object.compensationGroupID) !== -1);

                        if (!compAllowed && !scope.compOverride) {
                            event.preventDefault();
                        }
                    });

                }, 1);
            }
        }
    }]);
;
'use strict';

wbApp.directive('wbRegistrationAlert', ['notificationSvc','$window', 'tenantSettingSvc',
    function (notificationSvc, $window, tenantSettingSvc) {
        return {
            restrict: 'A',
            priority: 1,
            scope: { },
            template:
                "<div class='registration-alert registration-alert-min' ng-class='{\"registration-alert-min\": minimized, \"registration-alert-advertised\": advertised }'><div style='position:relative;'>" +
                    "<div class='message-panel'><h1>{{'TXT_LBL_WHO_ARE_YOU' | translate}}</h1><p>{{'TXT_LBL_LOGIN_REQUIRED' | translate}}</p></div>" +
                    "<div class='close-panel' ng-click='onActionPanelClick()'>" +
                        "<i ng-hide='minimized' class='fa fa-lg fa-chevron-left'></i>" +
                        "<i ng-show='minimized' class='fa fa-lg fa-chevron-right'></i>" +
                    "</div>" +
                    "<div class='action-button' style='top: 0; padding-top: 20px;'><a ng-href='/Login?{{urlParams}}' class='btn btn-lg btn-success'>{{'TXT_BTN_LOGIN'|translate}}</a></div>" +
                    "<div ng-if='enableUserRegistration' class='action-button' style='top: 75px; padding-top: 10px;' ><a href='https://idm.webooker.eu/Account/Register?{{urlRegisterParams}}' class='btn btn-lg btn-warning'>{{'TXT_LBL_NEW_ACCOUNT' | translate}}</a></div>" +
                "</div></div>",
            link: function (scope, element, attr, ctrl) {
                scope.minimized = true;
                scope.minClicked = false;
                scope.enableUserRegistration = tenantSettingSvc.settings.enableUserRegistration;

                var origUrlParams =  location.pathname;
                var origRegisterUrlParams = $window.location.origin + '/MyAccount?registration=true&idmRefreshCache=true&returnUrl=';

                scope.urlParams = 'returnUrl=' + encodeURIComponent(origUrlParams);
                scope.urlRegisterParams = 'returnUrl=' + encodeURIComponent(origRegisterUrlParams) +  encodeURIComponent(origUrlParams);

                scope.onActionPanelClick = function (urlParams) {
                    scope.advertised = !scope.advertised;
                    scope.minimized = !scope.advertised;

                    if (!!urlParams) {
                        scope.urlParams = 'returnUrl=' + encodeURIComponent(origUrlParams + '?' + urlParams);
                        scope.urlRegisterParams = 'returnUrl=' + encodeURIComponent(origRegisterUrlParams  +  encodeURIComponent(origUrlParams + '?' + urlParams));
                    }
                }

                notificationSvc.registerAdvertiseCallback(scope.onActionPanelClick);
            }
        }
    }]);;
'use strict';

wbApp.filter('ageRangeFlt', function () {
    return function (input, courseAgeRangeID) {
        if (!courseAgeRangeID) {
            return input;
        }

        var out = [];
        for (var i = 0; i < input.length; i++) {
            var entity = input[i];
            if (entity.courseAgeRangeID == courseAgeRangeID) {
                out.push(entity);
            }
        }
        return out;
    }
});;
'use strict';

wbApp.filter('classroomFlt', function () {
    return function (input, classroomID) {
        if (!classroomID) {
            return input;
        }

        var out = [];
        for (var i = 0; i < input.length; i++) {
            var entity = input[i];
            if (entity.classroomID == classroomID) {
                out.push(entity);
            }
        }
        return out;
    }
});;
wbApp.filter('courseTextFlt', function () {
    return function (items, query) {
        if (!query) {
            return items;
        }

        var lowerCaseQuery = query.toLowerCase();

        var filtered = [];
        angular.forEach(items, function (value, key) {

            var courseAbbreviation = (value.courseAbbreviation || '').toLowerCase();
            var subjectName = (value.subjectName || '').toLowerCase();
            var courseName = (value.courseName || '').toLowerCase();
            var compensationGroupName = (value.compensationGroupName || '').toLowerCase();
            var teacherFullName = (value.teacherFullName || '').toLowerCase();
            var scheduleDay = (value.scheduleDay || '').toLowerCase();

            if (courseAbbreviation.includes(lowerCaseQuery) ||
                subjectName.includes(lowerCaseQuery) ||
                courseName.includes(lowerCaseQuery) ||
                compensationGroupName.includes(lowerCaseQuery) ||
                teacherFullName.includes(lowerCaseQuery) ||
                scheduleDay.includes(lowerCaseQuery)) {
                this.push(value);
            }
        }, filtered);

        return filtered;
    }
});
;
'use strict';

wbApp.filter('courseTypeFlt', function () {
    return function (input, courseTypeID) {
        if (!courseTypeID) {
            return input;
        }

        var out = [];
        for (var i = 0; i < input.length; i++) {
            var entity = input[i];
            if (entity.courseTypeID == courseTypeID) {
                out.push(entity);
            }
        }
        return out;
    }
});;
wbApp.config(['$translateProvider', 'preferredLanguage',
    function ($translateProvider, preferredLanguage) {

        $translateProvider.translations('en', {

            TXT_NAME: 'Name',
            TXT_HUMAN_NAME: 'Name',
            TXT_HUMAN_SURNAME: 'Surname',
            TXT_SEARCH: 'Search',
            TXT_LANG_EN: 'English',
            TXT_LANG_CS: 'Czech',


            TXT_BTN_REGISTER: 'Register',
            TXT_BTN_REGISTER_ON_COURSE: 'Register on course',
            TXT_BTN_BOOK_PREVIEW: 'Book preview',
            TXT_BTN_BOOK: 'Book',
            TXT_BTN_EXCUSE: 'Excuse',


            TXT_BTN_YES: 'Yes',
            TXT_BTN_NO: 'No',
            TXT_BTN_FINISH: 'Finish',
            TXT_BTN_DELETE: 'Delete',
            TXT_BTN_ADD_STUDENT: 'Add student',
            TXT_BTN_DELETE_STUDENT: 'Delete student',
            TXT_BTN_REGISTRATION: 'Registration',
            TXT_BTN_LOGIN: 'Login',
            TXT_BTN_COMPLETE: 'Completed',
            TXT_BTN_OLDER: 'Older',
            TXT_BTN_HIDE: 'Hide',
            TXT_BTN_CLOSE: 'Close',
            TXT_BTN_BACK_TO_COURSE_LIST: 'Back to course list',
            TXT_BTN_I_HAVE_A_QUESTION: 'I have a question',

            TXT_BTN_IDM: 'Edit account details',


            // Tabs
            TXT_TAB_COURSE_SELECTION: 'Course selection',
            TXT_TAB_LESSON_SELECTION: 'Lesson selection',
            TXT_TAB_ACTIVITY_SELECTION: 'Class selection',
            TXT_TAB_DAY_SELECTION: 'Day selection',

            TXT_TAB_ATTENDANCE: 'Attendance',
            TXT_TAB_COURSE_DETAIL: 'Course detail',
            TXT_TAB_ACTION_DETAIL: 'Event detail',
            TXT_TAB_BOOKING: 'Booking',
            TXT_TAB_BOOK_PREVIEW: 'Preview lesson',
            TXT_TAB_STUDENT: 'Student',
            TXT_TAB_USER_ACCOUNT: 'User account',
            TXT_TAB_STUDENTS: 'Students',
            TXT_TAB_CONTACT_DETAILS: 'Contact details',
            TXT_TAB_PASSWORD_RESET: 'Password reset',
            TXT_TAB_CONFIRM_COURSE_BOOKING: 'Confirmation',

            TXT_SEMESTER: 'Semester',
            TXT_EXCUSE_ACTION: 'Excuse from lesson',
            TXT_EXCUSE_CANCEL_ACTION: 'Cancel excuse from lesson',
            TXT_EXCUSE_ACTION_DESC: 'Are you sure you want to excuse student {0} from lesson {1} of course {2}?',
            TXT_EXCUSE_ACTION_DESC_BRIEF: 'Are you sure you want to excuse student {0} from lesson {1}?',
            TXT_EXCUSE_CANCEL_ACTION_DESC: 'Are you sure you want to cancel the excuse for student {0} and attend the lesson {1} of course {2}?',
            TXT_EXCUSE_CANCEL_ACTION_W_DESC: 'Because of capacity restrictions on this lesson, the student {0} is currently in a waiting queue. Are you sure you want to delete student from waiting queue and NOT attend the lesson {1} of the course {2}?',

            TXT_REGISTER_FOR_PREVIEW_ACTION: 'Register to preview',
            TXT_REGISTER_FOR_PREVIEW_ACTION_DESC: 'Are you sure you want to register student {0} for preview lesson {1}?',
            TXT_REGISTER_TO_COURSE: 'Register for course',
            TXT_REGISTER_TO_COURSE_DESC: 'Are you sure you want to register {0} for course {1}?',
            TXT_UNREGISTER_FROM_COURSE_DESC: 'Are you sure you want to un-register {0} from course {1}?',
            TXT_REGISTER_TO_ACTION: 'Register to action',
            TXT_REGISTER_TO_ACTION_DESC: 'Are you sure you want to register {0} to event {1}?',
            TXT_UNREGISTER_FROM_ACTION_DESC: 'Are you sure you want to un-register {0} from event {1}?',
            TXT_STUDENT_SINGULAR: 'student',
            TXT_STUDENT_PLULAR: 'students',
            TXT_CONFIRM_DELETE_STUDENT_ATTENDANCE: 'Are you sure you want to delete attendance for student {0}?',

            TXT_COURSE_SCHEDULE_EXT: '{0} lessons ({1} - {2}), lesson length {3} minutes.',
            TXT_COURSE_SCHEDULE_EXT_WARN: 'Closest lesson: {0}, remaining lessons: {1}',

            TXT_TITLE_ABOUTME: 'About me',
            TXT_TITLE_WORKEXPERIENCE: 'Work experience',
            TXT_TITLE_BOOK_PREVIEW: 'Choose when you want to attend preview lesson',
            TXT_TITLE_ATTENDANCE_COURSE_SELECTION: 'Course selection for attendance',
            TXT_TITLE_ATTENDANCE_SELECT_LESSON: 'Select lesson:',
            TXT_TITLE_CHANGE_LESSON_NOTE: 'Change lesson note',
            TXT_TITLE_ATTENDANCE_SELECT_STUDENT: 'Select student:',
            TXT_TITLE_STUDENT_ATTENDANCE: 'Student attendance:',
            TXT_TITLE_FIX_ERRORS: 'Please fix the following errors:',
            TXT_TITLE_ATTENDANCE: 'Attendance',
            TXT_TITLE_COURSES: 'Course',
            TXT_TITLE_PAYMENTS: 'Payments',
            TXT_TITLE_PAYMENTS_ENTRY: 'Enter new payment',

            TXT_TITLE_SUMMARY: 'Summary',
            TXT_TITLE_COURSE_PRICE: 'Course price',
            TXT_TITLE_ACTION_PRICE: 'Event price',
            TXT_TITLE_ACTIONS: 'Events',
            TXT_TITLE_ACTIONS_FOR_PERIOD: 'One-off events for period',
            TXT_TITLE_MY_ACCOUNT: 'My account',
            TXT_TITLE_USER_DETAIL: 'Information about user',

            TXT_TITLE_USER_DETAIL_HELP_1: 'Your user account (information on this tab) is common to all systems',
            TXT_TITLE_USER_DETAIL_HELP_2: 'You can sign in to any of them using login details shown below.',
            TXT_TITLE_USER_DETAIL_HELP_3: 'Information on this page are used to identify the person who is working with this system. Courses, events and kindergarten are attended by students configured on the students tab.',

            TXT_TITLE_STUDENTS: 'Students - your children',
            TXT_TITLE_STUDENTS_HELP: 'Fill in information about all students. This means both your children or yourself if you also attend events and courses for parents.',
            TXT_TITLE_CONTACT_DETAIL: 'Contact details',
            TXT_TITLE_CONTACT_DETAIL_HELP: 'Additional contact details you want to share with this organization.',
            TXT_TITLE_REGISTRATION: 'Registration',
            TXT_TITLE_LOGIN: 'Login',
            TXT_TITLE_PASSWORD_RECOVERY: 'Recovery of lost password',
            TXT_TITLE_PASSWORD_RECOVERY_HELP: 'Here you can recover your lost password. If you forgot or lost your account password, please enter the email address you used during registration. New login details will be sent to this email address.',
            TXT_TITLE_ATTENDANCE_ACTIVITY_SELECTION: 'Class selection for attendance',
            TXT_TITLE_SELECT_STUDENT: 'Select student',
            TXT_TITLE_DELETE_STUDENT_ATTENDANCE: 'Delete student attendance',
            TXT_TITLE_MY_ACTIVITIES: 'My kindergarten',
            TXT_TITLE_ATTENDANCE_ACTIVITY_LIST: 'Your student\'s classes',
            TXT_STUDENT_ACTIVITY_CLICK_FOR_DETAIL: 'List of classes your students are or were attending. For attendance detail click on the particular class.',
            TXT_TITLE_EXCUSE: 'Excuse student',
            TXT_TITLE_ATTENDANCE_ACTIVITY_EDIT: 'Student\'s attendance',
            TXT_EDIT_ACTIVITY_ATTENDANCE: 'Below is listed student\'s attendance. If you want to excuse or book student click on the green button.',
            TXT_TITLE_EDIT_ATTENDANCE: 'Change attendance',
            TXT_TITLE_STUDENT_INFO: 'Student info',
            TXT_TITLE_INSTRUCTIONS: 'Instructions',
            TXT_TITLE_TERMS_AND_CONDITIONS: 'Terms and conditions',
            TXT_TITLE_ACTIVITIES: 'Kindergarten',
            TXT_TITLE_SCHEDULE: 'Schedule',
            TXT_TITLE_QUESTION_ABOUT_COURSE: 'Question about course',


            TXT_PAYMENTS_ENTRY_HELP: 'To enter the new payment select either invoice or students, the rest of the form will be filled automatically.',

            TXT_SELECT_COURSE_FOR_ATTENDANCE: 'Select course for which you want to fill in an attendance sheet.',
            TXT_SELECT_LESSON_FOR_ATTENDANCE: 'Select lesson for which you want to fill in the attendance.',
            TXT_SELECT_STUDENT_FOR_ATTENDANCE: 'Select student for whom you want to fill in the attendance.',
            TXT_SELECT_ACTIVITY_FOR_ATTENDANCE: 'Select class for which you want to fill in an attendance sheet',
            TXT_SELECT_DAY_FOR_ATTENDANCE: 'Select day for which you want to fill in the attendance sheet',

            TXT_CHANGE_STUDENT_ATTENDANCE: 'Update student attendance and click Save.',
            TXT_CHANGE_STUDENTS_ACTION_ATTENDANCE: 'Update student attendance if needed and then check Confirmed',
            TXT_REGISTER_INTEREST_DESC: 'By booking a student to one of these course you are just expressing a will to attend this course. Concrete course assignment will be done based on available capacity with regards to student age and proficiency level. You will be informed about the concrete course assignment by email.',


            TXT_COL_DATE: 'Date',
            TXT_COL_TIME: 'Time',
            TXT_COL_NOTE: 'Note',
            TXT_COL_FREE: 'Free',
            TXT_COL_CAPACITY: 'Capacity',
            TXT_COL_SCHEDULE: 'Schedule',
            TXT_COL_SUBJECT: 'Subject',
            TXT_COL_TEACHER: 'Teacher',
            TXT_COL_ATTENDANCE: 'Attendance',
            TXT_COL_STUDENT: 'Student',
            TXT_COL_PHONE1: 'Phone',
            TXT_COL_BIRTHDAY: 'Birthday',
            TXT_COL_ARREAR: 'Arrear',
            TXT_COL_ATTENDANCE_STATUS: 'Present',
            TXT_COL_ATTENDANCE_TYPE: 'Registered',
            TXT_COL_CONFIRMED: 'Confirmed',
            TXT_COL_PRICE: 'Price',
            TXT_COL_PER_LESSON: 'Per lesson',
            TXT_COL_LESSONS: 'Lessons',
            TXT_COL_DISCOUNT: 'Discount',

            TXT_COL_ACTION: 'Event',
            TXT_COL_ACTIVITY: 'Class',
            TXT_COL_CLASSROOM: 'Classroom',


            TXT_LAB_PRESENT: 'Present:',
            TXT_LAB_ATTENDANCE_TYPE: 'Attendance type',

            TXT_LAB_NOTES: 'Notes',
            TXT_LAB_COMPENSATION_FOR: 'Compensation for:',
            TXT_LBL_COURSES_AND_BOOKING: 'Courses and booking',
            TXT_LBL_ACTIONS: 'One off events',
            TXT_LBL_EXUSES_AND_COMPENSATIONS: 'Excuses and comp.',
            TXT_LBL_KINDERGARTEN: 'Kindergarten',


            TXT_LAB_HEALTH_DESCRIPTION: 'with relation to class (alergy, epilepsy, etc.)',
            TXT_LAB_PROFICIENCY_LEVEL: 'Proficiency level',
            TXT_LAB_PLACE: 'Place',
            TXT_LAB_TYPE: 'Type',
            TXT_LAB_NAME: 'Name',
            TXT_LAB_SURNAME: 'Surname',
            TXT_LAB_ADDRESS: 'Address',
            TXT_LAB_MIDDLE_NAME: 'Middle name',
            TXT_LAB_PHONE2: 'Second phone',
            TXT_LAB_PHONE: 'Phone',
            TXT_LAB_EMAIL: 'Email',
            TXT_LAB_YOUR_EMAIL: 'Your email',
            TXT_LAB_GENDER: 'Gender',
            TXT_LAB_BIRTHDAY: 'Birthday',
            TXT_LAB_USER_NAME: 'User name',
            TXT_LAB_PASSWORD: 'Password',
            TXT_LAB_PASSWORD_AGAIN: 'Confirm password',
            TXT_LAB_PASSWORD_STRENGTH: 'Password strength',
            TXT_LAB_I_AM_STUDENT: 'I am student',
            TXT_LAB_I_AM_NOT_STUDENT: 'I am not student',
            TXT_LAB_KEEP_ME_SIGNED: 'Remember me',
            TXT_LAB_EXCUSE_FROM: 'Excuse from',
            TXT_LAB_EXCUSE_TO: 'Excuse to',
            TXT_LAB_EXCUSE: 'Excuse',
            TXT_LAB_BOOK: 'Book',
            TXT_LAB_AM_PERIOD: 'morning',
            TXT_LAB_PM_PERIOD: 'afternoon',
            TXT_LAB_AM_PM_PERIOD: 'morning and afternoon',
            TXT_LAB_STUDENT_WILL_BE_EXCUSED: 'Student will be excused from',
            TXT_LAB_STUDENT_WILL_BE_EXCUSED_END: 'lesson.',
            TXT_LAB_STUDENT_WILL_BE_BOOKED: 'Student will be booked to',
            TXT_LAB_STUDENT_WILL_BE_BOOKED_END: 'lesson.',
            TXT_LBL_I_AM_INTERESTED_IN_KINDERGARTEN: 'I am interested',
            TXT_LBL_WELCOME: 'Welcome in Information System',
            TXT_LBL_ARE_YOU_INTERESTED: 'Are you interested in our kindergarten',
            TXT_LBL_ARE_YOU_INTERESTED_CLICK: 'If you are interested in our kindergarten click on the following button. We will contact you.',
            TXT_LBL_LIST_OF_CLASSES: 'Below is the list of classes we\'ve opened in semester',
            TXT_LBL_OPENED: '',
            TXT_LBL_OPENED_CLASSES: 'Opened classes',
            TXT_LBL_NEW_ACCOUNT: 'New account',
            TXT_LBL_LOGIN_REQUIRED: 'This action requires you to login to the system.',
            TXT_LBL_WHO_ARE_YOU: 'Who you are?',
            TXT_LBL_AVAILABLE_AMENDS: 'Comp.',
            TXT_LBL_WAIT_QUEUE_POSITION: 'Queue position',
            TXT_LBL_BEGINING: 'Start',
            TXT_LBL_YOUR_ADDRESS: 'Your address',
            TXT_LBL_ENTER_MY_ADDRESS_TO_LIMIT_SEARCH: 'Enter address of your location to zoom the map',
            TXT_LBL_COURSE_DESCRIPTION: 'Course description',
            TXT_LBL_ACTION_DESCRIPTION: 'Event description',
            TXT_LBL_MORE_INFO: 'More information',
            TXT_LBL_LESSON_NOTE: 'Lesson note',
            TXT_LBL_FOR_EXISTING_CLIENTS: 'For existing clients',
            TXT_LBL_FOR_NEW_CLIENTS: 'For new clients',
            TXT_LBL_THANKS: 'Thank you',
            TXT_LBL_COURSE_REGISTRATION_WAS_SUCCESFULL: 'Your registration for the course was successful!',
            TXT_LBL_REG_MAIL_WAS_SENT: 'A confirmation about this booking was sent to your email. If you do not receive the confirmation, please check the spam folder for email from noreply@{0}',
            TXT_LBL_INVOICE_WAS_SEND: 'An {0} for this course will arrive together with the course registration confirmation.',
            TXT_LBL_PLACE_WILL_BE_RESERVED: 'The place for this course will be reserved for you after you pay the invoiced amount.',
            TXT_LBL_YOUR_QUESTION: 'Your question text',
            TXT_LBL_INVOICE: 'Invoice',
            TXT_LBL_ONLINE_ENABLED_IN: 'Online lesson will be available in',
            TXT_LBL_START_ONLINE_LESSON: 'Start online lesson',
            TXT_LBL_CONNECT_TO_ONLINE_LESSON: 'Connect to online lesson',
            TXT_LBL_FREE_PLACES: 'Free places',

            TXT_PLACEHOLDER_SELECT_STUDENT: 'Select student ...',
            TXT_PLACEHOLDER_SELECT_COURSE: 'Select course ...',
            TXT_PLACEHOLDER_SELECT_CLASSROOM: 'Select classroom ...',
            TXT_PLACEHOLDER_SELECT_PROFICIENCY_LEVEL: 'Select proficiency level ...',
            TXT_PLACEHOLDER_HEALTH_OK: 'Good',
            TXT_PLACEHOLDER_REFERENCE_SOURCE: 'How did you find out about us?',
            TXT_PLACEHOLDER_SELECT_ACTIVITY_ATTENDANCE: 'Compensation for ...',

            TXT_ERROR_NOT_LOGGED_IN: 'You are not logged in. If you want to book on this course you need to first log in',
            TXT_ERROR_NO_STUDENTS: 'You do not have any students set up. You can set up students in menu "More / My account"',
            TXT_ERROR_TITLE: 'Please fix the following errors',
            TXT_ERROR_INVALID_EMAIL: 'Email address is not valid',
            TXT_ERROR_REQUIRED: 'This field is required',
            TXT_ERROR_MAX_LENGTH: 'Maximum length exceeded',
            TXT_ERROR_MIN_LENGTH: 'Length is less then minimum required',
            TXT_ERROR_PATTERN: 'Value is not valid',
            TXT_ERROR_UNIQUE_EMAIL: 'Email address is not unique',
            TXT_ERROR_UNIQUE_USER_NAME: 'User name is not unique',
            TXT_ERROR_PASSWORDS_MUST_MATCH: '"Password" and "Confirm Password" must match',
            TXT_ERROR_MIN: 'Entered value is smaller than minimum allowed',
            TXT_ERROR_MAX: 'Entered value is larger than maximum allowed',
            TXT_ERROR_NO_STUDENTS_REGISTERED_ON_THIS_LESSON: 'None of your students is registered on this lesson.',

            TXT_AGREE_TO_TERMS_AND_CONDITIONS: 'First you need to agree to the terms and conditions.',

            IMG_COURSE_FILLED: 'Areas/Client/Images/Full.png',

            TXT_ALERT_TITLE_ENTITY_SAVED: 'Saved successfully',
            TXT_ALERT_TITLE_ENTITY_SAVE_ERROR: 'Error during save',

            //TXT_ALERT_TITLE_PAYMENT_SAVED: 'Payment was saved successfully',

            TXT_TICK_STUDENT_TO_REGISTER_HELP: 'To register the student tick the check box next to her/his name.',
            TXT_GO_TO_SCHEDULE_HELP: 'Here you are registering to the whole course, i.e. all remaining lessons. If you want to attend only once or you want to attend irregularly book concrete lesson in the',
            TXT_ALERT_TITLE_COURSE_PREVIEW_ATTENDANCE_CHANGE_SUCCESS: 'Preview attendance change was successful',
            TXT_ALERT_TITLE_COURSE_PREVIEW_ATTENDANCE_CHANGE_FAILURE: 'There was an error while saving preview attendance change',
            TXT_ALERT_TITLE_COURSE_REGISTRATION_SUCCESS: 'Course registration was saved successfully',
            TXT_ALERT_TITLE_COURSE_REGISTRATION_FAILURE: 'There was an error while saving course registration',
            TXT_ALERT_TITLE_ACTION_REGISTRATION_SUCCESS: 'Event registration was saved successfully',
            TXT_ALERT_TITLE_ACTION_REGISTRATION_FAILURE: 'There was an error while saving event registration',
            TXT_ALERT_TITLE_DATA_SAVED: 'Changes were saved successfully',
            TXT_ALERT_TITLE_USER_REGISTERED: 'New user has been registered and logged in',
            TXT_ALERT_TITLE_PASSWORD_RESET_OK: 'Your password was reset successfully',
            TXT_ALERT_ATTENDANCE_CONFIRM_SUCCESS: 'Attendance confirmation for student {0} was saved successfully',
            TXT_ALERT_ATTENDANCE_CONFIRM_FAILURE: 'There was an error while saving attendance confirmation for student {0}',
            TXT_ALERT_ATTENDANCE_SAVE_SUCCESS: 'Attendance was saved successfully',
            TXT_ALERT_ATTENDANCE_SAVE_FAILURE: 'There was an error while saving attendance',
            TXT_ALERT_TITLE_STUDENT_ALREADY_IN_ATTENDANCE: 'Selected student is already in the attendance sheet',
            TXT_ALERT_SERVER_ERROR: 'Server error',
            TXT_ALERT_TITLE_ACTIVITY_INTEREST_REQUESTED: 'Kindergarten interest recorder successfully',
            TXT_ALERT_TITLE_REGISTERING_USER_QUESTION_SUCCESS: 'Your question about this course was registered successfully',
            TXT_ALERT_TITLE_REGISTERING_USER_QUESTION_FAILURE: 'There was an error while registering question about this course',


            TXT_REGISTER_INTEREST_HELP: 'If you want to attend to this course please tick the checkbox next to student name. Since we are assigning concrete courses by hand based on many different factors, please also fill in student proficiency level and any notes you might have, “like cannot attend on Thursday’s“ so we can match your needs as close as possible.',

            TXT_STUDENT_IS_REGISTERED: 'Student is registered',
            TXT_HLP_ADD_SELF_AS_STUDENT: 'If you are going to attend courses and / or one-off events yourself you should be a student too.',
            TXT_DISCLAIMER: 'I declare that until revocation I agree with processing, collecting and storing of mine and mine children personal information (name, surname, permanent address, date of birth, phone number, email) into the client database {0} domicile {1} with accordance with law no. 101/2000 Col. about personal information protection. I can revoke this declaration any time in a written form. This declaration is voluntarily and I agree with their usage especially for marketing activities, sending offers etc. {0} claims that this information will not be given to any third party. Furthermore, I agree with making photos and videos and with archiving of these materials and with it\'s usage for marketing purposes (for example in press, on internet etc.)',

            TXT_DAY: 'Day',
            TXT_AM: 'AM',
            TXT_PM: 'PM',
            TXT_LUNCH: 'Lunch',
            TXT_FIRST_SNACK: '1 Snack',
            TXT_SECOND_SNACK: '2 Snack',
            TXT_SNACK: 'Snack',
            TXT_DATE_PART_AM: 'AM',
            TXT_DATE_PART_PM: 'PM',

            TXT_TOOLTIP_EDIT_ATTENDANCE: 'Change student attendance',
            TXT_TOOLTIP_EXCUSE_FROM_LESSON: 'Enter longer absence',

            TXT_MSG_LOADING: 'Loading data ...',

            TXT_HLP_COMPENSATION_GROUP_HELP: 'This course belongs to the "{0}" compensation group. Compensations can be claimed only within the same compensation group.',
            TXT_HLP_WARNING_CANNOT_CHANGE_ATTENDANCE_DUE_TO_TIME_LIMIT: 'Attendance cannot be changed any more, lesson is either in progress or in the past.',
            TXT_HLP_HOW_TO_REGISTER_ONE_OFF_HELP: 'To book a student to this lesson check "Present" checkbox next to his name.',
            TXT_HLP_HOW_TO_USE_AMEND_HELP: 'To attend this lesson utilizing available compensation hours check "Present" checkbox next to the student with non zero available amends.',
            TXT_HLP_HOW_TO_LATE_EXCUSE_ONLINE_HELP: 'To excuse a student from this lesson uncheck the "Present" checkbox next to his name. (Not eligible to compensation.)',
            TXT_HLP_HOW_TO_EXCUSE_ONLINE_HELP: 'To excuse a student from this lesson uncheck the "Present" checkbox next to his name.',
            TXT_HLP_COMPENSATION_WAIT_QUEUE_HELP: 'There is no free place on this lesson. However you will be added to the wait queue. When the space is freed you will be automatically booked to the lesson. Order shows your place in the wait queue.',
            TXT_HLP_COMPENSATION_WAIT_QUEUE_HELP2: 'There is no free place on this lesson. However you will be added to the wait queue. When the space is freed you will be automatically booked to the lesson.',
            TXT_HLP_COMPENSATION_WAIT_QUEUE_FOR_ACTION_HELP: 'There is no free place on this event. However you will be added to the wait queue. When the space is freed you will be automatically booked to the event. Order shows your place in the wait queue',
            TXT_HLP_ONE_OFFS_ARE_DISABLED: 'Students cannot be booked on this lesson with one-off attendance since one-off attendance has been disabled for this course.',
            TXT_HLP_HOW_TO_REGISTER_ACTION_HELP: 'To register student to this one-off event check "Present" checkbox next to his name.',
            TXT_HLP_HOW_TO_UNREGISTER_ACTION_HELP: 'To unregister student from this one-off event uncheck "Present" checkbox next to his name.',
            TXT_HLP_NO_STUDENTS_ATTENDANCE: 'User does not have any students configured and therefore cannot change the attendance',

            TXT_SELECT_ALL_LESSONS: 'Select all lessons',
            TXT_LBL_SUMMARY_OF_CHANGES: 'Summary of changes',
            TXT_TITLE_SUMMARY_OF_ATTENDANCE_CHANGES_STUDENT: 'Summary of attendance changes for student',
            TXT_TITLE_SUMMARY_OF_ATTENDANCE_CHANGES_STUDENT_DESC: 'Chart shows how much valid excuses remains to student for each day (Move mouse cursor over the chart to get exact values). Table under the chart shows list of attendance changes.',

            TXT_AVAILABLE_AMENDS: "Compensations",
            TXT_FREE_PLACES: "Free places",
            TXT_EDIT: "Edit",
            TXT_NEW_ONE_OFF_CONFIRMATION: "You have entered a new One Off attendance. This kind of attendance can impose additional fees! Are you sure you want to save this attendance change?",

            TXT_DUE_PAYMENTS: 'Due payments',
            TXT_TITLE_DUE_PAYMENTS_HELP: 'List of due-payments / overpayments for all your students. Due-payments are red, overpayments are green.',
            TXT_TITLE_DUE_PAYMENTS_HELP2: 'List of due-payments - not payed or partially paid invoiced for all your students.',
            TXT_TITLE_CONFIRM_ONLINE_PAYMENT: 'Pay online',
            TXT_CONFIRM_CONFIRM_START_ONLINE_PAYMENT: 'Click Yes if you want to pay online with your card. You will be redirected to a payment gateway.',

            TXT_FINISH: 'Finish',
            TXT_FILLED: 'Filled',
            TXT_DUE_PAYMENT_DETAIL: 'Due payment detail',
            TXT_NEW_WAIT_QUEUE_CONFIRMATION: "You are booking to a wait queue. You will be automatically booked when there is a free place.",
            TXT_NEW_WAIT_QUEUE_CONFIRMATION_ONE_OFF: "Attendance type (compensation / one-off) is determined at the time of booking, when there is a free place. One-off attendance can impose additional fees.",
            TXT_IN_A_WAIT_QUEUE: 'In a wait queue ({0})',

            TXT_PAYMENT_FOR_COURSE: 'Payment for course',
            TXT_ONLINE_PAYMENT_FAILD_HELP: 'In case the online payment was not completed successfully you can try the it again form',
            TXT_PAYMENT_QUERYING_PROGRESS: 'Getting online payment status',


            TXT_PREFERRED_BOOKING: 'Preferred booking',
            TXT_PREFERRED_BOOKING_DESC1: 'In the period',
            TXT_PREFERRED_BOOKING_DESC2: 'booking is allowed to continuing students only',

            TXT_TAB_MY_CONSENTS: 'Consents',
            TXT_TITLE_MY_CONSENTS: 'Consents',
            TXT_TITLE_MY_CONSENTS_HELP: 'Below you find requests for consents for processing of your personal information. You can deny already approved consent at any time.',

            TXT_APPROVE: 'Approve',
            TXT_DENY: 'Deny',
            TXT_VALID: 'Valid',
            TXT_VALIDITY: 'Validity',
            TXT_INVALID: 'Invalid',
            TXT_APPROVED_BY: 'Approved by',
            TXT_APPROVED_AT: 'Approved at',
            TXT_DENIED_BY: 'Denied by',
            TXT_DENIED_AT: 'Denied at',

            TXT_REGISTRATION_NOTE: 'Registration notes',
            TXT_ATTENDANCE_NOTE: 'Attendance notes',
            TXT_TITLE_RESERVATIONS: 'Reservations',
            TXT_CANNOT_CHANGE_EVENT_ATTENDANCE_DUE_TO_DISABLED_REGISTRATION: 'Registration has been closed. Attendance cannot be changed anymore. Please contact us if you want to excuse from this event.',

            TXT_REGISTER_TENANT: 'I want {0}',
            TXT_TENANT_REGISTRATION_TAB_TITLE: 'Creation of own system {0}',
            TXT_TENANT_REGISTRATION_TAB_SUB_TITLE: 'Here you can create your own system {0} for free and immediately start offer courses and / or events. Your courses will be offered not only in your system but also in the central system. Your premisses will show on the map automatically.',

            TXT_TITLE_FORMS: 'Forms',
            TXT_LBL_FORMS_RESPONSE: 'Form response',
            TXT_FILL_IN: 'Fill in',
            TXT_ERROR_NO_STUDENTS_2: 'You do not have any students set up. You can set up students in menu "More / My account"',
            TXT_LBL_FORM_RESPONSE_WAS_SUCCESFULL: 'for filling in the form. Your answers where saved successfully!',
            TXT_LBL_FORM_RESPONSE_WAS_SEND: 'You will receive a confirmation into your mailbox.',
            TXT_BTN_BACK_TO_FORM_LIST: 'Back to forms list',

            TXT_BTN_FULL_COURSE_INTEREST: 'Book as surrogate',

            TXT_LBL_FULL_COURSE_INTEREST_REGISTRATION_WAS_SUCCESFULL: 'Your course booking as a surrogate was successful!',
            TXT_LBL_FULL_COURSE_INTEREST_REGISTRATION_DESCRIPTION: 'This course is full already and therefore we cannot book you directly! We will keep you as a surrogate or will try to find you a suitable alternative.',

            TXT_COURSE_IS_FULL: 'Full',
            TXT_COURSE_IS_FULL_SUB_TITLE: 'Book as stand-in',
            TXT_COPIED_TO_CLIPBOARD: 'Copied to clipboard',

            TXT_RENT_WITHOUT_REGISTRATION: 'Rent without registration',

            TXT_PUBLISHED_FILES: 'Available files',
            TXT_THIS_COURSE_IS_ONLINE: 'This course takes place online'
        });

        $translateProvider.preferredLanguage(preferredLanguage);
    }]);
;
wbApp.config(['$translateProvider', 'preferredLanguage',
    function ($translateProvider, preferredLanguage) {
        $translateProvider.translations('cs', {

            TXT_NAME: 'Název',
            TXT_HUMAN_NAME: 'Jméno',
            TXT_HUMAN_SURNAME: 'Příjmení',
            TXT_SEARCH: 'Hledat',
            TXT_LANG_EN: 'Anglicky',
            TXT_LANG_CS: 'Česky',


            TXT_BTN_REGISTER: 'Registrovat',
            TXT_BTN_REGISTER_ON_COURSE: 'Registrovat na kurz',
            TXT_BTN_BOOK_PREVIEW: 'Zkušební hodina',
            TXT_BTN_BOOK: 'Přihlásit',
            TXT_BTN_EXCUSE: 'Omluvit',
            
            
            TXT_BTN_YES: 'Ano',
            TXT_BTN_NO: 'Ne',
            TXT_BTN_FINISH: 'Dokončit',
            TXT_BTN_DELETE: 'Smazat',
            TXT_BTN_ADD_STUDENT: 'Přidat studenta',
            TXT_BTN_DELETE_STUDENT: 'Smazat studenta',
            TXT_BTN_REGISTRATION: 'Registrace',
            TXT_BTN_LOGIN: 'Přihlášení',
            TXT_BTN_COMPLETE: 'Hotovo',
            TXT_BTN_OLDER: 'Starší',
            TXT_BTN_HIDE: 'Skrýt',
            TXT_BTN_CLOSE: 'Zavřít',
            TXT_BTN_BACK_TO_COURSE_LIST: 'Zpět na seznam kurzů',
            TXT_BTN_I_HAVE_A_QUESTION: 'Mám dotaz',

            TXT_BTN_IDM: 'Upravit uživatelský účet',

            // Tabs
            TXT_TAB_COURSE_SELECTION: 'Výběr kurzu',
            TXT_TAB_LESSON_SELECTION: 'Výběr lekce',
            TXT_TAB_ACTIVITY_SELECTION: 'Výběr třídy',
            TXT_TAB_DAY_SELECTION: 'Výběr dne',

            TXT_TAB_ATTENDANCE: 'Docházka',
            TXT_TAB_COURSE_DETAIL: 'Detail kurzu',
            TXT_TAB_ACTION_DETAIL: 'Detail akce',
            TXT_TAB_BOOKING: 'Zápis',
            TXT_TAB_BOOK_PREVIEW: 'Zkušební hodina',
            TXT_TAB_STUDENT: 'Student',
            TXT_TAB_USER_ACCOUNT: 'Uživatelský účet',
            TXT_TAB_STUDENTS: 'Studenti',
            TXT_TAB_CONTACT_DETAILS: 'Kontaktní údaje',
            TXT_TAB_PASSWORD_RESET: 'Reset hesla',            
            TXT_TAB_CONFIRM_COURSE_BOOKING: 'Potvrzení',

            TXT_SEMESTER: 'Semestr',
            TXT_EXCUSE_ACTION: 'Omluvit z hodiny',
            TXT_EXCUSE_CANCEL_ACTION: 'Zrušit omluvu z hodiny',
            TXT_EXCUSE_ACTION_DESC: 'Opravdu chcete omluvit studenta {0} z hodiny konané {1} kurzu {2}?',
            TXT_EXCUSE_ACTION_DESC_BRIEF: 'Opravdu chcete omluvit studenta {0} z hodiny konané {1}?',

            TXT_EXCUSE_CANCEL_ACTION_DESC: 'Opravdu chcete zrušit omluvu studenta {0} a zůčastnit se hodiny konané {1} kurzu {2}?',
            TXT_EXCUSE_CANCEL_ACTION_W_DESC: 'Z kapacitních důvodů je student {0} zařazen na čekací listině. Opravdu chcete smazat studenta z čekací listiny a NEZÚČASTNIT se hodiny konané {1} kurzu {2}?',

            TXT_REGISTER_FOR_PREVIEW_ACTION: 'Přihlášení na zkušební hodinu',
            TXT_REGISTER_FOR_PREVIEW_ACTION_DESC: 'Opravdu chcete přihlásit studenta {0} na zkušební hodinu, která se koná {1}?',
            TXT_REGISTER_TO_COURSE: 'Registrace na kurz',
            TXT_REGISTER_TO_COURSE_DESC: 'Opravdu chcete zaregistrovat {0} na kurz {1}?',
            TXT_UNREGISTER_FROM_COURSE_DESC: 'Opravdu chcete odregistrovat {0} z kurzu {1}?',
            TXT_REGISTER_TO_ACTION: 'Registrace na akci',
            TXT_REGISTER_TO_ACTION_DESC: 'Opravdu chcete zaregistrovat {0} na akci {1}?',
            TXT_UNREGISTER_FROM_ACTION_DESC: 'Opravdu chcete odhlásit {0} z akce {1}?',
            TXT_STUDENT_SINGULAR: 'studenta',
            TXT_STUDENT_PLULAR: 'studenty',
            TXT_CONFIRM_DELETE_STUDENT_ATTENDANCE: 'Opravdu chcete smazat docházku studenta {0}?',

            TXT_COURSE_SCHEDULE_EXT: '{0} lekcí ({1} - {2}), délka lekce: {3} minut.',
            TXT_COURSE_SCHEDULE_EXT_WARN: 'Nejbližší lekce: {0}, zbývá lekcí: {1}',

            TXT_TITLE_ABOUTME: 'O mně',
            TXT_TITLE_WORKEXPERIENCE: 'Praxe',
            TXT_TITLE_BOOK_PREVIEW: 'Vyberte, kdy chcete přijít na zkušební hodinu',
            TXT_TITLE_ATTENDANCE_COURSE_SELECTION: 'Výběr kurzu pro docházku',
            TXT_TITLE_ATTENDANCE_SELECT_LESSON: 'Výběr lekce kurzu:',
            TXT_TITLE_CHANGE_LESSON_NOTE: 'Změna poznámky lekce',
            TXT_TITLE_ATTENDANCE_SELECT_STUDENT: 'Výběr studenta:',
            TXT_TITLE_STUDENT_ATTENDANCE: 'Docházka studenta:',
            TXT_TITLE_FIX_ERRORS: 'Prosím opravte následující chyby:',
            TXT_TITLE_ATTENDANCE: 'Docházka',
            TXT_TITLE_COURSES: 'Kurzy',
            TXT_TITLE_PAYMENTS: 'Platby',
            TXT_TITLE_PAYMENTS_ENTRY: 'Zadejte novou platbu',
            TXT_TITLE_SUMMARY: 'Rekapitulace',
            TXT_TITLE_COURSE_PRICE: 'Kurzovné',
            TXT_TITLE_ACTION_PRICE: 'Vstupné',
            TXT_TITLE_ACTIONS: 'Akce',
            TXT_TITLE_ACTIONS_FOR_PERIOD: 'Jednorázové akce pro období',
            TXT_TITLE_MY_ACCOUNT: 'Můj účet',
            TXT_TITLE_USER_DETAIL: 'Údaje o uživateli',
            TXT_TITLE_USER_DETAIL_HELP_1: 'Váš uživatelský účet (údaje na této záložce) je společný pro všechny systémy',
            TXT_TITLE_USER_DETAIL_HELP_2: 'Pomocí níže uvedených přihlašovacích údajů se můžete přihlásit do libovolného z nich.',
            TXT_TITLE_USER_DETAIL_HELP_3: 'Údaje zde uvedené slouží k identifikaci osoby, která se systémem pracuje. Kurzy, akce, tábory nebo školku navštěvují studenti, kteří se nastavují na záložce studenti.',
            TXT_TITLE_STUDENTS: 'Studenti',
            TXT_TITLE_STUDENTS_HELP: 'Vyplňte prosím informace o všech studentech. To znamená jak o vašich dětech tak o sobě, pokud budete také navštěvovat kurzy nebo akce.',
            TXT_TITLE_CONTACT_DETAIL: 'Kontaktní údaje',
            TXT_TITLE_CONTACT_DETAIL_HELP: 'Další kontaktní informace, které chcete sdílet s touto organizací.',
            TXT_TITLE_REGISTRATION: 'Registrace',
            TXT_TITLE_LOGIN: 'Přihlášení',
            TXT_TITLE_PASSWORD_RECOVERY: 'Obnova ztraceného hesla',
            TXT_TITLE_PASSWORD_RECOVERY_HELP: 'Zde si můžete obnovit ztracené heslo. Pokud jste ztratili nebo zapomněli heslo k vašemu účtu, zadejte e-mailovou adresu, kterou jste použili při registraci. Na tuto adresu vám budou poslány nové přihlašovací údaje.',
            TXT_TITLE_ATTENDANCE_ACTIVITY_SELECTION: 'Výběr třídy pro docházku',
            TXT_TITLE_SELECT_STUDENT: 'Výběr studenta',
            TXT_TITLE_DELETE_STUDENT_ATTENDANCE: 'Smazat docházku studenta',
            TXT_TITLE_MY_ACTIVITIES: 'Moje školka',
            TXT_TITLE_ATTENDANCE_ACTIVITY_LIST: 'Třídy vašich studentů',
            TXT_STUDENT_ACTIVITY_CLICK_FOR_DETAIL: 'Seznam tříd do kterých chodí, nebo chodili vaši studenti. Pro detail docházky klikněte na konkrétní třídu.',
            TXT_TITLE_EXCUSE: 'Omluvit studenta',
            TXT_TITLE_ATTENDANCE_ACTIVITY_EDIT: 'Docházka studenta',
            TXT_EDIT_ACTIVITY_ATTENDANCE: 'Níže je zobrazen přehled docházky. Pokud chcete studenta omluvit, nebo naopak přihlásit, stiskněte zelené tlačítko.',
            TXT_TITLE_EDIT_ATTENDANCE: 'Upravit docházku',
            TXT_TITLE_STUDENT_INFO: 'Informace o studentovi',
            TXT_TITLE_INSTRUCTIONS: 'Návod',
            TXT_TITLE_TERMS_AND_CONDITIONS: 'Provozní řád',
            TXT_TITLE_ACTIVITIES: 'Školka',
            TXT_TITLE_SCHEDULE: 'Rozvrh',
            TXT_TITLE_QUESTION_ABOUT_COURSE: 'Dotaz na kurz',

            TXT_PAYMENTS_ENTRY_HELP: 'Pro zadání nové platby vyberte buďto fakturu, nebo studenta. Zbytek formuláře se vyplní sám.',

            TXT_SELECT_COURSE_FOR_ATTENDANCE: 'Vyberte kurz, pro který chcete vyplnit docházku.',
            TXT_SELECT_LESSON_FOR_ATTENDANCE: 'Vyberte lekci kurzu pro kterou chcete vyplnit docházku.',
            TXT_SELECT_STUDENT_FOR_ATTENDANCE: 'Vyberte studenta pro kterého chcete upravit docházku.',
            TXT_SELECT_ACTIVITY_FOR_ATTENDANCE: 'Vyberte třídu, pro kterou chcete vyplnit docházku',
            TXT_SELECT_DAY_FOR_ATTENDANCE:'Vyberte den, pro který chcete vyplnit docházku',
            TXT_CHANGE_STUDENT_ATTENDANCE: 'Upravte docházku studenta dle skutečnosti a stiskněte Uložit.',
            TXT_CHANGE_STUDENTS_ACTION_ATTENDANCE: 'Upravte docházku studentů dle skutečnosti a pak zaškrtněnte Potvrzeno.',
            TXT_REGISTER_INTEREST_DESC: 'Zápisem na kurz pouze projevujete zájem na tento kurz chodit, skutečné přiřazení na konkrétní kurz bude provedeno dle dostupné kapacity, s přihlédnutím na věk a pokročilost studenta. O zápisu budete informováni e-mailem.',

            TXT_COL_DATE: 'Datum',
            TXT_COL_TIME: 'Čas',
            TXT_COL_NOTE: 'Poznámka',
            TXT_COL_FREE: 'Volno',
            TXT_COL_CAPACITY: 'Kapacita',
            TXT_COL_SCHEDULE: 'Rozvrh',
            TXT_COL_SUBJECT: 'Předmět',
            TXT_COL_TEACHER: 'Vyučující',
            TXT_COL_ATTENDANCE: 'Přihlášeno',
            TXT_COL_STUDENT: 'Student',
            TXT_COL_PHONE1: 'Telefon',
            TXT_COL_BIRTHDAY: 'Narozen',
            TXT_COL_ARREAR: 'Nedoplatek',
            TXT_COL_ATTENDANCE_STATUS: 'Přítomen',
            TXT_COL_ATTENDANCE_TYPE: 'Registrován',
            TXT_COL_CONFIRMED: 'Potvrzeno',
            TXT_COL_PRICE: 'Cena',
            TXT_COL_PER_LESSON: 'Za lekci',
            TXT_COL_LESSONS: 'Lekcí',
            TXT_COL_DISCOUNT: 'Sleva',
            TXT_COL_ACTION: 'Akce',
            TXT_COL_ACTIVITY: 'Třída',
            TXT_COL_CLASSROOM: 'Učebna',

            TXT_LAB_PRESENT: 'Přítomen:',
            TXT_LAB_ATTENDANCE_TYPE: 'Typ vstupu',
            TXT_LAB_NOTES: 'Poznámky',
            TXT_LAB_COMPENSATION_FOR: 'Náhrada za:',
            TXT_LBL_COURSES_AND_BOOKING: 'Nabídka kurzů a zápis',
            TXT_LBL_ACTIONS: 'Jednorázové akce',
            TXT_LBL_EXUSES_AND_COMPENSATIONS: 'Omluvy a náhrady',
            TXT_LBL_KINDERGARTEN: 'Školka',
                        
            TXT_LAB_HEALTH_DESCRIPTION: 'vztahující se k výuce (alergie, epilepsie atd.)',
            TXT_LAB_PROFICIENCY_LEVEL: 'Úroveň',
            TXT_LAB_PLACE: 'Místo',
            TXT_LAB_TYPE: 'Typ',
            TXT_LAB_NAME: 'Jméno',
            TXT_LAB_SURNAME: 'Příjmení',
            TXT_LAB_ADDRESS: 'Adresa',
            TXT_LAB_MIDDLE_NAME: 'Druhé jméno',
            TXT_LAB_PHONE2: 'Druhý telefon',
            TXT_LAB_PHONE: 'Telefon',
            TXT_LAB_EMAIL: 'E-mail',
            TXT_LAB_YOUR_EMAIL: 'Váš e-mail',
            TXT_LAB_GENDER: 'Pohlaví',
            TXT_LAB_BIRTHDAY: 'Datum narození',
            TXT_LAB_USER_NAME: 'Uživatelské jméno',
            TXT_LAB_PASSWORD: 'Heslo',
            TXT_LAB_PASSWORD_AGAIN: 'Heslo znovu',
            TXT_LAB_PASSWORD_STRENGTH: 'Síla hesla',
            TXT_LAB_I_AM_STUDENT: 'Jsem student',
            TXT_LAB_I_AM_NOT_STUDENT: 'Nejsem student',
            TXT_LAB_KEEP_ME_SIGNED: 'Zůstat přihlášený',
            TXT_LAB_EXCUSE_FROM: 'Omluvit od',
            TXT_LAB_EXCUSE_TO: 'Omluvit do',
            TXT_LAB_EXCUSE: 'Omluvit',
            TXT_LAB_BOOK: 'Přihlásit',
            TXT_LAB_AM_PERIOD: 'dopolední',
            TXT_LAB_PM_PERIOD: 'odpolední',
            TXT_LAB_AM_PM_PERIOD: 'dopolední a odpolední',
            TXT_LAB_STUDENT_WILL_BE_EXCUSED: 'Student bude omluven z',
            TXT_LAB_STUDENT_WILL_BE_EXCUSED_END: 'výuky.',
            TXT_LAB_STUDENT_WILL_BE_BOOKED: 'Student bude přihlášen na',
            TXT_LAB_STUDENT_WILL_BE_BOOKED_END: 'výuku.',
            TXT_LBL_I_AM_INTERESTED_IN_KINDERGARTEN: 'Mám zájem o školku',
            TXT_LBL_WELCOME: 'Vítejte v Informačním systému',
            TXT_LBL_ARE_YOU_INTERESTED: 'Máte zájem o naší školku?',
            TXT_LBL_ARE_YOU_INTERESTED_CLICK: 'Pokud máte zájem o naší školku klikněte na následující tlačítko. Budeme vás obratem kontaktovat.',
            TXT_LBL_LIST_OF_CLASSES: 'Níže je uveden seznam tříd, které jsme pro vás v semestru',
            TXT_LBL_OPENED: 'otevřeli',
            TXT_LBL_OPENED_CLASSES: 'Otevřené třídy',
            TXT_LBL_NEW_ACCOUNT: 'Nový účet',
            TXT_LBL_LOGIN_REQUIRED: 'Tato akce vyžaduje vaše přihlášení do systému.',
            TXT_LBL_WHO_ARE_YOU: 'Nevíme, kdo jste!',
            TXT_LBL_AVAILABLE_AMENDS: 'Náhrad',
            TXT_LBL_WAIT_QUEUE_POSITION: 'Pořadník',
            TXT_LBL_BEGINING: 'Začátek',
            TXT_LBL_YOUR_ADDRESS: 'Vaše adresa',
            TXT_LBL_ENTER_MY_ADDRESS_TO_LIMIT_SEARCH: 'Zadejte adresu kde se nacházíte pro přiblížení mapy',
            TXT_LBL_COURSE_DESCRIPTION: 'Popis kurzu',
            TXT_LBL_ACTION_DESCRIPTION: 'Popis akce',
            TXT_LBL_MORE_INFO: 'Další informace',
            TXT_LBL_LESSON_NOTE: 'Poznámka k lekci',
            TXT_LBL_FOR_EXISTING_CLIENTS: 'Pro stávající klienty',
            TXT_LBL_FOR_NEW_CLIENTS: 'Pro nové klienty',
            TXT_LBL_THANKS: 'Děkujeme',
            TXT_LBL_COURSE_REGISTRATION_WAS_SUCCESFULL: 'Vaše registrace do kurzu proběhla úspěšně!',
            TXT_LBL_REG_MAIL_WAS_SENT: 'Do vašeho e-mailu bylo zasláno potvrzení. Pokud potvrzení v e-mailu není, prohlédněte prosím složku nevyžádané pošty a hledejte e-mail z adresy noreply@{0}',
            TXT_LBL_INVOICE_WAS_SEND: 'V e-mailu s potvrzením o registraci bude příloha "{0}".',
            TXT_LBL_PLACE_WILL_BE_RESERVED: 'Po uhrazení kurzovného, vám bude místo závazně rezervováno.',
            TXT_LBL_YOUR_QUESTION: 'Text vašeho dotazu',
            TXT_LBL_INVOICE: 'Faktura',
            TXT_LBL_ONLINE_ENABLED_IN: 'Špuštění online lekce bude možné za',
            TXT_LBL_START_ONLINE_LESSON: 'Spustit online lekci',
            TXT_LBL_CONNECT_TO_ONLINE_LESSON: 'Připojit se k online lekci',
            TXT_LBL_FREE_PLACES: 'Volná místa',


            TXT_PLACEHOLDER_SELECT_STUDENT: 'Vyberte studenta ...',
            TXT_PLACEHOLDER_SELECT_COURSE: 'Vyberte kurz ...',
            TXT_PLACEHOLDER_SELECT_CLASSROOM: 'Vyberte místo ...',
    
            TXT_PLACEHOLDER_SELECT_PROFICIENCY_LEVEL: 'Vyberte úroveň ...',
            TXT_PLACEHOLDER_HEALTH_OK: 'Dobrý',
            TXT_PLACEHOLDER_REFERENCE_SOURCE: 'Jak jste se o nás dozvěděli?',
            TXT_PLACEHOLDER_SELECT_ACTIVITY_ATTENDANCE: 'Náhrada za ...',

            TXT_ERROR_NOT_LOGGED_IN: 'Nejste přihlášen. Pokud se chcete zapsat, musíte se nejdříve přihlásit do systému pod svým uživatelským jménem.',
            TXT_ERROR_NO_STUDENTS: 'Nemáte nastaveny žádné studenty, není koho přihlásit na kurz. Nastavit studenty můžete v menu "Další / Můj účet"',
            TXT_ERROR_TITLE: 'Opravte prosím následující chyby',
            TXT_ERROR_INVALID_EMAIL: 'E-mailová adresa není platná',
            TXT_ERROR_REQUIRED: 'Hodnota je povinná',
            TXT_ERROR_MAX_LENGTH: 'Byla překročena maximální délka vstupu',
            TXT_ERROR_MIN_LENGTH: 'Délka je menší něž minimální povolená',
            TXT_ERROR_PATTERN: 'Hodnota není platná',
            TXT_ERROR_UNIQUE_EMAIL: 'E-mailová adresa je již použita',
            TXT_ERROR_UNIQUE_USER_NAME: 'Uživatelské jméno je již použito',
            TXT_ERROR_PASSWORDS_MUST_MATCH: '"Heslo" a "Heslo znovu" se musí shodovat',
            TXT_ERROR_MIN: 'Zadaná hodnota je menší než minimální povolená',
            TXT_ERROR_MAX: 'Zadaná hodnota je větší než maximální povolená',
            TXT_ERROR_NO_STUDENTS_REGISTERED_ON_THIS_LESSON: 'Žádný z vašich studentů není na tuto lekci přihlášen',
            TXT_AGREE_TO_TERMS_AND_CONDITIONS: 'Nejdříve musíte odsouhlasit podmínky.',

            IMG_COURSE_FILLED: 'Areas/Client/Images/Full.cs.png',

            TXT_ALERT_TITLE_ENTITY_SAVED: 'Úspěšně uloženo',
            TXT_ALERT_TITLE_ENTITY_SAVE_ERROR: 'Chyba během ukládání',

//            TXT_ALERT_TITLE_PAYMENT_SAVED: 'Platba byla úspěšně uložena',
            TXT_TICK_STUDENT_TO_REGISTER_HELP: 'Pro přihlášení studenta zaškrtněte políčko před jeho jménem.',
            TXT_GO_TO_SCHEDULE_HELP: 'Zde se přihlašujete na celý kurz, tj. na všechny zbývající lekce. Pokud chcete přijít pouze jednou nebo chodit jen občas, přihlašte se na konkrétní lekci přes',
            TXT_ALERT_TITLE_COURSE_PREVIEW_ATTENDANCE_CHANGE_SUCCESS: 'Změna docházky byla úspěšně uložena',
            TXT_ALERT_TITLE_COURSE_PREVIEW_ATTENDANCE_CHANGE_FAILURE: 'Chyba při ukládání zmměny docházky',
            TXT_ALERT_TITLE_COURSE_REGISTRATION_SUCCESS: 'Registrace na kurz proběhla úspěšně',
            TXT_ALERT_TITLE_COURSE_REGISTRATION_FAILURE: 'Vyskytla se chyba při registrování studenta na kurz',
            TXT_ALERT_TITLE_ACTION_REGISTRATION_SUCCESS: 'Registrace na akci proběhla úspěšně',
            TXT_ALERT_TITLE_ACTION_REGISTRATION_FAILURE: 'Vyskytla se chyba při registrování studenta na akci',
            TXT_ALERT_TITLE_DATA_SAVED: 'Změny byly úspěšně uloženy',            
            TXT_ALERT_TITLE_USER_REGISTERED: 'Nový uživatel byl zaregistrován a přihlášen',
            TXT_ALERT_TITLE_PASSWORD_RESET_OK: 'Heslo bylo úspěšně změněno',
            TXT_ALERT_ATTENDANCE_CONFIRM_SUCCESS: 'Potvrzení docházky studenta {0} bylo úspěšně uloženo',
            TXT_ALERT_ATTENDANCE_CONFIRM_FAILURE: 'Vyskytla se chyba při ukládání potvrzení docházky studenta {0}',
            TXT_ALERT_ATTENDANCE_SAVE_SUCCESS: 'Docházka byla úspěšně uložena',
            TXT_ALERT_ATTENDANCE_SAVE_FAILURE: 'Vyskytla se chyba při ukládání docházky',
            TXT_ALERT_TITLE_STUDENT_ALREADY_IN_ATTENDANCE: 'Vybraný student již je v docházce',
            TXT_ALERT_SERVER_ERROR: 'Chyba při komunikaci se serverem',
            TXT_ALERT_TITLE_ACTIVITY_INTEREST_REQUESTED: 'Zájem o školku byl úspěšně zaznamenán',
            TXT_ALERT_TITLE_REGISTERING_USER_QUESTION_SUCCESS: 'Váš dotaz byl odeslán ke zpracování.',
            TXT_ALERT_TITLE_REGISTERING_USER_QUESTION_FAILURE: 'Během ukládání vašeho dotazu došlo k chybě',


            TXT_REGISTER_INTEREST_HELP: 'Pokud chcete přihlásit studenta na tento kurz, zaškrtněte políčko vedle jména studenta. Protože přiřazujeme studenty na jednotlivé kurzy ručně na základě mnoha různých faktorů, vyplňte prosím také úroveň a jakékoli poznámky, které se vztahují ke studentovým možnostem docházky.',

            TXT_STUDENT_IS_REGISTERED: 'Student je zaregistrován',
            TXT_HLP_ADD_SELF_AS_STUDENT: 'Pokud budete také navštěvovat kurzy a nebo akce, musíte být také studentem.',

            TXT_DISCLAIMER: 'Prohlašuji, že až do odvolání souhlasím se zpracováním, shromažďováním a uchováváním osobních údajů (jméno, příjmení, adresa trvalého bydliště, datum narození, telefonní číslo, e-mail) mých a mého dítěte a se zařazením těchto údajů do databáze klientů {0}, se sídlem: {1}, v souladu s příslušnými ustanovením zákona č. 101/2000 Sb., o ochraně osobních údajů a o změně některých zákonů v platném znění. Tento souhlas můžu kdykoli písemně odvolat. Poskytnutí osobních údajů je dobrovolné a souhlasím s jejich použitím. Tyto údaje {0} využívá k oznámení důležitých informací u kurzů. {0} se zavazuje, že informace o sdělených osobních údajích, neposkytne žádným způsobem třetí osobě. Dále uživatel (zákonný zástupce) i student souhlasí s fotografováním a videozáznamem, s archivací těchto fotografií i videozáznamů a s jejich použitím při prezentaci a propagaci (např. v tisku, na internetu, propagačních materiálech, atp.)',

            TXT_DAY: 'Den',
            TXT_AM: 'Dopoledne',
            TXT_PM: 'Odpoledne',            
            TXT_LUNCH: 'Oběd',
            TXT_FIRST_SNACK: '1. Svačina',
            TXT_SECOND_SNACK: '2. Svačina',
            TXT_SNACK: 'Svačina',
            TXT_DATE_PART_AM: 'Dop.',
            TXT_DATE_PART_PM: 'Odp.',

            TXT_TOOLTIP_EDIT_ATTENDANCE: 'Upravit docházku studenta',
            TXT_TOOLTIP_EXCUSE_FROM_LESSON: 'Zadání delší absence',

            TXT_MSG_LOADING: 'Nahrávám data ...',

            TXT_HLP_COMPENSATION_GROUP_HELP: 'Tento kurz patří do náhradové skupiny „{0}“. Náhrady lze uplatňovat pouze v rámci jednotlivých skupin.',
            TXT_HLP_WARNING_CANNOT_CHANGE_ATTENDANCE_DUE_TO_TIME_LIMIT: 'Docházka již nemůže být změněna, lekce buďto již probíhá, nebo je v minulosti.',
            TXT_HLP_HOW_TO_REGISTER_ONE_OFF_HELP: 'Pokud chcete přihlásit studenta na tuto hodinu zaškrtněte políčko "Přítomen".',
            TXT_HLP_HOW_TO_USE_AMEND_HELP: 'Pokud chcete přihlásit studenta na tuto hodinu a využít vaše volné náhradní hodiny, zaškrtněte políčko "Přítomen" u studenta s nenulovým počtem náhradních hodin.',
            TXT_HLP_HOW_TO_LATE_EXCUSE_ONLINE_HELP: 'Pokud chcete omluvit studenta z této hodiny, odškrtněte políčko "Přítomen". (Bez nároku na náhradu)',
            TXT_HLP_HOW_TO_EXCUSE_ONLINE_HELP: 'Pokud chcete omluvit studenta z této hodiny, odškrtněte políčko "Přítomen".',
            TXT_HLP_COMPENSATION_WAIT_QUEUE_HELP: 'Na této lekci již není volné místo. Budete však zařazeni na čekací listinu. Jakmile se místo uvolní budete automaticky přihlášeni. Pořadník ukazuje jaké bude vaše pořadí v čekací listině.',
            TXT_HLP_COMPENSATION_WAIT_QUEUE_HELP2: 'Na této lekci již není volné místo. Budete však zařazeni na čekací listinu. Jakmile se místo uvolní budete automaticky přihlášeni.',
            TXT_HLP_COMPENSATION_WAIT_QUEUE_FOR_ACTION_HELP: 'Na této akci již není volné místo. Budete však zařazeni na čekací listinu. Jakmile se místo uvolní budete automaticky přihlášeni. Pořadník ukazuje jaké bude vaše pořadí v čekací listině.',
            TXT_HLP_ONE_OFFS_ARE_DISABLED: 'Na tento kurz nelze přihlásit studenty jednorázově, protože jednorázové přihlášení není pro tento kurz povoleno.',
            TXT_HLP_HOW_TO_REGISTER_ACTION_HELP: 'Pokud chcete zaregistrovat studenta na tuto jednorázovou akci zaškrtněte políčko "Přítomen".',
            TXT_HLP_HOW_TO_UNREGISTER_ACTION_HELP: 'Pokud chcete odhlásit studenta z této akce odškrtněte políčko "Přítomen".',
            TXT_HLP_NO_STUDENTS_ATTENDANCE: 'Uživatel nemá nastaveny žádné studenty, není možné měnit docházku.',


            TXT_SELECT_ALL_LESSONS: 'Vybrat všechny lekce',
            TXT_LBL_SUMMARY_OF_CHANGES: 'Přehled změn',
            TXT_TITLE_SUMMARY_OF_ATTENDANCE_CHANGES_STUDENT: 'Přehled změn docházky studenta',
            TXT_TITLE_SUMMARY_OF_ATTENDANCE_CHANGES_STUDENT_DESC: 'Graf ukazuje kolik zbývá studentovi platných náhrad pro každý den (najeďte myší na graf pro získání konkrétní hodnoty). Tabulka pod grafem zobrazuje soupis změn v docházce.',

            TXT_AVAILABLE_AMENDS: "Náhrad",
            TXT_FREE_PLACES: "Volná místa",
            TXT_EDIT: "Upravit",
            TXT_NEW_ONE_OFF_CONFIRMATION: "Zadali jste nový jednorázový vstup. Tento typ vstupu může být zpoplatněn! Opravdu chcete takto docházku uložit?",

            TXT_DUE_PAYMENTS: 'K úhradě',
            TXT_TITLE_DUE_PAYMENTS_HELP: 'Seznam položek k úhradě - nedoplatků a přeplatků za všechny vaše studenty. Nedoplatky jsou červeně, přeplatky zeleně.',
            TXT_TITLE_DUE_PAYMENTS_HELP2: 'Seznam položek k úhradě - nezaplacené, nebo jen částečně zaplacené položky za všechny vaše studenty.',
            TXT_TITLE_CONFIRM_ONLINE_PAYMENT: 'Zaplatit online',
            TXT_CONFIRM_CONFIRM_START_ONLINE_PAYMENT: 'Pokud chcete zaplatit online svojí kartou, klikněte na tlačítko "Ano". Budete přesměrováni na platební bránu',

            TXT_FINISH: 'Konec',
            TXT_FILLED: 'Obsazeno',
            TXT_DUE_PAYMENT_DETAIL: 'K úhradě - detail',
            TXT_NEW_WAIT_QUEUE_CONFIRMATION: "Přihlašujete se na čekací listinu. Pokud se uvolní místo, budete automaticky přihlášen.",
            TXT_NEW_WAIT_QUEUE_CONFIRMATION_ONE_OFF: "Typ vstupu (náhrada / jednorázový vstup) se vyhodnotí až při uvolnění místa. Jednorázový vstup může být zpoplatněn.",
            TXT_IN_A_WAIT_QUEUE: 'Na čekací listině ({0})',

            TXT_PAYMENT_FOR_COURSE: 'Platba za kurz',
            TXT_ONLINE_PAYMENT_FAILD_HELP: 'V případě, že se online platbu nepodařilo zrealizovat, můžete tak učinit později z',
            TXT_PAYMENT_QUERYING_PROGRESS: 'Zjišťujeme stav online platby',

            TXT_PREFERRED_BOOKING: 'Přednostní zápis',
            TXT_PREFERRED_BOOKING_DESC1: 'V období',
            TXT_PREFERRED_BOOKING_DESC2: 'je umožněn zápis jen pokračujícím studentům',
            TXT_TAB_MY_CONSENTS: 'Souhlasy',

            TXT_TITLE_MY_CONSENTS: 'Souhlasy se zpracováním',
            TXT_TITLE_MY_CONSENTS_HELP: 'Níže najdete žádosti o udělení souhlasu / nesouhlasu se zpracování vašich osobních údajů. Udělený souhlas / nesouhlas můžete kdykoliv změnit.',

            TXT_REGISTRATION_NOTE: 'Poznámka k registraci',
            TXT_ATTENDANCE_NOTE: 'Poznámka k docházce',
            TXT_TITLE_RESERVATIONS: 'Rezervace',
            TXT_CANNOT_CHANGE_EVENT_ATTENDANCE_DUE_TO_DISABLED_REGISTRATION: 'Docházka již nemůže být změněna, registrace byla uzavřena. Pro omluvu nás prosím kontaktujte.',


            TXT_REGISTER_TENANT: 'Chci {0}',
            TXT_TENANT_REGISTRATION_TAB_TITLE: 'Založení vlastního systému {0}',
            TXT_TENANT_REGISTRATION_TAB_SUB_TITLE: 'Zde si můžete zdarma založit vlastní systém {0} a ihned začít vypisovat kurzy a/nebo akce. Vámi vypsané kurzy se budou nabízet nejen ve vašem systému, ale také v centrálním systému. Vaše provozovna se automaticky objeví na mapě.',
            TXT_TITLE_FORMS: 'Přihlášky',
            TXT_LBL_FORMS_RESPONSE: 'Vyplnění přihlášky',
            TXT_FILL_IN: 'Vyplnit',

            TXT_ERROR_NO_STUDENTS_2: 'Nemáte nastaveny žádné studenty. Nastavit studenty můžete v menu "Další / Můj účet"',
            TXT_LBL_FORM_RESPONSE_WAS_SUCCESFULL: 'za vyplnění přihlášky, Vaše odpovědi byly úspěšně uloženy!',
            TXT_LBL_FORM_RESPONSE_WAS_SEND: 'Do e-mailu Vám přijde potvrzení o vyplnění přihlášky. ',
            TXT_BTN_BACK_TO_FORM_LIST: 'Zpět na seznam přihlášek',

            TXT_BTN_FULL_COURSE_INTEREST: 'Zapsat jako náhradník',

            TXT_LBL_FULL_COURSE_INTEREST_REGISTRATION_WAS_SUCCESFULL: 'Vaše zapsání do kurzu jako náhradník proběhlo úspěšně!',
            TXT_LBL_FULL_COURSE_INTEREST_REGISTRATION_DESCRIPTION: 'Kurz je v současné době již zaplněn a proto Vás nemůžeme přímo zapsat! Budeme Vás však evidovat jako náhradníka, popřípadě se Vám budeme snažit zajistit alternativu.',
           
            TXT_COURSE_IS_FULL: 'Obsazeno',
            TXT_COURSE_IS_FULL_SUB_TITLE: 'Zapsat jako náhradník',
            TXT_COPIED_TO_CLIPBOARD: 'Zkopírováno do schránky',

            TXT_RENT_WITHOUT_REGISTRATION: 'Pronajmout bez registrace',

            TXT_PUBLISHED_FILES: 'Dostupné soubory',
            TXT_THIS_COURSE_IS_ONLINE: 'Tento kurz je pořádán online'
        });

        $translateProvider.preferredLanguage(preferredLanguage);
    }]);
;
'use strict';

wbApp.factory('cacheSvc', [
    function () {
        var data = {};

        return {
            contains: function (key) {
                return !!data[key];
            },
            get: function (key) {
                return data[key];
            },
            insert: function (key, value) {
                data[key] = value;
            },
            remove: function (key) {
                delete data[key];
            },
            removeAll: function () {
                data = {};
            }
        }
    }]);;
'use strict';

wbApp.factory('courseRegistrationCommonSvc', [
    '$http', '$q', 'notificationSvc', '$translate',
    'promotionSvc', 'securitySvc', 'coursePriceSvc',
    function ($http, $q, notificationSvc, $translate, promotionSvc, securitySvc, coursePriceSvc) {

        function prepareModelAsync(c, isAction) {
            var deferred = $q.defer();

            var m = { students: c.students };
            delete c.students;

            if (isAction) {
                m.action = c;
            } else {
                m.course = c;
            }

            c.courseFullName = !!c.courseAbbreviation
                ? c.courseName + '(' + c.courseAbbreviation + ')'
                : c.courseName;

            var promotionNow = c.nearestLesson === "0001-01-01T00:00:00"
                ? new Date()
                : c.nearestLesson;

            if (securitySvc.loggedInUser().isAuthenticated) {
                promotionSvc.getPromotionsByStudentsAsync(
                    securitySvc.loggedInUser().userID,
                    m.students,
                    isAction ? 'action' : 'course',
                    promotionNow,
                    false /* isAdmin */)
                .$promise.then(function (promoByStudent) {
                    for (var s = 0; s < m.students.length; s++) {
                        var student = m.students[s];
                        student.promotions = promoByStudent[student.studentID];
                    }

                    deferred.resolve(m);
                });
            } else {
                deferred.resolve(m);
            }

            m.$promise = deferred.promise;
            return m;
        }


        function setUpCoursePrices(course, students) {
            for (var s = 0; s < students.length; s++) {
                var student = students[s];

                if (student.isEditable) {
                    var priceDetails = coursePriceSvc.getPriceDetails(course, student);
                    student.priceDetails = priceDetails;
                } else {
                    student.priceDetails = {};
                }
            }
        }

        function getConfirmRegistrationDescription(students, origStudents, course, isAction) {

            var regResult = '';
            var unRegResult = '';

            var regPlular = false;
            var regStudents = '';

            var unRegPlular = false;
            var unRegStudents = '';

            for (var idx = 0; idx < students.length; idx++) {
                var student = students[idx];
                var origStudent = getOrigStudent(student.studentID, origStudents);

                if (student.attend &&
                    student.attend !== origStudent.attend) {
                    if (regStudents) {
                        regStudents = regStudents + ', ' + student.studentFullName;
                        regPlular = true;
                    } else {
                        regStudents = student.studentFullName;
                    }
                } else {
                    if (!student.attend &&
                        student.attend !== origStudent.attend) {
                        if (unRegStudents) {
                            unRegStudents = unRegStudents + ', ' + student.studentFullName;
                            unRegPlular = true;
                        } else {
                            unRegStudents = student.studentFullName;
                        }
                    }
                }
            }

            if (regStudents) {
                if (regPlular) {
                    regResult = $translate.instant('TXT_STUDENT_PLULAR') + ' ' + regStudents;
                } else {
                    regResult = $translate.instant('TXT_STUDENT_SINGULAR') + ' ' + regStudents;
                }
            }

            if (unRegStudents) {
                if (unRegPlular) {
                    unRegResult = $translate.instant('TXT_STUDENT_PLULAR') + ' ' + unRegStudents;
                } else {
                    unRegResult = $translate.instant('TXT_STUDENT_SINGULAR') + ' ' + unRegStudents;
                }
            }

            if (isAction) {
                if (regResult) {
                    regResult = $translate.instant('TXT_REGISTER_TO_ACTION_DESC').f(
                        regResult,
                        course.subjectName + ' ' + course.name);
                }
                if (unRegResult) {
                    unRegResult = $translate.instant('TXT_UNREGISTER_FROM_ACTION_DESC').f(
                        unRegResult,
                        course.subjectName + ' ' + course.name);
                }
            } else {
                if (regResult) {
                    regResult = $translate.instant('TXT_REGISTER_TO_COURSE_DESC').f(
                        regResult,
                        course.subjectName + ' ' + course.name);
                }
                if (unRegResult) {
                    unRegResult = $translate.instant('TXT_UNREGISTER_FROM_COURSE_DESC').f(
                        unRegResult,
                        course.subjectName + ' ' + course.name);
                }
            }

            return { regDescription: regResult, unRegDescription: unRegResult };
        }

        function getOrigStudent(studentID, origStudents) {

            if (!origStudents) {
                return { attend: false };
            }

            for (var idx = 0; idx < origStudents.length; idx++) {
                var os = origStudents[idx];
                if (os.studentID === studentID) {
                    return os;
                }
            }

            return { attend: false };
        }

        function getConfirmRegistrationStudents(students, origStudents, includeAll) {
            var result = [];
            for (var idx = 0; idx < students.length; idx++) {
                var student = students[idx];
                if (student.attend &&
                    student.isEditable &&
                    student.attend !== getOrigStudent(student.studentID, origStudents).attend) {
                    var newCopy = angular.copy(student);
                    newCopy.newRegistration = true;
                    result.push(newCopy);
                } else {
                    if (includeAll) {
                        var existingCopy = angular.copy(student);
                        existingCopy.newRegistration = false;
                        result.push(existingCopy);
                    }
                }
            }

            return result;
        }

        function updatePriceDetails(course, student) {
            var priceDetails = coursePriceSvc.getPriceDetails(course, student);
            student.priceDetails = priceDetails;
        }

        return {
            prepareModelAsync: prepareModelAsync,
            setUpCoursePrices: setUpCoursePrices,
            getConfirmRegistrationDescription: getConfirmRegistrationDescription,
            getConfirmRegistrationStudents: getConfirmRegistrationStudents,
            updatePriceDetails: updatePriceDetails
        }
    }]);;
wbApp.directive('wbSameValueValidator', [function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attr, ctrl) {

            attr.$observe('wbSameValueValidator', function (val) {
                ctrl.$setValidity('sameValue', ctrl.$viewValue === val);
            });

            scope.$watch(attr.ngModel, function (model) {
                var otherVal = attr.wbSameValueValidator;
                ctrl.$setValidity('sameValue', model === otherVal);
            });
        }
    };
}]);;
wbApp.directive('wbUniqueEmailValidator', ['$http', function ($http) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attr, ctrl) {

            scope.$watch(attr.ngModel, function (model) {
                if (model) {
                    $http({
                        method: 'POST',
                        url: '/Api/Validation/UniqueEmail',
                        data: { email: model, userID: attr.wbUniqueEmailValidator }
                    }).success(function (data, status, headers, cfg) {
                        ctrl.$setValidity('uniqueEmail', data.isValid);
                    }).error(function (data, status, headers, cfg) {
                        ctrl.$setValidity('uniqueEmail', false);
                    });
                } else {
                    ctrl.$setValidity('uniqueEmail', true);
                }
            });
        }
    };
}]);;
wbApp.directive('wbUniqueTenantValidator', ['$http', function ($http) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attr, ctrl) {

            scope.$watch(attr.ngModel, function (model) {
                if (model) {
                    $http({
                        method: 'POST',
                        url: '/Api/TenantRegistration/UniqueTenant',
                        data: { alias: model }
                    }).success(function (data, status, headers, cfg) {
                        ctrl.$setValidity('uniqueTenant', data.isValid);
                    }).error(function (data, status, headers, cfg) {
                        ctrl.$setValidity('uniqueTenant', false);
                    });
                } else {
                    ctrl.$setValidity('uniqueTenant', true);
                }
            });
        }
    };
}]);;
wbApp.directive('wbUniqueUserNameValidator', ['$http', function ($http) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attr, ctrl) {

            scope.$watch(attr.ngModel, function (model) {
                if (model) {
                    $http({
                        method: 'POST',
                        url: '/Api/Validation/UniqueUserName',
                        data: { userName: model, userID: attr.wbUniqueUserNameValidator }
                    }).success(function (data, status, headers, cfg) {
                        ctrl.$setValidity('uniqueUserName', data.isValid);
                    }).error(function (data, status, headers, cfg) {
                        ctrl.$setValidity('uniqueUserName', false);
                    });
                } else {
                    ctrl.$setValidity('uniqueUserName', true);
                }
            });
        }
    };
}]);;
'use strict';

wbApp.controller('ContentCtrl', ['$scope', '$timeout', 'urlUtils', 'tenantSettingSvc',
function ($scope, $timeout, urlUtils, tenantSettingSvc) {

    $scope.contentType = Number(urlUtils.getQueryParams()['contentType']) || 0;

    $scope.tabs = [
    {
        title: 'TXT_LBL_TERMS_AND_CONDITIONS',
        template: 'content/content-tab.html'
    }];

    switch ($scope.contentType) 
    {
        case 0: // TermsAndConditions
            $scope.tabs[0].title = 'TXT_LBL_TERMS_AND_CONDITIONS';
            break;
        case 1: // Instructions
            $scope.tabs[0].title = 'TXT_LBL_INSTRUCTIONS';
            break;
        case 2: // TradeTerms
            $scope.tabs[0].title = 'TXT_LBL_TRADE_TERMS';
            break;
        case 3: // ProtectionOfPersonalData
            $scope.tabs[0].title = 'TXT_LBL_PROTECTION_OF_PERSONAL_DATA';
            break;
        case 4: // Custome
            $scope.tabs[0].title = tenantSettingSvc.settings.customContentTypeText;
            break;
    }


    $scope.tabs.activeTab = 0;
}]);;
wbApp.controller('AmortizationScheduleCtrl', ['$scope', 'coursePriceSvc', 'invoiceSvc',
    function ($scope, coursePriceSvc, invoiceSvc) {

        if (!!$scope.invoiceID) {
            $scope.model.invoice = invoiceSvc.getByID($scope.invoiceID);
            $scope.model.invoice.$promise.then(function (data) {
                $scope.amortizationSchedules = data.amortizationSchedules;
            });
        }
        else {
            $scope.amortizationSchedules = coursePriceSvc.calculateAmortizationSchedules(
                $scope.model.invoice.total,
                moment().toDate(),
                $scope.amortizationScheduleTemplates);
        }
}]);;
'use strict';

wbApp.controller('CourseRegistrationCtrl', ['$scope', '$q', '$translate', '$modal', '$timeout', '$window', '$filter', 'notificationSvc', 
    'securitySvc', 'tenantSettingSvc', 'messageBoxSvc', 'classroomSvc', 'userSvc', 'urlUtils',
    'courseRegistrationSvc', 'studentSvc', 'courseSvc', 'employeeSvc', 'courseDetailSvc', 'courseScheduleSvc', 'onlinePaymentsSvc', '$analytics', 'tenantInfo',
function ($scope, $q, $translate, $modal, $timeout, $window, $filter, notificationSvc, securitySvc,
    tenantSettingSvc, messageBoxSvc, classroomSvc, userSvc, urlUtils,
    courseRegistrationSvc, studentSvc, courseSvc, employeeSvc, courseDetailSvc, courseScheduleSvc, onlinePaymentsSvc, $analytics, tenantInfo) {

    $scope.tenantSettings = tenantSettingSvc.settings;
    $scope.courseIsLoading = true;
    $scope.employeeIsLoading = true;
    $scope.studentsAreLoading = true;
    $scope.isSaving = false;
    $scope.students = null;
    $scope.userStudents = null;
    $scope.userSchedules = null;
    $scope.courseInterestsSupport = tenantSettingSvc.settings.courseInterestsSupport;
    $scope.showAskQuestionInCourseRegistration = tenantSettingSvc.settings.showAskQuestionInCourseRegistration;

    var quickRegistrationMode = tenantSettingSvc.settings.quickUserRegistrationMode;
    var previewMode = false;

    $scope.emailWasSentMessage = $translate.instant('TXT_LBL_REG_MAIL_WAS_SENT').f(tenantInfo.domain.substring(1, tenantInfo.domain.length));
    
    function validateConditionForBooking(noOfStudents) {

        if (!$scope.registrationAllowed) {
            return;
        }

        if (!securitySvc.isAuthenticated()) {
            if (!quickRegistrationMode) {
                $scope.serverError = { errors: [{ message: $translate.instant('TXT_ERROR_NOT_LOGGED_IN') }] };
            }
        } else {
            if (!noOfStudents) {
                $scope.serverError = { errors: [{ message: $translate.instant('TXT_ERROR_NO_STUDENTS') }] };
            }
        }
    }

    function prepareQuickRegistrationReturnUrls(preview) {
        var origUrlParams = 'returnUrl=' + encodeURIComponent(location.pathname + '?tabName=' + (preview ? 'book-preview' : 'book-course'));
        var origRegisterUrlParams = 'returnUrl=' + encodeURIComponent($window.location.origin + '/Login?quickUserRegistration=true&idmRefreshCache=true&returnUrl=' + location.pathname + '?tabName=' + (preview ? 'book-preview' : 'book-course'));
        $scope.urlLoginParams = origUrlParams;
        $scope.urlRegisterParams = origRegisterUrlParams;
    }


    var courseID = urlUtils.getLastUrlPart();
    $scope.employee = {};

    function loadStudentRegs(refresh, registrationsLoadedCallback) {
        if ($scope.userStudents.length && (!$scope.students || refresh)) {
            $scope.students = courseRegistrationSvc.getAllForCourseAndUser(
                securitySvc.loggedInUser().userID,
                $scope.course,
                $scope.userStudents,
                false,
                tenantSettingSvc.settings.courseInterestsSupport,
                $scope.showLessonSelection);

            $scope.students.$promise.then(function () {
                $scope.studentsAreLoading = false;
                setUpScope($scope.students);
                if (!!registrationsLoadedCallback) {
                    registrationsLoadedCallback($scope.students);
                }
            });
        }
    }

    function loadPreviewData(refresh) {
        if (!$scope.userSchedules || refresh) {
            $scope.userSchedules = courseScheduleSvc.getAllForCurrentUserAndCourse($scope.course.courseID);
        }
    }

    $scope.supportsOnlinePayment = false;

    function loadData(registrationsLoadedCallback) {

        $scope.userSchedules = null;
        $scope.course = courseSvc.getByCourseID(courseID);
        $scope.course.$promise.then(function (course) {

            $scope.supportsOnlinePayment = course.supportsOnlinePayment && !$scope.courseInterestsSupport;

            $scope.showLessonSelection = !!course.allowClientLessonSelection && 
                !tenantSettingSvc.settings.courseInterestsSupport;

            var courseFreeCapacity = $scope.showLessonSelection
                ? course.maxFreePlacesForLessonSelection
                : Math.max(0, course.capacity - course.filled);

            $scope.employee = employeeSvc.getBriefByEmployeeID(course.employeeID);
            $scope.employee.$promise.then(function () {
                $scope.employeeIsLoading = false;
            });

            $scope.courseScheduleDesc = $translate.instant('TXT_COURSE_SCHEDULE_EXT').f(
                course.noOfLessons,
                !!course.firstLesson ? $filter('date')(course.firstLesson, 'short') : '',
                !!course.lastLesson ? $filter('date')(course.lastLesson, 'short') : '',
                course.lessonLengthInMinutes);

            $scope.courseScheduleWarningDesc = $translate.instant('TXT_COURSE_SCHEDULE_EXT_WARN').f(
                !!course.nearestLesson ? $filter('date')(course.nearestLesson, 'short') : '-',
                course.noOfRemainingLessons);

            $scope.showGoToScheduleHelp = !tenantSettingSvc.settings.disableClientCalendar && !!course.causalPrice;

            $scope.isCourseFull = courseFreeCapacity === 0 && !tenantSettingSvc.settings.courseInterestsSupport; // &&
                //!tenantSettingSvc.settings.coursePreviewOnlyRegistration;

            $scope.registrationAllowed = (courseFreeCapacity !== 0 ||
                (tenantSettingSvc.settings.courseInterestsSupport || tenantSettingSvc.settings.coursePreviewOnlyRegistration)) &&
                !tenantSettingSvc.settings.readOnlyClientCourseRegistration;

            $scope.images = _.map(course.pictures, function (p) {
                return {
                    thumb: p.imageUrl,
                    img: p.imageUrl
                };
            });

            if ($scope.course.amortizationScheduleMode == 2 &&
                !!$scope.course.amortizationSchedules &&
                !!$scope.course.amortizationSchedules.length) {
                var factor = ($scope.course.amortizationScheduleSurchargePct / 100) + 1;
                $scope.course.remainingPriceWithSurcharges = $scope.course.remainingPrice * factor;
            } else {
                $scope.course.remainingPriceWithSurcharges = $scope.course.remainingPrice;
            }

            if (securitySvc.isAuthenticated()) {
                studentSvc.getCurrentAsync().$promise.then(function (students) {

                    $scope.userStudents = students;

                    validateConditionForBooking(students.length);

                    if (!students.length) {
                        $scope.students = [];
                        $scope.studentsAreLoading = false;
                    } else {
                        prepareTabs();
                        if (!!$scope.students) {
                            loadStudentRegs(true, registrationsLoadedCallback);
                        }
                    }
                });
            } else{ 
                $scope.students = [];
                $scope.studentsAreLoading = false;

                validateConditionForBooking(0);
                //prepareTabs();
            }

            if ($scope.course.classroomID) {
                classroomSvc.getAsync($scope.course.classroomID).then(function (data) {
                    angular.extend($scope.classroom, data);
                });
            }

            $scope.courseIsLoading = false;
        });
    }

    loadData();
    
    $scope.classroom = { address: { location: {} } };
    $scope.loginDetails = {};
    $scope.user = {};
    $scope.loadingData = true && (!quickRegistrationMode || securitySvc.isAuthenticated());
    $scope.bookCourseTabContent = 'courses/book-course-tab-default-content.html';
    //  $scope.bookCourseTabContent = 'courses/book-course-tab-confirmation-content.html';
    $scope.allowTeacherEmailInClientSection = tenantSettingSvc.settings.allowTeacherEmailInClientSection;
    $scope.courseRegistrationEmailEnabled = tenantSettingSvc.isCourseRegistrationNotificationEnabled();
    $scope.fullCourseInterestEmailEnabled = tenantSettingSvc.isFullCourseInterestNotificationEnabled();

    $scope.invoiceSupportEnabled = tenantSettingSvc.isCourseRegistrationNotificationEnabled() && tenantSettingSvc.settings.sendInvoicesToClients;
    $scope.enableUserRegistration = tenantSettingSvc.settings.enableUserRegistration;
    $scope.shouldHidePrice = !tenantSettingSvc.settings.showPriceInCourseRegistration;
    $scope.invoiceWasSendMsg = $translate.instant('TXT_LBL_INVOICE_WAS_SEND').f(
        !tenantSettingSvc.settings.printedInvoiceName 
        ? $translate.instant('TXT_LBL_INVOICE')
        : tenantSettingSvc.settings.printedInvoiceName);

    $scope.onQuickPrevBtnClick = function () {
        $scope.tabs.activeTab -= 1;
    }


    function getReturnUrlParams() {
        var param;
        if (previewMode) {
            param = 'tabName=book-preview';
        } else {
            param = 'tabName=book-course';
        }
        return param;
    }

    function guessGender(surname) {
        if (endsWith(surname, 'ová') ||
            endsWith(surname, 'ova')) {
            return 'F';
        } else {
            return 'M';
        }

        function endsWith(str, suffix) {
            return str.indexOf(suffix, str.length - suffix.length) !== -1;
        }
    }

    $scope.showMore = false;
    $scope.noteDescriptionInCourseRegistration = tenantSettingSvc.settings.noteDescriptionInCourseRegistration;
    $scope.showHealthInCourseRegistration = tenantSettingSvc.settings.showHealthInCourseRegistration;
    $scope.showNoteInCourseRegistration = tenantSettingSvc.settings.showNoteInCourseRegistration;
    $scope.showLessonSelection = false;
    $scope.showNearestLessonInCourses = tenantSettingSvc.settings.showNearestLessonInCourses;
    $scope.allowShareOnFBForCourses = tenantSettingSvc.settings.allowShareOnFBForCourses;
    $scope.courseRegistrationAgreement = tenantSettingSvc.settings.courseRegistrationAgreement;

    $scope.onPrevBtnClick = function (returnUrl) {
        if ($scope.tabs.activeTab === 0) {
            window.location = returnUrl;
        } else {
            $scope.tabs.activeTab = 0;
        }
    }

    $scope.onBookPreviewBtnClick = function () {
        previewMode = true;

        if (!securitySvc.isAuthenticated()) {
            if (quickRegistrationMode) {
                courseDetailSvc.addQuickUserRegistrationTabIfNeeded($scope.tabs);
                courseDetailSvc.switchToQuickUserRegistrationTab($scope.tabs);
                prepareQuickRegistrationReturnUrls(true);
            } else {
                notificationSvc.advertiseLogin(getReturnUrlParams());
            }
            return;
        }

        courseDetailSvc.switchToBookPreviewTab($scope.tabs);
    }

    $scope.onBtnNextClick = function () {
        $scope.tabs.activeTab += 1;
    }

    $scope.setSelectedSchedule = function (selectedSchedule) {
        $scope.selectedSchedule = selectedSchedule;
    }

    $scope.confirmPreview = { title: "" };

    var confirmPreviewDlg = $modal({
        templateUrl: '/partials/confirm-preview.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    $scope.onPreviewButtonClick = function (schedule, attendance, courseID) {
        $scope.confirmPreview.title = getAttendanceOperationTitle(attendance);
        $scope.confirmPreview.description = getAttendanceOperationDescription(attendance, schedule);
        $scope.confirmPreview.attendance = attendance;
        $scope.confirmPreview.schedule = schedule;
        $scope.confirmPreview.courseID = courseID;

        confirmPreviewDlg.$promise.then(function () {
            confirmPreviewDlg.show();
        });
    }

    var confirmRegistrationDlg = $modal({
        templateUrl: '/partials/confirm-registration.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    $scope.confirmRegistration = {
        students: []
    };

    // TODO: courseDetailSvc
    $scope.onBookCourseBtnClick = function () {
        $scope.course.$promise.then(function (course) {
            if ($scope.students && $scope.students.$promise) {
                $scope.students.$promise.then(function () {
                    $scope.confirmRegistration.courseRegistrationAgreementAccepted = !$scope.courseRegistrationAgreement;
                    $scope.confirmRegistration.students = _.filter($scope.students, { isNew: true, attend: true });
                    $scope.confirmRegistration.courseID = $scope.course.courseID;
                    $scope.confirmRegistration.description = courseDetailSvc.getConfirmRegistrationDescription(
                        $scope.students,
                        $scope.origStudents,
                        $scope.course);

                    confirmRegistrationDlg.$promise.then(function () {
                        confirmRegistrationDlg.show();

                        $analytics.eventTrack('CourseRegistrationConfirm');
                    });
                });
            }
        });
    }

    $scope.onRegisterClick = function (returnUrl) {
        previewMode = false;

        if (!securitySvc.isAuthenticated()) {
            if (quickRegistrationMode) {
                courseDetailSvc.addQuickUserRegistrationTabIfNeeded($scope.tabs);
                courseDetailSvc.switchToQuickUserRegistrationTab($scope.tabs);
                prepareQuickRegistrationReturnUrls(false);
            } else {
                notificationSvc.advertiseLogin(getReturnUrlParams());
            }
            return;
        }

        if (!$scope.tabs.activeTab) {
            if (tenantSettingSvc.settings.courseInterestsSupport) {
                $scope.tabs.activeTab += 1;
            } else {
                courseDetailSvc.switchToCourseRegistrationTab($scope.tabs);
            }
        }
    }

    $scope.onAttendanceChangeClick = function (attendance, schedule, courseID) {
        function success(schedules, selected) {
            $scope.userSchedules = schedules;

            $scope.setSelectedSchedule(selected);
        }

        courseDetailSvc.savePreviewAttendanceChange(
            attendance.studentID,
            schedule.courseScheduleID,
            courseID,
            success);
    }

    $scope.onBookFullCourseInterestClick = function () {
        var students = _.filter($scope.students, { isNew: true, attend: true });
        var course = $scope.course;
        var classroom = $scope.classroom;

        courseRegistrationSvc.createFullCourseInterest(students, course, classroom).then(function () {
            $scope.bookCourseTabContent = 'courses/book-full-course-interest-tab-confirmation-content.html';
        }, function (error) {
        });
    }
    
    $scope.onRegistrationConfirmClick = function (courseID, students, hideFn) {

        if (!$scope.confirmRegistration.courseRegistrationAgreementAccepted) {

            var m = {
                title: 'TXT_TITLE_INFORMATION',
                message: 'TXT_AGREE_TO_TERMS_AND_CONDITIONS',
                buttons: [{
                    text: 'TXT_BTN_OK'
                }]
            };

            messageBoxSvc.showMessageDlg(m);

        } else {
            $scope.isSaving = true;

            var notificationConfig = {
                sendEmailNotification: true,
                sendSmsNotification: false 
            };

            // Clear all errors
            _.forEach(students, function (student) {
                student.markErrorAttendance.call(student, []);
            });

            courseRegistrationSvc.insertAll(students, courseID, notificationConfig, 1, function () {
                $scope.bookCourseTabContent = 'courses/book-course-tab-confirmation-content.html';
                hideFn();
                $analytics.eventTrack('CourseRegistrationAccepted');
                loadData(function (registrations) {

                    if ($scope.supportsOnlinePayment) {

                        var newRegistrations = _.intersectionBy(registrations, students, 'studentID');
                        var invoiceIDs = _.map(newRegistrations, 'invoiceID');
                        var price = _.sumBy(newRegistrations, 'arrearByAmortizationSchedule');

                        messageBoxSvc.showMessageDlg({
                            title: 'TXT_TITLE_CONFIRM_ONLINE_PAYMENT',
                            message: '<i class="fa fa-3x fa-credit-card text-success pull-right" aria-hidden="true"></i>' +
                                $translate.instant('TXT_CONFIRM_CONFIRM_START_ONLINE_PAYMENT'),
                            buttons: [{
                                text: 'TXT_BTN_NO'
                            }, {
                                text: 'TXT_BTN_YES',
                                callback: function () { return onlinePaymentsSvc.startOnlinePayment(invoiceIDs, price).$promise; }
                            }]
                        });
                    }
                });

                $scope.isSaving = false;
            }, function (errorResult) {               
                $scope.isSaving = false;

                // If error is CourseFullException 
                if ($scope.showLessonSelection) {

                    if (errorResult && errorResult.errors && errorResult.errors.length === 1 &&
                        errorResult.errors[0].code === 5) {

                        var scheduleIDs = _.transform(errorResult.errors[0].data.courseScheduleIDs.split(","),
                            function (result, n) {
                                result.push(parseInt(n));
                            }, []);

                        _.forEach(students, function (student) {
                            student.markErrorAttendance.call(student, scheduleIDs);
                        });

                        courseRegistrationSvc.refreshSchedules(students, courseID).then(function () {
                            hideFn();
                        });
                    }
                }
            });
        }
    }

    $scope.onConfirmRegistrationPrevBtnClick = function () {
        $scope.bookCourseTabContent = 'courses/book-course-tab-default-content.html';
    }

    $scope.onConfirmFullCourseInterestPrevBtnClick = function () {
        $scope.bookCourseTabContent = 'courses/book-course-tab-default-content.html';
        $scope.tabs.activeTab = 0;
        urlUtils.setUrlParam("tabName", $scope.tabs[$scope.tabs.activeTab].name);
    }

    $scope.onConfirmRegistrationBackToCourseListBtnClick = function () {
        $window.location.href = $window.location.origin + '/Courses'
    }

    function getAttendanceOperationTitle(attendance) {
        if (attendance.canRegisterForPreview) {
            return $translate.instant("TXT_REGISTER_FOR_PREVIEW_ACTION");
        } else {
            return $translate.instant("TXT_EXCUSE_ACTION");
        }
    }

    function getAttendanceOperationDescription(attendance, schedule) {
        if (attendance.canRegisterForPreview) {
            return $translate.instant("TXT_REGISTER_FOR_PREVIEW_ACTION_DESC")
                .f(attendance.fullName, schedule.scheduleDate + " " + schedule.scheduleTime);
        } else {
            return $translate.instant("TXT_EXCUSE_ACTION_DESC_BRIEF")
                .f(attendance.fullName, schedule.scheduleDate + " " + schedule.scheduleTime);
        }
    }

    $scope.tabs = [
        {
            title: 'TXT_TAB_COURSE_DETAIL',
            template: 'courses/course-detail-tab.html',
            name: 'detail',
            disable: false
        }];

    $scope.showOnlinePaymentResult = false;
    $scope.onlinePaymentResultMessage = null;
    $scope.onlinePaymentStatusColor = 'inherit';
    $scope.showRetryOnlinePayment = false;

    function showOnlinePaymentResultsIfNeeded() {
        var onlinePaymentIDStr = urlUtils.getQueryParams()['onlinePaymentID'];
        if (!!onlinePaymentIDStr) {
            var onlinePaymentID = Number(onlinePaymentIDStr);

            $scope.showOnlinePaymentResult = $scope.supportsOnlinePayment;
            $scope.bookCourseTabContent = 'courses/book-course-tab-confirmation-content.html';

            onlinePaymentsSvc.getTransactionState(onlinePaymentID).$promise.then(
                function (data) {
                    $scope.onlinePaymentResultMessage = onlinePaymentsSvc.getOnlinePaymentResultMessage(data);
                    switch (data.state) {
                        case 2: // Pending
                            $scope.onlinePaymentStatusColor = 'orange';
                            break;
                        case 3: // Paid
                            $scope.onlinePaymentStatusColor = 'green';
                            break;
                        default:
                            $scope.onlinePaymentStatusColor = 'red';
                            $scope.showRetryOnlinePayment = true;
                            break;
                    }
                    $scope.onlinePaymentStatus = data.state;
                    urlUtils.removeUrlParam('onlinePaymentID');
                }
            );
        } else {
            $scope.showOnlinePaymentResult = false;
        }
    }

    function switchToCorrectTab() {
        var tabName = urlUtils.getQueryParams()['tabName'];
        if (!!tabName) {
            // find correct tab
            var tabIndexToActivate = _.findIndex($scope.tabs, { name: tabName });
            if (tabIndexToActivate !== -1) {
                if ($scope.tabs.activeTab !== tabIndexToActivate) {
                    $scope.tabs.activeTab = tabIndexToActivate;
                }
                showOnlinePaymentResultsIfNeeded();
                return;
            }

        }

        $scope.tabs.activeTab = 0;
        urlUtils.setUrlParam("tabName", $scope.tabs[$scope.tabs.activeTab].name);
        showOnlinePaymentResultsIfNeeded();
    }

    var preparedTabsCalled = false;

    function prepareTabs() {
        if (!quickRegistrationMode || securitySvc.isAuthenticated()) {
            if (!$scope.serverError && ($scope.registrationAllowed || ($scope.isCourseFull && tenantSettingSvc.settings.enableFullCourseInterest))) {

                if (($scope.isCourseFull && tenantSettingSvc.settings.enableFullCourseInterest) || !$scope.isCourseFull) {
                    courseDetailSvc.addBookCourseTabIfNeeded($scope.tabs);
                }
                courseDetailSvc.addBookInterestTabIfNeeded($scope.tabs);
                courseDetailSvc.addBookPreviewTabIfNeeded($scope.tabs);

                switchToCorrectTab();
            }
        }

        preparedTabsCalled = true;
    }

    $scope.tabs.activeTab = 0;

    $scope.$watch('tabs.activeTab', function (newValue, oldValue) {

        if (preparedTabsCalled || !urlUtils.getQueryParams()['tabName']) {
            var tabName = $scope.tabs[newValue].name;
            urlUtils.setUrlParam("tabName", tabName);
        }

        if (courseDetailSvc.isOnBookCourseTab($scope.tabs, newValue) ||
            courseDetailSvc.isOnBookInterestTab($scope.tabs, newValue)) {
            loadStudentRegs(false);
        } else if (courseDetailSvc.isOnBookPreviewTab($scope.tabs, newValue))
        {
            loadPreviewData(false);
        }
    });

    $scope.shouldShowPreviewButton = function () {
        if (!tenantSettingSvc.settings.coursePreviewOnlyRegistration) {
            return false;
        }

        if (!!$scope.serverError) {
            if (securitySvc.isAuthenticated()) {
                return false;
            }
        }

        if ($scope.tabs.length > 2) {
            return $scope.tabs.activeTab != 2;
        }

        return ($scope.tabs.activeTab == 0) && $scope.registrationAllowed;
    }

    $scope.shouldShowRegisterButton = function () {
        if (!tenantSettingSvc.settings.allowClientCourseRegistration && 
            !tenantSettingSvc.settings.courseInterestsSupport) {
            return false;
        }

        if (!!$scope.serverError) {
            if (securitySvc.isAuthenticated()) {
                return false;
            }
        }

        if ($scope.isCourseFull) {
            return false;
        }

        if ($scope.tabs.length > 2) {
            return $scope.tabs.activeTab != 2;
        }

        return $scope.registrationAllowed;
    }

    $scope.shouldShowFullCourseInterestButton = function () {
        if (!tenantSettingSvc.settings.allowClientCourseRegistration &&
            !tenantSettingSvc.settings.courseInterestsSupport) {
            return false;
        }

        if (tenantSettingSvc.settings.readOnlyClientCourseRegistration || 
            !tenantSettingSvc.settings.enableFullCourseInterest) {
            return false;
        }

        if (!$scope.isCourseFull) {
            return false;
        }

        if (!!$scope.serverError) {
            if (securitySvc.isAuthenticated()) {
                return false;
            }
        }

        if ($scope.tabs.length > 2) {
            return $scope.tabs.activeTab != 2;
        }



        return true;
    }


    $scope.shouldEnableRegisterButton = function() {
        if (!$scope.tabs.activeTab)
            return true;

        if (courseDetailSvc.isOnBookCourseTab($scope.tabs, $scope.tabs.activeTab) || 
            courseDetailSvc.isOnBookInterestTab($scope.tabs, $scope.tabs.activeTab)) {
            if ($scope.students && !$scope.studentsAreLoading) {
                return !angular.equals($scope.origStudents, $scope.students) &&
                    !!_.find($scope.students, { attend: true, isNew: true });
            }
        }

        return false;
    }

    $scope.onAttendClick = function (student) {
        if (tenantSettingSvc.settings.courseInterestsSupport &&
            !student.attend && student.isEditable) {
            student.selfAssessedProficiencyLevelID = null;
            student.notes = null;
            student.health = null;
        }
    }

    function setUpScope(students) {
       
        $scope.origStudents = angular.copy(students);

        // Preselect student if only one is defined
        if (!!students && students.length == 1) {
            var student = students[0];
            if (student.isNew) {
                student.attend = true;
            }
        }
    }

    var userQuestionDlg = $modal({
        templateUrl: '/partials/user-question.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    var amortizationScheduleDlg = $modal({
        templateUrl: '/partials/book-course-amortization-schedule.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    $scope.showAmortizationSchedule = function(studentRegistration) {
        amortizationScheduleDlg.$promise.then(function () {
            amortizationScheduleDlg.$scope.model = studentRegistration;
            amortizationScheduleDlg.$scope.amortizationScheduleTemplates = $scope.course.amortizationSchedules;
            amortizationScheduleDlg.show();
        });
    }

    $scope.onUserQuestionAsk = function () {
        $scope.course.$promise.then(function (course) {
            userQuestionDlg.$promise.then(function () {
                userQuestionDlg.$scope.isAuthenticated = securitySvc.isAuthenticated();
                userQuestionDlg.$scope.userQuestion = { courseID: $scope.course.courseID, emailAddress: null, question: null };
                userQuestionDlg.show();
            });
        });
    }


    // TODO: courseDetailSvc
    $scope.onUserQuestionSend = function (userQuestion) {

        courseDetailSvc.askQuestionAboutCourse(
            userQuestion.courseID,
            userQuestion.emailAddress,
            userQuestion.question);
    }

}]);;
'use strict';

wbApp.controller('CoursesCtrl', ['$scope', '$window', 'tenantSettingSvc', 'urlUtils',
function ($scope, $window, tenantSettingSvc, urlUtils) {
    var data = semestersWithCourses;

    $scope.tenantSettings = tenantSettingSvc.settings;

    $scope.semesters = data;
    $scope.availableAgeRanges = [];
    $scope.availableCourseTypes = [];

    $scope.courseTypeID = urlUtils.getQueryParams()['courseTypeID'];

    $scope.setSelectedCourse = function (course) {
        //if (course.freeCapacity !== 0 ||
           // $scope.tenantSettings.courseInterestsSupport ||
           // $scope.tenantSettings.coursePreviewOnlyRegistration) {
            $scope.selectedCourse = course;
            $window.location.assign("/Courses/Register/" + course.id + "?returnUrl=Courses");
       // }
    }

    $scope.tabs = [];

    function PrepareTabs() {
        for (var i = 0; i < $scope.semesters.length; i++) {
            var semester = $scope.semesters[i];
            $scope.tabs.push({ 
                title: semester.name,
                semesterID: semester.semesterID,
                template: "courses/semester-detail-tab.html",
            });
            $scope.availableAgeRanges.push(_.keyBy(_.uniq(_.map(semester.courses, 'courseAgeRangeID'))));
            $scope.availableCourseTypes.push(_.keyBy(_.uniq(_.map(semester.courses, 'courseTypeID'))));
        }
    }

    PrepareTabs();

    switchToCorrectTab();


    function switchToCorrectTab() {
        var semesterIDStr = urlUtils.getQueryParams()['semesterID'];
        if (!!semesterIDStr) {

            var semesterID = Number(semesterIDStr);
            // find correct tab
            var tabIndexToActivate = _.findIndex($scope.tabs, { semesterID: semesterID });
            if (tabIndexToActivate !== -1 && $scope.tabs.activeTab !== tabIndexToActivate) {
                $scope.tabs.activeTab = tabIndexToActivate;
                return;
            }

        } 

        urlUtils.setUrlParam("semesterID", null);
        $scope.tabs.activeTab = 0;        
    }

    $scope.$watch('tabs.activeTab', function (newValue, oldValue) {
        var semesterID = $scope.tabs[newValue].semesterID;

        urlUtils.setUrlParam("semesterID", semesterID);       
    });
    
}]);;
wbApp.directive('wbFullCourseStamp', ['$timeout', '$translate',
    function ($timeout, $translate) {

        return {
            restrict: 'A',            
            priority: 1,
            scope: {
                stampSize: '@',
                allowBooking: '='
            },
            template: "<div class='rubber_stamp' ng-class='{\"rubber_stamp_medium\": stampSize==\"medium\", \"rubber_stamp_small\": stampSize==\"small\"}'>" +
                      "  <div class='rubber_stamp_title'>{{'TXT_COURSE_IS_FULL' | translate}}</div>" +
                      "  <div ng-if='allowBooking' class='rubber_stamp_sub_title'>{{'TXT_COURSE_IS_FULL_SUB_TITLE' | translate}}</div>" +
                      "</div>",
            link: function (scope, elm, attrs, ctrl) {
            }
        }
    }]);
;
'use strict';

wbApp.factory('courseDetailSvc', [
    '$http', 'notificationSvc', '$translate', '$timeout', 'tenantSettingSvc', 'courseRegistrationCommonSvc',
    function ($http, notificationSvc, $translate, $timeout, tenantSettingSvc, courseRegistrationCommonSvc) {

        function askQuestionAboutCourse(courseID, emailAddress, question, onSuccess, onError) {
            $http({
                method: 'POST',
                url: '/Courses/AskQuestionAboutCourse',
                data: {
                    courseID: courseID,
                    emailAddress: emailAddress,
                    question: question
                }
            })
            .success(function (actionDetail, status, headers, config) {
                if (onSuccess) {
                    onSuccess();
                }

                notificationSvc.notifyInfo(
                    $translate.instant('TXT_ALERT_TITLE_REGISTERING_USER_QUESTION_SUCCESS'));
            })
            .error(function (errorResult, status, headers, config) {
                if (onError) {
                    onError(errorResult);
                }

                notificationSvc.notifyError(
                    $translate.instant('TXT_ALERT_TITLE_REGISTERING_USER_QUESTION_FAILURE'),
                    notificationSvc.translateError(errorResult));
            });
        }

        function savePreviewAttendanceChange(studentID, courseScheduleID, courseID, onSuccess) {
            $http({
                method: 'POST',
                url: '/Api/UserSchedule/ChangePreviewAttendance',
                params: { StudentID: studentID, CourseScheduleID: courseScheduleID, CourseID: courseID }
            })
            .success(function (schedules, status, headers, config) {
                
                var selected;
                angular.forEach(schedules, function (value, key) {
                    if (value.courseScheduleID === courseScheduleID) {
                        selected = value;
                    }
                });

                if (onSuccess) {
                    onSuccess(schedules, selected);
                }

                notificationSvc.notifyInfo(
                    $translate.instant('TXT_ALERT_TITLE_COURSE_PREVIEW_ATTENDANCE_CHANGE_SUCCESS'));

            })
            .error(function (errorResult, status, headers, config) {
                notificationSvc.notifyError(
                    $translate.instant('TXT_ALERT_TITLE_COURSE_PREVIEW_ATTENDANCE_CHANGE_FAILURE'),
                    notificationSvc.translateError(errorResult));
            });
        }

        function getConfirmRegistrationDescription(students, origStudents, course) {
            return courseRegistrationCommonSvc.getConfirmRegistrationDescription(students, origStudents, course, false);
        }

        function switchToTab(tabs, tabName) {
            var tabIndexToActivate = _.findIndex(tabs, { name: tabName });
            if (tabIndexToActivate !== -1 && tabs.activeTab !== tabIndexToActivate) {
                tabs.activeTab = tabIndexToActivate;
                $timeout(function () {
                    tabs.activeTab = tabIndexToActivate;
                });
                return;
            }
        }

        function addTabIfNotExist(tabs, template, name, title) {
            var idx = _.findIndex(tabs, { template: template });
            if (idx === -1) {
                tabs.push(
                    {
                        title: title,
                        name: name,
                        template: template,
                        disabled: false
                    });
                idx = tabs.length - 1;
            }
        }

        var bookPreviewTabTemplate = 'courses/book-preview-tab.html';
        var bookCourseTabTemplate = 'courses/book-course-tab.html';
        var bookInterestTabTemplate = 'courses/book-interest-tab.html';
        var quickUserRegistrationTabTemplate = 'courses/quick-user-registration-tab.html';

        function isOnSpecificTabByTemplate(tabs, template, newIndex) {
            return _.findIndex(tabs, { template: template }) == newIndex;
        }

        function isOnBookCourseTab(tabs, newIndex) {
            return isOnSpecificTabByTemplate(tabs, bookCourseTabTemplate, newIndex);
        }

        function isOnBookInterestTab(tabs, newIndex) {
            return isOnSpecificTabByTemplate(tabs, bookInterestTabTemplate, newIndex);
        }

        function isOnBookPreviewTab(tabs, newIndex) {
            return isOnSpecificTabByTemplate(tabs, bookPreviewTabTemplate, newIndex);
        }

        function addBookPreviewTabIfNeeded(tabs) {
            if (tenantSettingSvc.settings.coursePreviewOnlyRegistration) {
                addTabIfNotExist(
                    tabs,
                    bookPreviewTabTemplate,
                    'book-preview',
                    'TXT_TAB_BOOK_PREVIEW');
            }
        }

        function addBookCourseTabIfNeeded(tabs) {
            if (tenantSettingSvc.settings.allowClientCourseRegistration &&
                !tenantSettingSvc.settings.courseInterestsSupport) {

                addTabIfNotExist(
                    tabs,
                    bookCourseTabTemplate,
                    'book-course',
                    'TXT_TAB_BOOKING');
            }
        }

        function addBookInterestTabIfNeeded(tabs) {
            if (tenantSettingSvc.settings.courseInterestsSupport) {

                addTabIfNotExist(
                    tabs,
                    bookInterestTabTemplate,
                    'book-interest',
                    'TXT_TAB_BOOKING');
            }
        }

        function addQuickUserRegistrationTabIfNeeded(tabs) {
            addTabIfNotExist(
                tabs,
                quickUserRegistrationTabTemplate,
                'user-quick-registration',
                'TXT_TITLE_LOGIN');
        }

        function switchToBookPreviewTab(tabs) {
            switchToTab(tabs, 'book-preview');
        }

        function switchToCourseRegistrationTab(tabs) {
            switchToTab(tabs, 'book-course');
        }

        function switchToQuickUserRegistrationTab(tabs) {
            switchToTab(tabs, 'user-quick-registration');
        }

        return {
            savePreviewAttendanceChange: savePreviewAttendanceChange,
            getConfirmRegistrationDescription: getConfirmRegistrationDescription,           
            askQuestionAboutCourse: askQuestionAboutCourse,

            addBookPreviewTabIfNeeded: addBookPreviewTabIfNeeded,
            addBookCourseTabIfNeeded: addBookCourseTabIfNeeded,
            addBookInterestTabIfNeeded: addBookInterestTabIfNeeded,
            addQuickUserRegistrationTabIfNeeded: addQuickUserRegistrationTabIfNeeded,
            switchToBookPreviewTab: switchToBookPreviewTab,
            switchToCourseRegistrationTab: switchToCourseRegistrationTab,
            switchToQuickUserRegistrationTab: switchToQuickUserRegistrationTab,

            isOnBookCourseTab: isOnBookCourseTab,
            isOnBookInterestTab: isOnBookInterestTab,
            isOnBookPreviewTab: isOnBookPreviewTab
        }
    }]);
;
wbApp.controller('FormsCtrl', ['$scope', '$modal', '$window', 'formSvc', 'securitySvc', 'notificationSvc',
function ($scope, $modal, $window, formSvc, securitySvc, notificationSvc) {

    $scope.formsAreLoading = true;
    $scope.forms = [];

    formSvc.getAllActive().then(function (forms) {
        $scope.forms = _.orderBy(forms, ['name'], ['asc'])
        $scope.formsAreLoading = false;
    }, function (error) {
        $scope.formsAreLoading = false;
    });

    $scope.onFormClick = function (form) {
        // href="/Forms/FormsResponse?formId={{form.id}}"

        if (form.accessPermissions == 0) {
            if (!securitySvc.isAuthenticated()) {
                notificationSvc.advertiseLogin();
                return;
            }
        }

        $window.location.href = $window.location.origin + '/Forms/FormsResponse?formId=' + form.id;
    }

    $scope.tabs = [
    {
        title: 'TXT_TITLE_FORMS',
        template: 'forms/forms-tab.html'
    }];

    $scope.tabs.activeTab = 0;

}]);;
wbApp.controller('FormsResponseCtrl', ['$scope', '$modal', '$window', 'urlUtils', 'formSvc', 'formResponseSvc',
function ($scope, $modal, $window, urlUtils, formSvc, formResponseSvc) {

    $scope.formId = urlUtils.getQueryParams().formId;
    $scope.formResponse = {};
    $scope.isSaving = false;
    $scope.respondedSuccesfully = false;

    $scope.shouldEnableSaveButton = function () {
        return !!$scope.formResponse.isValid && !$scope.isSaving;
    }

    $scope.onSaveClick = function () {
        if ($scope.isSaving) {
            return;
        }

        $scope.isSaving = true;

        formResponseSvc.insert($scope.formResponse).$promise.then(function (success) {
            $scope.isSaving = false;
            $scope.respondedSuccesfully = true;
        },
        function (error) {
            $scope.isSaving = false;
            $scope.respondedSuccesfully = false;
            $scope.errorDetail = error;
        })
    }
    
    $scope.onBackToFormListBtnClick = function () {
        $window.location.href = $window.location.origin + '/Forms'
    }

    $scope.onPrevBtnClick = function () {
        $window.location.href = $window.location.origin;
    }

    $scope.tabs = [
    {
        title: 'TXT_LBL_FORMS_RESPONSE',
        template: 'forms/forms-response-tab.html'
    }];

    $scope.tabs.activeTab = 0;

}]);;
wbApp.controller('HeaderNavigationCtrl', ['$scope', 'activeFeaturesSvc',
function ($scope, activeFeaturesSvc) {

    if (!!window.MainMenu) {
        var formMenuItem = window.MainMenu.GetItemByName('MenuItemForms');
        if (!!formMenuItem) {
            formMenuItem.SetVisible(!!activeFeaturesSvc.isClientFormSupportEnabled());
        }
        var formMenuItem2 = window.MainMenu.GetItemByName('MenuItemForms2');
        if (!!formMenuItem2) {
            formMenuItem2.SetVisible(!!activeFeaturesSvc.isClientFormSupportEnabled());
        }
    }
}]);;
'use strict';

wbApp.controller('FCHomeCtrl', ['$scope', '$window', '$q', '$popover', '$timeout', '$filter', 'subjectsSvc', 'courseSvc', 'tenantInfo', 'urlUtils',
function ($scope, $window, $q, $popover, $timeout, $filter, subjectsSvc, courseSvc, tenantInfo, urlUtils) {

    $scope.tenantInfo = tenantInfo;
    $scope.levelZeroTitle = tenantInfo.franchiseLevels.length > 0
        ? tenantInfo.franchiseLevels[0].name
        : tenantInfo.friendlyName;

    $scope.supportSubjectLicenses = tenantInfo.isFranchiseCentral && tenantInfo.franchiseCentralSettings.supportSubjectLicenses;

    $scope.filteredCourses = [];
    $scope.groupsByAddress = [];
    $scope.markerControl = {};

    function onBoundsChanged() {
        if (dataReady) {
            bindModel($scope.subjects, $scope.courses);
        }
    }

    function setDefaultLocation() {
        $scope.$apply(function () {
            $scope.userAddress.location.latitude = 50.0755381;
            $scope.userAddress.location.longitude = 14.43780049999998;
        });
    }

    var dataReady = false;

    $scope.userAddress = {
        location: {},
        formattedAddress: ''
    };

    $scope.$watch('userAddress.location', function () {
        if (dataReady && $scope.userAddress.location.latitude && $scope.userAddress.location.longitude) {
            $scope.map.center.latitude = $scope.userAddress.location.latitude;
            $scope.map.center.longitude = $scope.userAddress.location.longitude;
            $scope.map.zoom = 10;
        }
    });

    $scope.map = {
        control: {},
        center: {
            latitude: 49.804333,
            longitude: 15.580293
        },
        zoom: 7,
        markerOptions: {
            labelContent: "",
            labelAnchor: "0 0",
            labelClass: "marker-labels"
        },
        events: { 'bounds_changed': onBoundsChanged }
    }

    $scope.subjects = $scope.supportSubjectLicenses
        ? subjectsSvc.getAllAsync()
        : subjectsSvc.getAllActiveFranchiseSubjects();

    $scope.courses = $scope.supportSubjectLicenses
        ? courseSvc.getFranchiseCourses()
        : { $promise: $q(function(resolve, reject) { resolve([]); } ) };

    $q.all([$scope.subjects.$promise, $scope.courses.$promise]).then(function () {
        dataReady = true;

        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (position) {
                $scope.$apply(function () {
                    $scope.userAddress.location.latitude = position.coords.latitude;
                    $scope.userAddress.location.longitude = position.coords.longitude;
                })
            }, function (error) {
                setDefaultLocation();
            });
        } else {
            setDefaultLocation();
        }
    });

    $scope.windowOptions = {
        show: false,
        position: {
            lat: 51.5286416,
            lng: -0.1015987
        }
    };

    $scope.windowParams = {
    }

    $scope.closeWindow = function () {
        $scope.windowOptions.show = false;
    }

    $scope.onClick = function (marker, eventName, model) {

        var filteredModel = _.find($scope.groupsByAddress, { id: model.id });

        $scope.windowOptions.pixelOffset = new google.maps.Size(0, -30);
        $scope.windowOptions.position.lat = filteredModel.location.latitude;
        $scope.windowOptions.position.lng = filteredModel.location.longitude;

        $scope.windowParams.model = filteredModel;

        $scope.windowOptions.show = true;//!$scope.windowOptions.show;
    };

    $scope.filterOptions = {
        filterText: ""
    };

    function bindModel(subjects, courses) {
        if ($scope.supportSubjectLicenses)
        {
            return bindModelCourses(subjects, courses);
        }
        else
        {
            return bindModelSubjects(subjects);
        }
    }

    function bindModelSubjects(subjects) {
        var bounds = null;
        if ($scope.map.control.getGMap) {
            bounds = $scope.map.control.getGMap().getBounds();
        }

        var filteredSubjects = !!bounds
            ? _.filter(subjects, function (subject) {
                return bounds.contains(new google.maps.LatLng(subject.latitude, subject.longitude));
            })
            : subjects;        

        filteredSubjects = _.sortBy(
            $filter('filter')(filteredSubjects, $scope.filterOptions.filterText),
            ['tenantFriendlyName', 'formatedAddress', 'subjectName']);

        $scope.filteredCourses.length = 0;
        $scope.filteredCourses.push.apply($scope.filteredCourses, filteredSubjects);

        var addressGroups = _.groupBy(filteredSubjects, function (subject) {
            return '_' + subject.longitude + '_' + subject.latitude;
        });

        var grouping = [];
        for (var property in addressGroups) {
            var locations = addressGroups[property];
            var first = _.head(locations);
            grouping.push({
                id: property,
                location: {
                    latitude: first.latitude,
                    longitude: first.longitude
                },
                courses: locations
            });
        }

        $scope.groupsByAddress.length = 0;
        $scope.groupsByAddress.push.apply($scope.groupsByAddress, grouping);
    }


    function bindModelCourses(subjects, courses) {
        var subjectDict = _.keyBy(subjects, 'id');

        var bounds = null;
        if ($scope.map.control.getGMap) {
            bounds = $scope.map.control.getGMap().getBounds();
        }

        var filteredCourses = _.filter(courses, function (course) {
            var include = subjectDict[course.franchiseSubjectID].include;

            if (bounds && include) {
                var point = new google.maps.LatLng(course.classroomLocation.latitude, course.classroomLocation.longitude);
                include = include && bounds.contains(point);
            }

            return include;
        });

        filteredCourses = $filter('filter')(filteredCourses, $scope.filterOptions.filterText);

        var model = courseSvc.enhanceFranchiseCoursesAndsort(filteredCourses, tenantInfo);

        var newGroupsByAddress = courseSvc.breakFranchiseCoursesByAddress(filteredCourses);

        $scope.groupsByAddress.length = 0;
        $scope.groupsByAddress.push.apply($scope.groupsByAddress, newGroupsByAddress);
        
        $scope.filteredCourses.length = 0;
        $scope.filteredCourses.push.apply($scope.filteredCourses, model);
    }

    $scope.$watch('filterOptions.filterText', function () {
        bindModel($scope.subjects, $scope.courses);
    });

    function setSubjectIDsUrl() {
        if (!$scope.supportSubjectLicenses) {
            return;
        }

        var urlParam = '';

        angular.forEach($scope.subjects, function (s) {
            if (s.include) {
                if (!urlParam) {
                    urlParam = '' + s.id;
                } else {
                    urlParam = urlParam + '-' + s.id;
                }
            }
        });

        if (!!$window.history.pushState) {
            if (!urlParam) {
                $window.history.pushState("Filter ", "Filter", "/");
            } else {
                $window.history.pushState("Filter ", "Filter", "/?subjectIDs=" + urlParam);
            }
        }
    }

    $scope.onSubjectIncludeChange = function () {
        
        setSubjectIDsUrl();

        bindModel($scope.subjects, $scope.courses);
    }

    $q.all([$scope.subjects.$promise, $scope.courses.$promise]).then(function (data) {
        var subjects = data[0];
        var courses = data[1];

        var urlParam = urlUtils.getQueryParams()['subjectIDs'];
        var subjectIDs = [];
        if (!!urlParam) {
            subjectIDs = urlParam.split('-');
        }

        _.forEach(subjects, function (subject) {
            if (subjectIDs.length > 0) {
                if (!!_.find(subjectIDs, function(s) { return s == subject.id; } ))  {
                    subject.include = true;
                } else {
                    subject.include = false;
                }
            } else {
                subject.include = true;
            }
        });

        if (subjectIDs.length === 0) {
            setSubjectIDsUrl();
        }

        bindModel(subjects, courses);
    });

    $scope.showTeacherDetail = function (course, $event) {
        var myPopover = $popover(angular.element(document.querySelector('#popover' + course.courseID)), {
            title: course.teacherFullName,
            content: '<img class="teacher-photo-max" src="' + course.teacherPhotoUrl + '">',
            trigger: 'manual',
            autoClose: true,
            html: true
        });
        myPopover.$promise.then(function () {
           
            myPopover.toggle();
            $timeout(function () {
                myPopover.$applyPlacement();
            }, 10);
        });
    }

    $scope.rowSelected = function (row) {
        var markers = $scope.markerControl.getGMarkers();
        if (markers && markers.length) {
            var id = '_' + row.longitude + '_' + row.latitude;
            var marker = _.find(markers, { 'key': id });
            if (marker) {
                if (marker.getAnimation() != google.maps.Animation.BOUNCE) {
                    marker.setAnimation(google.maps.Animation.BOUNCE);
                    $timeout(function () {
                        marker.setAnimation(null);
                    }, 5000);
                }
            }
        }
    }

    if ($scope.supportSubjectLicenses) {
        $scope.gridOptions = {
            columnDefs: [
                         { field: 'placeName', displayName: "TXT_LAB_PLACE", sort: 'locale', width: '140px' },
                         { field: 'subjectName', displayName: "TXT_COL_SUBJECT", sort: 'locale', width: '140px' },
                         { field: 'courseName', displayName: "TXT_LAB_COURSE", sort: 'locale' },
                         { field: 'teacherSurname', displayName: "TXT_COL_TEACHER", sort: 'locale', width: '140px' },
                         { field: 'firstLessonStartDate', displayName: "TXT_LBL_BEGINING", cellFilter: 'date:dd.MM.yy', width: '75px' },
                         { field: 'firstLessonStartDate', displayName: "TXT_TITLE_SCHEDULE", cellFilter: 'date:EEE HH:mm', width: '75px', align: 'right' },
                         { field: 'courseUrl', displayName: "", width: '75px', cellFilter: 'urlButton', align: 'right', html: true },
            ],
            noCommandColumn: true,
            pageSize: 20,
            disableRowSelection: true,
            grouping: {
                enabled: true,
                isGroupRowPropertyName: 'isGroupRow',
                subItemsPropertyName: 'courses'
            }
        };
    } else {
        $scope.gridOptions = {
            columnDefs: [
                         { field: 'tenantFriendlyName', displayName: "TXT_NAME", sort: 'locale', width: '240px' },
                         { field: 'formatedAddress', displayName: "TXT_LAB_PLACE", sort: 'locale', width: '240px' },
                         { field: 'subjectName', displayName: "TXT_COL_SUBJECT", sort: 'locale' },
                         { field: 'tenantHost', displayName: "", width: '75px', cellFilter: 'urlButton', align: 'right', html: true },
            ],
            noCommandColumn: true,
            pageSize: 20,
            disableRowSelection: false,
        };

    }

}]);;
'use strict';

wbApp.controller('HomeCtrl', ['$scope', '$timeout', 'tenantSettingSvc', 'securitySvc', 'activeFeaturesSvc',
function ($scope, $timeout, tenantSettingSvc, securitySvc, activeFeaturesSvc) {

    $scope.tenantSetting = tenantSettingSvc.settings;
    $scope.tenantInfo = tenantInfo; // External dependency
    $scope.pages = _.take(actions, 25); // External dependency
    $scope.selectedPage = $scope.pages[0];
    for (var i = 0; i < $scope.pages.length; i++) {
        if (i === 0 && $scope.tenantSetting.showQuickNavOnHomePage) {
            $scope.pages[i].url = 'home/pages/home-page.html';
        } else {
            $scope.pages[i].url = 'home/pages/action-page.html';
        }
    }

    $scope.templateUrl = $scope.selectedPage.url;

    $scope.activitiesHref = hasStudentOnAction ? 'MyActivities' : 'Activities';
    $scope.shouldShowActivitiesBtn = $scope.tenantSetting.enableKindergartenSupport;
    $scope.shouldShowExcusesAndCompBtn = 
        !$scope.tenantSetting.disableClientCalendar &&
        ($scope.tenantSetting.allowClientCourseRegistration || securitySvc.isAuthenticated());
    $scope.shouldShowCoursesBtn =
        $scope.tenantSetting.allowClientCourseRegistration ||
        $scope.tenantSetting.coursePreviewOnlyRegistration ||
        $scope.tenantSetting.courseInterestsSupport;
    $scope.shouldShowActionsBtn =
        ($scope.tenantSetting.allowClientActionRegistration) && $scope.pages.length > 1;
    $scope.shouldShowReservationBtn = $scope.tenantSetting.enableReservationSupport;
    $scope.shouldShowFormsBtn = activeFeaturesSvc.isClientFormSupportEnabled(function (enabled) {
        $scope.shouldShowFormsBtn = enabled;
    });


    $scope.employeesSrc = employees; // External dependency
    $scope.employees = [];
    $scope.lastEmplIdx = 0;

    $scope.removeEmployees = function () {
        $scope.employees.length = 0;
    }

    $scope.selectEmployees = function () {
        if ($scope.employeesSrc.length > 0) {
            var idx1 = ($scope.lastEmplIdx + 1) % $scope.employeesSrc.length;
            var idx2 = ($scope.lastEmplIdx + 2) % $scope.employeesSrc.length;

            $scope.lastEmplIdx = idx2;

            $scope.employees.push($scope.employeesSrc[idx1]);

            if (idx1 !== idx2) {
                $scope.employees.push($scope.employeesSrc[idx2]);
            }
        }
    }

    $scope.selectEmployees();
    $scope.backwards = false;

    $scope.selectPage = function (page) {
        if ($scope.selectedPage === page) {
            return;
        }

        $scope.backwards = $scope.selectedPage.index > page.index;
        $scope.selectedPage = page;
        if (page.index !== 0 && $scope.templateUrl === 'home/pages/action-page.html') {
            $scope.templateUrl = 'home/pages/action-page-alt.html';
        } else {
            $scope.templateUrl = $scope.selectedPage.url;
        }
    }

    $scope.nextPage = function () {
        if ($scope.pages.length > ($scope.selectedPage.index + 1)) {
            $scope.selectPage($scope.pages[$scope.selectedPage.index + 1]);
        }
    }

    $scope.prevPage = function () {
        if ($scope.selectedPage.index > 0) {
            $scope.selectPage($scope.pages[$scope.selectedPage.index - 1]);
        }
    }

    $scope.cyclePage = function () {
        if ($scope.pages.length > ($scope.selectedPage.index + 1)) {
            $scope.selectPage($scope.pages[$scope.selectedPage.index + 1]);
        } else {
            $scope.selectPage($scope.pages[0]);
        }
    }

    $scope.isJPEG = function (url) {
        var lowerUrl = url.toLowerCase();
        return lowerUrl.endsWith('.jpg') || lowerUrl.endsWith('.jpeg');
    }

    $scope.onRegisterClick = function(page) {
        if (page.index === 0) {
            window.location = "/Courses";
        } else {
            window.location = "/Actions/Register/" + page.actionID + "?returnUrl=Actions";
        }
    }

    setInterval(function () {
        $scope.$apply(function () {
            $scope.cyclePage();
        })
    }, 15000);

    setInterval(function () {
        $scope.$apply(function () {
            $scope.removeEmployees();

            $timeout(function () {
                $scope.selectEmployees();
            },1000);
        })
    }, 5000);
}]);;
'use strict';

wbApp.controller('InstructionsCtrl', ['$scope', '$timeout',
function ($scope, $timeout) {

    $scope.tabs = [
    {
        title: 'TXT_TAB_INSTRUCTIONS',
        template: 'instructions/instructions-tab.html'
    }];

    $scope.tabs.activeTab = 0;

    $timeout(function () {
        $('iframe.auto-height').iframeAutoHeight({ minHeight: 400, heightOffset: 40 });
    });
}]);;
'use strict';

wbApp.controller('MyAccountCtrl', ['$scope', '$q', '$window', '$modal', 'tenantSettingSvc', 'userSvc', 'studentSvc',
    'referenceSourceSvc', 'duePaymentsSvc', 'paymentsSvc', '$timeout', 'messageBoxSvc', 'onlinePaymentsSvc', 'urlUtils', '$translate', '$http',
    'consentSvc', 'securitySvc',
function ($scope, $q, $window, $modal, tenantSettingSvc, userSvc, studentSvc,
    referenceSourceSvc, duePaymentsSvc, paymentsSvc, $timeout, messageBoxSvc, onlinePaymentsSvc, urlUtils, $translate, $http,
    consentSvc, securitySvc) {

    $scope.isInRegistrationMode = urlUtils.getQueryParams()['registration'] === "true";
    $scope.isDataLoaded = false;
    $scope.isBusy = true;    

    $scope.tabs = [
        {
            title: 'TXT_TAB_USER_ACCOUNT',
            template: 'my-account/user-account-tab.html',
            name: 'user-account'
        },
        {
            title: 'TXT_TAB_STUDENTS',
            template: 'my-account/students-tab.html',
            name: 'students'
        },
        {
            title: 'TXT_TAB_CONTACT_DETAILS',
            template: 'my-account/contact-details-tab.html',
            name: 'contact-details'
        }];

    if (tenantSettingSvc.settings.enableDuePaymentsInClient && !$scope.isInRegistrationMode) {
        $scope.tabs.push({
            title: 'TXT_DUE_PAYMENTS',
            template: 'my-account/due-payments-tab.html',
            name: 'due-payments'
        });
    }

    if (!$scope.isInRegistrationMode) {
        $scope.tabs.push({
            title: 'TXT_TAB_MY_CONSENTS',
            template: 'my-account/my-consents.html',
            name: 'my-consents'
        });
    } else {
        loadMyConsents(function (consentInfo) {
            if (!!consentInfo && !!consentInfo.consents && consentInfo.consents.length > 0) {
                $scope.tabs.push({
                    title: 'TXT_TAB_MY_CONSENTS',
                    template: 'my-account/my-consents.html',
                    name: 'my-consents'
                });
            }
        });
    }

    function switchToCorrectTab() {
        var tabName = urlUtils.getQueryParams()['tabName'];
        if (!tabName) {
            tabName = $scope.isInRegistrationMode
                ? 'students'
                : 'user-account';
        }
        
        // find correct tab
        var tabIndexToActivate = _.findIndex($scope.tabs, { name: tabName });
        if (tabIndexToActivate !== -1 && $scope.tabs.activeTab !== tabIndexToActivate) {
            $scope.tabs.activeTab = tabIndexToActivate;
            return;
        }

        $scope.tabs.activeTab = 0;
        urlUtils.setUrlParam("tabName", $scope.tabs[$scope.tabs.activeTab].name);
    }

    switchToCorrectTab();

    $scope.isSaveBusy = false;    

    $scope.$watch('tabs.activeTab', function (newValue) {
        var tabName = $scope.tabs[newValue].name;
        urlUtils.setUrlParam("tabName", tabName);

        if (tabName === 'due-payments') {
            loadDuePayments();
        }

        if (tabName === 'my-consents') {
            loadMyConsents();
        }
    });

    $scope.tenantSetting = tenantSettingSvc.settings;

    $scope.hasReferrenceSource = false;

    referenceSourceSvc.getAllAsync().$promise
        .then(function (data) {
            $scope.hasReferrenceSource = data.length;
            loadData();
        });

    var paneCtrls = [];
    $scope.$on('$includeContentLoaded', function (event) {
        paneCtrls.push(event.targetScope.$$childTail);
        event.stopPropagation();
    });

    $scope.serverErrors = null;
    $scope.formErrors = {};

    $scope.areAllFormsValid = function () {
        return _.reduce(paneCtrls, function(sum, item) { 
            return !!item.form ? sum && item.form.$valid : sum;
        }, true);
    }

    $scope.isCurrentFormValid = function () {
        if ($scope.tabs.activeTab < paneCtrls.length) {
            var form = paneCtrls[$scope.tabs.activeTab].form;
            var isFormValid = !form || form.$valid;
            if (isFormValid) {
                $scope.formErrors = {};
                return true;
            } else {
                $scope.formErrors = form.$error;
            }

        }
        return false;
    }

    function setAllFormsPristine() {
        _.forEach(paneCtrls, function (item) {
            if (!!item.form) {
                item.form.$setPristine();
            }
        });
    }

    function swithToFirstInvalidForm() {
        var idx = _.findIndex(paneCtrls, function (item) { return !item.form.$valid; });
        if (idx !== -1) {
            $scope.tabs.activeTab = idx;
        }
    }

    //#region: User



    function isContactDetailsUnchanged(data) {
        return angular.equals(data, $scope.userOrig);
    }

    function isStudentsUnchanged(data) {
        return angular.equals(data, $scope.studentsOrig);
    }


    $scope.onSaveBtnClick = function (formCtrl, data) {

        if ($scope.isSaveBusy) {
            return;
        }

        if (!$scope.isCurrentFormValid()) {
            return;
        }

        if (!$scope.areAllFormsValid()) {
            swithToFirstInvalidForm();
            return;
        }

        $scope.isSaveBusy = true;
        $scope.isBusy = true;
        $scope.serverErrors = null;
        var errorTabIndex = 0;

        var promises = [];

        function userSaveSuccess(data) {
            $scope.user = data;
            $scope.userOrig = angular.copy(data);
        }

        function userSaveError(errorResult) {
            $scope.serverErrors = errorResult;
            errorTabIndex = _.findIndex($scope.tabs, { name: 'contact-details' });
        }

        if (!isContactDetailsUnchanged($scope.user) || $scope.isInRegistrationMode) {
            // Save user
            promises.push(userSvc.update($scope.user, userSaveSuccess, userSaveError).$promise);
        }

        function studentsSaveSuccess(data) {
            $scope.students = data;
            $scope.studentsOrig = angular.copy(data);
        }

        function studentsSaveError(errorResult) {
            $scope.serverErrors = errorResult;
            errorTabIndex = _.findIndex($scope.tabs, { name: 'students' });
        }

        if (!isStudentsUnchanged($scope.students)) {
            promises.push(studentSvc.saveAll($scope.students, studentsSaveSuccess, studentsSaveError).$promise);
        }

        if (promises.length) {
            $q.all(promises).then(function (data) {

                $scope.isSaveBusy = false;
                $scope.isBusy = false;

                if ($scope.isInRegistrationMode) {
                    var queryParams = urlUtils.getQueryParams();
                    var returnUrl = urlUtils.getReturnUrl(queryParams);
                    if (returnUrl) {
                        //var params = urlUtils.getParamsStringWithoutReturnUrl(queryParams);
                        //if (!!params) {
                        //    $window.location.replace(returnUrl + '?' + params);
                        //} else {
                            $window.location.replace(returnUrl);
                       // }
                    } else {
                        $window.location.replace("/");
                    }
                } else {
                    setAllFormsPristine();

                    var queryParams = urlUtils.getQueryParams();
                    if (queryParams['returnOnSave'] == 'true') {
                        var returnUrl = urlUtils.getReturnUrl(queryParams);
                        $window.location.replace(returnUrl);
                    }
                }
            }, function (errorResult) {
                $scope.isSaveBusy = false;
                $scope.isBusy = false;
                $scope.tabs.activeTab = errorTabIndex;
            });
        } else {
            $scope.isSaveBusy = false;
            $scope.isBusy = false;
        }
    }


    $scope.onPrevBtnClick = function() {
        if ($scope.isPrevButtonVisible()) {
            $scope.tabs.activeTab = $scope.tabs.activeTab - 1;
        }
    }

    $scope.onNextBtnClick = function () {
        if ($scope.isCurrentFormValid()) {
            if ($scope.isNextButtonVisible()) {
                $scope.tabs.activeTab = $scope.tabs.activeTab + 1;
            }
        }
    }

    $scope.isIDMButtonVisible = function () {
        return $scope.tabs.activeTab === _.findIndex($scope.tabs, { name: 'user-account' }) && !$scope.isInRegistrationMode;
    }

    $scope.onIDMBtnClick = function () {

        var returnUrl = $window.location.href;
        if (returnUrl.indexOf('?') !== -1) {
            returnUrl = $window.encodeURIComponent(returnUrl + '&idmRefreshCache=true');
        } else {
            returnUrl = $window.encodeURIComponent(returnUrl + '?idmRefreshCache=true');
        }

        $window.location.assign("https://idm.webooker.eu/Manage/Index?idmRefreshCache=true&returnUrl=" + returnUrl);
    }


    $scope.isNextButtonVisible = function () {
        return ($scope.tabs.activeTab < ($scope.tabs.length - 1));
    }

    $scope.isPrevButtonVisible = function () {
        return $scope.tabs.activeTab > 0;
    }    

    $scope.isSaveButtonVisible = function () {
        return ($scope.tabs.activeTab === ($scope.tabs.length - 1) && $scope.isInRegistrationMode) ||
            (!$scope.isInRegistrationMode &&
                $scope.tabs.activeTab !== _.findIndex($scope.tabs, { name: 'due-payments' }) &&
                $scope.tabs.activeTab !== _.findIndex($scope.tabs, { name: 'user-account' }) &&
                $scope.tabs.activeTab !== _.findIndex($scope.tabs, { name: 'my-consents' })
            );
    }

    $scope.isSaveButtonDisabled = function () {
        return $scope.isSaveBusy || (isContactDetailsUnchanged($scope.user) && isStudentsUnchanged($scope.students) && !$scope.isInRegistrationMode);
    }

    function loadData() {
        
        $scope.isBusy = true;

        $q.all([
            userSvc.getCurrentAsync().$promise,
            studentSvc.getCurrentAsync().$promise
        ]).then(function (data) {
            $scope.user = data[0];
            $scope.userOrig = angular.copy($scope.user);

            $scope.students = data[1];
            $scope.studentsOrig = angular.copy($scope.students);

            $scope.isBusy = false;
            $scope.isDataLoaded = true;

            //var goeResult = $scope.getAddress($scope.user.address);
            //if (goeResult) {
            //    goeResult.then(function (a) {
            //        if (a && a.length > 1) {
            //            $scope.user.address = a[0].formatted_address;
            //        }
            //        $scope.isBusy = false;
            //        $scope.isDataLoaded = true;
            //    });
            //} else {
            //    $scope.isBusy = false;
            //    $scope.isDataLoaded = true;
            //}            
        }, function (errorResult) {
            $scope.isBusy = false;
        });
    }

   
    //#endregion

    //#region Students


    $scope.onAddStudent = function () {
        if ($scope.isDataLoaded) {
            $scope.students.push(studentSvc.createNew($scope.user));
        }
    }

    $scope.onDeleteStudent = function (student) {
        if ($scope.isDataLoaded) {
            var index = $scope.students.indexOf(student);
            $scope.students.splice(index, 1);
        }
    }

    //#endregion

    function loadMyConsents(success) {
        $timeout(function () {
            $scope.isBusy = true;
        }, 1);

        var currentUserID = securitySvc.loggedInUser().userID;

        var consents = consentSvc.getConsentsInfoForUser(currentUserID);
        consents.$promise.then(function (data) {
            $timeout(function () {
               
                var now = moment();
                var validConsents = [];
                var invalidConsesnts = [];
                _.forEach(data.consents, function (c) {
                    if (moment(c.validFrom).isSameOrBefore(now) &&
                        moment(c.validTo).isSameOrAfter(now)) {
                        validConsents.push(c);
                    } else {
                        invalidConsesnts.push(c);
                    }
                });

                data.consents = _.orderBy(validConsents, ['validFrom'], ['desc']);
                data.invalidConsents = invalidConsesnts;

                $scope.consentInfo = data;
                $scope.isBusy = false;

                if (success) {
                    success($scope.consentInfo);
                }
            }, 100);
        }, function () {
            $timeout(function () {
                $scope.isBusy = false;
            }, 100);
        });
    }

    $scope.approveConsent = function (consent) {

        if ($scope.isSaveBusy) {
            return;
        }

        $scope.isSaveBusy = true;

        consentSvc.approveConsent(
            consent,
            function () {
                // Success
                $scope.isSaveBusy = false;

                loadMyConsents();
            }, function () {
                $scope.isSaveBusy = false;
            });
    }

    $scope.rejectConsent = function (consent) {

        if ($scope.isSaveBusy) {
            return;
        }

        $scope.isSaveBusy = true;

        consentSvc.rejectConsent(
            consent,
            function () {
                // Success
                $scope.isSaveBusy = false;

                loadMyConsents();
            }, function () {
                $scope.isSaveBusy = false;
            });
    }


    $scope.duePayments = [];

    function loadDuePayments() {
        $timeout(function () {
            $scope.isBusy = true;
        }, 1);
        
        $scope.duePayments = duePaymentsSvc.getAllForCurrentUser(!$scope.tenantSetting.showOverpaymentsInClientDuePayments);
        $scope.duePayments.$promise.then(function (data) {
            $timeout(function () {
                $scope.isBusy = false;
            }, 100);
        }, function () {
            $timeout(function () {
                $scope.isBusy = false;
            }, 100);
        });
    }

    function startOnlinePayment(invoiceID, price) 
    {
        return onlinePaymentsSvc.startOnlinePayment([invoiceID], price);
    }

    $scope.onPrintInvoice = function(invoiceID) {
        $window.open('/Admin/Report/Invoice?ReportID=' + invoiceID + '&ReportIDType=1',
            '_blank', 'width=1000,height=500,toolbar=no,resizable=yes,location=no,directories=no,status=no,menubar=no,copyhistory=no');
    }

    $scope.onlinePayment = function (invoiceID, price) {
        messageBoxSvc.showMessageDlg({
            title: 'TXT_TITLE_CONFIRM_ONLINE_PAYMENT',
            message: '<i class="fa fa-3x fa-credit-card text-success pull-right" aria-hidden="true"></i>' +
                $translate.instant('TXT_CONFIRM_CONFIRM_START_ONLINE_PAYMENT'),
            buttons: [{
                text: 'TXT_BTN_CANCEL'
            }, {
                text: 'TXT_BTN_YES',
                callback: function () { return startOnlinePayment(invoiceID, price).$promise; }
            }]
        });
    }

    $scope.showPayments = function (duePayment) {
        $q.all([
            paymentsSvc.getAllForUserAsync(duePayment.parentID).$promise,
            modalPromise.$promise]).then(function (data) {
                modalPromise.$scope.model = duePayment;
                modalPromise.$scope.payments = _.filter(data[0], function(o) 
                {
                    if (duePayment.typeID > 3) // ? Can this even happen, this seems to have only 
                    {
                        return duePayment.invoiceID == o.invoiceID;
                    }
                    return duePayment.typeReferenceID == o.typeReferenceID &&
                           duePayment.typeReference2ID == o.typeReference2ID;                    
                });
                modalPromise.show();
            });
    }

    var modalPromise = $modal({
        templateUrl: 'my-account/due-payments-detail.html',
        show: false,
        backdrop: true,
        scope: $scope.$new()
    });

    shouldDisplayOnlinePaymentResult();

    function shouldDisplayOnlinePaymentResult() 
    {
        var onlinePaymentIDStr = urlUtils.getQueryParams()['onlinePaymentID'];
        if (!!onlinePaymentIDStr) {
            var onlinePaymentID = Number(onlinePaymentIDStr);

            onlinePaymentsSvc.getTransactionState(onlinePaymentID).$promise.then(
                function (data) {
                    messageBoxSvc.showMessageDlg({
                        title: 'TXT_PAYMENT_RESULT',
                        message: onlinePaymentsSvc.getOnlinePaymentResultMessage(data),
                        buttons: [{
                            text: 'TXT_BTN_OK',
                            callback: function () {
                                urlUtils.removeUrlParam('onlinePaymentID');
                                if (data.state === 3) {
                                    loadDuePayments();
                                }
                            }
                        }]
                    });
                });
        }
    }

    $scope.typeAheadAddress = [];

    $scope.allMatch = function () {
        return true;
    };

    $scope.getAddress = function (viewValue) {
        if (viewValue) {
            var params = {
                address: viewValue,
                language: 'cs',
                region: 'cz',
                bounds: '48.270777,12.172380|51.246709,19.922157', // Czech republic bounds
                key: 'AIzaSyDdpRFWJaEcASaUgQxTdi8i42aaCaKfS0A'
            };
            return $http.get('https://maps.googleapis.com/maps/api/geocode/json', { params: params })
                .then(function (res) {
                    $scope.typeAheadAddress.length = 0;                   
                    $scope.typeAheadAddress.push.apply($scope.typeAheadAddress, res.data.results);
                });
        } 
    };

    var amortizationScheduleDlg = $modal({
        templateUrl: '/partials/book-course-amortization-schedule.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    $scope.showAmortizationSchedule = function (model) {
        amortizationScheduleDlg.$promise.then(function () {
            amortizationScheduleDlg.$scope.invoiceID = model.invoiceID;
            amortizationScheduleDlg.$scope.model = { studentFullName: model.studentFullName };
            amortizationScheduleDlg.show();
        });
    }

}]);
;
wbApp.controller('MyActivitiesBookDetailCtrl', ['$scope', '$translate', 'activityAttendanceSvc', 'messageBoxSvc',
function ($scope, $translate, activityAttendanceSvc, messageBoxSvc) {

    $scope.isSaving = false;

    function finalizeSave(schedule) {
        schedule.studentID = $scope.selectedStudent.studentID;

        var res = activityAttendanceSvc.saveAttendanceAsync(schedule, true);

        res.$promise.then(function (data) {
            var newAttendanceByActivityScheduleID = _.keyBy(data, 'activityScheduleID');

            _.forEach($scope.scheduleMonths, function (month) {
                for (var s = 0; s < month.schedules.length; s++) {
                    var schedule = month.schedules[s];
                    var newSchedule = newAttendanceByActivityScheduleID[schedule.activityScheduleID];
                    if (!!newSchedule) {
                        var differs =
                            schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                            schedule.firstPeriodAttendanceStatusID !== newSchedule.firstPeriodAttendanceStatusID ||
                            schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                            schedule.secondPeriodAttendanceStatusID !== newSchedule.secondPeriodAttendanceStatusID ||
                            schedule.numberOfExcuses !== newSchedule.numberOfExcuses ||
                            schedule.firstPeriodFilled !== newSchedule.firstPeriodFilled ||
                            schedule.secondPeriodFilled !== newSchedule.secondPeriodFilled ||
                            schedule.firstPeriodWaitQueuePosition !== newSchedule.firstPeriodWaitQueuePosition ||
                            schedule.secondPeriodWaitQueuePosition !== newSchedule.secondPeriodWaitQueuePosition;

                        if (differs) {
                            month.schedules[s] = newSchedule;
                        }
                    }
                }
            });

            for (var s = 0; s < $scope.studentAttendanceData.length; s++) {
                var schedule = $scope.studentAttendanceData[s];
                var newSchedule = newAttendanceByActivityScheduleID[schedule.activityScheduleID];
                if (!!newSchedule) {
                    var differs =
                        schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                        schedule.firstPeriodAttendanceStatusID !== newSchedule.firstPeriodAttendanceStatusID ||
                        schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                        schedule.secondPeriodAttendanceStatusID !== newSchedule.secondPeriodAttendanceStatusID ||
                        schedule.numberOfExcuses !== newSchedule.numberOfExcuses ||
                        schedule.firstPeriodFilled !== newSchedule.firstPeriodFilled ||
                        schedule.secondPeriodFilled !== newSchedule.secondPeriodFilled ||
                        schedule.firstPeriodWaitQueuePosition !== newSchedule.firstPeriodWaitQueuePosition ||
                        schedule.secondPeriodWaitQueuePosition !== newSchedule.secondPeriodWaitQueuePosition;

                    if (differs) {
                        $scope.studentAttendanceData[s] = newSchedule;
                    }
                }
            };

            $scope.$hide();
            $scope.bookModal.onSave();
            $scope.isSaving = false;
        }, function (err) {
            $scope.isSaving = false;
        });
    }

    $scope.onAttendanceBookConfirmClick = function (schedule) {

        if ($scope.isSaving) {
            return;
        }

        $scope.isSaving = true;

        if (schedule.hasNewWaitQueue) {
            messageBoxSvc.showMessageDlg({
                title: 'TXT_TITLE_CONFIRMATION',
                message: schedule.isOneOffAttendanceEnabled 
                    ? $translate.instant('TXT_NEW_WAIT_QUEUE_CONFIRMATION') + $translate.instant('TXT_NEW_WAIT_QUEUE_CONFIRMATION_ONE_OFF')
                    : $translate.instant('TXT_NEW_WAIT_QUEUE_CONFIRMATION'),
                buttons: [{
                    text: 'TXT_BTN_NO'
                }, {
                    text: 'TXT_BTN_YES',
                    callback: function () {
                        finalizeSave(schedule);                        
                    }
                }]
            });
        }
        else {
            if (schedule.hasNewOneOff) {
                messageBoxSvc.showMessageDlg({
                    title: 'TXT_TITLE_CONFIRMATION',
                    message: 'TXT_NEW_ONE_OFF_CONFIRMATION',
                    buttons: [{
                        text: 'TXT_BTN_NO'
                    }, {
                        text: 'TXT_BTN_YES',
                        callback: function () {
                            finalizeSave(schedule);                            
                        }
                    }]
                });
            } else {
                finalizeSave(schedule);               
            }
        }
    }
}]);
;
'use strict';

wbApp.controller('MyActivitiesCtrl', ['$scope', '$modal', '$translate', '$timeout', 'tenantSettingSvc', 'activitySvc', 'activityAttendanceSvc', 'activityReconciliationSvc',
function ($scope, $modal, $translate, $timeout, tenantSettingSvc, activitySvc, activityAttendanceSvc, activityReconciliationSvc) {

    $scope.tabs = [
        {
            title: 'TXT_TAB_ACTIVITY_SELECTION',
            template: 'my-activities/activities-tab.html'
        },
        {
            title: 'TXT_TAB_ATTENDANCE',
            template: 'my-activities/activity-detail-tab.html'
        }];

    $scope.tabs.activeTab = 0;

    $scope.showGoogleChart = false;

    $scope.tenantSetting = tenantSettingSvc.settings;

    if ($scope.tenantSetting.showExcusesAndAmendsInMyActivities) {
        $scope.tabs.push({
            title: 'TXT_LBL_SUMMARY_OF_CHANGES',
            template: 'my-activities/excuses-and-amends.html'
        });
    }

    $scope.activitiesByStudents = activitySvc.getSummary();

    $scope.loadingAttendance = false;

    function extendModel(students) {
        for (var s = 0; s < students.length; s++) {
            var student = students[s];
            for (var a = 0; a < student.activities.length; a++) {
                var activity = student.activities[a];
                activity.isOld = moment(activity.activityEndDate).isBefore(moment());
                student.hasOld |= activity.isOld;
                student.hasNew |= !activity.isOld;
            }
        }
    }

    $scope.activitiesByStudents.$promise.then(function (data) {
        extendModel($scope.activitiesByStudents);
    });

    function resizeGoogleCharts() {
        $timeout(function () {
            $scope.referenceSourceTimeDevelopment.options.chartArea =
                { left: 90, top: 20, right: 30, bottom: 20, width: 800, height: 250 };

            $timeout(function () {
                $scope.referenceSourceTimeDevelopment.options.chartArea =
                    { left: 100, top: 20, right: 30, bottom: 20, width: 900, height: 250 };
            });
        });                
    }

    function loadExusesAndAmendsData(data) {
        $scope.excusesAndAmends = activityAttendanceSvc.getExcusesAndAmendsOnly(data, $scope.selectedActivity.activityID);
        $scope.availableExuses = activityReconciliationSvc.getAvailableExuses($scope.selectedActivity.activityID, $scope.selectedStudent.studentID);
        $scope.availableExuses.$promise.then(function (ex) {
            var rows = [];
            _.forEach(ex.excusesByDate, function (e) {
                rows.push({
                    c: [{ v: e.date }, { v: e.noOfExcuses }]
                });
            });
            $scope.referenceSourceTimeDevelopment.data.rows.length = 0;
            $scope.referenceSourceTimeDevelopment.data.rows.push.apply(
                $scope.referenceSourceTimeDevelopment.data.rows, rows);

            $scope.showGoogleChart = true;
        });
    }

    $scope.$watch('tabs.activeTab', function (newValue) {
        if (newValue === 2) {
            resizeGoogleCharts();
        }
    });

    $scope.setSelectedActivity = function (student, activity) {

        $scope.loadingAttendance = true;

        $scope.selectedActivity = activity;
        $scope.selectedStudent = student;
        $scope.selectedActivitySinglePeriodProgramOnly = false;

        $scope.studentAttendanceData = activityAttendanceSvc.getStudentAttendanceDetailAsync(activity.activityID, student.studentID);
        $scope.studentAttendanceData.$promise.then(function (data) {

            var firstAttenandace = _.head(data);
            if (!!firstAttenandace) {
                $scope.selectedActivitySinglePeriodProgramOnly = firstAttenandace.activity.singlePeriodProgramOnly;
            }

            $scope.scheduleMonths = activityAttendanceSvc.filterAndBreakByMonth(data, $scope.selectedActivity.activityID);
            loadExusesAndAmendsData($scope.studentAttendanceData);
            $timeout(function () {
                $scope.loadingAttendance = false;
            });
        });

        $scope.tabs.activeTab = 1;
    }

    $scope.onStudentExpanded = function (student) {
        student.expanded = !student.expanded;
    }

    $scope.setSelectedMonth = function (month) {
        $scope.selectedMonth = month;
        month.expanded = !month.expanded;
    }

    $scope.onExcuseButtonClick = function (schedule, month) {
        $scope.excuseModal = {
            studentName: $scope.selectedStudent.studentFullName,
            fromDate: schedule.startDate,
            toDate: schedule.startDate,
            scheduleOrig: schedule,
            period: {
                am: schedule.firstPeriodAttendanceStatusID == 0,
                pm: schedule.secondPeriodAttendanceStatusID == 0
            },
            notes: schedule.notes || $translate.instant('TXT_VAL_ILLNESS'),
            onSave: function () {
                loadExusesAndAmendsData($scope.studentAttendanceData);
            }
        }


        attendnaceExcuseModalPromise.$promise.then(function () {
            attendnaceExcuseModalPromise.$scope.singlePeriodProgramOnly = $scope.selectedActivitySinglePeriodProgramOnly;
            attendnaceExcuseModalPromise.show();
        });
    }

    $scope.onBookButtonClick = function (schedule, month) {
        $scope.bookModal = {
            studentName: $scope.selectedStudent.studentFullName,
            schedule: schedule.clone(),
            scheduleOrig: schedule,
            period: {
                am: schedule.firstPeriodAttendanceStatusID != 0,
                pm: schedule.secondPeriodAttendanceStatusID != 0
            },
            onSave: function () {
                loadExusesAndAmendsData($scope.studentAttendanceData);
            }
        }

        attendnaceBookModalPromise.$promise.then(function () {
            attendnaceBookModalPromise.$scope.singlePeriodProgramOnly = $scope.selectedActivitySinglePeriodProgramOnly;
            attendnaceBookModalPromise.show();
        });
    }

    var attendnaceExcuseModalPromise = $modal({
        template: 'my-activities/attendance-excuse-detail.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    var attendnaceBookModalPromise = $modal({
        template: 'my-activities/attendance-book-detail.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    $scope.referenceSourceTimeDevelopment = {
        type: 'AreaChart',
        data: {
            cols: [{
                id: 'date',
                label: 'Date',
                type: 'date',
                p: {}
            }, {
                id: 'excuses',
                label: $translate.instant('TXT_LBL_AVAILABLE_AMENDS'),
                type: 'number',
                p: {}
            }],
            rows: []
        },
        options: {
            displayExactValues: true,
            isStacked: true,
            chartArea: { left: 100, top: 20, right:0, bottom: 20, width: 900, height: 250 },
            legend: {
                position: 'none'
            },
            backgroundColor: '#F5F5F3',
            vAxis: { ticks: [5, 10, 15, 20] },
            hAxis: {},
            orientation: 'horizontal'
        }
    };

}]);
;
wbApp.controller('MyActivitiesExcuseCtrl', ['$scope', 'activityAttendanceSvc', 
function ($scope, activityAttendanceSvc) {

    $scope.isSaving = false;

    $scope.shouldDisableFirstPeriodExcuse = function (excuseModal) {
        if (moment(excuseModal.fromDate).isSame(moment(excuseModal.toDate), "day")) {
            return excuseModal.scheduleOrig.shouldDisableFirstPeriodExcuse;
        } else {
            return false;
        }
    }

    $scope.onDateChanged = function () {
        $scope.maxDate = moment($scope.excuseModal.toDate).endOf('day').toDate();
        $scope.minDate = moment($scope.excuseModal.fromDate).startOf('day').toDate();
    }

    $scope.onDateChanged();

    $scope.shouldDisableSecondPeriodExcuse = function (excuseModal) {
        if (moment(excuseModal.fromDate).isSame(moment(excuseModal.toDate), "day")) {
            return excuseModal.scheduleOrig.shouldDisableSecondPeriodExcuse;
        } else {
            return false;
        }
    }

    $scope.shouldShowAMExcuseMessage = function (excuseModal) {
        return (!excuseModal.period.am && !$scope.shouldDisableFirstPeriodExcuse(excuseModal)) &&
                (excuseModal.period.pm || $scope.shouldDisableSecondPeriodExcuse(excuseModal));
    }

    $scope.shouldShowPMExcuseMessage = function (excuseModal) {
        return (excuseModal.period.am ||  $scope.shouldDisableFirstPeriodExcuse(excuseModal)) &&
              (!excuseModal.period.pm && !$scope.shouldDisableSecondPeriodExcuse(excuseModal));
    }

    $scope.shouldShowAMPMExcuseMessage = function (excuseModal) {
        return (!excuseModal.period.am && !$scope.shouldDisableFirstPeriodExcuse(excuseModal)) &&
               (!excuseModal.period.pm && !$scope.shouldDisableSecondPeriodExcuse(excuseModal));
    }

    $scope.isOkDisabled = function (modal) {
        if (!modal || !modal.period) {
            alert('Error');
        }

        return !$scope.shouldShowAMExcuseMessage(modal) &&
               !$scope.shouldShowPMExcuseMessage(modal) &&
               !$scope.shouldShowAMPMExcuseMessage(modal);
    }

    $scope.onAttendanceExcuseConfirmClick = function (excuseModal) {

        if ($scope.isSaving) {
            return;
        }

        $scope.isSaving = true;

        var a = activityAttendanceSvc.excuseStudent(
            $scope.selectedActivity.activityID,
            $scope.selectedStudent.studentID,
            moment(excuseModal.fromDate).startOf('day').toDate(),
            moment(excuseModal.toDate).endOf('day').toDate(),
            !excuseModal.period.am,
            !excuseModal.period.pm,
            excuseModal.notes);
        a.$promise.then(function (data) {
            var newAttendanceByActivityScheduleID = _.keyBy(data, 'activityScheduleID');

            _.forEach($scope.scheduleMonths, function (month) {
                for (var s = 0; s < month.schedules.length; s++) {
                    var schedule = month.schedules[s];
                    var newSchedule = newAttendanceByActivityScheduleID[schedule.activityScheduleID];
                    if (!!newSchedule) {
                        var differs =
                            schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                            schedule.firstPeriodAttendanceStatusID !== newSchedule.firstPeriodAttendanceStatusID ||
                            schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                            schedule.secondPeriodAttendanceStatusID !== newSchedule.secondPeriodAttendanceStatusID ||
                            schedule.numberOfExcuses !== newSchedule.numberOfExcuses ||
                            schedule.firstPeriodFilled !== newSchedule.firstPeriodFilled ||
                            schedule.secondPeriodFilled !== newSchedule.secondPeriodFilled ||
                            schedule.firstPeriodWaitQueuePosition !== newSchedule.firstPeriodWaitQueuePosition ||
                            schedule.secondPeriodWaitQueuePosition !== newSchedule.secondPeriodWaitQueuePosition;

                        if (differs) {
                            month.schedules[s] = newSchedule;
                        }
                    }
                }
            });

            for (var s = 0; s < $scope.studentAttendanceData.length; s++) {
                var schedule = $scope.studentAttendanceData[s];
                var newSchedule = newAttendanceByActivityScheduleID[schedule.activityScheduleID];
                if (!!newSchedule) {
                    var differs =
                        schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                        schedule.firstPeriodAttendanceStatusID !== newSchedule.firstPeriodAttendanceStatusID ||
                        schedule.firstPeriodAttendanceTypeID !== newSchedule.firstPeriodAttendanceTypeID ||
                        schedule.secondPeriodAttendanceStatusID !== newSchedule.secondPeriodAttendanceStatusID ||
                        schedule.numberOfExcuses !== newSchedule.numberOfExcuses ||
                        schedule.firstPeriodFilled !== newSchedule.firstPeriodFilled ||
                        schedule.secondPeriodFilled !== newSchedule.secondPeriodFilled ||
                        schedule.firstPeriodWaitQueuePosition !== newSchedule.firstPeriodWaitQueuePosition ||
                        schedule.secondPeriodWaitQueuePosition !== newSchedule.secondPeriodWaitQueuePosition;

                    if (differs) {
                        $scope.studentAttendanceData[s] = newSchedule;
                    }
                }
            };

            excuseModal.onSave();

            $scope.isSaving = false;
        }, function (err) {
            $scope.isSaving = false;
        });
    }
}]);
;
'use strict';

wbApp.controller('MyCoursesCtrl', ['$scope', '$http', '$q', '$translate', '$modal', '$timeout', '$window', 'notificationSvc', 'tenantSettingSvc', 'urlUtils',
function ($scope, $http, $q, $translate, $modal, $timeout, $window, notificationSvc, tenantSettingSvc, urlUtils) {

    $scope.showArrearInMyCourses = tenantSettingSvc.settings.showArrearInMyCourses;
    $scope.disableExcuseInMyCourses = tenantSettingSvc.settings.disableExcuseInMyCourses;

    $scope.contentInfos = [];

    $scope.tabs = [
        {
            title: 'TXT_TAB_COURSE_SELECTION',
            template: 'my-courses/course-selection-tab.html'
        },
        {
            title: 'TXT_TAB_ATTENDANCE',
            template: 'my-courses/attendance-detail-tab.html'
        }];

    $scope.tabs.activeTab = 0;


    $scope.$watch('tabs.activeTab', function (newValue, oldValue) {
        if (newValue == 0) {
            urlUtils.setUrlParam("studentID", null);
            urlUtils.setUrlParam("courseID", null);
        } else if (!!$scope.selectedCourse && !!$scope.selectedStudent) {
            urlUtils.setUrlParam("studentID", $scope.selectedStudent.studentID);
            urlUtils.setUrlParam("courseID", $scope.selectedCourse.courseID);
        }
    });

    $scope.students = myCourses;

    $scope.selectedStudentID = urlUtils.getQueryParams()['studentID'];
    $scope.selectedCourseID = urlUtils.getQueryParams()['courseID'];

    function extendModel(students) {
        for (var s = 0; s < students.length; s++) {
            var student = students[s];            
            for (var c = 0; c < student.courses.length; c++) {
                var course = student.courses[c];
                course.isOld = (moment(course.endDate).isBefore(moment().subtract(1, 'w')) && !course.seasonTicket) || moment(course.endDate).isBefore(moment().subtract(20, 'w'));
                student.hasOld |= course.isOld;
                student.hasNew |= !course.isOld;
            }
        }
    }

    function setUpCorrespondingSelectedCourse(students) {
        for (var s = 0; s < students.length; s++) {
            var student = students[s];
            if ($scope.selectedStudent && student.studentID === $scope.selectedStudent.studentID) {
                $scope.selectedStudent = student;
                for (var c = 0; c < student.courses.length; c++) {
                    var course = student.courses[c];
                    if ($scope.selectedCourse && course.courseID === $scope.selectedCourse.courseID) {
                        $scope.selectedCourse = course;
                        return;
                    }
                }
            }
        }
    }

    var myTimeout = null;
    $scope.onlineStartDate = null;
    $scope.onlineEndDate = null;
    var onlineEnabledThreshold = 1;

    $scope.startOnlineMeetingDisabled = true;

    $scope.onTimeout = function () {
        var ms = moment($scope.onlineStartDate).subtract('h', onlineEnabledThreshold).diff(moment());
        if (ms > 0) {
            $scope.startOnlineMeetingDisabled = true;
            var d = moment.duration(ms);
            $scope.onlineEnabledIn = Math.floor(d.asHours()) + moment.utc(ms).format(":mm:ss");

            myTimeout = $timeout($scope.onTimeout, 1000);
        } else {
            $timeout.cancel(myTimeout);
            if (moment($scope.onlineEndDate).isAfter(moment())) {
                $scope.startOnlineMeetingDisabled = false;
            } else {
                // Start over again with next closest lesson
                $scope.startOnlineMeetingDisabled = true;
                $scope.extendAttendanceModel($scope.attendance);
            }
        }
    }

    $scope.extendAttendanceModel = function(attendance) {
      //  if ($scope.selectedCourse.isOnlineMeeting) {

            var lastInThePastIdx = _.findLastIndex(attendance, function (o) { return moment(o.endDate).isBefore(moment().subtract(1, 'h')) });
            if (attendance.length > (lastInThePastIdx + 1)) {

                var index = -1;
                for (var i = lastInThePastIdx + 1; i < attendance.length; i++) {
                    var att = attendance[i];
                    if (att.courseAttendanceStatusID === 0 && att.isOnline) {
                        index = i;
                        break;
                    }
                }

                if (index === -1) {
                    return;
                }

                angular.forEach(attendance, function (att, idx) {
                    att.closestLesson = idx === index;
                });

                if (!!myTimeout) {
                    $timeout.cancel(myTimeout);
                }

                $scope.onlineStartDate = attendance[index].startDate;
                $scope.onlineEndDate = attendance[index].endDate;
                $scope.onTimeout();
            }
       // }
    }

    $scope.setSelectedCourse = function (student, course) {
        $scope.selectedCourse = course;
        $scope.selectedStudent = student;
        $scope.tabs.activeTab = 1;

        urlUtils.setUrlParam("studentID", student.studentID);
        urlUtils.setUrlParam("courseID", course.courseID);

        $q.all([
            getAttendanceDetail(student.studentID, course.courseID),
            getAccessibleContentInfos(student.studentID, course.courseID)]).then(
            function (data) {
                $scope.attendance = data[0].data;
                $scope.contentInfos = data[1].data;
                $scope.extendAttendanceModel($scope.attendance);
            });
    }

    if ($scope.students.length) {
        extendModel($scope.students);

        if (!!$scope.selectedStudentID && !!$scope.selectedCourseID)
        {
            $scope.selectedStudent = _.find($scope.students, function (s) { return s.studentID == $scope.selectedStudentID; });
            if (!!$scope.selectedStudent) {
                $scope.selectedCourse = _.find($scope.selectedStudent.courses, function (c) { return c.courseID == $scope.selectedCourseID; });
            }
            if (!$scope.selectedCourse) {
                $scope.selectedStudent = null;

                urlUtils.setUrlParam("studentID", null);
                urlUtils.setUrlParam("courseID", null);

                if ($scope.students[0].courses.length) {
                    $scope.selectedStudent = $scope.students[0];
                    $scope.selectedCourse = $scope.students[0].courses[0];

                    $q.all([
                        getAttendanceDetail($scope.selectedStudent.studentID, $scope.selectedCourse.courseID),
                        getAccessibleContentInfos($scope.selectedStudent.studentID, $scope.selectedCourse.courseID)]).then(
                        function (data) {
                            $scope.attendance = data[0].data;
                            $scope.contentInfos = data[1].data;
                            $scope.extendAttendanceModel($scope.attendance);
                        });
                }
            }
            else
            {                
                $scope.setSelectedCourse($scope.selectedStudent, $scope.selectedCourse);
            }
        } else {
            if ($scope.students[0].courses.length) {
                $scope.selectedStudent = $scope.students[0];
                $scope.selectedCourse = $scope.students[0].courses[0];

                $q.all([
                    getAttendanceDetail($scope.selectedStudent.studentID, $scope.selectedCourse.courseID),
                    getAccessibleContentInfos($scope.selectedStudent.studentID, $scope.selectedCourse.courseID)]).then(
                    function (data) {
                        $scope.attendance = data[0].data;
                        $scope.contentInfos = data[1].data;
                        $scope.extendAttendanceModel($scope.attendance);
                    });
            }
        }
    }

    $scope.switchMe = function (idx) {
        $scope.tabs.activeTab = idx;
    }

    $scope.onPrevBtnClick = function () {
        $scope.tabs.activeTab = 0;
    }

    $scope.onNextBtnClick = function () {
        $scope.tabs.activeTab = 1;
    }

    $scope.onAttendanceChangeClick = function (at, course) {
        $http({
            method: 'POST',
            url: '/MyCourses/ChangeStudentAttendance',
            params: { StudentID: at.studentID, CourseScheduleID: at.courseScheduleID, CourseID : course.courseID }
        })
        .success(function (data, status, headers, config) {
            $scope.attendance = data.attendance;
            $scope.extendAttendanceModel($scope.attendance);
            $scope.students = data.students;
            extendModel($scope.students);
            setUpCorrespondingSelectedCourse($scope.students);
            notificationSvc.notifyInfo(
                $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_SUCCESS'));
        })
        .error(function (data, status, headers, config) {
            notificationSvc.notifyError(
                $translate.instant('TXT_ALERT_ATTENDANCE_SAVE_FAILURE'),
                notificationSvc.translateError(data));
        });
    }

    $scope.modal = { title: "", saved: false };

    var modalPromise = $modal({
        template: 'my-courses/attendance-change-detail.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    $scope.onClickMe = function (student, course, at) {

        if (tenantSettingSvc.settings.disableExcuseInMyCourses) {
            return;
        }

        $scope.modal.title = getAttendanceOperationTitle(at);
        $scope.modal.description = getAttendanceOperationDescription(student, at);
        $scope.modal.attendance = at;
        $scope.modal.course = course;

        modalPromise.$promise.then(function () {
            modalPromise.show();
        });
    }

    function getAttendanceOperationTitle (at) {
        if (at.courseAttendanceStatusID === 0) { // Present
            return $translate.instant("TXT_EXCUSE_ACTION");
        } else {
            if (at.operationPendingInWaitingQueue) {
                return $translate.instant("TXT_EXCUSE_ACTION");
            } else {
                return $translate.instant("TXT_EXCUSE_CANCEL_ACTION");
            }
        }
    }

    function getAttendanceOperationDescription(student, at) {
        if (at.courseAttendanceStatusID === 0) { // Present
            return $translate.instant("TXT_EXCUSE_ACTION_DESC")
                .f(student.studentFullName, at.schedule, at.courseFullName);
        } else {
            if (at.operationPendingInWaitingQueue) {
                return $translate.instant("TXT_EXCUSE_CANCEL_ACTION_W_DESC")
                    .f(student.studentFullName, at.schedule, at.courseFullName);
            } else {
                return $translate.instant("TXT_EXCUSE_CANCEL_ACTION_DESC")
                    .f(student.studentFullName, at.schedule, at.courseFullName);
            }
        }
    }

    function getAccessibleContentInfos(studentID, courseID)
    {
        return $http({
            method: 'GET',
            url: '/Api/CourseRegistrations/GetAccessibleContentInfos',
            params: { StudentID: studentID, CourseID: courseID }
        });
    }

    function downloadDataUrlFromJavascript(name, dataUrl) {
        var link = document.createElement("a");
        link.target = "_blank";
        link.setAttribute("download", name);
        link.href = dataUrl;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }

    $scope.onContentInfoClick = function (contentInfo)
    {
        if (contentInfo.accessType == 1)
        {
            // get download url and initiate download
            $http({
                method: 'POST',
                url: '/Api/CourseRegistrations/GetContentInfoDownloadUrl',
                params: { StudentID: $scope.selectedStudent.studentID, CourseID: $scope.selectedCourse.courseID },
                data: contentInfo
            }).then(function (payload) {
                downloadDataUrlFromJavascript(contentInfo.name, payload.data.url);
            });
        }
        else
        {
            // redirect to player
            var url = "/MediaPlayer?studentID=" +
                $scope.selectedStudent.studentID +
                "&courseID=" +
                $scope.selectedCourse.courseID +
                "&objectUri=" + encodeURI(contentInfo.objectUri);

            var iframe = '<html><head><style>body, html {width: 100%; height: 100%; margin: 0; padding: 0}</style><title>' + contentInfo.description + '</title></head><body><iframe src="' + url + '" style="height:calc(100% - 4px);width:calc(100% - 4px)"></iframe></html></body>';
            var win = window.open("", "", "width=1024,height=768,toolbar=no,resizable=yes,location=no,directories=no,status=no,menubar=no,copyhistory=no");
            win.document.write(iframe);
        }
    }


    function getAttendanceDetail(studentID, courseID) {
        return $http({
            method: 'GET',
            url: '/MyCourses/StudentCourseAttendance',
            params: { StudentID: studentID, CourseID: courseID }
        });
    }

    $scope.onStudentExpanded = function (student) {
        student.expanded = !student.expanded;
    }

    $scope.onPrintInvoice = function (courseRegistrationID) {
        $window.open('/Admin/Report/Invoice?ReportID=' + courseRegistrationID + '&ReportIDType=0',
            '_blank', 'width=1000,height=500,toolbar=no,resizable=yes,location=no,directories=no,status=no,menubar=no,copyhistory=no');
    }

}]);
;
'use strict';

wbApp.controller('OnlineCourseCtrl', ['$scope', '$translate',
function ($scope, $translate) {

    $scope.model = {
        isTeacher: isTeacher,
        joinMeetingUrl: courseSchedule.JoinMeetingUrl,
        startMeetingUrl: courseSchedule.StartMeetingUrl,
        courseFullName: courseSchedule.Subject,
        subjectName: courseSchedule.SubjectName,
        startDate: courseSchedule.StartDate,
        endDate: courseSchedule.EndDate,
        notes: courseSchedule.Notes,
        subjectDescription: course.SubjectDescription,
        courseDescription: course.CourseDescription,
        teacherFullName: course.TeacherFullName,
        teacherWorkExperience: course.TeacherWorkExperience,
        teacherWorkWithChildren: course.TeacherWorkWithChildren,
        teacherPhotoUrl: course.TeacherPhotoUrl
    }

    if ((!attendance || !attendance.length) && !$scope.model.isTeacher) {
        $scope.serverError = { errors: [{ message: $translate.instant('TXT_ERROR_NO_STUDENTS_REGISTERED_ON_THIS_LESSON') }] };        
    }
}]);
;
'use strict';

wbApp.controller('PaymentCtrl', ['$scope', '$translate', '$window', 'securitySvc', 'paymentsSvc', 'messageBoxSvc', 'terminalSvc', 'tenantSettingSvc',
    function ($scope, $translate, $window, securitySvc, paymentsSvc, messageBoxSvc, terminalSvc, tenantSettingSvc) {

        $scope.tabs = [
        {
            title: 'TXT_TITLE_PAYMENTS',
            template: 'payments/payment-tab.html'
        }];

        $scope.terminal = terminalSvc.getTerminalSetting();

        $scope.terminalChanged = function (terminal) {
            terminalSvc.setTerminalSetting(terminal);
        }

        $scope.tabs.activeTab = 0;

        $scope.model = paymentsSvc.initializePaymentEditModel();

        $scope.onClearBtnClick = function () {
            paymentsSvc.clearPaymentEditModel($scope.model);
        }

        $scope.onSaveBtnClick = function () {
            messageBoxSvc.showConfirmClientNotification({
                userSetting: ['confimNotificationCourseRegistrationPayment'],
                showSendSmsNotification: false,
                callback: function (notificationConfig) {
                    savePayment(notificationConfig.sendEmailNotification);
                }
            });
        }

        $scope.isPaymentValid = function () {
            if ($scope.terminal.isRequired && !$scope.terminal.terminalID) {
                return false;
            }

            return  paymentsSvc.isPaymentEditModelValid($scope.model);
        }

        function savePayment(sendNotification) {
            var model = $scope.model;

            paymentsSvc.savePayemntEditModel(model, sendNotification, success, error);

            function success(data) {
                if (model.paymentTypeID === 1 && securitySvc.isInRole('Payment.CashReceipt') && securitySvc.isInRole('Reports')) { // Cash
                    messageBoxSvc.showMessageDlg({
                        title: 'TXT_TITLE_CONFIRM_PRINT',
                        message: 'TXT_CONFIRM_PRINT_CASH_RECEIPT_MESSAGE',
                        buttons: [{
                            text: 'TXT_BTN_NO',
                            callback: function () { finalizePayment(); }
                        }, {
                            text: 'TXT_BTN_PRINT',
                            callback: function () { finalizePayment(); onPrintReceipt(data.paymentID); }
                        }]
                    });
                } else if (model.paymentTypeID === 2 && securitySvc.isInRole('Payment.ConfirmationReport') && securitySvc.isInRole('Reports') &&
                    tenantSettingSvc.settings.autoPaymentConfirmationPrintForCardPayments) { // Card
                    messageBoxSvc.showMessageDlg({
                        title: 'TXT_TITLE_CONFIRM_PRINT',
                        message: 'TXT_CONFIRM_PRINT_PAYMENT_EVIDENCE_MESSAGE',
                        buttons: [{
                            text: 'TXT_BTN_NO',
                            callback: function () { finalizePayment(); }
                        }, {
                            text: 'TXT_BTN_PRINT',
                            callback: function () { finalizePayment(); onPrintPaymentEvidence(data.paymentID); }
                        }]
                    });
                } else {
                    finalizePayment();
                }
            }

            function error(data) {
                $scope.serverError = data;
            }
        }

        function onPrintReceipt(paymentID) {
            $window.open('/Admin/Report/CashReceipt?PaymentID=' + paymentID,
                '_blank', 'width=1000,height=500,toolbar=no,resizable=yes,location=no,directories=no,status=no,menubar=no,copyhistory=no');
        }

        function onPrintPaymentEvidence(paymentID) {
            $window.open('/Admin/Report/PaymentConfirmation?PaymentID=' + paymentID,
                '_blank', 'width=1000,height=500,toolbar=no,resizable=yes,location=no,directories=no,status=no,menubar=no,copyhistory=no');
        }

        $scope.onClearBtnClick();

        function finalizePayment() {
            $scope.onClearBtnClick();
            //notificationSvc.notifyInfo(
            //    $translate.instant('TXT_ALERT_TITLE_PAYMENT_SAVED'));
        }
}]);;
'use strict';

wbApp.controller('RentCtrl', ['$scope', '$q', '$window', '$modal', '$translate', 'urlUtils', 'itemTypeSvc', 'rentCategorySvc', 'rentSvc',
    'classroomAvailabilitySchedulesSvc', 'notificationSvc', 'rentItemAvailabilitySvc', 'securitySvc', 'messageBoxSvc', 'rentItemSvc', 'localStorageService',
function ($scope, $q, $window, $modal, $translate, urlUtils, itemTypeSvc, rentCategorySvc, rentSvc,
    classroomAvailabilitySchedulesSvc, notificationSvc, rentItemAvailabilitySvc, securitySvc, messageBoxSvc, rentItemSvc, localStorageService) {

    var schedulerInstanceDeferred = $q.defer();

    DevExpress.localization.loadMessages({
        "cs": {
            "dxScheduler-switcherWeek": "Týden"
        },
        "en": {
            "dxScheduler-switcherWeek": "Week"
        }
    });

    $scope.selectedResourceId = null;
    $scope.selectedResource = {};

    $scope.onResourceHeaderClick = function (resourceId) {
        $scope.selectedResourceId = resourceId;
        $scope.rentItems.$promise.then(function () {
            $scope.selectedResource = _.find($scope.rentItems, { id: resourceId });
        });
    }

    var scheduleDataSource = new DevExpress.data.DataSource({
        store: new DevExpress.data.CustomStore({
            load: function (loadOptions) {
                return $q(function (resolve, reject) {
                    var startDate = moment(schedulerInstance.getStartViewDate()).startOf('day').toDate();
                    var endDate = moment(schedulerInstance.getEndViewDate()).endOf('day').toDate();

                    if (securitySvc.isAuthenticated() && !!$scope.itemToRent && $scope.itemToRent.itemTypeId) {
                        var rentsPromise = rentSvc.getAllByPlaceAndRentCategoryAndTypeAndUserDateRange(
                            $scope.placeId,
                            $scope.rentCategoryId,
                            $scope.itemToRent.itemTypeId,
                            securitySvc.loggedInUser().userID,
                            startDate,
                            endDate).$promise;   
                        rentsPromise.then(function (data) {
                            $scope.rentCategory.$promise.then(function () {

                                if ($scope.rentCategory.itemSelectionType == 0) { /* Manual */
                                    var result = _.flatMap(data, function (rentItem) {
                                        return _.map(rentItem.rentedItems, function (rentedItem) {
                                            var subRentItem = _.assign({}, rentItem, rentedItem, {
                                                id: rentItem.id + '-' + rentedItem.id,
                                                rentItemId: rentedItem.id
                                            });
                                            return subRentItem;
                                        });
                                    });
                                    resolve(result);
                                } else {
                                    resolve(data);
                                }
                            }, function (error) {
                                reject(error);
                            });
                        }, function (error) {
                            reject(error);
                        });
                    } else {
                        resolve([]);
                    }
                })
            },
            loadMode: 'processed'
        })
    });

    var rentItemsDataSource = new DevExpress.data.DataSource({
        store: new DevExpress.data.CustomStore({
            load: function (loadOptions) {
                return $q(function (resolve, reject) {
                    $q.all($scope.rentCategory.$promise,
                        $scope.rentItems.$promise).then(function () {
                            if ($scope.rentCategory.itemSelectionType == 0  && /* Manual */
                                !!$scope.selectedItemType) {

                                var filteredRentItems = _.orderBy(_.filter($scope.rentItems, { itemTypeId: $scope.selectedItemType.id }), ['name'], ['asc']);

                                if (!$scope.selectedResourceId && filteredRentItems.length > 0) {
                                    $scope.onResourceHeaderClick(filteredRentItems[0].id);
                                }

                                resolve(filteredRentItems);
                            }
                            else {
                                resolve([]);
                            }
                    }, function() {
                        reject();
                    });
                })
            },
            loadMode: 'processed'
        })
    });


    $scope.tabs = [];
    $scope.categories = [];
    $scope.itemSelectionType = 0;
    $scope.schedulerType = null; // 0 - week view, 1 - timeline day view

    $scope.rentCategoryId = urlUtils.getQueryParams()['rentCategoryId'];
    $scope.placeId = urlUtils.getQueryParams()['placeId'];

    $scope.cart = rentSvc.loadShoppingCart($scope.placeId);

    $scope.itemToRent = {        
        rentCategoryId: $scope.rentCategoryId,
        itemTypeId: localStorageService.get('selected-item-type-' + $scope.rentCategoryId)
    };

    var schedulerInstance = null;    

    var itemTypes = itemTypeSvc.getByPlaceAndRentCategory($scope.placeId, $scope.rentCategoryId);
    $scope.place = {};

    $scope.rentCategory = rentCategorySvc.getById($scope.rentCategoryId);
    $scope.rentItems = rentItemSvc.getAllByPlaceAndRentCategory($scope.placeId, $scope.rentCategoryId);

    function switchView(schedulerType) {
        schedulerInstanceDeferred.promise.then(function () {
            $scope.schedulerType = schedulerType;

            switch (schedulerType) {
                case 0: /* Manual */
                    schedulerInstance.option('currentView', 'timelineDay'); 
                    break;
                case 1: /* Manual */
                    schedulerInstance.option('currentView', 'week');
                    break;
            }
        });
    }

    function PrepareTabs() {

        $scope.rentCategory.$promise.then(function () {

            $scope.itemSelectionType = $scope.rentCategory.itemSelectionType;

            if ($scope.itemSelectionType == 0 /* Manual */) {
                $scope.tabs.push({
                    title: $scope.rentCategory.name,
                    template: "rents/rent-manual-selection-tab.html",
                });
                setUpViews($scope.itemSelectionType)
                switchView($scope.itemSelectionType);
            } else {
                $scope.tabs.push({
                    title: $scope.rentCategory.name,
                    template: "rents/rent-automatic-selection-tab.html",
                });
                setUpViews($scope.itemSelectionType)
                switchView($scope.itemSelectionType);
            }            
        });
    }

    function setUpViews(schedulerType) {
        schedulerInstanceDeferred.promise.then(function () {
            $scope.schedulerType = schedulerType;

            switch (schedulerType) {
                case 0:    /* Manual */
                    schedulerInstance.option('views').push({
                        type: "timelineDay",
                        appointmentTemplate: function (data, index, element) {
                            var cell = $(".dx-scheduler-date-table-cell");
                            element.parent().css("top", (cell.height() - 100) / 2);
                            return "item";
                        },
                        resourceCellTemplate: 'resourceCellTemplate'
                    });
                    schedulerInstance.option('groups').push('rentItemId');
                    break;
                case 1:    /* Automatic */                    
                    break;
            }
        });
    }

    PrepareTabs();

    var lastStartDate = moment().startOf('isoWeek').toDate();

    function getStartAndEndDayHourForSingleSchedule(schedule) {
        if (schedule.periods && schedule.periods.length > 0)
        {
            return { 
                startDayHour: moment(_.first(schedule.periods).start).hour(),
                endDayHour: Math.min(24, moment(_.last(schedule.periods).end).hour() + 1)
            };
        }

        return { startDayHour: 0, endDayHour: 24 };
    }

    
    var classroomAvailabilitySchedules = null;
    var itemAvailability = null;

    function setCellDuration() {
        $scope.rentCategory.$promise.then(function () {

            switch($scope.rentCategory.rentingPeriodType)
            {
                case 0:   // Minutes
                    if ($scope.rentCategory.minimumRentingPeriods <= 30) {
                        schedulerInstance.option('cellDuration', 30);
                    } else if ($scope.rentCategory.minimumRentingPeriods > 30 &&
                               $scope.rentCategory.minimumRentingPeriods <= 60) {
                        schedulerInstance.option('cellDuration', 60);
                    } else {
                        schedulerInstance.option('cellDuration', 60);
                    }
                    break;
                case 1:   // WholeCallendarDays
                    break;
            }

        });
    }

    function loadAvailabilitySchedulesForWeek(startDate) {

        $scope.rentCategory.$promise.then(function () {
            if (!$scope.itemToRent.itemTypeId) {
                var classroomAvailabilitySchedulesPromise = classroomAvailabilitySchedulesSvc.loadWeek($scope.placeId, startDate);
                classroomAvailabilitySchedulesPromise.then(function (schedules) {
                    classroomAvailabilitySchedules = schedules;
                    itemAvailability = null;
                    schedulerInstanceDeferred.promise.then(function () {
                        setStartAndEndDayHour(schedules);
                        setCellDuration();
                        schedulerInstance.repaint();
                    });
                });
            } else {

                var promises = [];

                var classroomAvailabilitySchedulesPromise = classroomAvailabilitySchedulesSvc.loadWeek($scope.placeId, startDate);
                promises.push(classroomAvailabilitySchedulesPromise);

                var groupBy = "GroupByRentCategory";
                switch ($scope.rentCategory.itemSelectionType) {
                    case 0:
                        groupBy = "GroupByRentItem"
                        break;
                    case 1:
                        groupBy = "GroupByRentCategory"
                        break;
                }

                var rentItemAvailabilityPromise = rentItemAvailabilitySvc.getAllByPlaceAndRentCategoryAndTypeAndDateRange(
                    $scope.placeId,
                    $scope.rentCategoryId,
                    $scope.itemToRent.itemTypeId,
                    startDate,
                    moment(startDate).endOf('isoWeek').toDate(),
                    groupBy).$promise;
                promises.push(rentItemAvailabilityPromise);

                $q.all(promises).then(function (data) {
                    classroomAvailabilitySchedules = data[0];
                    itemAvailability = data[1];
                    schedulerInstanceDeferred.promise.then(function () {
                        setStartAndEndDayHour(data[0]);
                        setCellDuration();
                        schedulerInstance.repaint();
                    })
                });
            }
        });
    }

    loadAvailabilitySchedulesForWeek(lastStartDate);

    function getStartAndEndDayHour(classroomAvailabilitySchedules) {
        var startAndEndDayPeriods = _.map(classroomAvailabilitySchedules, getStartAndEndDayHourForSingleSchedule);
        var start = _.minBy(startAndEndDayPeriods, 'startDayHour');
        var end = _.maxBy(startAndEndDayPeriods, 'endDayHour');
        return { startDayHour: start.startDayHour, endDayHour: end.endDayHour };
    }

    function setStartAndEndDayHour(schedules) {        
        if (!!classroomAvailabilitySchedules) {
            var setting = getStartAndEndDayHour(schedules);

            schedulerInstance.option('views[0].startDayHour', setting.startDayHour);
            schedulerInstance.option('views[0].endDayHour', setting.endDayHour);

            if ($scope.rentCategory.itemSelectionType == 0) {
                schedulerInstance.option('views[1].startDayHour', setting.startDayHour);
                schedulerInstance.option('views[1].endDayHour', setting.endDayHour);
            }
        } else {
            console.error('setStartAndEndDayHour not applied: !!classroomAvailabilitySchedules: ' + !!classroomAvailabilitySchedules + ' !!schedulerInstance:' + !!schedulerInstance);
        }
    }

    function isValidAppointment(appointmentData) {
        var startDate = appointmentData.startDate;
        if (moment().isAfter(startDate)) {
            notificationSvc.notifyWarning(
                $translate.instant('TXT_INVALID_SELECTION') + ':',
                $translate.instant('TXT_CANNOT_CREATE_RENT_INT_THE_PAST'));
            return false;
        }

        if (!!classroomAvailabilitySchedules) {
            var mStartDate = moment(startDate);
            var mdate = moment(startDate).startOf('day');
            var schedule = _.find(classroomAvailabilitySchedules, function (s) {
                return mdate.isSame(s.day);
            });
            if (!!schedule) {
                var startDatePeriod = _.find(schedule.periods || [], function (p) {
                    return mStartDate.isBefore(p.end) && mStartDate.isSameOrAfter(p.start);
                });
                if (!!startDatePeriod) {
                    // Start date ok
                    var mEndDate = moment(appointmentData.endDate);
                    mdate = moment(appointmentData.endDate).startOf('day');
                    schedule = _.find(classroomAvailabilitySchedules, function (s) {
                        return mdate.isSame(s.day);
                    });
                    if (!!schedule) {
                        var endDatePeriod = _.find(schedule.periods || [], function (p) {
                            return mEndDate.isSameOrBefore(p.end) && mEndDate.isAfter(p.start);
                        });
                    }
                    if (!!endDatePeriod) {
                        return true;
                    }
                }
            }
        }

        notificationSvc.notifyWarning(
            $translate.instant('TXT_INVALID_SELECTION') + ':',
            $translate.instant('TXT_START_AND_DATE_MUST_BE_IN_OPEN_PERIOD'));

        return false;
    }

    function isDateAvailableAccordingToSchedule(date) {
        if (!!classroomAvailabilitySchedules) {
            var mdatetime = moment(date);

            if (moment().isAfter(date)) {
                return false;
            }

            var mdate = moment(mdatetime).startOf('day');

            var schedule = _.find(classroomAvailabilitySchedules, function (s) {
                return mdate.isSame(s.day);
            });

            if (!!schedule) {
                var period = _.find(schedule.periods || [], function (p) {
                    return mdatetime.isBefore(p.end) && mdatetime.isSameOrAfter(p.start);
                });

                return !!period;
            }

        }

        return false;
    }

    function isDateAvailableAccordingToItems(date, groups) {
        if (!!itemAvailability && !!$scope.rentCategory) {

            if ($scope.rentCategory.itemSelectionType == 1) { // Automatic
                var mdatetime = moment(date);

                var period = _.find(itemAvailability[$scope.rentCategory.id] || [], function (p) {
                    return mdatetime.isBefore(p.endUtc) && mdatetime.isSameOrAfter(p.startUtc);
                });

                if (!period) {
                    return 0;
                }

                return period.availableItemsCount;
            }
            else if ($scope.rentCategory.itemSelectionType == 0 && !!groups && !!groups.rentItemId) //  Manual
            {
                var mdatetime = moment(date);

                var period = _.find(itemAvailability[groups.rentItemId] || [], function (p) {
                    return mdatetime.isBefore(p.endUtc) && mdatetime.isSameOrAfter(p.startUtc);
                });

                if (!period) {
                    return 0;
                }

                return period.availableItemsCount;
            }

        }

        return 0;
    }

    $scope.schedulerOptions = {
        dataSource: scheduleDataSource,
        showAllDayPanel: false,       
        height: "auto",
        currentView: 'week',
        crossScrollingEnabled: true,
        views: [{
            type: "week",
            startDayHour: 1,
            appointmentTemplate: function (data, index, element) {
                var cell = $(".dx-scheduler-date-table-cell");
                element.parent().css("min-width", cell.width());
                return "item";
            },
            resourceCellTemplate: 'resourceCellTemplate'
        }],
        resources: [{
            dataSource: rentItemsDataSource,
            fieldExpr: 'rentItemId',
            displayExpr: 'name',
            label: 'RentItem'
        }],
       // groups: ['rentItemId'],
        editing: {
            allowAdding: false,
            allowDeleting: false,
          //  allowDragging: false,
            allowTimeZoneEditing: false,
            allowResizing: false,
           // allowUpdating: false
        },
        onAppointmentAdding: function (e) {
            e.cancel = true;
        },
        onAppointmentFormOpening: function (e) {
            e.cancel = true;
        },
        onAppointmentUpdating: function (e) {
            e.cancel = true;
        },
        dataCellTemplate: function (itemData, itemIndex, itemElement) {
            var date = itemData.startDate;
            var isDisabled = !isDateAvailableAccordingToSchedule(date); 
            var availalbleCnt = isDateAvailableAccordingToItems(date, itemData.groups);

            var element = availalbleCnt == 0 || isDisabled
                ? $(`<div>${itemData.text}</div>`)
                : $scope.rentCategory.itemSelectionType == 1
                    ? $(`<div><div>${itemData.text}</div><div class='items-available-no'>${availalbleCnt}</div></div>`)
                    : $(`<div>${itemData.text}</div>`)

            if (isDisabled) {
                element.addClass('disable-date');
            }
            
            if (availalbleCnt > 5) {
                element.addClass('item-available-date-many');
            } else {
                element.addClass('item-available-date-' + availalbleCnt);
            }
            
            if ($scope.cart.startDate) {
                var mdate = moment(date);
                if (mdate.isBefore($scope.cart.endDate) && mdate.isSameOrAfter($scope.cart.startDate)) {
                    element.addClass('shopping-cart-range');
                }
            }

            return itemElement.append(element);
        },
        onInitialized: function (e) {
            schedulerInstance = e.component;
            schedulerInstanceDeferred.resolve(schedulerInstance);

            e.element.on("mouseup", function (ee) {
                if ($(ee.target).is(".dx-scheduler-date-table-cell")) {
                    var data = {};
                    
                    var selectedCells = $(ee.target).closest(".dx-scheduler-date-table").find(".dx-state-focused");
                    for (var i = 0; i < selectedCells.length; i++) {
                        var cellData = $(selectedCells[i]).data("dxCellData");
                        if (cellData) {
                            if (!data.startDate || moment(data.startDate).isAfter(cellData.startDate)) {
                                data.startDate = cellData.startDate;
                            }
                            if (!data.endDate || moment(data.endDate).isBefore(cellData.endDate)) {
                                data.endDate = cellData.endDate;
                            }

                            if (!!cellData.groups && !!cellData.groups.rentItemId) {
                                data.rentItem = _.find($scope.rentItems, { 'id': cellData.groups.rentItemId });
                            }
                        }
                    }
                    if ($scope.cart.startDate) {
                        var startDate = moment(data.startDate);
                        var endDate = moment(data.endDate);

                        var validSelection = startDate.isSameOrAfter($scope.cart.startDate) && startDate.isBefore($scope.cart.endDate) &&
                            endDate.isAfter($scope.cart.startDate) && endDate.isSameOrBefore($scope.cart.endDate);

                        if (!validSelection) {
                            notificationSvc.notifyWarning(
                                $translate.instant('TXT_INVALID_SELECTION') + ':',
                                $translate.instant('TXT_ONLY_CART_RANGE_IS_VALID'));
                            return;
                        } else {
                            data.startDate = $scope.cart.startDate;
                            data.endDate = $scope.cart.endDate;
                        }
                    }

                    if (isValidAppointment(data)) {
                        $scope.itemToRent.rentCategory = $scope.rentCategory;
                        $scope.itemToRent.startDate = data.startDate;
                        $scope.itemToRent.endDate = data.endDate;
                        $scope.itemToRent.numberOfItemsToAdd = 1;
                        $scope.itemToRent.rentItem = data.rentItem;

                        openAddItemDialog($scope.itemToRent);
                    }

                }
            });
        },
        onOptionChanged: function (e) {
            if (e.name === "currentDate") {
                var selectedDate = moment(e.value);

                var prevStartDate = moment(lastStartDate);
                var prevEndDate = moment(lastStartDate).endOf('isoWeek');
                if (selectedDate.isBefore(prevStartDate)) {
                    // load previous week
                    lastStartDate = selectedDate.startOf('isoWeek').toDate();
                    loadAvailabilitySchedulesForWeek(lastStartDate);
                }

                if (selectedDate.isAfter(prevEndDate)) {
                    // load next wek
                    lastStartDate = selectedDate.startOf('isoWeek').toDate();
                    loadAvailabilitySchedulesForWeek(lastStartDate);
                }
            }
        },
        startDateExpr: 'fromUtc',
        endDateExpr: 'toUtc',
        appointmentTooltipTemplate: 'tooltip'
    };

    function openAddItemDialog(model) {

        addItemDialog.$promise.then(function () {

            addItemDialog.$scope.model = model;
            addItemDialog.show();
        });
    }

    var addItemDialog = $modal({
        templateUrl: 'rents/add-rent-item-dialog.html',
        show: false,
        backdrop: 'static',
        scope: $scope.$new()
    });


    $scope.fromDateDateValidationRules = {
        validationRules: [{
            type: "required",
            message: $translate.instant('TXT_ERROR_REQUIRED')
        }]
    };

    $scope.fromDateTimeValidationRules = {
        validationRules: [{
            type: "required",
            message: $translate.instant('TXT_ERROR_REQUIRED')
        }]
    };

    $scope.toDateDateValidationRules = {
        validationRules: [{
            type: "required",
            message: $translate.instant('TXT_ERROR_REQUIRED')
        }]
    };

    $scope.toDateTimeValidationRules = {
        validationRules: [{
            type: "required",
            message: $translate.instant('TXT_ERROR_REQUIRED')
        }]
    };

    $scope.fromDateDateConfig = {
        type: "date",
        pickerType: "calendar",        
        bindingOptions: {
            value: "model.startDate",
            readOnly: "cart.startDate"
        }
    };

    $scope.fromDateTimeConfig = {
        type: "time",
        pickerType: "list",
        bindingOptions: {
            value: "model.startDate",
            readOnly: "cart.startDate"
        }
    };

    $scope.toDateDateConfig = {
        type: "date",
        pickerType: "calendar",
        bindingOptions: {
            value: "model.endDate",
            readOnly: "cart.startDate"
        }

    };

    $scope.toDateTimeConfig = {
        type: "time",
        pickerType: "list",
        bindingOptions: {
            value: "model.endDate",
            readOnly: "cart.startDate"
        }
    };

    $scope.onAddRentItmeToCart = function (model, hideFn) {
        var validationGroup = $("#addRentItemValidationGroup").dxValidationGroup("instance");
        const res = DevExpress.validationEngine.validateGroup(validationGroup);
        // For async validation
        //res.status === "pending" && res.complete.then((r) => {
        //    console.log(r.status);
        //});
        if (res.isValid) {
            rentSvc.addItemToShoppingCart($scope.cart, model);
            schedulerInstance.repaint();

            //schedulerInstance.addAppointment({
            //    text: 'XXX',
            //    startDate: model.startDate,
            //    endDate: model.endDate,
            //});
            hideFn();
        }
    }

    $scope.onItemTypeChange = function (itemTypeId) {

        localStorageService.set('selected-item-type-' + $scope.rentCategoryId, itemTypeId);

        $scope.rentCategory.$promise.then(function () {

            var groupBy = "GroupByRentCategory";
            switch ($scope.rentCategory.itemSelectionType) {
                case 0:
                    groupBy = "GroupByRentItem"
                    break;
                case 1:
                    groupBy = "GroupByRentCategory"
                    break;
            }

            rentItemAvailabilitySvc.getAllByPlaceAndRentCategoryAndTypeAndDateRange(
                $scope.placeId,
                $scope.rentCategoryId,
                itemTypeId,
                lastStartDate,
                moment(lastStartDate).endOf('isoWeek').toDate(),
                groupBy).$promise.then(function (items) {
                    itemAvailability = items;
                    if (!!schedulerInstance) {
                        scheduleDataSource.load();
                        schedulerInstance.repaint();
                    }
                });

            if (!!itemTypeId) {
                itemTypes.$promise.then(function () {
                    $scope.selectedItemType = _.find(itemTypes, { id: itemTypeId });
                    if ($scope.rentCategory.itemSelectionType == 0) { /* Manual */
                        //rentItemsDataSource.reload();
                        //schedulerInstance.option('resources[0].dataSource').reload();
                        var resources = schedulerInstance.option("resources");
                        var ds = resources[0].dataSource;
                       // ds.filter(["itemTypeId", "=", itemTypeId]);  //Applying filter
                        schedulerInstance.option("resources", resources);
                        //schedulerInstance.repaint();
                    }
                });
            } else {
                $scope.selectedItemType = {};
            }
        });
    }

    $scope.$on('onRentShoppingCartSaved', function (event, data) {
        loadAvailabilitySchedulesForWeek(lastStartDate);
        scheduleDataSource.load();
    });


    $scope.$on('onRemoveItemFromShoppingCart', function (event, data) {
        schedulerInstance.repaint();
    });

}]);;
'use strict';

wbApp.controller('RentsSelectCategoryCtrl', ['$scope', '$http', '$window', 'urlUtils', 'classroomSvc', 'rentCategorySvc', 'rentCategoryGroupSvc', 'rentSvc',
function ($scope, $http, $window, urlUtils, classroomSvc, rentCategorySvc, rentCategoryGroupSvc, rentSvc) {

    $scope.tabs = [];
    $scope.categories = [];

    var placesWithRents = classroomSvc.getAllActiveAsync(null, false, false, true);
    $scope.place = {};

    var selectedCategoryGroupId = urlUtils.getQueryParams()['rentCategoryGroupId'];
    $scope.selectedCategoryGroup = null;

    function PrepareTabs() {
        placesWithRents.$promise.then(function () {
            for (var i = 0; i < placesWithRents.length; i++) {
                var place = placesWithRents[i];
                $scope.tabs.push({
                    title: place.name,
                    placeId: place.id,
                    template: "rents/select-category-tab.html",
                });
            }

            if (placesWithRents.length) {
                switchToCorrectTab();
            }
        });
    }

    PrepareTabs();

    function loadRentData(placeId)
    {
        if (!!selectedCategoryGroupId) {
            $scope.groups = [];
            rentCategorySvc.getAllByPlace(placeId).$promise.then(function (data) {
                $scope.categories = _.filter(data, function (category) {
                    return category.rentCategoryGroupId == selectedCategoryGroupId;
                });
            });
            $scope.selectedCategoryGroup = rentCategoryGroupSvc.getById(selectedCategoryGroupId);
        } else {
            rentCategorySvc.getAllByPlace(placeId).$promise.then(function (data) {
                $scope.categories = _.filter(data, function (category) {
                    return !category.rentCategoryGroupId;
                });
            });
            $scope.groups = rentCategoryGroupSvc.getAllByPlace(placeId);
        }

        $scope.cart = rentSvc.loadShoppingCart(placeId);
    }

    $scope.cart = {};

    $scope.rentCategoryListOptions = {
        bindingOptions: {
            dataSource: "categories"
        }
    };

    function switchToCorrectTab() {
        placesWithRents.$promise.then(function () {
            var placeIdStr = urlUtils.getQueryParams()['placeId'];
            if (!!placeIdStr) {

                var placeId = Number(placeIdStr);
                // find correct tab
                var tabIndexToActivate = _.findIndex($scope.tabs, { placeId: placeId });
                if (tabIndexToActivate !== -1 && $scope.tabs.activeTab !== tabIndexToActivate) {
                    $scope.tabs.activeTab = tabIndexToActivate;
                    return;
                }
            }

            urlUtils.setUrlParam("placeId", null);
            $scope.tabs.activeTab = 0;
        });
    }

    $scope.$watch('tabs.activeTab', function (newValue, oldValue) {

        if (newValue !== null && newValue !== undefined) {

            placesWithRents.$promise.then(function () {                
                var placeId = $scope.tabs[newValue].placeId;
                $scope.place = _.find(placesWithRents, { id: placeId });

                loadRentData(placeId);

                urlUtils.setUrlParam("placeId", placeId);
            });
        }
    });


}]);;
wbApp.directive('wbShoppingCart', [
    function () {

        return {
            restrict: 'A',
            priority: 1,
            scope: {
                ngModel: '='
            },
            template:
            '<button type="button" class="btn btn-lg btn-warning shopping-cart-btn"' +
            '       data-animation="am-flip-x"' +
            '       data-auto-close="0"' +
            '       data-template-url="rents/shopping-cart-popover.html"' +
            '       data-container="body"' +
            '       data-placement="bottom-right"' +
            '       title="{{\'TXT_SHOPPING_CART\' | translate}}"' +
            '       bs-popover>' +
            '   <i class="fa fa-2x fa-shopping-cart" aria-hidden="true"></i>' +            
            '   <div class="badge">{{ngModel.rentedItems.length}}</div>' +
            '</button>',
            controller: ['$scope', '$modal', 'securitySvc', 'rentSvc', 'studentSvc', 'rentCategorySvc', 'notificationSvc', 'urlUtils', 'messageBoxSvc',
                function ($scope, $modal, securitySvc, rentSvc, studentSvc, rentCategorySvc, notificationSvc, urlUtils, messageBoxSvc) {

                    var selectStudentDlg = $modal({
                        template: 'rents/select-student-dialog.html',
                        show: false,
                        backdrop: 'static',
                        scope: $scope
                    });


                    var notRegisteredUserDlg = $modal({
                        template: 'rents/not-registered-user-dialog.html',
                        show: false,
                        backdrop: 'static',
                        scope: $scope
                    });

                    $scope.removeItem = function ($index) {
                        rentSvc.removeItemFromShoppingCart($scope.ngModel, $index);
                        $scope.$emit('onRemoveItemFromShoppingCart', $scope.ngModel);
                    }
                   
                    $scope.onRentBtnClick = function (model, hideFn) {
                        
                        rentCategorySvc.getAllByPlace(model.placeId).$promise.then(function (allRentCategories) {
                            var usedCategories = _.filter(allRentCategories, function (c) {
                                return !!_.find(model.rentedItems, { rentCategoryId: c.id });
                            });

                            // Full validation is on server, just collect all needed info, server desides
                            // if the setting makes any sense at all
                            var accessPermissions = _.reduce(usedCategories, function (result, value, key) {
                                switch (value.accessPermissions) {
                                    case 0: // LoggedInUsersOnlyStudentRequired
                                        result.studentRequired = true;
                                        break;
                                    case 1: // AllowAnonymousNoStudent
                                        result.allowAnonymous = true;
                                        break;
                                    case 2: // AllowAnonymousStudentRequired
                                        result.allowAnonymous = true;
                                        result.studentRequired = true;
                                        break;
                                    case 3: // LoggedInUsersOnlyNoStudent
                                        break;
                                }
                                return result;
                            }, {
                                studentRequired: false,
                                allowAnonymous:false
                            });
                            
                            if (!securitySvc.isAuthenticated() && !accessPermissions.allowAnonymous) {
                                notificationSvc.advertiseLogin(urlUtils.getParamsStringWithoutReturnUrl(urlUtils.getQueryParams()));
                                return;
                            }

                            if (securitySvc.isAuthenticated() && !!accessPermissions.studentRequired) {
                                studentSvc.getCurrentAsync().$promise.then(function (students) {

                                    if (!students || !students.length) {

                                        messageBoxSvc.showMessageDlg({
                                            title: 'TXT_PLACEHOLDER_SELECT_STUDENT',
                                            message: 'TXT_ERROR_NO_STUDENTS_2',
                                            buttons: [{
                                                text: 'TXT_BTN_CANCEL'
                                            }, {
                                                text: 'TXT_BTN_ADD_STUDENT',
                                                callback: function () {
                                                    window.location = "/MyAccount?tabName=students&returnOnSave=true&returnUrl=" + encodeURIComponent(location.pathname + location.search);
                                                    return;
                                                }
                                            }]
                                        });
                                    } else {
                                        // Show select student form

                                        selectStudentDlg.$promise.then(function () {
                                            selectStudentDlg.$scope.students = students;
                                            selectStudentDlg.$scope.isStudentSelected = false;
                                            selectStudentDlg.$scope.onSelectStudent = function (student) {
                                                _.forEach(students, function (s) {
                                                    if (s != student) {
                                                        s.selected = null;
                                                    } else {
                                                        s.selected = true;
                                                    }
                                                });
                                                selectStudentDlg.$scope.isStudentSelected = true;
                                            };
                                            selectStudentDlg.$scope.onRentAfterStudentSelection = function (d, hideFn2) {

                                                var loggedInUser = securitySvc.loggedInUser();
                                                model.userId = loggedInUser.userID;
                                                model.studentId = _.find(students, { selected: true }).id;
                                                model.isNotRegisteredUser = false;
                                                model.notRegisteredUserInfo = null;

                                                rentSvc.rentShoppingCart(model).$promise.then(function () {
                                                    rentSvc.emptyShoppingCart($scope.ngModel);
                                                    hideFn2();
                                                    hideFn();
                                                    $scope.$emit('onRentShoppingCartSaved', $scope.ngModel);
                                                });
                                            };
                                            selectStudentDlg.show();
                                        });
                                    }
                                });
                            }
                            else {

                                if (securitySvc.isAuthenticated() && !accessPermissions.studentRequired) {
                                    var loggedInUser = securitySvc.loggedInUser();
                                    model.userId = loggedInUser.userID;
                                    model.studentId = null;
                                    model.isNotRegisteredUser = false;
                                    model.notRegisteredUserInfo = null;

                                    rentSvc.rentShoppingCart(model).$promise.then(function () {
                                        rentSvc.emptyShoppingCart($scope.ngModel);
                                        hideFn();
                                        $scope.$emit('onRentShoppingCartSaved', $scope.ngModel);
                                    });
                                }
                                else {
                                    if (!!accessPermissions.allowAnonymous) {
                                        notRegisteredUserDlg.$promise.then(function () {
                                            notRegisteredUserDlg.$scope.registration = { notRegisteredUserInfo: null };
                                            notRegisteredUserDlg.$scope.isStudentRequired = accessPermissions.studentRequired;
                                            notRegisteredUserDlg.$scope.onAnonymousBtnClick = function () {
                                                notRegisteredUserDlg.$scope.registration.notRegisteredUserInfo = {
                                                    surname: null,
                                                    email: null,
                                                    phone: null,
                                                    students: accessPermissions.studentRequired ? [] : null
                                                };
                                            };
                                            notRegisteredUserDlg.$scope.onRentAfterNotRegisteredUserClick = function (d, hideFn2) {
                                                model.userId = null;
                                                model.studentId = null;
                                                model.isNotRegisteredUser = true;
                                                model.notRegisteredUserInfo = notRegisteredUserDlg.$scope.registration.notRegisteredUserInfo;

                                                rentSvc.rentShoppingCart(model).$promise.then(function () {
                                                    rentSvc.emptyShoppingCart($scope.ngModel);
                                                    hideFn2();
                                                    hideFn();
                                                    $scope.$emit('onRentShoppingCartSaved', $scope.ngModel);
                                                });
                                            }
                                            notRegisteredUserDlg.show();
                                        });
                                    }
                                }
                            }
                        });
                    }
                }]
        }
    }]);;
wbApp.controller('ReservationConfirmDetailCtrl', ['$scope', '$translate', 'messageBoxSvc', 'studentSvc', 'pricingSvc',
    'reservationsSvc', 'securitySvc',
function ($scope, $translate, messageBoxSvc, studentSvc, pricingSvc, reservationsSvc, securitySvc) {

    $scope.price = null;
    $scope.isCalculating = false;

    $scope.domainName = $scope.domain[0].name +
        (!!$scope.domain[0].specializations.length
            ? ' - ' + $scope.domain[0].specializations[0].name
            : '');

    function updatePrice() {
        var selectedStudentsIds = _.map(_.filter($scope.students, { buy: true }), 'id');
        if (selectedStudentsIds.length > 0 &&
            !!$scope.selectedEmployee) {

            $scope.isCalculating = true;
            pricingSvc.calculateReservationPrice({
                userId: securitySvc.loggedInUser().userID,
                placeId: $scope.place.id,
                studentsIds: selectedStudentsIds,
                employeeId: $scope.selectedEmployee.id,
                reservationStartDate: $scope.startDate,
                reservationEndDate: $scope.endDate
            }).$promise.then(
                function (data) {
                    $scope.price = data.price;
                    $scope.isCalculating = false;
                },
                function (error) {
                    $scope.price = null;
                    $scope.isCalculating = false;
                });
        } else {
            $scope.price = null;
        }
    }

    $scope.students = studentSvc.getCurrentAsync();

    $scope.selectedEmployee = _.head($scope.filteredEmployees);
    $scope.selectedEmployeeId = !!$scope.selectedEmployee
        ? $scope.selectedEmployee.id
        : 0;



    $scope.employeesSelectBoxOptions = {
        bindingOptions: {
            value: 'selectedEmployeeId'
        },
        valueExpr: "id",
        displayExpr: "fullName",
        items: $scope.filteredEmployees,
        onValueChanged: function (e) {
            $scope.selectedEmployee = _.find($scope.filteredEmployees, { id: e.value });
            updatePrice();
        }
    }

    $scope.onStudentSelectionChanged = function () {
        updatePrice();
    }

    $scope.isSaveDisabled = function () {
        return $scope.isCalculating ||
               $scope.isSaving ||
               (_.map(_.filter($scope.students, { buy: true }), 'id').length == 0);
    }

    $scope.onReservationConfimClick = function ($hide) {

        var model = {
            employeeId: $scope.selectedEmployeeId,
            placeId: $scope.place.id,
            price: $scope.price,
            registrationDate: moment().toDate(),
            reservationStartDate: $scope.startDate,
            reservationEndDate: $scope.endDate,
            userId: securitySvc.loggedInUser().userID,
            studentIds: (_.map(_.filter($scope.students, { buy: true }), 'id')),
            notes: $scope.note,
            domain: {
                id: $scope.domain[0].id,
                name: $scope.domain[0].name
            },
            domainSpecialization: !!$scope.domain[0].specializations.length
                ? {
                    id: $scope.domain[0].specializations[0].id,
                    name: $scope.domain[0].specializations[0].name
                }
                : null
        };

        $scope.isSaving = true;

        var insertResultPromise = reservationsSvc.insert(model);
        insertResultPromise.$promise.then(
            function (data) {
                $scope.isSaving = false;
                $hide();
                $scope.onSave(data);
            },
            function (error) {
                $scope.isSaving = false;
                messageBoxSvc.showMessageDlg({
                    title: 'TXT_ALERT_TITLE_ENTITY_SAVE_ERROR',
                    message: error.message,
                    buttons: [{
                        text: 'TXT_BTN_OK'
                    }]
                });
            });        
    }
}]);
;
wbApp.controller('ReservationsCtrl', ['$scope', '$modal', '$q', '$timeout', 'tenantSettingSvc',
    'classroomSvc', 'reservationsSvc', 'domainsSvc', 'employeeSvc', 'securitySvc', 'notificationSvc',
function ($scope, $modal, $q, $timeout, tenantSettingSvc, classroomSvc, reservationsSvc, domainsSvc, employeeSvc, securitySvc, notificationSvc) {

    $scope.isBusy = true;
    $scope.tenantSettings = tenantSettingSvc.settings;

    var resources = classroomSvc.getAllActiveAsync( /* classroomIDtoInclude */ null, /* filterForReservations */ true, /* filterForCourses */ false);
    var domains = domainsSvc.getAllExpanded();
    var employeesPromise = employeeSvc.getAll();
    var employees = [];   
    $scope.filteredEmployees = [];

    $scope.selectedPlace = null;

    function convertDomainSelection(domains, includeNames) {
        var domainsFilter = [];

        _.forEach(domains, function (d) {
            var domain = null;
            if (_.indexOf($scope.selectedDomains, d.id) != -1) {
                domain = {
                    id: d.id,
                    specializations: []
                };
                if (includeNames) {
                    domain.name = d.name;
                }
                domainsFilter.push(domain);
            }

            _.forEach(d.specializations, function (s) {
                if (_.indexOf($scope.selectedDomains, s.id) != -1) {
                    if (!domain) {
                        domain = {
                            id: d.id,
                            specializations: []
                        };
                        if (includeNames) {
                            domain.name = d.name;
                        }
                        domainsFilter.push(domain);
                    }

                    var specialization = {
                        id: s.id
                    };
                    if (includeNames) {
                        specialization.name = s.name;
                    };
                    domain.specializations.push(specialization);
                }
            });
        });

        return domainsFilter;
    }

    function loadAvailability(domainsChangeOnly) {

        $scope.filteredEmployees = [];

        if (!$scope.selectedPlace || !$scope.selectedDomains.length) {
            $scope.schedulerSettings.availability = [];
            if (!$scope.selectedPlace) {
                $scope.schedulerSettings.actions = [];
            }
        } else {
            var domainsFilter = convertDomainSelection(domains);
            $scope.isBusy = true;

            var promisses = [];

            promisses.push(classroomSvc.availabilityByDomainsAndRange(
                $scope.selectedPlace,
                domainsFilter,
                $scope.schedulerSettings.startDate));

            if (!domainsChangeOnly && securitySvc.isAuthenticated()) {
                promisses.push(reservationsSvc.getAllByRangeAndUser(
                    securitySvc.loggedInUser().userID,
                    $scope.schedulerSettings.startDate,
                    moment($scope.schedulerSettings.startDate).add(7, 'day').toDate(),
                    employees));
            }

            $q.all(promisses).then(
                function (data) {
                    $scope.schedulerSettings.availability = data[0];
                    if (data.length > 1) {
                        $scope.schedulerSettings.actions = data[1];
                    }
                    $scope.isBusy = false;
                },
                function (error) {
                    $scope.isBusy = false;
                }
            );
        }
        
    }

    var domainsDataSource = new DevExpress.data.DataSource({
        load: function (loadOptions) {
            return domains.$promise;
        },
        byKey: function (e) {
            return $q(function (resolve, reject) {
                domains.$promise.then(function (data) {
                    _.forEach(data, function (d) {
                        if (d.id == e) {
                            resolve(d);
                            return d;
                        }

                        var found = false;

                        _.forEach(d.specializations, function(s) {
                            if (s.id == e) {
                                resolve(s);
                                found = true;
                                return s;
                            }
                        })

                        if (found) {
                            return;
                        }
                    });
                },
                function(error) {
                    reject(error);
                })
            })           
        },
        loadMode: 'processed'
    });

    var placesDataSource = new DevExpress.data.DataSource({
        paginate: false,
        load: function (loadOptions) {            
            return resources.$promise;            
        },
        byKey: function (e) {
            return $q(function (resolve, reject) {
                resources.$promise.then(function (data) {
                    var item = _.find(data, { id: e });
                    resolve(item);
                },
                function (error) {
                    reject(error);
                })
            })
        },
        loadMode: 'processed'
    });

    $q.all([resources.$promise, domains.$promise, employeesPromise]).then(
        function (data) {
            $scope.isBusy = false;
            if (resources.length > 0) {

                $scope.selectedPlace = resources[0].id;
            }
            if (domains.length > 0) {
                $scope.selectedDomains = [domains[0].id];
            }
            employees = data[2];            
        }, function (error) {
            $scope.isBusy = false;
        }
    );

    var showReservationConfirmDialog = function(startDate, endDate, event)
    {
        reservationConfirmModalPromise.$promise.then(function () {
            reservationConfirmModalPromise.$scope.filteredEmployees = $scope.filteredEmployees;
            reservationConfirmModalPromise.$scope.startDate = startDate;
            reservationConfirmModalPromise.$scope.endDate = endDate;
            reservationConfirmModalPromise.$scope.place = _.find(resources, { id: $scope.selectedPlace });
            reservationConfirmModalPromise.$scope.domain = convertDomainSelection(domains, true);
            reservationConfirmModalPromise.$scope.onSave = function (data) {
                loadAvailability();
            };
            reservationConfirmModalPromise.show();
        });
    }

    $scope.employeeScollViewOptions = {
        height: 160,
        width: 580,
        direction: "horizontal",
        scrollByContent: true,
        scrollByThumb: true,
        showScrollbar: 'onHover'
    }

    $scope.schedulerSettings = {
        weekView: true,
        autoHourRange: false, // TODO
        visibleResources: 1,
        selectedResourceID: $scope.selectedPlace,
        startHour: tenantSettingSvc.settings.scheduleVisibleTimeStart,
        endHour: tenantSettingSvc.settings.scheduleVisibleTimeEnd,
        startDate: moment().startOf('isoWeek').toDate(),
        resources: resources,
        resourcesMapping: { resourceID: 'id' },
        actions: [],
        scale: 30,
        selectByBlocks: 2,
        maximumSelectedBlocks: 4,
        showWeekend: true,
        availability: [],
        actionsMapping: {
            resourceID: 'placeId',
            name: 'subject',
            teacher: 'teacherName',
            filled: 'filledCapacity'
        },
        commands: [{
            text: 'Vytvořit rezervaci',
            callback: function (event, startDate, endDate) {
                if (securitySvc.isAuthenticated()) {
                    showReservationConfirmDialog(startDate, endDate, event);
                } else {
                    notificationSvc.advertiseLogin();
                }
            }
        }]
    }

    $scope.onActionClicked = function (reservation) {

    }

    $scope.onSelectionChanged = function (selection) {
        var selectionStart = moment(selection.startDate);
        var selectionEnd = moment(selection.endDate);

        var filteredAvailability = _.filter(
            $scope.schedulerSettings.availability,
            function(a) {
                var result = selectionStart.isBefore(a.end) && selectionEnd.isAfter(a.start);
                return result;
            });

        var filteredEmployeeIds = _.uniq(_.flatMap(
            filteredAvailability,
            function (d) {
                return d.employeeIds;
            }));

        $scope.filteredEmployees = _.filter(
            employees,
            function (e) {
                return _.includes(filteredEmployeeIds, e.id);
            });
    }

    $scope.calendarOptions = {        
        value: $scope.schedulerSettings.startDate,
        onValueChanged: function (e) {
            var startOfWeek = moment(e.value).startOf('isoWeek').toDate();
            if (!moment($scope.schedulerSettings.startDate).isSame(startOfWeek)) {
                $scope.schedulerSettings.startDate = startOfWeek;
                loadAvailability();
            }
        }
    }

    $scope.placeSelectBox = {
        bindingOptions: {
            value: 'selectedPlace'
        },
        valueExpr: "id",
        displayExpr: "name",
        dataSource: placesDataSource,
        onValueChanged: function (e) {

            if ($scope.schedulerSettings.selectedResourceID != e.value)
            {
                $scope.schedulerSettings.selectedResourceID = e.value;

                var place = _.find(resources, { id: e.value });
                if (!!place) {
                    $scope.schedulerSettings.startTimeType = place.reservationStartTimeType;
                }

                loadAvailability();
            }
        }
    }

    $scope.selectedDomains = [];

    var treeView = null;

    var getSelectedItemsKeys = function (items) {
        var result = [];
        items.forEach(function (item) {
            if (item.selected) {
                result.push(item.key);
            }
            if (item.items.length) {
                result = result.concat(getSelectedItemsKeys(item.items));
            }
        });
        return result;
    };

    var syncTreeViewSelection = function (treeView) {
        if (!treeView) return;

        if (!$scope.selectedDomains) {
            treeView.unselectAll();
            return;
        }

        $scope.selectedDomains.forEach(function (key) {
            treeView.selectItem(key);
        });
    };

    $scope.domainsBoxOptions = {
        dataSource: domainsDataSource,
        bindingOptions: {
            value: 'selectedDomains'            
        },
        valueExpr: "id",
        displayExpr: "name",
        dropDownOptions: {
            height: '300px',
            resizeEnabled: true
        },
        showClearButton: false,
        onValueChanged: function () {
            syncTreeViewSelection(treeView);
        },
        treeView: {            
            dataSource: domainsDataSource,
            dataStructure: "tree",
            keyExpr: 'id',
            itemsExpr: 'specializations',
            displayExpr: "name",
            selectByClick: true,
            selectNodesRecursive: false,
            selectionMode: "single",
            onContentReady: function (e) {
                treeView = e.component;

                syncTreeViewSelection(treeView);
            },
            onItemSelectionChanged: function (args) {
                var nodes = args.component.getNodes();

                $scope.selectedDomains = getSelectedItemsKeys(nodes);

                loadAvailability(true);
            }
        }
    }

    var reservationConfirmModalPromise = $modal({
        template: 'reservations/confirm-reservation-dialog.html',
        show: false,
        backdrop: true,
        scope: $scope
    });
}]);;
wbApp.controller('EventDetailCtrl', ['$scope', '$translate', 'securitySvc', 'clientSchedulerSvc', 'notificationSvc', 'tenantSettingSvc',
function ($scope, $translate, securitySvc, clientSchedulerSvc, notificationSvc, tenantSettingSvc) {

    $scope.showCourseWaitQueueIndexInClient = tenantSettingSvc.settings.showCourseWaitQueueIndexInClient;



    $scope.eventDetail;
    $scope.isSaving = false;

    if (securitySvc.isAuthenticated()) {
        var promise = clientSchedulerSvc.getUserScheduleDetail(
            $scope.eventModal.currentStudent
                ? $scope.eventModal.currentStudent.userID
                : securitySvc.loggedInUser().userID,
            $scope.eventModal.action.courseScheduleID);

        promise.then(function (data) {
            $scope.eventDetail = data;
            $scope.compensationGrpHelp = $translate.instant('TXT_HLP_COMPENSATION_GROUP_HELP').f(data.compensationGroup);
        });
    }

    $scope.detailIsUnchanged = function (data) {
        if (!securitySvc.isAuthenticated()) {
            return false; // Special case when user is not logged in, we will show login adver on click
        }

        if (data) {
            return !data.isDirty;
        }
        return true;
    };

    $scope.onAttendanceSave = function (detailModel) {
        if (!securitySvc.isAuthenticated()) {
            notificationSvc.advertiseLogin();
            return;
        }

        $scope.isSaving = true;
        $scope.detailError = null;

        clientSchedulerSvc.setNewAttendance(
            $scope.eventModal.currentStudent
                ? $scope.eventModal.currentStudent.userID
                : securitySvc.loggedInUser().userID,
            $scope.eventModal.action.courseScheduleID,
            detailModel)
        .then(function () {
            $scope.isSaving = false;
            $scope.$hide();
            $scope.onSaved();
        }, function (rejectReason) {
            $scope.isSaving = false;
            $scope.detailError = rejectReason;
        });
    }

    // #region Tabs

    $scope.detailTabs = [];

    if (securitySvc.isAuthenticated()) {
        $scope.detailTabs.push({
            title: 'TXT_TAB_ATTENDANCE',
            template: "schedule/event-detail-dialog/attendance-tab.html"
        });
    }

    $scope.detailTabs.push({
        title: $scope.eventModal.action.subjectCategoryID === 1 ? 'TXT_TAB_COURSE_DETAIL' : 'TXT_TAB_ACTION_DETAIL',
        template: "schedule/event-detail-dialog/course-description-tab.html"
    });

    $scope.detailTabs.activeTab = 0;

    // #endregion
}]);;
'use strict';

wbApp.controller('SchedulerCtrl', ['$scope', '$timeout', 'tenantSettingSvc', 'semesterSvc', 'classroomSvc', 'urlUtils',
function ($scope, $timeout, tenantSettingSvc, semesterSvc, classroomSvc, urlUtils) {

    $scope.semesters = semesterSvc.getAllShowInAttendancenAsync();

    $scope.semesters.$promise.then(function () {
        prepareTabs();
        switchToCorrectTab();
        $timeout(function () {
            watchSemesterChanges();
        });
    });

    $scope.tenantSettings = tenantSettingSvc.settings;

    $scope.tabs = [];

    function prepareTabs() {
        for (var i = 0; i < $scope.semesters.length; i++) {
            var semester = $scope.semesters[i];
            $scope.tabs.push({ 
                title: semester.name,
                semesterID: semester.id,
                template: "schedule/semester-detail-tab.html",
            });
        }
    }

    function watchSemesterChanges() {
        $scope.$watch('tabs.activeTab', function (newValue) {
            $scope.semesters.$promise.then(function () {
                var semester = $scope.semesters[newValue];
                if (!!semester) {
                    urlUtils.setUrlParam("semesterID", semester.id);
                    $scope.$broadcast('semesterchanged', newValue, semester);
                }
            });
        });
    }

    function switchToCorrectTab() {
        var semesterIDStr = urlUtils.getQueryParams()['semesterID'];
        if (!!semesterIDStr) {

            var semesterID = Number(semesterIDStr);
            // find correct tab
            var tabIndexToActivate = _.findIndex($scope.tabs, { semesterID: semesterID });
            if (tabIndexToActivate !== -1 && $scope.tabs.activeTab !== tabIndexToActivate) {
                $scope.tabs.activeTab = tabIndexToActivate;
                return;
            }

        }

        urlUtils.setUrlParam("semesterID", null);
        $scope.tabs.activeTab = 0;
    }
}]);;
'use strict';

wbApp.controller('SemestrSchedulerCtrl', ['$scope', '$modal', 'tenantSettingSvc', 'securitySvc', 'currentUser', 'classroomSvc', 'clientSchedulerSvc',
    function ($scope, $modal, tenantSettingSvc, securitySvc, currentUser, classroomSvc, clientSchedulerSvc) {


        // TODO: preselect today if in the middle of semester or fisrt day of semester if outside

        $scope.showClearButton = securitySvc.isInRole('ClientAttendanceAdmin') || tenantSettingSvc.settings.showAllCoursesInClientSchedule;
        var thisTabIndex = $scope.$index;
        var currentSemester = null;
        var currentStudent = null;

        $scope.semesterID = 0;
        $scope.studentCompGrpID = null;
        $scope.isBusy = false;
        

        var lastStartDate = tenantSettingSvc.settings.clientScheduleWeekView
                                ? moment().startOf('isoWeek').toDate()
                                : moment().startOf('day').toDate();
        var lastEndDate = tenantSettingSvc.settings.clientScheduleWeekView
                                ? moment(lastStartDate).add(7, 'day').startOf('day').toDate()
                                : moment(lastStartDate).add(1, 'day').startOf('day').toDate();

        var resources = classroomSvc.getAllActiveAsync( /* classroomIDtoInclude */ null, /* filterForReservations */ false, /* filterForCourses */ true);
        var schedules = [];

        $scope.schedulerSettings = {
            weekView: tenantSettingSvc.settings.clientScheduleWeekView,
            autoHourRange: tenantSettingSvc.settings.scheduleEnableAutoHourRange,
            visibleResources: tenantSettingSvc.settings.scheduleDayViewResourcesPerPage,
           // selectedResourceID: 1,
            startHour: tenantSettingSvc.settings.scheduleVisibleTimeStart,
            endHour: tenantSettingSvc.settings.scheduleVisibleTimeEnd,
            scale: tenantSettingSvc.settings.scheduleTimeScale,
            startDate: lastStartDate,
            resources: resources,
            resourcesMapping: { resourceID: 'id' },
            actions: schedules,
            actionsMapping: {
                resourceID: 'classroomID',
                name: 'subject',
                teacher: 'teacherName',
                filled: 'filledCapacity'
            }
        }

        $scope.onActionClicked = function (action) {
            if (!tenantSettingSvc.settings.disableClientCalendar) {
                eventDetailDlg.$scope.eventModal = {
                    action: angular.copy(action),
                    currentStudent: currentStudent
                };
                eventDetailDlg.$scope.onSaved = function () {
                    loadSemesterScheduleWithLastValues();
                };
                eventDetailDlg.$promise.then(function () {
                    eventDetailDlg.show();
                });
            }
        }

        $scope.onDateChanged = function (startDate, endDate) {
            if (Date.prototype.isValidDate(startDate) && Date.prototype.isValidDate(endDate)) {
                if (currentStudent) {
                    loadSemesterSchedule(currentSemester.id, startDate, endDate, currentStudent.compensationGroupID, currentStudent.userID);
                } else {
                    loadSemesterSchedule(currentSemester.id, startDate, endDate, null, currentUser.userID);
                }
            }
        }

        $scope.onStudentChanged = function (student) {
            currentStudent = student;
            loadSemesterScheduleWithLastValues();
        }

        function loadSemesterScheduleWithLastValues() {
            if (currentStudent) {
                loadSemesterSchedule(currentSemester.id, lastStartDate, lastEndDate, currentStudent.compensationGroupID, currentStudent.userID);
            } else {
                loadSemesterSchedule(currentSemester.id, lastStartDate, lastEndDate, null, currentUser.userID);
            }
        }

        function loadSemesterSchedule(semesterID, startDate, endDate, compensationGroupID, userID) {
            if (!Date.prototype.isValidDate(startDate) || !Date.prototype.isValidDate(endDate)) {
                return;
            }

            lastStartDate = startDate;
            lastEndDate = endDate;

            $scope.isBusy = true;

            clientSchedulerSvc.getAllForSemesterAsync(
                semesterID,
                compensationGroupID,
                userID,
                startDate,
                endDate)
            .$promise.then(function (data) {
                schedules.length = 0;
                schedules.push.apply(schedules, data);
                $scope.isBusy = false;
            }, function () {
                $scope.isBusy = false;
            });
        }

        $scope.$on('semesterchanged', function (event, tabIndex, semester) {
            if (thisTabIndex === tabIndex) {
                currentSemester = semester;
                $scope.semesterID = semester.id;
                loadSemesterSchedule(semester.id, lastStartDate, lastEndDate);
            }
        });

        var eventDetailDlg = $modal({
            template: 'schedule/event-detail-dialog.html',
            show: false,
            backdrop: true,
            scope: $scope.$new()
        });
    }
]);;
'use strict';

wbApp.directive('wbStudentCompGrpLookup', ['$translate', '$timeout', '$q', 'studentSvc',
    function ($translate, $timeout, $q, studentSvc) {
        function formatResult(student) {
            if (!student) { return; }

            return "<div class='row'>" +
                        "<div class='col-md-6'>" + student.studentFullName + "</div>" +
                        "<div class='col-md-6'>" + student.compensationGroupName + "</div>" +
                    "</div>";
        }

        function formatSelection(student) {
            return student.studentFullName + ' - ' + student.compensationGroupName;
        }

        return {
            restrict: 'EA',
            require: 'ngModel',
            scope: {
                semesterId: '=',
                selectionChanged: '&onSelectionChanged',
                showClearButton: '='
            },
            link: function (scope, elm, attrs, controller) {

                var deferred = $q.defer();

                $timeout(function () {
                    $(elm).select2({
                        placeholder: $translate.instant('TXT_PLACEHOLDER_SELECT_STUDENT'),
                        formatResult: formatResult,
                        formatSelection: formatSelection,
                        dropdownAutoWidth: true,
                        allowClear: scope.showClearButton,
                        query: function (query) {
                            studentSvc.getStudentsWithCompGrpLookupQuery(
                                query.term, 10, query.page, scope.semesterId, onSuccess, onError);

                            function onSuccess(data) {
                                query.callback({ results: data, more: data.length > 0 });
                            }

                            function onError() {
                                query.callback({ results: [], more: false });
                            }
                        },
                        initSelection: function (element, callback) {
                            function onSuccess(data) {
                                controller.$setViewValue(data.id);
                                callback(data);
                            }

                            function onError() {
                                callback(null);
                            }

                            var id = $(element).val();
                            if (!!id) {
                                studentSvc.getStudentsWithCompGrpLookupID(
                                    id, scope.semesterId, onSuccess, onError);
                            } else {
                                controller.$setViewValue(null);
                                callback(null);
                            }
                        }
                    });

                    controller.$parsers.unshift(function (viewValue) {
                        if (!viewValue) {
                            return 0;
                        } else {
                            return parseInt(viewValue);
                        }
                    });

                    controller.$formatters.unshift(function (value) {
                        if (!value) {
                            return "0";
                        } else {
                            return value + "";
                        }
                    });

                    elm.on('change', function (e) {
                        scope.$apply(function () {
                            controller.$setViewValue(e.val);
                            if (scope.selectionChanged) {
                                scope.selectionChanged({ student: e.added });
                            }
                        });
                    });

                    attrs.$observe('readonly', function (value) {
                        elm.select2('readonly', !!value);
                    });

                    elm.bind("$destroy", function () {
                        elm.select2("destroy");
                    });


                    deferred.resolve(1);
                }, 1);

                controller.$render = function () {
                    deferred.promise.then(function () {
                        elm.select2('val', controller.$viewValue);
                    });
                };

            }
        }
}]);
;
var webooker_schedule_models = webooker_schedule_models || {};

(function (ns) {

    ns.UserScheduleDetail = function (userScheduleDetailDto) {

        this.dto = userScheduleDetailDto;

        this.attendanceChangesAllowed = userScheduleDetailDto.attendanceChangesAllowed;
        this.attendanceChangesInTime = userScheduleDetailDto.attendanceChangesInTime;
        this.compensationGroup = userScheduleDetailDto.compensationGroup;
        this.freeSlots = userScheduleDetailDto.freeSlots;      
        this.subjectCategoryID = userScheduleDetailDto.subjectCategoryID;

        this.waitQueue = [];
        for (var w = 0; w < userScheduleDetailDto.waitQueue.length; w++) {
            var userScheduleDetailWaitQueueItemDto = userScheduleDetailDto.waitQueue[w];
            this.waitQueue.push(new ns.UserScheduleDetailWaitQueueItem(userScheduleDetailWaitQueueItemDto, this));
        }

        this.showCompensationGroupHelp = !!this.compensationGroup && this.attendanceChangesAllowed && this.subjectCategoryID === 1;
        this.oneOffDisabledHelp = false;
        this.showPriceColum = false;
        this.showExcuseHelp = false;
        this.showUnregisterHelp = false;
        this.showRegisterHelp = false;
        this.showAmendHelp = false;
        this.showOneOffRegHelp = false;

        this.showActionRegHelp = false;
        this.showActionUnRegHelp = false;
        this.showAttendanceTypeColumn = this.subjectCategoryID === 1; // RegularCourses
        this.showAvailableAmendsColumn = this.subjectCategoryID === 1; // RegularCourses

        this.studentsAttendance = [];
        for (var s = 0; s < userScheduleDetailDto.studentsAttendance.length; s++) {
            var userScheduleDetailAttendanceDto = userScheduleDetailDto.studentsAttendance[s];
            var userScheduleDetailAttendance = new ns.UserScheduleDetailAttendance(userScheduleDetailAttendanceDto, this);
            this.studentsAttendance.push(userScheduleDetailAttendance);

            this.oneOffDisabledHelp = this.oneOffDisabledHelp || userScheduleDetailAttendance.oneOffDisabled;
            this.showPriceColum = this.showPriceColum || 
                                   (userScheduleDetailAttendance.courseAttendanceTypeID === 1 &&
                                   !!userScheduleDetailAttendance.causalPrice &&
                                   (this.attendanceChangesAllowed || userScheduleDetailAttendance.present));

            var effectivePresent = userScheduleDetailAttendance.present;
            if (!effectivePresent) {
                var waitQueuePresent = _.find(this.waitQueue, function (w) { return w.studentID === userScheduleDetailAttendance.studentID });
                effectivePresent = !!waitQueuePresent;
            }

            if (effectivePresent) {
                this.showExcuseHelp = this.attendanceChangesAllowed && this.subjectCategoryID === 1;
                this.showUnregisterHelp = this.attendanceChangesAllowed && this.subjectCategoryID === 1;
                this.showActionUnRegHelp = this.attendanceChangesAllowed && this.subjectCategoryID === 2;
            } else {
                this.showRegisterHelp = this.attendanceChangesAllowed && this.subjectCategoryID === 1;
                this.showActionRegHelp = this.attendanceChangesAllowed && this.subjectCategoryID === 2;

                if (userScheduleDetailAttendance.effectiveCourseAttendanceTypeID === 2) {
                    this.showAmendHelp = this.attendanceChangesAllowed && this.subjectCategoryID === 1;
                }

                if (userScheduleDetailAttendance.effectiveCourseAttendanceTypeID === 1) {
                    this.showOneOffRegHelp = (this.showOneOffRegHelp ||
                        (this.attendanceChangesAllowed && !userScheduleDetailAttendance.presentReadOnly)) && this.subjectCategoryID === 1;
                }
            }

        }

        this.showNoStudentsHelp = this.studentsAttendance.length === 0;
        this.oneOffDisabledHelp = this.oneOffDisabledHelp && this.attendanceChangesAllowed && this.subjectCategoryID === 1;
    }

    ns.UserScheduleDetail.prototype.getVirtualWaitQueueIndex = function (attendance, newPresent, oldPresent) {
        //var queueIndex = -1;
        var virtualIndex = -this.freeSlots;
        var a, att;


        for (var q = 0; q < this.waitQueue.length; q++) {
            var queueItem = this.waitQueue[q];

            virtualIndex = virtualIndex + 1;

            att = _.find(this.studentsAttendance, function (a) { return a.studentID === queueItem.studentID });
            if (att) {
                if (att === attendance) {
                    if (!newPresent) {
                        virtualIndex = virtualIndex - 1;
                    }
                } else {
                    if (!att.present) {
                        virtualIndex = virtualIndex - 1;
                    }
                }
            }

            if (att === attendance) {
                if (newPresent) {
                    return virtualIndex;
                } else {
                    return null;
                }
            }
        }

        for (a = 0; a < this.studentsAttendance.length; a++) {
            att = this.studentsAttendance[a];

            if (att === attendance) {
                if (newPresent && !oldPresent) {
                    // new present
                    virtualIndex = virtualIndex + 1;
                } else {
                    if (!newPresent && oldPresent) {
                        if (!_.find(this.waitQueue, function (w) { return w.studentID === att.studentID })) {
                            virtualIndex = virtualIndex - 1;
                        }
                    }
                }

            }
            else {
                if (att.present && !att.dto.present) {
                    // new present
                    virtualIndex = virtualIndex + 1;
                } else {
                    if (!att.present && att.dto.present) {
                        if (!_.find(this.waitQueue, function (w) { return w.studentID === att.studentID })) {
                            virtualIndex = virtualIndex - 1;
                        }
                    }
                }
            }

            if (att === attendance) {
                if (virtualIndex > 0 && newPresent && !oldPresent) {
                    return virtualIndex;
                } else {
                    return null;
                }
            }

        }

        return null;
    }

    ns.UserScheduleDetail.prototype.getPresentStudentsIDs = function () {

        var studentIDs = [];
        for (var a = 0; a < this.studentsAttendance.length; a++) {
            var att = this.studentsAttendance[a];
            if (att.present) {
                studentIDs.push(att.studentID);
            }
        }

        return studentIDs;
    }

    Object.defineProperty(ns.UserScheduleDetail.prototype, 'showQueueColumn', {
        enumerable: true, configurable: true,
        get: function () {

            for (var a = 0; a < this.studentsAttendance.length; a++) {
                var att = this.studentsAttendance[a];
                if (att.waitQueueIndex !== null) {
                    return true;
                }
            }

            return false;
        }
    });

    Object.defineProperty(ns.UserScheduleDetail.prototype, 'showCompensationWaitQueueHelp', {
        enumerable: true, configurable: true,
        get: function () {
            return this.showQueueColumn && this.subjectCategoryID === 1; // RegularCourses
        }
    });

    Object.defineProperty(ns.UserScheduleDetail.prototype, 'showCompensationWaitQueueForActionHelp', {
        enumerable: true, configurable: true,
        get: function () {
            return this.showQueueColumn && this.subjectCategoryID === 2; // OneOffActions
        }
    });

    Object.defineProperty(ns.UserScheduleDetail.prototype, 'isDirty', {
        enumerable: true, configurable: true,
        get: function () {

            for (var a = 0; a < this.studentsAttendance.length; a++) {
                var att = this.studentsAttendance[a];
                if (att.present !== att.dto.present) {
                    return true;
                }
            }

            return false;
        }
    });


})(webooker_schedule_models);;
var webooker_schedule_models = webooker_schedule_models || {};

(function (ns) {

    ns.UserScheduleDetailAttendance = function (userScheduleDetailAttendanceDto, userScheduleDetail) {

        this.dto = userScheduleDetailAttendanceDto;
        this.userScheduleDetail = userScheduleDetail;

        this.studentID = userScheduleDetailAttendanceDto.studentID;
        this.fullName = userScheduleDetailAttendanceDto.fullName;
        this.courseAttendanceTypeID = userScheduleDetailAttendanceDto.courseAttendanceTypeID;
        this.present = userScheduleDetailAttendanceDto.present;
        this.noOfAvailableAmends = userScheduleDetailAttendanceDto.noOfAvailableAmends;
        this.preAmendsCount = userScheduleDetailAttendanceDto.preAmendsCount;
        this.timeBoundAmendCount = userScheduleDetailAttendanceDto.timeBoundAmendCount;
        this.waitQueueReservationsCount = userScheduleDetailAttendanceDto.waitQueueReservationsCount;
        this.causalPrice = userScheduleDetailAttendanceDto.causalPrice;

        // Calculated

        this.effectiveCourseAttendanceTypeID = this.present
            ? this.courseAttendanceTypeID
            : this.noOfAvailableAmends > 0
                ? 2 // amend
                : (this.preAmendsCount - this.noOfAvailableAmends + this.timeBoundAmendCount) > 0
                    ? 2 // amend
                    : 1; // oneOff

        this.oneOffDisabled = this.effectiveCourseAttendanceTypeID === 1 && this.causalPrice == null;
        this.showPrice = this.effectiveCourseAttendanceTypeID === 1 && !!this.causalPrice &&
                         (this.userScheduleDetail.attendanceChangesAllowed || this.present);

        this.presentReadOnly =
            !this.userScheduleDetail.attendanceChangesAllowed ||
            (this.oneOffDisabled && this.effectiveCourseAttendanceTypeID === 1 && !this.present  /* OneOff */);
    }

    Object.defineProperty(ns.UserScheduleDetailAttendance.prototype, 'actualPreAmendsCount', {
        enumerable: true, configurable: true,
        get: function () {

            if (this.effectiveCourseAttendanceTypeID === 2 && (this.present !== this.dto.present)) {
                if (this.present && !this.dto.present) {
                    if (this.waitQueueIndex > 0) {
                        return this.noOfAvailableAmends <= 0
                            ? Math.max(0, this.preAmendsCount + this.noOfAvailableAmends + this.timeBoundAmendCount)
                            : this.preAmendsCount + this.timeBoundAmendCount;
                    } else {
                        return this.noOfAvailableAmends <= 0
                            ? Math.max(0, this.preAmendsCount + this.noOfAvailableAmends + this.timeBoundAmendCount - 1)
                            : this.preAmendsCount + this.timeBoundAmendCount - 1;
                    }
                }

                if (!this.present && this.dto.present) {
                    if (this.noOfAvailableAmends < 0) {
                        if (this.userScheduleDetail.attendanceChangesInTime) {
                            var virtualWaitQueueIndex = this.userScheduleDetail.getVirtualWaitQueueIndex.call(this.userScheduleDetail, this, true, true);
                            if (virtualWaitQueueIndex > 0) {
                                return Math.max(0, this.preAmendsCount + this.noOfAvailableAmends + this.timeBoundAmendCount);
                            } else {
                                return Math.max(0, this.preAmendsCount + this.noOfAvailableAmends + this.timeBoundAmendCount + 1);
                            }
                        } else {
                            return Math.max(0, this.preAmendsCount + this.noOfAvailableAmends + this.timeBoundAmendCount);
                        }
                    } else {
                        return this.preAmendsCount + this.timeBoundAmendCount;
                    }
                }

            } else {
                return this.noOfAvailableAmends < 0
                    ? Math.max(0, this.preAmendsCount + this.noOfAvailableAmends + this.timeBoundAmendCount)
                    : this.preAmendsCount + this.timeBoundAmendCount;
            }
        }
    });

    Object.defineProperty(ns.UserScheduleDetailAttendance.prototype, 'actualAmendsCount', {
        enumerable: true, configurable: true,
        get: function () {
            if ((this.effectiveCourseAttendanceTypeID === 2 || this.effectiveCourseAttendanceTypeID === 0) && (this.present !== this.dto.present)) {
                if (this.present && !this.dto.present) {
                    if (this.waitQueueIndex > 0) {
                        return this.noOfAvailableAmends;
                    } else {
                        if ((this.preAmendsCount + this.timeBoundAmendCount) > 0) {
                            return Math.max(this.noOfAvailableAmends, 0);
                        }
                        else {
                            return Math.max(this.noOfAvailableAmends - 1, 0);
                        }
                    }
                }

                if (!this.present && this.dto.present) {
                    if (this.noOfAvailableAmends < 0 || !this.userScheduleDetail.attendanceChangesInTime) {
                        return Math.max(this.noOfAvailableAmends, 0);
                    } else {
                        var studentID = this.studentID;
                        var waitQueuePresent = _.find(this.userScheduleDetail.waitQueue, function (w) { return w.studentID === studentID });
                        if (waitQueuePresent) {
                            return this.noOfAvailableAmends;
                        } else {
                            return Math.max(this.noOfAvailableAmends + 1, 0);
                        }
                    }
                }

            } else {
                return Math.max(this.noOfAvailableAmends, 0);
            }
        }
    });

    Object.defineProperty(ns.UserScheduleDetailAttendance.prototype, 'waitQueueIndex', {
        enumerable: true, configurable: true,
        get: function () {
            return this.userScheduleDetail.getVirtualWaitQueueIndex.call(this.userScheduleDetail, this, this.present, this.dto.present);
        }
    });

})(webooker_schedule_models);;
var webooker_schedule_models = webooker_schedule_models || {};

(function (ns) {

    ns.UserScheduleDetailWaitQueueItem = function (userScheduleDetailWaitQueueItemDto, userScheduleDetail) {
        this.dto = userScheduleDetailWaitQueueItemDto;
        this.userScheduleDetail = userScheduleDetail;

        this.compensationWaitQueueID = userScheduleDetailWaitQueueItemDto.compensationWaitQueueID;
        this.studentID = userScheduleDetailWaitQueueItemDto.studentID;
    }

})(webooker_schedule_models);;
'use strict';

wbApp.factory('clientSchedulerSvc', ['$resource', '$q', 'repositorySvc',
    function ($resource, $q, repositorySvc) {

        var UserSchedule = $resource('/Api/UserSchedule/:id', {}, {
            'getAllForSemester': { method: 'GET', isArray: true, url: '/Api/UserSchedule/GetAllForSemester' },
            'getUserScheduleDetail': { method: 'GET', url: '/Api/UserSchedule/GetUserScheduleDetail' },
            'setNewAttendance': { method: 'POST', url: '/Api/UserSchedule/SetNewAttendance' }
        });

        function getAllForSemesterAsync(semesterID, compensationGroupID, userID, startDate, endDate) {
            return repositorySvc.customGet('getAllForSemester', UserSchedule, {
                semesterID: semesterID,
                compensationGroupID: compensationGroupID,
                userID: userID,
                startDate: startDate,
                endDate: endDate
            });
        }

        function getUserScheduleDetail(userID, courseScheduleID) {
            return $q(function (resolve, reject) {
                repositorySvc.customGet('getUserScheduleDetail', UserSchedule, {
                    userID: userID,
                    courseScheduleID: courseScheduleID
                }).$promise.then(function (dto) {
                    resolve(new webooker_schedule_models.UserScheduleDetail(dto));
                }, function (rejectReason) {
                    reject(rejectReason);
                });
            });
        }

        function setNewAttendance(userID, courseScheduleID, userScheduleDetail) {
            var studentIDs = userScheduleDetail.getPresentStudentsIDs.call(userScheduleDetail);

            return $q(function (resolve, reject) {
                repositorySvc.customPost(
                    'setNewAttendance',
                    UserSchedule, {
                        userID: userID,
                        courseScheduleID: courseScheduleID,
                        studentIDs: studentIDs
                    },
                    resolve,
                    reject
                )
            });
        }

        return {
            getAllForSemesterAsync: getAllForSemesterAsync,
            getUserScheduleDetail: getUserScheduleDetail,
            setNewAttendance: setNewAttendance
        }
    }]);
;
wbApp.controller('TenantRegistrationCtrl', ['$window', '$scope', '$timeout', '$translate', '$http', '$modal', 'tenantInfo', 'tenantSettingSvc', 'notificationSvc',
function ($window, $scope, $timeout, $translate, $http, $modal, tenantInfo, tenantSettingSvc, notificationSvc) {

    $scope.model = {
        currency: 'CZK',
        countryCode: 'CZ'
    }

    $scope.isSaveBusy = false;
    $scope.tenantInfo = tenantInfo;
    $scope.tenantFriendlyName = tenantInfo.friendlyName;
    $scope.registerTenantHeader = $translate.instant('TXT_REGISTER_TENANT').f(tenantInfo.friendlyName);

    $scope.tabs = [
    {
        title: 'TXT_TITLE_REGISTRATION',
        template: 'tenant-registration/tenant-registration-tab.html'
    }, {
        title: 'TXT_LBL_USER',
        template: 'tenant-registration/admin-registration-tab.html'
    }, {
        title: 'TXT_LBL_SETTING',
        template: 'tenant-registration/setting-registration-tab.html'
    }];

    $scope.tabs.activeTab = 0;

    $scope.getAddress = function (viewValue) {
        if (viewValue) {
            var params =
                {
                    address: viewValue,
                    sensor: false,
                    key: 'AIzaSyDdpRFWJaEcASaUgQxTdi8i42aaCaKfS0A'
                };
            return $http.get('https://maps.googleapis.com/maps/api/geocode/json', { params: params })
            .then(function (res) {
                return res.data.results;
            });
        }
    };


    var paneCtrls = [];
    $scope.$on('$includeContentLoaded', function (event) {
        paneCtrls.push(event.targetScope.$$childTail);
        event.stopPropagation();
    });

    $scope.serverErrors = null;
    $scope.formErrors = {};

    $scope.areAllFormsValid = function () {
        return _.reduce(paneCtrls, function (sum, item) {
            return !!item.form ? sum && item.form.$valid : sum;
        }, true);
    }

    $scope.isCurrentFormValid = function () {
        if ($scope.tabs.activeTab < paneCtrls.length) {
            var form = paneCtrls[$scope.tabs.activeTab].form;
            var isFormValid = !form || form.$valid;
            if (isFormValid) {
                $scope.formErrors = {};
                return true;
            } else {
                $scope.formErrors = form.$error;
            }

        }
        return false;
    }

    $scope.isPrevButtonVisible = function () {
        return $scope.tabs.activeTab > 0;
    }

    $scope.onPrevBtnClick = function () {
        if ($scope.isPrevButtonVisible()) {
            $scope.tabs.activeTab = $scope.tabs.activeTab - 1;
        }
    }

    $scope.isNextButtonVisible = function () {
        return ($scope.tabs.activeTab < ($scope.tabs.length - 1));
    }

    $scope.onNextBtnClick = function () {
        if ($scope.isCurrentFormValid()) {
            if ($scope.isNextButtonVisible()) {
                $scope.tabs.activeTab = $scope.tabs.activeTab + 1;
            }
        }
    }

    $scope.isSaveButtonVisible = function () {
        return $scope.tabs.activeTab === ($scope.tabs.length - 1);
    }

    $scope.isSaveButtonDisabled = function () {
        return $scope.isSaveBusy || !$scope.areAllFormsValid();
    }

    var confirmTenantCreatedDlg = $modal({
        templateUrl: 'tenant-registration/confirm-tenant-crearted-dialog.html',
        show: false,
        backdrop: true,
        scope: $scope
    });

    function swithToFirstInvalidForm() {
        var idx = _.findIndex(paneCtrls, function (item) { return !item.form.$valid; });
        if (idx !== -1) {
            $scope.tabs.activeTab = idx;
            $scope.isCurrentFormValid();
        }
    }

    $scope.onSaveBtnClick = function () {
        if ($scope.isSaveBusy) {
            return;
        }

        if (!$scope.isCurrentFormValid()) {
            return;
        }

        if (!$scope.areAllFormsValid()) {
            swithToFirstInvalidForm();
            return;
        }

        $scope.isSaveBusy = true;

        $http({
            method: 'POST',
            url: '/Api/TenantRegistration/RegisterTenant',
            data: {
                model: $scope.model
            }
        }).success(function (data, status, headers, config) {
            
            confirmTenantCreatedDlg.$promise.then(function () {
                confirmTenantCreatedDlg.$scope.tenantFriendlyName = $scope.model.friendlyName;
                confirmTenantCreatedDlg.$scope.tenantUrl = "https://" + $scope.model.tenantName + tenantInfo.domain;
                confirmTenantCreatedDlg.show();
            });

        }).error(function (data, status, headers, config) {
            $scope.isSaveBusy = false;

            notificationSvc.notifyError(
                $translate.instant('TXT_ALERT_SERVER_ERROR'),
                notificationSvc.translateError(data));
        });
    }

    $scope.onConfirmTenantCreatedOkClick = function () {
        $window.location.href = "https://" + $scope.model.tenantName + tenantInfo.domain;
        $scope.isSaveBusy = false;
    }
}]);;
!function(e,t,n){"use strict";angular.module("wb.directives",["mgcrea.ngStrap","pascalprecht.translate"]),angular.module("wb.directives").directive("wbBusyIndicator",["$tooltip",function(e){return{restrict:"A",priority:1e5,scope:!0,link:function(t,n,r){var o=n.html(),a=!1,i=!1,c=null;t.tooltipTop=100,t.$watch(r.wbBusyIndicator,function(t){if(t){if(r.wbBusyIndicatorOverlay){var s=Math.min(350,n.height()/3);i=!0;c=e(n,{trigger:"manual",placement:"top center",template:"busyIndicator/templates/wb-busy-indicator.tpl.html"}),c.$promise.then(function(){c.show(),n.next().css({"margin-top":s+"px"})})}else o=n.html(),n.html("<i class='fa-lg fa fa-spinner fa-spin'></i>");a=!0}else a&&(i?c.$promise.then(function(){c.hide()}):n.html(o))},!0)}}}]),angular.module("wb.directives").directive("wbCheckboxBitmaskEdit",function(){return{restrict:"AE",require:"ngModel",priority:1,scope:{ngModel:"=ngModel",value:"="},replace:!0,templateUrl:"checkbox/templates/wb-checkbox-bitmask-edit.tpl.html",link:function(e,t,n,r){e.spanChecked=0,e.spanClick=function(n){r.$setViewValue(e.spanChecked?r.$viewValue&~e.value:r.$viewValue|e.value,n.type),e.spanChecked=(r.$viewValue&e.value)>0,n.preventDefault(),$(t).focus()},r.$render=function(){e.spanChecked=(r.$viewValue&e.value)>0}}}}),angular.module("wb.directives").directive("wbCheckboxEdit",function(){return{restrict:"A",require:"ngModel",priority:1,scope:{ngModel:"=ngModel",indeterminate:"="},replace:!0,templateUrl:"checkbox/templates/wb-checkbox-edit.tpl.html",link:function(e,t,n,r){function o(e){return 0===e?1:0}function a(e){return 1===e||0!==e&&("indeterminate"===e&&e)}function i(e){return!0===e||"true"===e?1:!1===e||"false"===e?0:"indeterminate"===e?e:0}e.spanClick=function(n){e.spanChecked=o(e.spanChecked),r.$setViewValue(a(e.spanChecked),n.type),n.preventDefault(),$(t).focus()},r.$render=function(){e.spanChecked=i(r.$viewValue)},e.spanChecked=i(r.$viewValue),r.$render()}}}),angular.module("wb.directives").directive("wbRadioEdit",function(){return{restrict:"A",require:"ngModel",priority:1,scope:{ngModel:"=ngModel",value:"="},replace:!0,templateUrl:"checkbox/templates/wb-radio-edit.tpl.html",link:function(e,t,n,r){e.spanChecked=0,e.spanClick=function(n){r.$setViewValue(e.value,n.type),e.spanChecked=!0,n.preventDefault(),$(t).focus()},r.$render=function(){e.spanChecked=r.$viewValue==e.value}}}}),angular.module("wb.directives").config(["$translateProvider",function(e){e.translations("cs",{TXT_TODAY:"Dnes",TXT_BUSY:"Prosím čekejte",TXT_LBL_START_DATE:"Začátek",TXT_LBL_END_DATE:"Konec",TXT_LBL_EMPLOYEE:"Učitel",TXT_LBL_NAME:"Název",TXT_LBL_FILLED:"Obsazeno",TXT_NOTE:"Poznámka",TXT_RECURRENCE_TYPE_DAILY:"Denně",TXT_RECURRENCE_TYPE_WEEKLY:"Týdně",TXT_RECURRENCE_TYPE_MONTHLY:"Měsíčně",TXT_RECURRENCE_TYPE_YEARLY:"Ročně",TXT_RECURRENCE_WEEK_DAYS_SUNDAY:"Ne",TXT_RECURRENCE_WEEK_DAYS_MONDAY:"Po",TXT_RECURRENCE_WEEK_DAYS_TUESDAY:"Út",TXT_RECURRENCE_WEEK_DAYS_WEDNESDAY:"St",TXT_RECURRENCE_WEEK_DAYS_THURSDAY:"Čt",TXT_RECURRENCE_WEEK_DAYS_FRIDAY:"Pá",TXT_RECURRENCE_WEEK_DAYS_SATURDAY:"So",TXT_RECURRENCE_WEEK_EVERY_1:"Opakuje se každý",TXT_RECURRENCE_WEEK_EVERY_2:"Opakuje se každé",TXT_RECURRENCE_WEEK_EVERY_3:"Opakuje se každých",TXT_RECURRENCE_WEEK_1:"týden",TXT_RECURRENCE_WEEK_2:"týdny",TXT_RECURRENCE_WEEK_3:"týdnů",TXT_RECURRENCE_DAY_1:"den",TXT_RECURRENCE_DAY_2:"dny",TXT_RECURRENCE_DAY_3:"dnů",TXT_RECURRENCE_WEEK_WORKDAY:"pracovní den",TXT_RECURRENCE_MONTH_EVERY_1:"Každý",TXT_RECURRENCE_MONTH_EVERY_2:"Každé",TXT_RECURRENCE_MONTH_EVERY_3:"Každých",TXT_RECURRENCE_MONTH_FROM_EVERY:"každého",TXT_RECURRENCE_MONTH_MONTH:"měsíce",TXT_RECURRENCE_WEEK_OF_MONTH_FIRST:"první",TXT_RECURRENCE_WEEK_OF_MONTH_SECOND:"druhý",TXT_RECURRENCE_WEEK_OF_MONTH_THIRD:"třetí",TXT_RECURRENCE_WEEK_OF_MONTH_FOURTH:"čtvrtý",TXT_RECURRENCE_WEEK_OF_MONTH_LAST:"poslední",TXT_RECURRENCE_MONTH_JANUARY:"leden",TXT_RECURRENCE_MONTH_FEBRUARY:"únor",TXT_RECURRENCE_MONTH_MARCH:"březen",TXT_RECURRENCE_MONTH_APRIL:"duben",TXT_RECURRENCE_MONTH_MAY:"květen",TXT_RECURRENCE_MONTH_JUNE:"červen",TXT_RECURRENCE_MONTH_JULY:"červenec",TXT_RECURRENCE_MONTH_AUGUST:"srpen",TXT_RECURRENCE_MONTH_SEPTEMBER:"září",TXT_RECURRENCE_MONTH_OCTOBER:"říjen",TXT_RECURRENCE_MONTH_NOVEMBER:"listopad",TXT_RECURRENCE_MONTH_DECEMBER:"prosinec",TXT_RECURRENCE_IN:"v",TXT_RECURRENCE_ENDS_AFTER:"Končí po",TXT_RECURRENCE_ENDS_AT:"Končí dne",TXT_RECURRENCE_OCCURRENCES:"výskytech"})}]),angular.module("wb.directives").config(["$translateProvider",function(e){e.translations("en",{TXT_TODAY:"Today",TXT_BUSY:"Please wait",TXT_LBL_START_DATE:"Start",TXT_LBL_END_DATE:"End",TXT_LBL_EMPLOYEE:"Teacher",TXT_LBL_NAME:"Name",TXT_LBL_FILLED:"Filled",TXT_NOTE:"Note",TXT_RECURRENCE_TYPE_DAILY:"Daily",TXT_RECURRENCE_TYPE_WEEKLY:"Weekly",TXT_RECURRENCE_TYPE_MONTHLY:"Monthly",TXT_RECURRENCE_TYPE_YEARLY:"Yearly",TXT_RECURRENCE_WEEK_DAYS_SUNDAY:"Su",TXT_RECURRENCE_WEEK_DAYS_MONDAY:"Mo",TXT_RECURRENCE_WEEK_DAYS_TUESDAY:"Tu",TXT_RECURRENCE_WEEK_DAYS_WEDNESDAY:"We",TXT_RECURRENCE_WEEK_DAYS_THURSDAY:"Th",TXT_RECURRENCE_WEEK_DAYS_FRIDAY:"Fr",TXT_RECURRENCE_WEEK_DAYS_SATURDAY:"Sa",TXT_RECURRENCE_WEEK_EVERY_1:"Repeats every",TXT_RECURRENCE_WEEK_EVERY_2:"Repeats every",TXT_RECURRENCE_WEEK_EVERY_3:"Repeats every",TXT_RECURRENCE_WEEK_1:"week",TXT_RECURRENCE_WEEK_2:"weeks",TXT_RECURRENCE_WEEK_3:"weeks",TXT_RECURRENCE_DAY_1:"day",TXT_RECURRENCE_DAY_2:"days",TXT_RECURRENCE_DAY_3:"days",TXT_RECURRENCE_WEEK_WORKDAY:"work day",TXT_RECURRENCE_MONTH_EVERY_1:"Every",TXT_RECURRENCE_MONTH_EVERY_2:"Every",TXT_RECURRENCE_MONTH_EVERY_3:"Every",TXT_RECURRENCE_MONTH_FROM_EVERY:"on every",TXT_RECURRENCE_MONTH_MONTH:"month",TXT_RECURRENCE_WEEK_OF_MONTH_FIRST:"first",TXT_RECURRENCE_WEEK_OF_MONTH_SECOND:"second",TXT_RECURRENCE_WEEK_OF_MONTH_THIRD:"third",TXT_RECURRENCE_WEEK_OF_MONTH_FOURTH:"fourth",TXT_RECURRENCE_WEEK_OF_MONTH_LAST:"last",TXT_RECURRENCE_MONTH_JANUARY:"january",TXT_RECURRENCE_MONTH_FEBRUARY:"february",TXT_RECURRENCE_MONTH_MARCH:"march",TXT_RECURRENCE_MONTH_APRIL:"april",TXT_RECURRENCE_MONTH_MAY:"may",TXT_RECURRENCE_MONTH_JUNE:"june",TXT_RECURRENCE_MONTH_JULY:"july",TXT_RECURRENCE_MONTH_AUGUST:"august",TXT_RECURRENCE_MONTH_SEPTEMBER:"september",TXT_RECURRENCE_MONTH_OCTOBER:"october",TXT_RECURRENCE_MONTH_NOVEMBER:"november",TXT_RECURRENCE_MONTH_DECEMBER:"december",TXT_RECURRENCE_IN:"in",TXT_RECURRENCE_ENDS_AFTER:"Ends after",TXT_RECURRENCE_ENDS_AT:"Ends at",TXT_RECURRENCE_OCCURRENCES:"occurrences"})}]),angular.module("wb.directives").directive("wbRightClick",["$parse",function(e){return function(t,n,r){var o=e(r.wbRightClick);n.bind("contextmenu",function(e){t.$apply(function(){e.preventDefault(),o(t,{$event:e})})})}}]),angular.module("wb.directives").directive("wbScheduler",["$timeout","$dropdown","$translate","$rootScope","wbSchedulerSvc",function(e,t,n,r,o){var a={weekView:!0,autoHourRange:!1,startHour:8,endHour:20,scale:15,width:"1000px",noHeader:!1,showWeekend:!1,toolTipDelay:800,toolTipTemplateUrl:"scheduler/templates/wb-scheduler-tooltip.tpl.html",toolTipTrigger:"hover",showRecurrence:!1,selectedResourceID:0,startDate:new Date,columns:[],resources:[],rows:[],events:[],commands:[],selectByBlocks:1,maximumSelectedBlocks:-1,startTimeType:-1};return{restrict:"E",scope:{sourceSettings:"=settings",actionClicked:"&onActionClicked",selectionChanged:"&onSelectionChanged"},templateUrl:"scheduler/templates/wb-scheduler.tpl.html",replace:!0,controller:["$scope",function(i){function c(){R=null,_=null,T=!1,s(R,_)}function s(t,n){if(!(t&&n&&E&&i.sourceSettings.weekView))return void Object.keys(i.selection).forEach(function(e){delete i.selection[e]});var r,a,c,s,u={};t.colIndex<n.colIndex?(r=t.colIndex,a=n.colIndex,c=t.rowIndex,s=n.rowIndex):t.colIndex===n.colIndex?(r=t.colIndex,a=t.colIndex,t.rowIndex<n.rowIndex?(c=t.rowIndex,s=n.rowIndex):(c=n.rowIndex,s=t.rowIndex)):(r=n.colIndex,a=t.colIndex,c=n.rowIndex,s=t.rowIndex);for(var l=r;l<=a;l++)for(var d=l===r?c:0,R=l===a?s:i.option.rows.length,_=d;_<=R;_++)u[_+"-"+l]=!0;if(Object.keys(i.selection).forEach(function(e){u[e]||delete i.selection[e]}),Object.keys(u).forEach(function(e){i.selection[e]=!0}),i.selectionChanged){var T=o.getStartEndDateBySelection(i.option,t,n);e(function(){i.selectionChanged({selection:T})})}}function u(){d&&d.destroy&&d.destroy(),d=null}function l(o,a,c,s){u();var l=[];angular.forEach(i.sourceSettings.commands,function(e){if(i.sourceSettings.commands&&i.sourceSettings.commands.length){var t=!0;e.isVisible&&(t=e.isVisible(a,c,s)),t&&l.push({text:n.instant(e.text),click:angular.bind(this,function(t,n,r){u(),e.callback(t,n,r)},a,c,s)})}});var E=r.$new(!0);E.content=l,d=t(angular.element(o.target),{scope:E,placement:"auto bottom",container:"body",onHide:function(){u()}}),d.$promise.then(function(){e(function(){d.show()})})}var d=null;i.$watch("sourceSettings",function(e){i.option=angular.extend({},angular.copy(a),e),o.calculateColumns(i.option),o.calculateRows(i.option),o.calculateSizes(i.option),o.calculateEvents(i.option),o.calculateAvailability(i.option),i.toolTipEnabled=!0},!0),i.selection={};var E=!!i.sourceSettings.commands&&!!i.sourceSettings.commands.length,R=null,_=null,T=!1;i.onCellMouseDown=function(e,t){u(),R={rowIndex:e,colIndex:t},_={rowIndex:e+(i.option.selectByBlocks-1),colIndex:t},o.canSelectRegion(i.option,R,_)?(T=!0,s(R,_)):c()},i.onCellMouseMove=function(e,t){T&&Math.abs(R.rowIndex-e)>0&&Math.abs(R.rowIndex-e+1)%i.option.selectByBlocks==0&&(-1!==i.option.maximumSelectedBlocks?R.colIndex===t&&Math.abs(R.rowIndex-e)<i.option.maximumSelectedBlocks&&(_={rowIndex:e,colIndex:t},o.canSelectRegion(i.option,R,_)&&s(R,_)):(_={rowIndex:e,colIndex:t},o.canSelectRegion(i.option,R,_)&&s(R,_)))},i.onCellMouseUp=function(e){if(T=!1,R&&_){var t=o.getStartEndDateBySelection(i.option,R,_);l(e,null,t.startDate,t.endDate)}};var m=!1,f=null;i.onSelectEvent=function(t,n){if(c(),u(),i.option.selectedAction=n.origAction,m&&f===n)return m=!1,f=null,i.toolTipEnabled=!1,e(function(){i.toolTipEnabled=!0},5e3),void l(t,n,n.startTime,n.endTime);m=!0,f=n,e(function(){m=!1},800),i.actionClicked&&(i.toolTipEnabled=!1,e(function(){i.actionClicked({action:i.option.selectedAction})}),e(function(){i.toolTipEnabled=!0},5e3))}}]}}]),angular.module("wb.directives").directive("wbSchedulerDatePicker",["wbSchedulerSvc",function(e){return{restrict:"E",scope:{sourceSettings:"=settings",dateChanged:"&onDateChanged"},templateUrl:"scheduler/templates/wb-scheduler-date-picker.tpl.html",controller:["$scope",function(t){t.onPrevBtnClick=function(){var n=e.selectPrevDate(t.sourceSettings);t.dateChanged&&t.dateChanged(n)},t.onNextBtnClick=function(){var n=e.selectNextDate(t.sourceSettings);t.dateChanged&&t.dateChanged(n)},t.onTodayBtnClick=function(){var n=e.selectToday(t.sourceSettings);t.dateChanged&&t.dateChanged(n)},t.onDatePickerChange=function(){var n=e.fixSelectedDate(t.sourceSettings);t.dateChanged&&t.dateChanged(n)}}]}}]),angular.module("wb.directives").directive("wbSchedulerRecurrence",["wbSchedulerSvc",function(e){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence.tpl.html",link:function(t,n,r,o){t.model={},o.$render=function(){t.model=e.mapRecurrenceDtoToModel(t.model,o.$viewValue)},t.$watch("ngModel",function(n){t.model=e.mapRecurrenceDtoToModel(t.model,o.$viewValue)},!0),t.$watch("model",function(t){o.$setViewValue(e.mapRecurrenceModelToDto(o.$viewValue,t))},!0)}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceDayPeriodicity",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-day-periodicity.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceDayWeekDays",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-day-week-days.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceMonthCombo",["$timeout","$translate",function(e,t){function n(e){if(e)return t.instant(e.text)}function r(e){return t.instant(e.text)}return{restrict:"AE",require:"ngModel",link:function(t,o,a,i){e(function(){$(o).select2({formatResult:n,formatSelection:r,dropdownAutoWidth:!0,allowClear:!1,minimumResultsForSearch:-1,data:[{id:1,text:"TXT_RECURRENCE_MONTH_JANUARY"},{id:2,text:"TXT_RECURRENCE_MONTH_FEBRUARY"},{id:3,text:"TXT_RECURRENCE_MONTH_MARCH"},{id:4,text:"TXT_RECURRENCE_MONTH_APRIL"},{id:5,text:"TXT_RECURRENCE_MONTH_MAY"},{id:6,text:"TXT_RECURRENCE_MONTH_JUNE"},{id:7,text:"TXT_RECURRENCE_MONTH_JULY"},{id:8,text:"TXT_RECURRENCE_MONTH_AUGUST"},{id:9,text:"TXT_RECURRENCE_MONTH_SEPTEMBER"},{id:10,text:"TXT_RECURRENCE_MONTH_OCTOBER"},{id:11,text:"TXT_RECURRENCE_MONTH_NOVEMBER"},{id:12,text:"TXT_RECURRENCE_MONTH_DECEMBER"}]}),i.$render=function(){o.select2("val",i.$viewValue)},i.$parsers.unshift(function(e){return e?parseInt(e):0}),i.$formatters.unshift(function(e){return e?e+"":"0"}),o.on("change",function(){t.$apply(function(){i.$setViewValue(o.select2("val"))})}),a.$observe("disabled",function(e){o.select2("enable",!e)}),a.$observe("readonly",function(e){o.select2("readonly",!!e)}),o.bind("$destroy",function(){o.select2("destroy")}),i.$render()},1)}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceMonthPeriodicity",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-month-periodicity.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceMonthWeekDays",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-month-week-days.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceWeekDaysCombo",["$timeout","$translate",function(e,t){function n(e){if(e)return t.instant(e.text)}function r(e){return t.instant(e.text)}return{restrict:"AE",require:"ngModel",link:function(t,o,a,i){e(function(){$(o).select2({formatResult:n,formatSelection:r,dropdownAutoWidth:!0,allowClear:!1,minimumResultsForSearch:-1,data:[{id:1,text:"TXT_RECURRENCE_WEEK_DAYS_SUNDAY"},{id:2,text:"TXT_RECURRENCE_WEEK_DAYS_MONDAY"},{id:4,text:"TXT_RECURRENCE_WEEK_DAYS_TUESDAY"},{id:8,text:"TXT_RECURRENCE_WEEK_DAYS_WEDNESDAY"},{id:16,text:"TXT_RECURRENCE_WEEK_DAYS_THURSDAY"},{id:32,text:"TXT_RECURRENCE_WEEK_DAYS_FRIDAY"},{id:64,text:"TXT_RECURRENCE_WEEK_DAYS_SATURDAY"}]}),i.$render=function(){o.select2("val",i.$viewValue)},i.$parsers.unshift(function(e){return e?parseInt(e):0}),i.$formatters.unshift(function(e){return e?e+"":"0"}),o.on("change",function(){t.$apply(function(){i.$setViewValue(o.select2("val"))})}),a.$observe("disabled",function(e){o.select2("enable",!e)}),a.$observe("readonly",function(e){o.select2("readonly",!!e)}),o.bind("$destroy",function(){o.select2("destroy")}),i.$render()},1)}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceWeekOfMonthCombo",["$timeout","$translate",function(e,t){function n(e){if(e)return t.instant(e.text)}function r(e){return t.instant(e.text)}return{restrict:"AE",require:"ngModel",link:function(t,o,a,i){e(function(){$(o).select2({formatResult:n,formatSelection:r,dropdownAutoWidth:!0,allowClear:!1,minimumResultsForSearch:-1,data:[{id:1,text:"TXT_RECURRENCE_WEEK_OF_MONTH_FIRST"},{id:2,text:"TXT_RECURRENCE_WEEK_OF_MONTH_SECOND"},{id:3,text:"TXT_RECURRENCE_WEEK_OF_MONTH_THIRD"},{id:4,text:"TXT_RECURRENCE_WEEK_OF_MONTH_FOURTH"},{id:5,text:"TXT_RECURRENCE_WEEK_OF_MONTH_LAST"}]}),i.$render=function(){o.select2("val",i.$viewValue)},i.$parsers.unshift(function(e){return e?parseInt(e):0}),i.$formatters.unshift(function(e){return e?e+"":"0"}),o.on("change",function(){t.$apply(function(){i.$setViewValue(o.select2("val"))})}),a.$observe("disabled",function(e){o.select2("enable",!e)}),a.$observe("readonly",function(e){o.select2("readonly",!!e)}),o.bind("$destroy",function(){o.select2("destroy")}),i.$render()},1)}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceWeekPeriodicity",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-week-periodicity.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceWeekWeekDays",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-week-week-days.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceYearPeriodicity",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-year-periodicity.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerRecurrenceYearWeekDays",[function(){return{restrict:"AE",require:"ngModel",scope:{ngModel:"=ngModel"},templateUrl:"scheduler/templates/wb-scheduler-recurrence-year-week-days.tpl.html",link:function(e,t,n,r){}}}]),angular.module("wb.directives").directive("wbSchedulerResourceCombo",["$timeout","wbSchedulerSvc",function(e,t){function n(e){if(e)return e.name}return{restrict:"E",scope:{sourceSettings:"=settings"},replace:!0,priority:1,link:function(r,o,a){function i(e){if(!e)return"";var n=t.getSelectedResources(r.sourceSettings,t.getMappedResourceID(r.sourceSettings.resourcesMapping,e)),o=null;return angular.forEach(n,function(e){null===o?o=e.name:o+=", "+e.name}),o||""}var c=r.sourceSettings.weekView,s=r.sourceSettings.visibleResources;e(function(){$(o).select2({minimumResultsForSearch:-1,formatResult:n,formatSelection:i,id:function(e){return t.getMappedResourceID(r.sourceSettings.resourcesMapping,e)},data:r.sourceSettings.resources}),o.on("change",function(e){r.$apply(function(){r.sourceSettings.selectedResourceID=parseInt(e.val||"0")})}),r.$watch("sourceSettings",function(e){var n=parseInt($(o).select2("val")||"0"),a=t.getValidSelectedResourceID(e,e.selectedResourceID);a===n&&c===r.sourceSettings.weekView&&s===r.sourceSettings.visibleResources||(c=r.sourceSettings.weekView,s=r.sourceSettings.visibleResources,r.sourceSettings.selectedResourceID=a||0,$(o).select2("val",a?a+"":"0"))},!0),o.bind("$destroy",function(){o.select2("destroy")}),a.$observe("disabled",function(e){o.select2("enable",!e)}),a.$observe("readonly",function(e){o.select2("readonly",!!e)})})}}}]),angular.module("wb.directives").factory("wbSchedulerSvc",["$filter",function(e){function t(e,t){for(var n=moment(t.startDate).startOf("day"),r=0;r<e.columns.length;r++){var o=e.columns[r];if(moment(o.date).isSame(n)&&t.resourceID==o.resourceID)return r}return-1}function n(e,t,n,r,o){var a=t*(60/e.scale)+n/e.scale;return 0>a?{startTime:0,startOverflow:!0,startOverflowDay:moment(r).startOf("day").isBefore(moment(o).startOf("day"))}:{startTime:a,startOverflow:!1,startOverflowDay:!1}}function r(e,t,n,r,o){var a=60/e.scale*(e.endHour-e.startHour),i=t*(60/e.scale)+n/e.scale;return a<i?{endTime:a,endOverflow:!0,endOverflowDay:moment(r).startOf("day").isAfter(moment(o).startOf("day"))}:{endTime:i,endOverflow:!1,endOverflowDay:!1}}function o(e,n,r){var o=t(e,n);if(-1!==o){var a=moment(n.startDate),i=moment(n.endDate),c=a.hour()-e.startHour,s=a.minute(),u=i.hour()-e.startHour,l=i.minute();u<0||0===u&&0===l||c>=e.endHour-e.startHour||(n.startHour=c,n.startMinute=s,n.endHour=u,n.endMinute=l,n.column=o,r.push(n))}}function a(e,t){var n=[];return angular.forEach(t,function(t){var r=moment(t.startDate),a=moment(t.endDate);if(!r.isAfter(a))for(var i=moment(t.startDate).startOf("day"),c=moment(t.endDate).startOf("day"),s=moment(t.startDate),u=moment(t.endDate);;){var l=moment(s).startOf("day");l.isAfter(i)&&(s=l),l.isBefore(c)?u=moment(s).endOf("day"):(u=moment(l),u.set("hour",a.get("hour")),u.set("minute",a.get("minute")),u.set("second",a.get("second")));var d=t[m(e.actionsMapping)],E={startDate:s.toDate(),endDate:u.toDate(),resourceID:d,origAction:t};if(o(e,E,n),c.isSame(l))break;s.add(1,"days").startOf("day")}}),_.sortBy(n,function(e){return 1e3*e.column+60*e.startHour+e.startMinute})}function i(e){var t=[];if(e.events.length>1)for(var n=1;n<e.events.length;n++){var r=e.events[n-1],o=e.events[n];if(o.start<r.end&&o.column===r.column)0===t.length?(t.push(r),t.push(o)):t.push(o);else if(t.length>1){for(var a=0;a<t.length;a++){var i=t[a];i.noOfSubColumns=t.length,i.subColumn=a}t=[]}}t.length>1&&angular.forEach(t,function(e,n){e.noOfSubColumns=t.length,e.subColumn=n})}function c(e,t){var o=a(e,t);angular.forEach(o,function(t){var o=n(e,t.startHour,t.startMinute,t.origAction.startDate,e.columns[t.column].date),a=r(e,t.endHour,t.endMinute,t.origAction.endDate,e.columns[t.column].date),i={column:t.column,noOfSubColumns:1,subColumn:0,start:o.startTime,startOverflow:o.startOverflow,startOverflowDay:o.startOverflowDay,end:a.endTime,endOverflow:a.endOverflow,endOverflowDay:a.endOverflowDay,name:t.origAction[T(e.actionsMapping,"name")],status:t.origAction.status||1,type:t.origAction.type||1,startTime:t.origAction.startDate,endTime:t.origAction.endDate,teacher:t.origAction[T(e.actionsMapping,"teacher")],filled:t.origAction[T(e.actionsMapping,"filled")],showWaitQueue:t.origAction.showWaitQueue,showActionNote:t.origAction.showActionNote,origAction:t.origAction,notes:t.origAction[T(e.actionsMapping,"notes")],recurrenceType:t.origAction[T(e.actionsMapping,"recurrenceType")]};e.events.push(i)}),i(e)}function s(e){c(e,e.actions)}function u(e){var t={startDate:e.startDate,endDate:e.startDate};return e.weekView?(e.startDate=moment(e.startDate).startOf("isoWeek").add(-7,"d").toDate(),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(7,"d").toDate()):(e.startDate=moment(e.startDate).startOf("day").add(-1,"d").toDate(),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(1,"d").toDate()),t}function l(e){var t={startDate:e.startDate,endDate:e.startDate};return e.weekView?(e.startDate=moment(e.startDate).startOf("isoWeek").add(7,"d").toDate(),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(7,"d").toDate()):(e.startDate=moment(e.startDate).startOf("day").add(1,"d").toDate(),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(1,"d").toDate()),t}function d(e){var t={startDate:e.startDate,endDate:e.startDate};return e.weekView?(e.startDate=moment().startOf("isoWeek").toDate(),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(7,"d").toDate()):(e.startDate=moment().startOf("day").toDate(),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(1,"d").toDate()),t}function E(e){var t={startDate:e.startDate,endDate:e.startDate};if(e.weekView){var n=moment(e.startDate).startOf("isoweek"),r=moment(e.startDate);n.isSame(r)||(e.startDate=n.toDate()),t.startDate=e.startDate,t.endDate=moment(e.startDate).add(7,"d").toDate()}else t.endDate=moment(e.startDate).add(1,"d").toDate();return t}function R(e,t,n){for(var r=n.clone().isoWeekday(6).startOf("day"),o=n.clone().isoWeekday(7).endOf("day"),a=0;a<e.actions.length;a++){var i=e.actions[a],c=moment(i.startDate),s=moment(i.endDate);if(c.isBefore(o)&&s.isAfter(r)&&_.find(t,function(t){return i[T(e.actionsMapping,"resourceID")]==t[T(e.recourcesMapping,"resourceID")]}))return!0}return!1}function T(e,t){return e&&e[t]?e[t]:t}function m(e){return T(e,"resourceID")}function f(e,t){return e&&e.resourceID?t[e.resourceID]:t.resourceID}function p(e,t){var n={};n[m(e.resourcesMapping)]=t;var r=t?_.findIndex(e.resources,n):0;return r<0&&(r=0),r}function C(e,t){if(e.resources.length){var n=p(e,t);return e.resources[n][m(e.resourcesMapping)]}return t}function h(e,t){var n,r=[],o=p(e,t);n=e.weekView?1:Math.min(e.visibleResources,e.resources.length)||1;for(var a=0;a<n;a++){var i=o+a;if(0!==e.resources.length){var c=e.resources[i%e.resources.length];r.push({name:c.name,resourceID:c[m(e.resourcesMapping)],origResource:c})}else{var s={name:"",origResource:null};s[m(e.resourcesMapping)]=0,r.push(s)}}return r}function D(t){var n=moment().startOf("day");t.todayIndex=-1;var r,o,a=h(t,t.selectedResourceID);t.weekView?(o=moment(t.startDate).startOf("isoWeek"),r=t.showWeekend||R(t,a,o)?7:5):(r=1,o=moment(t.startDate).startOf("day"));for(var i=0;i<r;i++){n.isSame(o)&&(t.todayIndex=i);for(var c=o.clone().toDate(),s=0;s<a.length;s++){var u=a[s];t.columns.push({date:c,resourceID:u.resourceID,resourceName:u.name,caption:t.weekView?e("date")(c,"EEE d. MMM"):u.name})}o.add(1,"days")}}function v(e,t,n){if(!e.availability)return!0;for(var r=t.colIndex>n.colIndex||t.colIndex==n.colIndex&&t.rowIndex>n.rowIndex,o=r?n.rowIndex:t.rowIndex,a=r?n.colIndex:t.colIndex,i=r?t.rowIndex:n.rowIndex,c=r?t.colIndex:n.colIndex,s=o;a<=c&&!(a>=e.columns.length);){for(i=a<c?e.rows.length:n.rowIndex;o<=i;){if(!e.availabilityObj[o+"-"+a])return!1;o+=1}a+=1,o=0}switch(e.startTimeType){case 1:break;case 2:if(s%2!=0)return!1;break;case 3:if(s%2!=1)return!1}return!0}function w(e){e.availabilityObj={};var t;t=e.weekView?moment(e.startDate).startOf("isoWeek"):moment(e.startDate).startOf("day"),_.forEach(e.availability||[],function(n){for(var r=moment(n.start),o=moment(n.end),a=r.diff(t,"days"),i=moment(r).subtract(e.startHour,"hours"),c=i.hour()*e.noOfSubRows+i.minute()/e.scale,s=moment(o).subtract(e.startHour,"hours"),u=s.hour()*e.noOfSubRows+s.minute()/e.scale,l=c;l<u;l++)e.availabilityObj[l+"-"+a]=!0})}function g(e,t){return e.columns[t].date}function y(e,t,n){var r=e.rows[t];return n?{hour:r.hour,minute:r.subIndex*(60/e.noOfSubRows)}:{hour:r.hour,minute:(r.subIndex+1)*(60/e.noOfSubRows)}}function N(e,t,n,r){var o=g(e,t),a=y(e,n,r);return moment(o).startOf("day").add(a.hour,"h").add(a.minute,"m").toDate()}function M(e,t,n){return t.colIndex<n.colIndex||t.colIndex===n.colIndex&&t.rowIndex<n.rowIndex?{startDate:N(e,t.colIndex,t.rowIndex,!0),endDate:N(e,n.colIndex,n.rowIndex,!1)}:{startDate:N(e,n.colIndex,n.rowIndex,!0),endDate:N(e,t.colIndex,t.rowIndex,!1)}}function O(e){for(var t=[],n=[],r=e.startHour||8,o=e.endHour||20,a=0;a<e.actions.length;a++)for(var i=e.actions[a],c=moment(i.startDate),s=moment(i.endDate),u=c.clone().startOf("day"),l=s.clone().startOf("day"),d=0;d<e.columns.length;d++){var E=e.columns[d],R=moment(E.date),m=i[T(e.actionsMapping,"resourceID")];m==E.resourceID&&(R.isSame(u)&&t.push(i),R.isSame(l)&&n.push(i))}var f,p;if(t.length>0){var C=_.sortBy(t,function(e){return 60*moment(e.startDate).hour()+moment(e.startDate).minute()});f=moment(C[0].startDate),p=moment(C[C.length-1].startDate),e.autoHourRange?r=f.hour():(r>f.hour()&&(r=f.hour()),o<p.hour()&&(o=p.hour(),p.minute()>0&&(o+=1)))}if(n.length>0){var h=_.sortBy(n,function(e){return 60*moment(e.endDate).hour()+moment(e.endDate).minute()});f=moment(h[0].endDate),p=moment(h[h.length-1].endDate),e.autoHourRange?(o=p.hour(),p.minute()>0&&(o+=1)):(o<p.hour()&&(o=p.hour(),p.minute()>0&&(o+=1)),r>f.hour()&&(r=f.hour()))}return e.autoHourRange&&o-r<3&&(o=r+3),!e.autoHourRange||t.length||n.length||(o=r+3),{startHour:r,endHour:o}}function b(e){var t=Math.ceil(60/e.scale);e.noOfSubRows=t;var n=O(e);e.startHour=n.startHour,e.endHour=n.endHour;for(var r=e.startHour;r<e.endHour;r++)for(var o=0;o<t;o++)e.rows.push({firstRow:0===o,lastRow:o===t-1,subIndex:o,hour:r})}function U(e){e.columnWidth=100/e.columns.length,e.rowHeigh=100/e.rows.length}function S(e){switch(moment(e).day()){case 0:return 1;case 1:return 2;case 2:return 4;case 3:return 8;case 4:return 16;case 5:return 32;case 6:return 64}return 0}function k(e,t){return e.recurrenceType=t.type,e.range=t.range,e.occurrenceCount=t.occurrenceCount||10,e.start=t.start||moment().toDate(),e.end=t.end||moment(e.start).add(3,"month").toDate(),0===e.recurrenceType?(e.dayWeekDays=62===t.weekDays?62:0,e.dayPeriodicity=t.periodicity||1):(e.dayWeekDays=0,e.dayPeriodicity=1),e.weekPeriodicity=t.periodicity||1,1===e.recurrenceType?e.weekWeekDays=t.weekDays||S(e.start):e.weekWeekDays=S(e.start),e.monthRecurrenceType=t.weekOfMonth?1:0,e.monthDayNumber=t.dayNumber||1,e.monthWeekOfMonth=t.weekOfMonth||1,2===e.recurrenceType?(e.monthPeriodicity0=t.periodicity||1,e.monthPeriodicity1=t.periodicity||1,e.monthWeekDays=t.weekDays||S(e.start)):(e.monthPeriodicity0=1,e.monthPeriodicity1=1,e.monthWeekDays=S(e.start)),e.yearRecurrenceType=t.weekOfMonth?1:0,e.yearWeekOfMonth=t.weekOfMonth||1,e.yearMonth0=t.month||1,e.yearMonth1=t.month||1,3===e.recurrenceType?(e.yearWeekDays=t.weekDays||S(e.start),e.yearDayNumber=t.dayNumber||1):(e.yearWeekDays=S(e.start),e.yearDayNumber=1),e}function A(e,t){return Object.keys(e).forEach(function(t){delete e[t]}),e.type=t.recurrenceType,e.range=t.range,e.start=t.start,1==t.range?e.occurrenceCount=t.occurrenceCount:e.end=t.end,0===t.recurrenceType?(1!==t.dayPeriodicity&&(e.periodicity=t.dayPeriodicity),t.dayWeekDays&&(e.weekDays=t.dayWeekDays)):1===t.recurrenceType?(e.periodicity=t.weekPeriodicity,e.weekDays=t.weekWeekDays):2===t.recurrenceType?0===t.monthRecurrenceType?(e.weekOfMonth=0,e.dayNumber=t.monthDayNumber,1!==t.monthPeriodicity0&&(e.periodicity=t.monthPeriodicity0)):(e.weekOfMonth=t.monthWeekOfMonth,e.weekDays=t.monthWeekDays,1!==t.monthPeriodicity1&&(e.periodicity=t.monthPeriodicity1)):3===t.recurrenceType&&(0===t.yearRecurrenceType?(e.weekOfMonth=0,e.month=t.yearMonth0,e.dayNumber=t.yearDayNumber):(e.weekDays=t.yearWeekDays,e.weekOfMonth=t.yearWeekOfMonth,e.month=t.yearMonth1),e.periodicity=1),e}return{calculateEvents:s,selectPrevDate:u,selectNextDate:l,selectToday:d,fixSelectedDate:E,calculateColumns:D,getSelectedResources:h,calculateRows:b,calculateSizes:U,getMappedResourceID:f,getValidSelectedResourceID:C,mapRecurrenceDtoToModel:k,mapRecurrenceModelToDto:A,getStartEndDateBySelection:M,calculateAvailability:w,canSelectRegion:v}}]),angular.module("wb.directives").directive("wbSplitter",["$compile",function(e){return{restrict:"EA",replace:!0,transclude:!0,scope:{orientation:"@"},template:'<div class="split-panes {{orientation}}"></div>',controller:["$scope",function(e){e.panes=[],this.addPane=function(t){if(e.panes.length>1)throw"splitters can only have two panes";return e.panes.push(t),e.panes.length}}],link:function(n,r,o,a,i){function c(e,t){s.css("top",e+"px"),l.elem.css("height",e+"px"),d.elem.css("top",e+"px"),u!==e&&(u=e,$(r).resize(),n.$parent.$broadcast("splitter-pane-resized")),e>=t-s.height()-10?(n.minified=!0,f||(f=t-100)):(n.minified=!1,f=0)}var s=angular.element('<div class="split-handler"><div ng-click="onMinimizeUp()" ng-show="minified" class="split-handler-button-up"><i class="fa fa-arrow-circle-up hit"></i></div><div ng-click="onMinimizeDown()" ng-hide="minified" class="split-handler-button-down"><i class="fa fa-arrow-circle-down hit"></i></div></div>');i(n.$parent,function(e,t){r.append(e)});var u,l=n.panes[0],d=n.panes[1],E="vertical"==n.orientation,R=l.minSize||0,_=d.minSize||8,T=d.initSize||100,m=!1,f=0;n.minified=!1,l.elem.after(e(s)(n));var p=r[0].getBoundingClientRect().height;c(p-T,p),r.bind("mousemove",function(e){if(m){var t=r[0].getBoundingClientRect(),n=0;if(E){var o=t.bottom-t.top;if((n=e.clientY-t.top)<R)return;if(o-n<_)return;c(n,o)}else{var a=t.right-t.left;if((n=e.clientX-t.left)<R)return;if(a-n<_)return;s.css("left",n+"px"),l.elem.css("width",n+"px"),d.elem.css("left",n+"px")}}}),s.bind("mousedown",function(e){e.preventDefault(),m=!0}),angular.element(t).bind("mouseup",function(e){m=!1}),n.onMinimizeUp=function(){var e=r[0].getBoundingClientRect();if(E){c(f,e.bottom-e.top)}},n.onMinimizeDown=function(){var e=r[0].getBoundingClientRect(),t=0;if(E){var n=e.bottom-e.top;t=n-s.height(),f=l.elem.height(),c(t,n)}}}}}]).directive("wbPane",function(){return{restrict:"EA",require:"^wbSplitter",replace:!0,transclude:!0,scope:{minSize:"=",initSize:"="},template:'<div class="split-pane{{index}}"></div>',link:function(e,t,n,r,o){e.elem=t,e.index=r.addPane(e),o(e.$parent,function(e,n){t.append(e)})}}})}(window,document);
//# sourceMappingURL=wb-directives.min.js.map
;
!function(e,l,t){"use strict";angular.module("wb.directives").run(["$templateCache",function(e){e.put("busyIndicator/templates/wb-busy-indicator.tpl.html",'<div class="tooltip in"><div class="tooltip-inner"><h4><i class="fa fa-spinner fa-spin"></i> <span>{{\'TXT_BUSY\' | translate}}</span></h4></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("checkbox/templates/wb-checkbox-bitmask-edit.tpl.html",'<button type="button" ng-click="spanClick($event);$event.stopPropagation();" class="wb-checkbox-span wb-radio-span"><i ng-if="spanChecked == 1" class="fa fa fa-check"></i></button>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("checkbox/templates/wb-checkbox-edit.tpl.html",'<button type="button" ng-click="spanClick($event);$event.stopPropagation();" class="wb-checkbox-span"><i ng-if="spanChecked == 1 && !indeterminate" class="fa fa-check"></i> <i ng-if=\'spanChecked == "indeterminate" || indeterminate\' class="fa fa-minus"></i></button>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("checkbox/templates/wb-radio-edit.tpl.html",'<button type="button" ng-click="spanClick($event);$event.stopPropagation();" class="wb-checkbox-span wb-radio-span"><i ng-if="spanChecked == 1" class="fa fa fa-check"></i></button>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-date-picker.tpl.html",'<div class="form-inline" role="form"><button type="button" class="btn btn-default" ng-click="onPrevBtnClick()"><i class="fa fa-chevron-left"></i></button> <input type="text" style="width: 110px" class="form-control" ng-model="sourceSettings.startDate" ng-change="onDatePickerChange()" name="date" autoclose="true" use-native="true" container="body" date-format="dd.MM.yy" bs-datepicker> <button type="button" class="btn btn-default" ng-click="onNextBtnClick()"><i class="fa fa-chevron-right"></i></button> <button class="btn btn-success" type="button" ng-click="onTodayBtnClick()">{{ \'TXT_TODAY\' | translate }}</button></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-day-periodicity.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="ngModel.dayWeekDays" value="0"></div><label class="control-label" ng-show="ngModel.dayPeriodicity === 1">{{\'TXT_RECURRENCE_WEEK_EVERY_1\' | translate}}</label> <label class="control-label" ng-show="ngModel.dayPeriodicity > 1 && ngModel.dayPeriodicity < 5">{{\'TXT_RECURRENCE_WEEK_EVERY_2\' | translate}}</label> <label class="control-label" ng-show="ngModel.dayPeriodicity >= 5">{{\'TXT_RECURRENCE_WEEK_EVERY_3\' | translate}}</label> <input type="number" ng-model="ngModel.dayPeriodicity" ng-disabled="ngModel.dayWeekDays !== 0" class="form-control" style="width: 60px;" min="1" max="365"> <label class="control-label text-left" ng-show="ngModel.dayPeriodicity === 1">{{\'TXT_RECURRENCE_DAY_1\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.dayPeriodicity > 1 && ngModel.dayPeriodicity < 5">{{\'TXT_RECURRENCE_DAY_2\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.dayPeriodicity >= 5">{{\'TXT_RECURRENCE_DAY_3\' | translate}}</label></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-day-week-days.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="ngModel.dayWeekDays" value="62"></div><label class="control-label">{{\'TXT_RECURRENCE_WEEK_EVERY_1\' | translate}} {{\'TXT_RECURRENCE_WEEK_WORKDAY\' | translate}}</label></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-month-periodicity.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="ngModel.monthRecurrenceType" value="0"></div><label class="control-label text-left" ng-show="ngModel.monthDayNumber === 1">{{\'TXT_RECURRENCE_MONTH_EVERY_1\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.monthDayNumber > 1 && ngModel.monthDayNumber < 5">{{\'TXT_RECURRENCE_MONTH_EVERY_2\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.monthDayNumber >= 5">{{\'TXT_RECURRENCE_MONTH_EVERY_3\' | translate}}</label> <input type="number" ng-model="ngModel.monthDayNumber" ng-disabled="ngModel.monthRecurrenceType !== 0" class="form-control" style="width: 60px;" min="1" max="31"> <label class="control-label text-left" ng-show="ngModel.monthDayNumber === 1">{{\'TXT_RECURRENCE_DAY_1\' | translate}} {{\'TXT_RECURRENCE_MONTH_FROM_EVERY\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.monthDayNumber > 1 && ngModel.monthDayNumber < 5">{{\'TXT_RECURRENCE_DAY_2\' | translate}} {{\'TXT_RECURRENCE_MONTH_FROM_EVERY\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.monthDayNumber >= 5">{{\'TXT_RECURRENCE_DAY_3\' | translate}} {{\'TXT_RECURRENCE_MONTH_FROM_EVERY\' | translate}}</label> <input type="number" ng-model="ngModel.monthPeriodicity0" ng-disabled="ngModel.monthRecurrenceType !== 0" class="form-control" style="width: 60px;" min="1" max="99"> <label class="control-label text-left">{{\'TXT_RECURRENCE_MONTH_MONTH\' | translate}}</label></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-month-week-days.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="ngModel.monthRecurrenceType" value="1"></div><label class="control-label">{{\'TXT_RECURRENCE_MONTH_EVERY_1\' | translate}}</label><div wb-scheduler-recurrence-week-of-month-combo ng-disabled="ngModel.monthRecurrenceType !== 1" ng-model="ngModel.monthWeekOfMonth"></div><div wb-scheduler-recurrence-week-days-combo ng-disabled="ngModel.monthRecurrenceType !== 1" ng-model="ngModel.monthWeekDays"></div><label class="control-label text-left" ng-show="ngModel.monthDayNumber === 1">{{\'TXT_RECURRENCE_MONTH_FROM_EVERY\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.monthDayNumber > 1 && ngModel.monthDayNumber < 5">{{\'TXT_RECURRENCE_MONTH_FROM_EVERY\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel.monthDayNumber >= 5">{{\'TXT_RECURRENCE_MONTH_FROM_EVERY\' | translate}}</label> <input type="number" ng-model="ngModel.monthPeriodicity1" ng-disabled="ngModel.monthRecurrenceType !== 1" class="form-control" style="width: 60px;" min="1" max="99"> <label class="control-label text-left">{{\'TXT_RECURRENCE_MONTH_MONTH\' | translate}}</label></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-week-periodicity.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><label class="control-label" ng-show="ngModel === 1">{{\'TXT_RECURRENCE_WEEK_EVERY_1\' | translate}}</label> <label class="control-label" ng-show="ngModel > 1 && ngModel < 5">{{\'TXT_RECURRENCE_WEEK_EVERY_2\' | translate}}</label> <label class="control-label" ng-show="ngModel >= 5">{{\'TXT_RECURRENCE_WEEK_EVERY_3\' | translate}}</label> <input type="number" ng-model="ngModel" class="form-control" style="width: 60px;" min="1" max="44"> <label class="control-label text-left" ng-show="ngModel === 1">{{\'TXT_RECURRENCE_WEEK_1\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel > 1 && ngModel < 5">{{\'TXT_RECURRENCE_WEEK_2\' | translate}}</label> <label class="control-label text-left" ng-show="ngModel >= 5">{{\'TXT_RECURRENCE_WEEK_3\' | translate}}</label></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-week-week-days.tpl.html",'<div class="form-group wb-scheduler-recurrence-week-days"><label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="1">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_SUNDAY\' | translate}}</label> <label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="2">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_MONDAY\' | translate}}</label> <label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="4">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_TUESDAY\' | translate}}</label> <label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="8">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_WEDNESDAY\' | translate}}</label> <label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="16">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_THURSDAY\' | translate}}</label> <label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="32">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_FRIDAY\' | translate}}</label> <label class="checkbox-inline"><input class="checkbox" wb-checkbox-bitmask-edit ng-model="ngModel" value="64">&nbsp;{{\'TXT_RECURRENCE_WEEK_DAYS_SATURDAY\' | translate}}</label></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-year-periodicity.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="ngModel.yearRecurrenceType" value="0"></div><label class="control-label text-left">{{\'TXT_RECURRENCE_MONTH_EVERY_1\' | translate}}</label> <input type="number" ng-model="ngModel.yearDayNumber" ng-disabled="ngModel.yearRecurrenceType !== 0" class="form-control" style="width: 60px;" min="1" max="31"><div wb-scheduler-recurrence-month-combo ng-disabled="ngModel.yearRecurrenceType !== 0" ng-model="ngModel.yearMonth0"></div></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence-year-week-days.tpl.html",'<div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="ngModel.yearRecurrenceType" value="1"></div><label class="control-label">{{\'TXT_RECURRENCE_MONTH_EVERY_1\' | translate}}</label><div wb-scheduler-recurrence-week-of-month-combo ng-disabled="ngModel.yearRecurrenceType !== 1" ng-model="ngModel.yearWeekOfMonth"></div><div wb-scheduler-recurrence-week-days-combo ng-disabled="ngModel.yearRecurrenceType !== 1" ng-model="ngModel.yearWeekDays"></div><label class="control-label text-left">{{\'TXT_RECURRENCE_IN\' | translate}}</label><div wb-scheduler-recurrence-month-combo ng-disabled="ngModel.yearRecurrenceType !== 1" ng-model="ngModel.yearMonth1"></div></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-recurrence.tpl.html",'<div style="width: 650px;"><div class="row"><div class="col-xs-3"><div class="checkbox"><label><input wb-radio-edit ng-model="model.recurrenceType" value="0">&nbsp;{{\'TXT_RECURRENCE_TYPE_DAILY\' | translate}}</label></div><div class="checkbox"><label><input wb-radio-edit ng-model="model.recurrenceType" value="1">&nbsp;{{\'TXT_RECURRENCE_TYPE_WEEKLY\' | translate}}</label></div><div class="checkbox"><label><input wb-radio-edit ng-model="model.recurrenceType" value="2">&nbsp;{{\'TXT_RECURRENCE_TYPE_MONTHLY\' | translate}}</label></div><div class="checkbox"><label><input wb-radio-edit ng-model="model.recurrenceType" value="3">&nbsp;{{\'TXT_RECURRENCE_TYPE_YEARLY\' | translate}}</label></div></div><div class="col-xs-9" ng-show="model.recurrenceType === 0"><div wb-scheduler-recurrence-day-periodicity ng-model="model"></div><div wb-scheduler-recurrence-day-week-days ng-model="model"></div></div><div class="col-xs-9" ng-show="model.recurrenceType === 1"><div wb-scheduler-recurrence-week-periodicity ng-model="model.weekPeriodicity"></div><div wb-scheduler-recurrence-week-week-days ng-model="model.weekWeekDays"></div></div><div class="col-xs-9" ng-show="model.recurrenceType === 2"><div wb-scheduler-recurrence-month-periodicity ng-model="model"></div><div wb-scheduler-recurrence-month-week-days ng-model="model"></div></div><div class="col-xs-9" ng-show="model.recurrenceType === 3"><div wb-scheduler-recurrence-year-periodicity ng-model="model"></div><div wb-scheduler-recurrence-year-week-days ng-model="model"></div></div></div><div class="row"><div class="col-xs-8"><div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="model.range" value="1"></div><label class="control-label">{{\'TXT_RECURRENCE_ENDS_AFTER\' | translate}}</label> <input type="number" ng-model="model.occurrenceCount" ng-disabled="model.range !== 1" class="form-control" style="width: 60px;" min="1" max="200"> <label class="control-label">{{\'TXT_RECURRENCE_OCCURRENCES\' | translate}}</label></div></div><div class="form-inline wb-inline-controls"><div class="form-group"><div wb-radio-edit ng-model="model.range" value="2"></div><label class="control-label">{{\'TXT_RECURRENCE_ENDS_AT\' | translate}}</label> <input bs-datepicker style="width:90px" ng-model="model.end" class="form-control" ng-disabled="model.range !== 2"></div></div></div></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler-tooltip.tpl.html",'<div class="popover" tabindex="-1" style="width: 350px;"><div class="arrow"></div><h3 class="popover-title">{{startTime | date:\'shortTime\'}} - {{endTime | date:\'shortTime\'}}</h3><div class="popover-content"><div class="form-horizontal"><div class="form-group"><label class="col-sm-3 control-label">{{\'TXT_LBL_START_DATE\' | translate}}</label><div class="col-sm-9"><p class="form-control-static">{{startTime | date:\'short\'}}</p></div></div><div class="form-group"><label class="col-sm-3 control-label">{{\'TXT_LBL_END_DATE\' | translate}}</label><div class="col-sm-9"><p class="form-control-static">{{endTime | date:\'short\'}}</p></div></div><div class="form-group"><label class="col-sm-3 control-label">{{\'TXT_LBL_EMPLOYEE\' | translate}}</label><div class="col-sm-9"><p class="form-control-static">{{teacher}}</p></div></div><div class="form-group"><label class="col-sm-3 control-label">{{\'TXT_LBL_NAME\' | translate}}</label><div class="col-sm-9"><p class="form-control-static">{{name}}</p></div></div><div class="form-group" ng-if="!!notes"><label class="col-sm-3 control-label">{{\'TXT_NOTE\' | translate}}</label><div class="col-sm-9"><p class="form-control-static">{{notes}}</p></div></div><div class="form-group"><label class="col-sm-3 control-label">{{\'TXT_LBL_FILLED\' | translate}}</label><div class="col-sm-9"><p class="form-control-static">{{filled}}</p></div></div></div></div></div>')}]),angular.module("wb.directives").run(["$templateCache",function(e){e.put("scheduler/templates/wb-scheduler.tpl.html",'<div class="scheduler" ng-style="{\'width\':option.width}" title=""><table class="scheduler-table"><thead><tr ng-hide="option.noHeader"><th class="scheduler-time-column"></th><th class="scheduler-column scheduler-column-lg scheduler-column-last" colspan="{{option.columns.length}}"><span ng-if="!option.weekView">{{option.columns[0].date | date:\'EEEE d. MMMM\'}}</span> <span ng-if="option.weekView">{{option.columns[0].resourceName }}</span></th></tr><tr><th class="scheduler-time-column"></th><th class="scheduler-column" ng-class="{\'scheduler-column-today\': option.todayIndex === $index && option.weekView, \'scheduler-column-last\': $last  }" ng-style="::{\'width\': 90 / option.columns.length + \'%\' }" ng-repeat="column in option.columns">{{::column.caption}}</th></tr></thead><tbody><tr ng-repeat="row in option.rows"><td ng-if="::row.firstRow" class="scheduler-time-column" rowspan="{{::option.noOfSubRows}}"><div>{{::row.hour}} <sup>00</sup></div></td><td class="scheduler-column" ng-style="::{\'width\': 90 / option.columns.length + \'%\' }" ng-mousedown="onCellMouseDown($parent.$index, $index)" ng-mousemove="onCellMouseMove($parent.$index, $index)" ng-mouseup="onCellMouseUp($event)" ng-class="{\'scheduler-column-last-row\': row.lastRow,\n                           \'scheduler-column-today\': option.todayIndex === $index && option.weekView,\n                           \'scheduler-column-last\': $last,\n                           \'scheduler-column-available\': option.availabilityObj[$parent.$index + \'-\' + $index],\n                           \'scheduler-column-selected\': selection[$parent.$index + \'-\' + $index]}" ng-repeat="column in option.columns">&nbsp;</td></tr></tbody></table><div class="scheduler-events" ng-class="{\'scheduler-events-no-header\': option.noHeader}" style="pointer-events: none;"><div ng-repeat="event in option.events" class="scheduler-cell" ng-class="{\'scheduler-cell-selected\': option.selectedAction === event.origAction }" ng-click="onSelectEvent($event, event)" ng-style="::{ \'left\':   ((option.columnWidth * event.column) + ((option.columnWidth / event.noOfSubColumns) * event.subColumn)) + \'%\',\n                         \'width\':  (option.columnWidth / event.noOfSubColumns) + \'%\',\n                         \'top\':    (option.rowHeigh * event.start) + \'%\',\n                         \'height\': (option.rowHeigh * (event.end - event.start)) + \'%\'}" data-placement="auto right" data-trigger="hover" data-animation="am-flip-x" data-auto-close="1" data-delay="{{option.toolTipDelay}}" data-template-url="{{option.toolTipTemplateUrl}}" bs-tooltip="event" bs-enabled="toolTipEnabled"><div class="scheduler-cell-content" style="pointer-events:auto;"><div class="scheduler-cell-inner-content" ng-class="::{\'scheduler-event-status-2\': event.status === 2,\n                                \'scheduler-event-status-3\': event.status === 3,\n                                \'scheduler-event-type-2\': event.type === 2,\n                                \'scheduler-event-type-3\': event.type === 3}"><div ng-show="::event.startOverflow" class="scheduler-cell-overflow-top"><i class="fa fa-angle-double-up"></i></div><div class="scheduler-cell-start-time"><span ng-show="::event.startOverflowDay" ng-class="::{\'scheduler-cell-time-overflow\' : event.startOverflow }">{{::event.startTime | date:\'short\'}}</span> <span ng-hide="::event.startOverflowDay" ng-class="::{\'scheduler-cell-time-overflow\' : event.startOverflow }">{{::event.startTime | date:\'shortTime\'}}</span> - <span ng-show="::event.endOverflowDay" ng-class="::{\'scheduler-cell-time-overflow\' : event.endOverflow }">{{::event.endTime | date:\'short\'}}</span> <span ng-hide="::event.endOverflowDay" ng-class="::{\'scheduler-cell-time-overflow\' : event.endOverflow }">{{::event.endTime | date:\'shortTime\'}}</span></div><div class="scheduler-cell-event-name" ng-class="::{\'scheduler-cell-event-name-sm\' : option.columns.length > 3, \'scheduler-cell-event-name-xs\': option.columns.length > 5}">{{::event.name}}</div><div class="scheduler-cell-event-teacher">{{::event.teacher}}</div><div class="scheduler-info-icon-area"><span ng-if="::event.showActionNote"><i class="fa fa fa-sticky-note-o"></i></span> <span ng-if="::event.showWaitQueue"><i class="fa fa-clock-o"></i></span><span ng-if="::option.showRecurrence && event.recurrenceType === -1" style="padding-left: 4px;"><i class="fa fa-refresh"></i></span><span ng-if="::option.showRecurrence && event.recurrenceType === 3" style="padding-left: 4px;"><i class="fa fa-refresh text-danger"></i></span><span ng-if="::option.showRecurrence && event.recurrenceType === 4" style="padding-left: 4px;"><i class="fa fa-refresh text-muted"></i></span></div><div class="scheduler-cell-event-capacity">{{::event.filled}}</div><div ng-show="::event.endOverflow" class="scheduler-cell-overflow-bottom"><i class="fa fa-angle-double-down"></i></div></div></div></div></div></div>')}])}(window,document);;
(function () {
    'use-strict';

    angular.module('jkuri.gallery', []).directive('ngGallery', ngGallery);

    ngGallery.$inject = ['$document', '$timeout', '$q', '$templateCache'];

    function ngGallery($document, $timeout, $q, $templateCache) {

        var defaults = {
            baseClass: 'ng-gallery',
            thumbClass: 'ng-thumb',
            templateUrl: 'ng-gallery.html'
        };

        var keys_codes = {
            enter: 13,
            esc: 27,
            left: 37,
            right: 39
        };

        function setScopeValues(scope, attrs) {
            scope.baseClass = scope.class || defaults.baseClass;
            scope.thumbClass = scope.thumbClass || defaults.thumbClass;
            scope.thumbsNum = scope.thumbsNum || 3; // should be odd
        }

        var template_url = defaults.templateUrl;
        // Set the default template
        $templateCache.put(template_url,
            '<div class="{{ baseClass }}">' +
            '  <div ng-repeat="i in images">' +
            '    <img ng-src="{{ i.thumb }}" class="{{ thumbClass }}" ng-click="openGallery($index)" alt="Image {{ $index + 1 }}" />' +
            '  </div>' +
            '</div>' +
            '<div class="ng-overlay" ng-show="opened">' +
            '</div>' +
            '<div class="ng-gallery-content" unselectable="on" ng-show="opened" ng-swipe-left="nextImage()" ng-swipe-right="prevImage()">' +
            '  <div class="uil-ring-css" ng-show="loading"><div></div></div>' +
            '<a href="{{getImageDownloadSrc()}}" target="_blank" ng-show="showImageDownloadButton()" class="download-image"><i class="fa fa-download"></i></a>' +
            '  <a class="close-popup" ng-click="closeGallery()"><i class="fa fa-close"></i></a>' +
            '  <a class="nav-left" ng-click="prevImage()"><i class="fa fa-angle-left"></i></a>' +
            '  <img ondragstart="return false;" draggable="false" ng-src="{{ img }}" ng-click="nextImage()" ng-show="!loading" class="effect" />' +
            '  <a class="nav-right" ng-click="nextImage()"><i class="fa fa-angle-right"></i></a>' +
            '  <span class="info-text">{{ index + 1 }}/{{ images.length }} - {{ description }}</span>' +
            '  <div class="ng-thumbnails-wrapper">' +
            '    <div class="ng-thumbnails slide-left">' +
            '      <div ng-repeat="i in images">' +
            '        <img ng-src="{{ i.thumb }}" ng-class="{\'active\': index === $index}" ng-click="changeImage($index)" />' +
            '      </div>' +
            '    </div>' +
            '  </div>' +
            '</div>'
        );

        return {
            restrict: 'EA',
            scope: {
                images: '=',
                thumbsNum: '@'
            },
            controller: [
                '$scope',
                function ($scope) {
                    $scope.$on('openGallery', function (e, args) {
                        $scope.openGallery(args.index);
                    });
                }
            ],
            templateUrl: function (element, attrs) {
                return attrs.templateUrl || defaults.templateUrl;
            },
            link: function (scope, element, attrs) {
                setScopeValues(scope, attrs);

                if (scope.thumbsNum >= 11) {
                    scope.thumbsNum = 11;
                }

                var $body = $document.find('body');
                var $thumbwrapper = angular.element(element[0].querySelectorAll('.ng-thumbnails-wrapper'));
                var $thumbnails = angular.element(element[0].querySelectorAll('.ng-thumbnails'));

                scope.index = 0;
                scope.opened = false;

                scope.thumb_wrapper_width = 0;
                scope.thumbs_width = 0;

                var loadImage = function (i) {
                    var deferred = $q.defer();
                    var image = new Image();

                    image.onload = function () {
                        scope.loading = false;
                        if (typeof this.complete === false || this.naturalWidth === 0) {
                            deferred.reject();
                        }
                        deferred.resolve(image);
                    };

                    image.onerror = function () {
                        deferred.reject();
                    };

                    image.src = scope.images[i].img;
                    scope.loading = true;

                    return deferred.promise;
                };

                var showImage = function (i) {
                    loadImage(scope.index).then(function (resp) {
                        scope.img = resp.src;
                        smartScroll(scope.index);
                    });
                    scope.description = scope.images[i].description || '';
                };

                scope.showImageDownloadButton = function () {
                    if (scope.images[scope.index] == null || scope.images[scope.index].downloadSrc == null) return
                    var image = scope.images[scope.index];
                    return angular.isDefined(image.downloadSrc) && 0 < image.downloadSrc.length;
                };

                scope.getImageDownloadSrc = function () {
                    if (scope.images[scope.index] == null || scope.images[scope.index].downloadSrc == null) return
                    return scope.images[scope.index].downloadSrc;
                };

                scope.changeImage = function (i) {
                    scope.index = i;
                    showImage(i);
                };

                scope.nextImage = function () {
                    scope.index += 1;
                    if (scope.index === scope.images.length) {
                        scope.index = 0;
                    }
                    showImage(scope.index);
                };

                scope.prevImage = function () {
                    scope.index -= 1;
                    if (scope.index < 0) {
                        scope.index = scope.images.length - 1;
                    }
                    showImage(scope.index);
                };

                scope.openGallery = function (i) {
                    if (typeof i !== undefined) {
                        scope.index = i;
                        showImage(scope.index);
                    }
                    scope.opened = true;

                    $timeout(function () {
                        var calculatedWidth = calculateThumbsWidth();
                        scope.thumbs_width = calculatedWidth.width;
                        //Add 1px, otherwise some browsers move the last image into a new line
                        var thumbnailsWidth = calculatedWidth.width+1;
                        $thumbnails.css({width: thumbnailsWidth + 'px'});
                        $thumbwrapper.css({width: calculatedWidth.visible_width + 'px'});
                        smartScroll(scope.index);
                    });
                };

                scope.closeGallery = function () {
                    scope.opened = false;
                };

                $body.bind('keydown', function (event) {
                    if (!scope.opened) {
                        return;
                    }
                    var which = event.which;
                    if (which === keys_codes.esc) {
                        scope.closeGallery();
                    } else if (which === keys_codes.right || which === keys_codes.enter) {
                        scope.nextImage();
                    } else if (which === keys_codes.left) {
                        scope.prevImage();
                    }

                    scope.$apply();
                });

                var calculateThumbsWidth = function () {
                    var width = 0,
                        visible_width = 0;
                    angular.forEach($thumbnails.find('img'), function (thumb) {
                        width += thumb.clientWidth;
                        width += 10; // margin-right
                        visible_width = thumb.clientWidth + 10;
                    });
                    return {
                        width: width,
                        visible_width: visible_width * scope.thumbsNum
                    };
                };

                var smartScroll = function (index) {
                    $timeout(function () {
                        var len = scope.images.length,
                            width = scope.thumbs_width,
                            item_scroll = parseInt(width / len, 10),
                            i = index + 1,
                            s = Math.ceil(len / i);

                        $thumbwrapper[0].scrollLeft = 0;
                        $thumbwrapper[0].scrollLeft = i * item_scroll - (s * item_scroll);
                    }, 100);
                };

            }
        };
    }
})();
;
