public function calculate_progress() {
        global $USER, $DB;

        // Check if the user is reviewing the attempt.
        if (isset($USER->modattempts[$this->properties->id])) {
            return 100;
        }

        // All of the lesson pages.
        $pages = $this->load_all_pages();
        foreach ($pages as $page) {
            if ($page->prevpageid == 0) {
                $pageid = $page->id;  // Find the first page id.
                break;
            }
        }

        // Current attempt number.
        if (!$ntries = $DB->count_records("lesson_grades", array("lessonid" => $this->properties->id, "userid" => $USER->id))) {
            $ntries = 0;  // May not be necessary.
        }

        $viewedpageids = array();
        if ($attempts = $this->get_attempts($ntries, false)) {
            foreach ($attempts as $attempt) {
                $viewedpageids[$attempt->pageid] = $attempt;
            }
        }

        $viewedbranches = array();
        // Collect all of the branch tables viewed.
        if ($branches = $this->get_content_pages_viewed($ntries, $USER->id, 'timeseen ASC', 'id, pageid')) {
            foreach ($branches as $branch) {
                $viewedbranches[$branch->pageid] = $branch;
            }
            $viewedpageids = array_merge($viewedpageids, $viewedbranches);
        }

        // Filter out the following pages:
        // - End of Cluster
        // - End of Branch
        // - Pages found inside of Clusters
        // Do not filter out Cluster Page(s) because we count a cluster as one.
        // By keeping the cluster page, we get our 1.
        $validpages = array();
        while ($pageid != 0) {
            $pageid = $pages[$pageid]->valid_page_and_view($validpages, $viewedpageids);
        }

        // Progress calculation as a percent.
        $progress = round(count($viewedpageids) / count($validpages), 2) * 100;
        return (int) $progress;
    }