/**
 * This is the function that actually process log entries and calculate sessions
 *
 * Calculate and Save all new Sessions of a given User
 * starting from a given timestamp.
 * Optionally updates a progress_bar
 *
 * Also Updates User's Aggregates
 *
 * @param Attendanceregister $register
 * @param int $userId
 * @param int $fromTime (default 0)
 * @param progress_bar optional instance of progress_bar to update
 * @return int number of new sessions found
 */
function attendanceregister__build_new_user_sessions($register, $userId, $fromTime = 0, progress_bar $progressbar = null)
{
    global $DB;
    // Retrieve ID of Course containing Register
    $course = attendanceregister__get_register_course($register);
    $user = attendanceregister__getUser($userId);
    // All Courses where User's activities are tracked (Always contains current Course)
    $trackedCoursesIds = attendanceregister__get_tracked_courses_ids($register, $course);
    // Retrieve logs entries for all tracked courses, after fromTime
    $totalLogEntriesCount = 0;
    $logEntries = attendanceregister__get_user_log_entries_in_courses($userId, $fromTime, $trackedCoursesIds, $totalLogEntriesCount);
    $sessionTimeoutSeconds = $register->sessiontimeout * 60;
    $prevLogEntry = null;
    $sessionStartTimestamp = null;
    $logEntriesCount = 0;
    $newSessionsCount = 0;
    $sessionLastEntryTimestamp = 0;
    // loop new entries if any
    if (is_array($logEntries) && count($logEntries) > 0) {
        // Scroll all log entries
        foreach ($logEntries as $logEntry) {
            $logEntriesCount++;
            // On first element, get prev entry and session start, than loop.
            if (!$prevLogEntry) {
                $prevLogEntry = $logEntry;
                $sessionStartTimestamp = $logEntry->timecreated;
                continue;
            }
            // Check if between prev and current log, last more than Session Timeout
            // if so, the Session ends on the _prev_ log entry
            if ($logEntry->timecreated - $prevLogEntry->timecreated > $sessionTimeoutSeconds) {
                $newSessionsCount++;
                // Estimate Session ended half the Session Timeout after the prev log entry
                // (prev log entry is the last entry of the Session)
                $sessionLastEntryTimestamp = $prevLogEntry->timecreated;
                $estimatedSessionEnd = $sessionLastEntryTimestamp + $sessionTimeoutSeconds / 2;
                // Save a new session to the prev entry
                attendanceregister__save_session($register, $userId, $sessionStartTimestamp, $estimatedSessionEnd);
                // Update the progress bar, if any
                if ($progressbar) {
                    $msg = get_string('updating_online_sessions_of', 'attendanceregister', fullname($user));
                    $progressbar->update($logEntriesCount, $totalLogEntriesCount, $msg);
                }
                // Session has ended: session start on current log entry
                $sessionStartTimestamp = $logEntry->timecreated;
            }
            $prevLogEntry = $logEntry;
        }
        // If le last log entry is not the end of the last calculated session and is older than SessionTimeout
        // create a last session
        if ($logEntry->timecreated > $sessionLastEntryTimestamp && time() - $logEntry->timecreated > $sessionTimeoutSeconds) {
            $newSessionsCount++;
            // In this case logEntry (and not prevLogEntry is the last entry of the Session)
            $sessionLastEntryTimestamp = $logEntry->timecreated;
            $estimatedSessionEnd = $sessionLastEntryTimestamp + $sessionTimeoutSeconds / 2;
            // Save a new session to the prev entry
            attendanceregister__save_session($register, $userId, $sessionStartTimestamp, $estimatedSessionEnd);
            // Update the progress bar, if any
            if ($progressbar) {
                $msg = get_string('updating_online_sessions_of', 'attendanceregister', fullname($user));
                $progressbar->update($logEntriesCount, $totalLogEntriesCount, $msg);
            }
        }
    }
    /// Updates Aggregates, only on new session creation
    if ($newSessionsCount) {
        attendanceregister__update_user_aggregates($register, $userId);
    }
    // Finalize Progress Bar
    if ($progressbar) {
        $a = new stdClass();
        $a->fullname = fullname($user);
        $a->numnewsessions = $newSessionsCount;
        $msg = get_string('online_session_updated_report', 'attendanceregister', $a);
        attendanceregister__finalize_progress_bar($progressbar, $msg);
    }
    return $newSessionsCount;
}
/**
 * Updates recorded Sessions of a User
 * if User's Register is not Locked
 * AND if $recalculation is set
 *      OR attendanceregister_check_user_sessions_need_update(...) returns true
 *
 * @param object $register Register instance
 * @param int $userId User->id
 * @param progress_bar $progressbar optional instance of progress_bar to update
 * @param boolean $recalculation true on recalculation: ignore locks and needUpdate check
 * @return boolean true if any new session has been found
 */
function attendanceregister_update_user_sessions($register, $userId, progress_bar $progressbar = null, $recalculation = false)
{
    // If not running in Recalc,
    // check if a Lock exists on this User's Register; if so, exit immediately
    if (!$recalculation && attendanceregister__check_lock_exists($register, $userId)) {
        // (if a progress bar exists, before exiting reset it)
        attendanceregister__finalize_progress_bar($progressbar, get_string('online_session_updated', 'attendanceregister'));
        mtrace("Lock found on registerId:{$register->id}, userId:{$userId}. Skip updating.");
        return false;
    }
    // Check if Update is needed
    if ($recalculation) {
        $lastSessionLogout = 0;
        $needUpdate = true;
        mtrace("Forced recalc of sessions");
    } else {
        $lastSessionLogout = 0;
        $needUpdate = attendanceregister_check_user_sessions_need_update($register, $userId, $lastSessionLogout);
        mtrace("registerId:{$register->id}, userId:{$userId} " . ($needUpdate ? "needs update" : "doesn't need update"));
    }
    if ($needUpdate) {
        // Calculate all new sesssions after that timestamp
        $newSessionsFound = attendanceregister__build_new_user_sessions($register, $userId, $lastSessionLogout, $progressbar) > 0;
        return $newSessionsFound;
    } else {
        attendanceregister__finalize_progress_bar($progressbar, get_string('online_session_updated', 'attendanceregister'));
        return false;
    }
}