public function regrade_final_grades($userid=null) {
        global $CFG, $DB;

        // locked grade items already have correct final grades
        if ($this->is_locked()) {
            return true;
        }

        // calculation produces final value using formula from other final values
        if ($this->is_calculated()) {
            if ($this->compute($userid)) {
                return true;
            } else {
                return "Could not calculate grades for grade item"; // TODO: improve and localize
            }

        // noncalculated outcomes already have final values - raw grades not used
        } else if ($this->is_outcome_item()) {
            return true;

        // aggregate the category grade
        } else if ($this->is_category_item() or $this->is_course_item()) {
            // aggregate category grade item
            $category = $this->load_item_category();
            $category->grade_item =& $this;
            if ($category->generate_grades($userid)) {
                return true;
            } else {
                return "Could not aggregate final grades for category:".$this->id; // TODO: improve and localize
            }

        } else if ($this->is_manual_item()) {
            // manual items track only final grades, no raw grades
            return true;

        } else if (!$this->is_raw_used()) {
            // hmm - raw grades are not used- nothing to regrade
            return true;
        }

        // normal grade item - just new final grades
        $result = true;
        $grade_inst = new grade_grade();
        $fields = implode(',', $grade_inst->required_fields);
        if ($userid) {
            $params = array($this->id, $userid);
            $rs = $DB->get_recordset_select('grade_grades', "itemid=? AND userid=?", $params, '', $fields);
        } else {
            $rs = $DB->get_recordset('grade_grades', array('itemid' => $this->id), '', $fields);
        }
        if ($rs) {
            foreach ($rs as $grade_record) {
                $grade = new grade_grade($grade_record, false);

                if (!empty($grade_record->locked) or !empty($grade_record->overridden)) {
                    // this grade is locked - final grade must be ok
                    continue;
                }

                $grade->finalgrade = $this->adjust_raw_grade($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);

                if (grade_floats_different($grade_record->finalgrade, $grade->finalgrade)) {
                    $success = $grade->update('system');

                    // If successful trigger a user_graded event.
                    if ($success) {
                        $grade->load_grade_item();
                        \core\event\user_graded::create_from_grade($grade, \core\event\base::USER_OTHER)->trigger();
                    } else {
                        $result = "Internal error updating final grade";
                    }
                }
            }
            $rs->close();
        }

        return $result;
    }