/**
  * Create an instance for a given register and user
  * @param object $register
  * @param int $userId
  * @param attendanceregister_user_sessions $userSessions
  */
 public function __construct($register, $userId, attendanceregister_user_sessions $userSessions)
 {
     global $DB;
     $this->userSessions = $userSessions;
     // Retrieve User instance
     $this->user = attendanceregister__getUser($userId);
     // Retrieve attendanceregister_aggregate records
     $aggregates = attendanceregister__get_user_aggregates($register, $userId);
     foreach ($aggregates as $aggregate) {
         if ($aggregate->grandtotal) {
             $this->grandTotalDuration = $aggregate->duration;
             $this->lastSassionLogout = $aggregate->lastsessionlogout;
         } else {
             if ($aggregate->total && $aggregate->onlinesess == 1) {
                 $this->onlineTotalDuration = $aggregate->duration;
             } else {
                 if ($aggregate->total && $aggregate->onlinesess == 0) {
                     $this->offlineTotalDuration = $aggregate->duration;
                 } else {
                     if (!$aggregate->total && $aggregate->onlinesess == 0 && $aggregate->refcourse != null) {
                         $this->perCourseOfflineSessions[$aggregate->refcourse] = $aggregate->duration;
                     } else {
                         if (!$aggregate->total && $aggregate->onlinesess == 0 && $aggregate->refcourse == null) {
                             $this->noCourseOfflineSessions = $aggregate->duration;
                         } else {
                             // Should not happen!
                             debugging('Unconsistent Aggregate: ' . print_r($aggregate, true), DEBUG_DEVELOPER);
                         }
                     }
                 }
             }
         }
     }
 }
 /**
  * Check if the current USER can add Offline Sessions for a specified User
  * @param int $userId (null means current user's register)
  * @return boolean
  */
 public function canAddThisUserOfflineSession($register, $userId)
 {
     global $DB;
     if (attendanceregister__isCurrentUser($userId)) {
         return $this->canAddOwnOfflineSessions;
     } else {
         if ($this->canAddOtherOfflineSessions) {
             // If adding Session for another user also check it is tracked by the register instance
             $user = attendanceregister__getUser($userId);
             return attendanceregister_is_tracked_user($register, $user);
         }
     }
     return false;
 }
        }
    }
}
// ===========================
// Retrieve data to be shown
// ===========================
// Retrieve Course Completion info object
$completion = new completion_info($course);
// If viewing/updating one User's Register, load the user into $userToProcess
// and retireve User's Sessions or retrieve the Register's Tracked Users
// If viewing all Users load tracked user list
$userToProcess = null;
$userSessions = null;
$trackedUsers = null;
if ($userId) {
    $userToProcess = attendanceregister__getUser($userId);
    $userToProcessFullname = fullname($userToProcess);
    $userSessions = new attendanceregister_user_sessions($register, $userId, $userCapabilities);
} else {
    $trackedUsers = new attendanceregister_tracked_users($register, $userCapabilities);
}
// ===========================
// Pepare PAGE for rendering
// ===========================
// Setup PAGE
$url = attendanceregister_makeUrl($register, $userId, $groupId, $inputAction);
$PAGE->set_url($url->out());
$PAGE->set_context($context);
$titleStr = $course->shortname . ': ' . $register->name . ($userId ? ': ' . $userToProcessFullname : '');
$PAGE->set_title(format_string($titleStr));
$PAGE->set_heading($course->fullname);
/**
 * Checks if a User's Sessions need update.
 * Need update if:
 * User->currentlogin is after User's Last Session Logout AND older than Register SessionTimeout
 *
 *
 * It uses Last Session Logout cached in Aggregates
 *
 * Note that this will report "update needed" also if the user logged in the site
 * after the last Session tracked in this Register, but did not touch any Course
 * tracked by this Register
 *
 * @param object $register
 * @param int $userId
 * @param int $lastSessionLogout (by ref.) lastSessionLogout returned if update needed
 * @eturn boolean true if update needed
 */
function attendanceregister_check_user_sessions_need_update($register, $userId, &$lastSessionLogout = null)
{
    global $DB;
    // Retrive User
    $user = attendanceregister__getUser($userId);
    // Retrieve User's Grand Total Aggregate (if any)
    $userGrandTotalAggregate = attendanceregister__get_cached_user_grandtotal($register, $userId);
    // If user never logged in, no update needed ;)
    if (!$user->lastaccess) {
        debugging("UserId:{$userId} never logged in: no session update needed on registerId:{$register->id}");
        return false;
    }
    // If No User Aggregate yet, need update and lastSessionLogout is 0
    if (!$userGrandTotalAggregate) {
        debugging("userId:{$userId} has no User Aggregate: session update needed on registerId:{$register->id}");
        $lastSessionLogout = 0;
        return true;
    }
    $now = time();
    // TODO this business rule is duplicated in attendanceregister__get_tracked_users_need_update() but in a different form: SQL subqery, negated (to exclude users that do not need updating). This is no good!
    if ($user->lastaccess > $userGrandTotalAggregate->lastsessionlogout && $now - $user->lastaccess > $register->sessiontimeout * 60) {
        $lastSessionLogout = $userGrandTotalAggregate->lastsessionlogout;
        debugging("userId:{$userId}; session update needed on registerId:{$register->id} as LastSession logout={$lastSessionLogout}, lastAccess={$user->lastaccess}");
        return true;
    } else {
        debugging("userId:{$userId}; no session update needed on registerId:{$register->id}");
        return false;
    }
}