diff --git a/lib/accesslib.php b/lib/accesslib.php
index 065b1b0..82df625 100755
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -171,6 +171,884 @@ $ACCESS = array(); // cache of caps for cron user switching and has_capability f
 $RDEFS = array(); // role definitions cache - helps a lot with mem usage in cron
 
 /**
+ * Abstract class for context levels.  The context level classes encapsulate
+ * context level-specific logic.
+ */
+abstract class context_level {
+    /**
+     * prints human readable context identifier
+     */
+    abstract public function print_context_name($context, $withprefix = true, $short = false);
+
+    /**
+     * Extracts the relevant capabilities given a contextid.
+     * All case based, example an instance of forum context.
+     * Will fetch all forum related capabilities, while course contexts
+     * Will fetch all capabilities
+     * @param object context
+     * @return array();
+     *
+     *  capabilities
+     * `name` varchar(150) NOT NULL,
+     * `captype` varchar(50) NOT NULL,
+     * `contextlevel` int(10) NOT NULL,
+     * `component` varchar(100) NOT NULL,
+     */
+    public function fetch_context_capabilities($context) {
+        $sort = 'ORDER BY contextlevel, component, name';    // To group them sensibly for display
+
+        $SQL = $this->fetch_context_capabilities_sql($context);
+
+        $records = get_records_sql($SQL.' '.$sort);
+
+        if (empty($records)) {
+            $records = array();
+        }
+
+        return $records;
+    }
+
+    /**
+     * sql for the removal of stale contexts
+     *
+     * @return string
+     */
+    public function cleanup_contexts_sql() {
+        global $CFG;
+
+        $sql = " SELECT c.contextlevel,
+                     c.instanceid
+              FROM {$CFG->prefix}context c
+              LEFT OUTER JOIN {$CFG->prefix}{$this->table} t
+                ON c.instanceid = t.id
+              WHERE t.id IS NULL AND c.contextlevel = {$this->level}";
+
+        return $sql;
+    }
+
+    /**
+     * returns sql string needed for fetch context capabilities
+     *
+     * @param object $context
+     * @return string;
+     */
+    abstract protected function fetch_context_capabilities_sql($context);
+
+    /**
+     * Recursive function which, given a context, find all its children context ids.
+     *
+     * When called for a course context, it will return the modules and blocks
+     * displayed in the course page.
+     *
+     * For course category contexts it will return categories and courses. It will
+     * NOT recurse into courses - if you want to do that, call it on the returned
+     * courses.
+     *
+     * If called on a course context it _will_ populate the cache with the appropriate
+     * contexts ;-)
+     *
+     * @param object $context.
+     * @return array of child records
+     */
+    abstract public function get_child_contexts($context);
+
+    /**
+     * This gets the mod/block/course/core etc strings.
+     * @param $component
+     * @param $contextlevel
+     */
+    abstract public function get_component_string($component, $contextlevel);
+
+    abstract public function build_context_path($force=false, $feedback=false);
+}
+
+class context_course extends context_level {
+    protected $level = CONTEXT_COURSE;
+    protected $table = 'course';
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        if ($context->instanceid == SITEID) {
+            $name = get_string('frontpage', 'admin');
+        } else {
+            if ($course = get_record('course', 'id', $context->instanceid)) {
+                $name = '';
+
+                if ($withprefix){
+                    $name .= get_string('course').': ';
+                }
+
+                if (!$short){
+                    $name .= format_string($course->shortname);
+                } else {
+                    $name .= format_string($course->fullname);
+                }
+            }
+        }
+
+        return $name;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG;
+
+        $SQL = "SELECT *
+                  FROM {$CFG->prefix}capabilities
+                 WHERE contextlevel IN (".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
+
+        return $SQL;
+    }
+
+    public function get_child_contexts($context) {
+        global $CFG, $context_cache;
+
+        // Find
+        // - module instances - easy
+        // - blocks assigned to the course-view page explicitly - easy
+        $sql = " SELECT ctx.*
+                     FROM {$CFG->prefix}context ctx
+                     WHERE ctx.path LIKE '{$context->path}/%'
+                           AND ctx.contextlevel IN (".CONTEXT_MODULE.",".CONTEXT_BLOCK.")
+            ";
+        $rs  = get_recordset_sql($sql);
+        $records = array();
+        while ($rec = rs_fetch_next_record($rs)) {
+            $records[$rec->id] = $rec;
+            $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+        }
+        rs_close($rs);
+        return $records;
+    }
+
+    public function get_component_string($component, $contextlevel) {
+        if (preg_match('|^gradeimport/|', $component)
+            || preg_match('|^gradeexport/|', $component)
+            || preg_match('|^gradereport/|', $component)) {
+            $string =  get_string('gradebook', 'admin');
+        } else if (preg_match('|^coursereport/|', $component)) {
+            $string = get_string('coursereports');
+        } else {
+            $string = get_string('course');
+        }
+
+        return $string;
+    }
+
+    public function build_context_path($force = false, $feedback = false) {
+        global $CFG;
+        require_once($CFG->libdir.'/ddllib.php');
+
+        // System context
+        $sitectx = get_system_context(!$force);
+        $base    = '/'.$sitectx->id;
+
+        // Sitecourse
+        $sitecoursectx = get_record('context',
+                                    'contextlevel', CONTEXT_COURSE,
+                                    'instanceid', SITEID);
+        if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+            set_field('context', 'path',  "$base/{$sitecoursectx->id}",
+                      'id', $sitecoursectx->id);
+            set_field('context', 'depth', 2,
+                      'id', $sitecoursectx->id);
+            $sitecoursectx = get_record('context',
+                                        'contextlevel', CONTEXT_COURSE,
+                                        'instanceid', SITEID);
+        }
+
+        $ctxemptyclause = " AND (ctx.path IS NULL
+                                  OR ctx.depth=0) ";
+        $emptyclause    = " AND ({$CFG->prefix}context.path IS NULL
+                                  OR {$CFG->prefix}context.depth=0) ";
+        if ($force) {
+            $ctxemptyclause = $emptyclause = '';
+        }
+
+        /* MDL-11347:
+         *  - mysql does not allow to use FROM in UPDATE statements
+         *  - using two tables after UPDATE works in mysql, but might give unexpected
+         *    results in pg 8 (depends on configuration)
+         *  - using table alias in UPDATE does not work in pg < 8.2
+         */
+        if ($CFG->dbfamily == 'mysql') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct, {$CFG->prefix}context_temp temp
+                             SET ct.path  = temp.path,
+                                 ct.depth = temp.depth
+                           WHERE ct.id = temp.id";
+        } else if ($CFG->dbfamily == 'oracle') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct
+                             SET (ct.path, ct.depth) =
+                                 (SELECT temp.path, temp.depth
+                                    FROM {$CFG->prefix}context_temp temp
+                                   WHERE temp.id=ct.id)
+                           WHERE EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ct.id)";
+        } else {
+            $updatesql = "UPDATE {$CFG->prefix}context
+                             SET path  = temp.path,
+                                 depth = temp.depth
+                            FROM {$CFG->prefix}context_temp temp
+                           WHERE temp.id={$CFG->prefix}context.id";
+        }
+
+        $udelsql = "TRUNCATE TABLE {$CFG->prefix}context_temp";
+
+        // Courses -- except sitecourse
+        $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
+                SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
+                  FROM {$CFG->prefix}context ctx
+                  JOIN {$CFG->prefix}course c ON ctx.instanceid=c.id
+                  JOIN {$CFG->prefix}context pctx ON c.category=pctx.instanceid
+                 WHERE ctx.contextlevel=".CONTEXT_COURSE."
+                       AND c.id!=".SITEID."
+                       AND pctx.contextlevel=".CONTEXT_COURSECAT."
+                           AND NOT EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ctx.id)
+                       $ctxemptyclause";
+        execute_sql($sql, $feedback);
+
+        execute_sql($updatesql, $feedback);
+        execute_sql($udelsql, $feedback);
+
+    }
+}
+
+class context_system extends context_level {
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        return get_string('coresystem');
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG;
+
+        $SQL = "SELECT *
+                  FROM {$CFG->prefix}capabilities";
+
+        return $SQL;
+    }
+
+    public function get_child_contexts($context) {
+        // Just get all the contexts except for CONTEXT_SYSTEM level
+        // and hope we don't OOM in the process - don't cache
+        $sql = 'SELECT c.*'.
+                 'FROM '.$CFG->prefix.'context c '.
+                'WHERE contextlevel != '.CONTEXT_SYSTEM;
+
+        return get_records_sql($sql);
+    }
+
+    public function get_component_string($component, $contextlevel) {
+        if (preg_match('|^enrol/|', $component)) {
+            $langname = str_replace('/', '_', $component);
+            $string = get_string('enrolname', $langname);
+        } else if (preg_match('|^block/|', $component)) {
+            $langname = str_replace('/', '_', $component);
+            $string = get_string('blockname', $langname);
+        } else if (preg_match('|^local|', $component)) {
+            $langname = str_replace('/', '_', $component);
+            $string = get_string('local');
+        } else if (preg_match('|^report/|', $component)) {
+            $string = get_string('reports');
+        } else {
+            $string = get_string('coresystem');
+        }
+
+        return $string;
+    }
+
+    public function cleanup_contexts_sql() {
+        return null;
+    }
+
+    public function build_context_path($force=false, $feedback=false) {}
+}
+
+class context_coursecat extends context_level {
+    protected $level = CONTEXT_COURSECAT;
+    protected $table = 'course_categories';
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        $name = '';
+
+        if ($category = get_record('course_categories', 'id', $context->instanceid)) {
+            if ($withprefix){
+                $name = get_string('category').': ';
+            }
+            $name .=format_string($category->name);
+        }
+
+        return $name;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG;
+
+        $SQL = "SELECT *
+                  FROM {$CFG->prefix}capabilities
+                 WHERE contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
+
+        return $SQL;
+    }
+
+    public function get_child_contexts($context) {
+        // Find
+        // - categories
+        // - courses
+        $sql = " SELECT ctx.*
+                 FROM {$CFG->prefix}context ctx
+                 WHERE ctx.path LIKE '{$context->path}/%'
+                       AND ctx.contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.")
+        ";
+        $rs  = get_recordset_sql($sql);
+        $records = array();
+        while ($rec = rs_fetch_next_record($rs)) {
+            $records[$rec->id] = $rec;
+            $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+        }
+        rs_close($rs);
+        return $records;
+    }
+
+    public function get_component_string($component, $contextlevel) {
+        return get_string('categories');
+    }
+
+    public function build_context_path($force = false, $feedback = false) {
+        global $CFG;
+        require_once($CFG->libdir.'/ddllib.php');
+
+        // System context
+        $sitectx = get_system_context(!$force);
+        $base    = '/'.$sitectx->id;
+
+        // Sitecourse
+        $sitecoursectx = get_record('context',
+                                    'contextlevel', CONTEXT_COURSE,
+                                    'instanceid', SITEID);
+        if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+            set_field('context', 'path',  "$base/{$sitecoursectx->id}",
+                      'id', $sitecoursectx->id);
+            set_field('context', 'depth', 2,
+                      'id', $sitecoursectx->id);
+            $sitecoursectx = get_record('context',
+                                        'contextlevel', CONTEXT_COURSE,
+                                        'instanceid', SITEID);
+        }
+
+        $ctxemptyclause = " AND (ctx.path IS NULL
+                                  OR ctx.depth=0) ";
+        $emptyclause    = " AND ({$CFG->prefix}context.path IS NULL
+                                  OR {$CFG->prefix}context.depth=0) ";
+        if ($force) {
+            $ctxemptyclause = $emptyclause = '';
+        }
+
+        /* MDL-11347:
+         *  - mysql does not allow to use FROM in UPDATE statements
+         *  - using two tables after UPDATE works in mysql, but might give unexpected
+         *    results in pg 8 (depends on configuration)
+         *  - using table alias in UPDATE does not work in pg < 8.2
+         */
+        if ($CFG->dbfamily == 'mysql') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct, {$CFG->prefix}context_temp temp
+                             SET ct.path  = temp.path,
+                                 ct.depth = temp.depth
+                           WHERE ct.id = temp.id";
+        } else if ($CFG->dbfamily == 'oracle') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct
+                             SET (ct.path, ct.depth) =
+                                 (SELECT temp.path, temp.depth
+                                    FROM {$CFG->prefix}context_temp temp
+                                   WHERE temp.id=ct.id)
+                           WHERE EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ct.id)";
+        } else {
+            $updatesql = "UPDATE {$CFG->prefix}context
+                             SET path  = temp.path,
+                                 depth = temp.depth
+                            FROM {$CFG->prefix}context_temp temp
+                           WHERE temp.id={$CFG->prefix}context.id";
+        }
+
+        $udelsql = "TRUNCATE TABLE {$CFG->prefix}context_temp";
+
+        // Top level categories
+        $sql = "UPDATE {$CFG->prefix}context
+                   SET depth=2, path=" . sql_concat("'$base/'", 'id') . "
+                 WHERE contextlevel=".CONTEXT_COURSECAT."
+                       AND EXISTS (SELECT 'x'
+                                     FROM {$CFG->prefix}course_categories cc
+                                    WHERE cc.id = {$CFG->prefix}context.instanceid
+                                          AND cc.depth=1)
+                       $emptyclause";
+
+        execute_sql($sql, $feedback);
+
+        execute_sql($udelsql, $feedback);
+
+        // Deeper categories - one query per depthlevel
+        $maxdepth = get_field_sql("SELECT MAX(depth)
+                                   FROM {$CFG->prefix}course_categories");
+        for ($n=2;$n<=$maxdepth;$n++) {
+            $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
+                    SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", $n+1
+                      FROM {$CFG->prefix}context ctx
+                      JOIN {$CFG->prefix}course_categories c ON ctx.instanceid=c.id
+                      JOIN {$CFG->prefix}context pctx ON c.parent=pctx.instanceid
+                     WHERE ctx.contextlevel=".CONTEXT_COURSECAT."
+                           AND pctx.contextlevel=".CONTEXT_COURSECAT."
+                           AND c.depth=$n
+                           AND NOT EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ctx.id)
+                           $ctxemptyclause";
+            execute_sql($sql, $feedback);
+
+            // this is needed after every loop
+            // MDL-11532
+            execute_sql($updatesql, $feedback);
+            execute_sql($udelsql, $feedback);
+        }
+
+    }
+}
+
+class context_module extends context_level {
+    protected $level = CONTEXT_MODULE;
+    protected $table = 'course_modules';
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        $name = '';
+
+        if ($cm = get_record('course_modules','id',$context->instanceid)) {
+            if ($module = get_record('modules','id',$cm->module)) {
+                if ($mod = get_record($module->name, 'id', $cm->instance)) {
+                    if ($withprefix){
+                        $name = get_string('activitymodule').': ';
+                    }
+                    $name .= $mod->name;
+                }
+            }
+        }
+
+        return $name;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG;
+
+        $cm = get_record('course_modules', 'id', $context->instanceid);
+        $module = get_record('modules', 'id', $cm->module);
+
+        $modfile = "$CFG->dirroot/mod/$module->name/lib.php";
+        if (file_exists($modfile)) {
+            include_once($modfile);
+            $modfunction = $module->name.'_get_extra_capabilities';
+            if (function_exists($modfunction)) {
+                $extracaps = $modfunction();
+            }
+        }
+        if(empty($extracaps)) {
+            $extracaps = array();
+        }
+
+        // All modules allow viewhiddenactivities. This is so you can hide
+        // the module then override to allow specific roles to see it.
+        // The actual check is in course page so not module-specific
+        $extracaps[]="moodle/course:viewhiddenactivities";
+        if (count($extracaps) == 1) {
+            $extra = "OR name = '".reset($extracaps)."'";
+        } else {
+            foreach ($extracaps as $key=>$value) {
+                $extracaps[$key]= "'$value'";
+            }
+            $extra = implode(',', $extracaps);
+            $extra = "OR name IN ($extra)";
+        }
+
+        $SQL = "SELECT *
+                  FROM {$CFG->prefix}capabilities
+                 WHERE (contextlevel = ".CONTEXT_MODULE."
+                       AND component = 'mod/$module->name')
+                       $extra";
+
+        return $SQL;
+    }
+
+    public function get_child_contexts($context) {
+        //no children by default
+        return array();
+    }
+
+    public function get_component_string($component, $contextlevel) {
+        return get_string('modulename', basename($component));
+    }
+
+    public function build_context_path($force=false, $feedback=false) {
+        global $CFG;
+        require_once($CFG->libdir.'/ddllib.php');
+
+        // System context
+        $sitectx = get_system_context(!$force);
+        $base    = '/'.$sitectx->id;
+
+        // Sitecourse
+        $sitecoursectx = get_record('context',
+                                    'contextlevel', CONTEXT_COURSE,
+                                    'instanceid', SITEID);
+        if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+            set_field('context', 'path',  "$base/{$sitecoursectx->id}",
+                      'id', $sitecoursectx->id);
+            set_field('context', 'depth', 2,
+                      'id', $sitecoursectx->id);
+            $sitecoursectx = get_record('context',
+                                        'contextlevel', CONTEXT_COURSE,
+                                        'instanceid', SITEID);
+        }
+
+        $ctxemptyclause = " AND (ctx.path IS NULL
+                                  OR ctx.depth=0) ";
+        $emptyclause    = " AND ({$CFG->prefix}context.path IS NULL
+                                  OR {$CFG->prefix}context.depth=0) ";
+        if ($force) {
+            $ctxemptyclause = $emptyclause = '';
+        }
+
+        /* MDL-11347:
+         *  - mysql does not allow to use FROM in UPDATE statements
+         *  - using two tables after UPDATE works in mysql, but might give unexpected
+         *    results in pg 8 (depends on configuration)
+         *  - using table alias in UPDATE does not work in pg < 8.2
+         */
+        if ($CFG->dbfamily == 'mysql') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct, {$CFG->prefix}context_temp temp
+                             SET ct.path  = temp.path,
+                                 ct.depth = temp.depth
+                           WHERE ct.id = temp.id";
+        } else if ($CFG->dbfamily == 'oracle') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct
+                             SET (ct.path, ct.depth) =
+                                 (SELECT temp.path, temp.depth
+                                    FROM {$CFG->prefix}context_temp temp
+                                   WHERE temp.id=ct.id)
+                           WHERE EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ct.id)";
+        } else {
+            $updatesql = "UPDATE {$CFG->prefix}context
+                             SET path  = temp.path,
+                                 depth = temp.depth
+                            FROM {$CFG->prefix}context_temp temp
+                           WHERE temp.id={$CFG->prefix}context.id";
+        }
+
+        $udelsql = "TRUNCATE TABLE {$CFG->prefix}context_temp";
+
+        // Module instances
+        $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
+                SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
+                  FROM {$CFG->prefix}context ctx
+                  JOIN {$CFG->prefix}course_modules cm ON ctx.instanceid=cm.id
+                  JOIN {$CFG->prefix}context pctx ON cm.course=pctx.instanceid
+                 WHERE ctx.contextlevel=".CONTEXT_MODULE."
+                       AND pctx.contextlevel=".CONTEXT_COURSE."
+                           AND NOT EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ctx.id)
+                       $ctxemptyclause";
+        execute_sql($sql, $feedback);
+
+        execute_sql($updatesql, $feedback);
+        execute_sql($udelsql, $feedback);
+    }
+}
+
+class context_block extends context_level {
+    protected $level = CONTEXT_BLOCK;
+    protected $table = 'block_instance';
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        $name = '';
+
+        if ($blockinstance = get_record('block_instance','id',$context->instanceid)) {
+            if ($block = get_record('block','id',$blockinstance->blockid)) {
+                global $CFG;
+                require_once("$CFG->dirroot/blocks/moodleblock.class.php");
+                require_once("$CFG->dirroot/blocks/$block->name/block_$block->name.php");
+                $blockname = "block_$block->name";
+                if ($blockobject = new $blockname()) {
+                    if ($withprefix){
+                        $name = get_string('block').': ';
+                    }
+                    $name .= $blockobject->title;
+                }
+            }
+        }
+
+        return $name;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG;
+
+        $cb = get_record('block_instance', 'id', $context->instanceid);
+        $block = get_record('block', 'id', $cb->blockid);
+
+        $extra = "";
+        if ($blockinstance = block_instance($block->name)) {
+            if ($extracaps = $blockinstance->get_extra_capabilities()) {
+                foreach ($extracaps as $key=>$value) {
+                    $extracaps[$key]= "'$value'";
+                }
+                $extra = implode(',', $extracaps);
+                $extra = "OR name IN ($extra)";
+            }
+        }
+
+        $SQL = "SELECT *
+                  FROM {$CFG->prefix}capabilities
+                 WHERE (contextlevel = ".CONTEXT_BLOCK."
+                       AND component = 'block/$block->name')
+                       $extra";
+
+       return $SQL;
+    }
+
+    public function get_child_contexts($context) {
+        //no children by default
+        return array();
+    }
+
+    public function get_component_string($component, $contextlevel) {
+        if( $component == 'moodle' ){
+            $string = get_string('block');
+        }else{
+            $string = get_string('blockname', 'block_'.basename($component));
+        }
+
+        return $string;
+    }
+
+    public function build_context_path($force=false, $feedback=false) {
+        global $CFG;
+        require_once($CFG->libdir.'/ddllib.php');
+
+        // System context
+        $sitectx = get_system_context(!$force);
+        $base    = '/'.$sitectx->id;
+
+        // Sitecourse
+        $sitecoursectx = get_record('context',
+                                    'contextlevel', CONTEXT_COURSE,
+                                    'instanceid', SITEID);
+        if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+            set_field('context', 'path',  "$base/{$sitecoursectx->id}",
+                      'id', $sitecoursectx->id);
+            set_field('context', 'depth', 2,
+                      'id', $sitecoursectx->id);
+            $sitecoursectx = get_record('context',
+                                        'contextlevel', CONTEXT_COURSE,
+                                        'instanceid', SITEID);
+        }
+
+        $ctxemptyclause = " AND (ctx.path IS NULL
+                                  OR ctx.depth=0) ";
+        $emptyclause    = " AND ({$CFG->prefix}context.path IS NULL
+                                  OR {$CFG->prefix}context.depth=0) ";
+        if ($force) {
+            $ctxemptyclause = $emptyclause = '';
+        }
+
+        /* MDL-11347:
+         *  - mysql does not allow to use FROM in UPDATE statements
+         *  - using two tables after UPDATE works in mysql, but might give unexpected
+         *    results in pg 8 (depends on configuration)
+         *  - using table alias in UPDATE does not work in pg < 8.2
+         */
+        if ($CFG->dbfamily == 'mysql') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct, {$CFG->prefix}context_temp temp
+                             SET ct.path  = temp.path,
+                                 ct.depth = temp.depth
+                           WHERE ct.id = temp.id";
+        } else if ($CFG->dbfamily == 'oracle') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct
+                             SET (ct.path, ct.depth) =
+                                 (SELECT temp.path, temp.depth
+                                    FROM {$CFG->prefix}context_temp temp
+                                   WHERE temp.id=ct.id)
+                           WHERE EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ct.id)";
+        } else {
+            $updatesql = "UPDATE {$CFG->prefix}context
+                             SET path  = temp.path,
+                                 depth = temp.depth
+                            FROM {$CFG->prefix}context_temp temp
+                           WHERE temp.id={$CFG->prefix}context.id";
+        }
+
+        $udelsql = "TRUNCATE TABLE {$CFG->prefix}context_temp";
+
+        // Blocks - non-pinned course-view only
+        $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
+                SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
+                  FROM {$CFG->prefix}context ctx
+                  JOIN {$CFG->prefix}block_instance bi ON ctx.instanceid = bi.id
+                  JOIN {$CFG->prefix}context pctx ON bi.pageid=pctx.instanceid
+                 WHERE ctx.contextlevel=".CONTEXT_BLOCK."
+                       AND pctx.contextlevel=".CONTEXT_COURSE."
+                       AND bi.pagetype='course-view'
+                           AND NOT EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ctx.id)
+                       $ctxemptyclause";
+        execute_sql($sql, $feedback);
+
+        execute_sql($updatesql, $feedback);
+        execute_sql($udelsql, $feedback);
+
+        // Blocks - others
+        $sql = "UPDATE {$CFG->prefix}context
+                   SET depth=2, path=".sql_concat("'$base/'", 'id')."
+                 WHERE contextlevel=".CONTEXT_BLOCK."
+                       AND EXISTS (SELECT 'x'
+                                     FROM {$CFG->prefix}block_instance bi
+                                    WHERE bi.id = {$CFG->prefix}context.instanceid
+                                          AND bi.pagetype!='course-view')
+                       $emptyclause ";
+        execute_sql($sql, $feedback);
+    }
+}
+
+class context_user extends context_level {
+    protected $level = CONTEXT_USER;
+    protected $table = 'user';
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        $name = '';
+        $user = get_record('user', 'id', $context->instanceid);
+
+        if (!empty($user)) {
+            if ($withprefix){
+                $name = get_string('user').': ';
+            }
+            $name .= fullname($user);
+        }
+
+        return $name;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG;
+
+        $extracaps = array('moodle/grade:viewall');
+
+        foreach ($extracaps as $key=>$value) {
+            $extracaps[$key]= "'$value'";
+        }
+
+        $extra = implode(',', $extracaps);
+        $SQL = "SELECT *
+                  FROM {$CFG->prefix}capabilities
+                 WHERE contextlevel = ".CONTEXT_USER."
+                       OR name IN ($extra)";
+
+        return $SQL;
+    }
+
+    public function get_child_contexts($context) {
+        //no children by default
+        return array();
+    }
+
+    public function get_component_string($component, $contextlevel) {
+        return get_string('users');
+    }
+
+    public function build_context_path($force=false, $feedback=false) {
+        global $CFG;
+        require_once($CFG->libdir.'/ddllib.php');
+
+        // System context
+        $sitectx = get_system_context(!$force);
+        $base    = '/'.$sitectx->id;
+
+        // Sitecourse
+        $sitecoursectx = get_record('context',
+                                    'contextlevel', CONTEXT_COURSE,
+                                    'instanceid', SITEID);
+        if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+            set_field('context', 'path',  "$base/{$sitecoursectx->id}",
+                      'id', $sitecoursectx->id);
+            set_field('context', 'depth', 2,
+                      'id', $sitecoursectx->id);
+            $sitecoursectx = get_record('context',
+                                        'contextlevel', CONTEXT_COURSE,
+                                        'instanceid', SITEID);
+        }
+
+        $ctxemptyclause = " AND (ctx.path IS NULL
+                                  OR ctx.depth=0) ";
+        $emptyclause    = " AND ({$CFG->prefix}context.path IS NULL
+                                  OR {$CFG->prefix}context.depth=0) ";
+        if ($force) {
+            $ctxemptyclause = $emptyclause = '';
+        }
+
+        /* MDL-11347:
+         *  - mysql does not allow to use FROM in UPDATE statements
+         *  - using two tables after UPDATE works in mysql, but might give unexpected
+         *    results in pg 8 (depends on configuration)
+         *  - using table alias in UPDATE does not work in pg < 8.2
+         */
+        if ($CFG->dbfamily == 'mysql') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct, {$CFG->prefix}context_temp temp
+                             SET ct.path  = temp.path,
+                                 ct.depth = temp.depth
+                           WHERE ct.id = temp.id";
+        } else if ($CFG->dbfamily == 'oracle') {
+            $updatesql = "UPDATE {$CFG->prefix}context ct
+                             SET (ct.path, ct.depth) =
+                                 (SELECT temp.path, temp.depth
+                                    FROM {$CFG->prefix}context_temp temp
+                                   WHERE temp.id=ct.id)
+                           WHERE EXISTS (SELECT 'x'
+                                           FROM {$CFG->prefix}context_temp temp
+                                           WHERE temp.id = ct.id)";
+        } else {
+            $updatesql = "UPDATE {$CFG->prefix}context
+                             SET path  = temp.path,
+                                 depth = temp.depth
+                            FROM {$CFG->prefix}context_temp temp
+                           WHERE temp.id={$CFG->prefix}context.id";
+        }
+
+        $udelsql = "TRUNCATE TABLE {$CFG->prefix}context_temp";
+
+        // User
+        $sql = "UPDATE {$CFG->prefix}context
+                   SET depth=2, path=".sql_concat("'$base/'", 'id')."
+                 WHERE contextlevel=".CONTEXT_USER."
+                       AND EXISTS (SELECT 'x'
+                                     FROM {$CFG->prefix}user u
+                                    WHERE u.id = {$CFG->prefix}context.instanceid)
+                       $emptyclause ";
+        execute_sql($sql, $feedback);
+    }
+}
+
+$context_levels = array(
+    CONTEXT_SYSTEM      => new context_system(),
+    CONTEXT_USER        => new context_user(),
+    CONTEXT_COURSECAT   => new context_coursecat(),
+    CONTEXT_COURSE      => new context_course(),
+    CONTEXT_MODULE      => new context_module(),
+    CONTEXT_BLOCK       => new context_block(),
+    );
+
+/**
  * Adds a context to the cache.
  * @param object $context Context object to be cached
  */
@@ -2389,43 +3267,23 @@ function create_contexts($contextlevel=null, $buildpaths=true, $feedback=false)
  * @return bool
  */
 function cleanup_contexts() {
-    global $CFG;
+    global $CFG, $context_levels;
+
+    // context class will contain function with the sql returned
+    // iterate over all the contexts to generate the sql
+
+    $pre_sql = array();
+
+    foreach($context_levels as $cl) {
+        $current_sql = $cl->cleanup_contexts_sql();
+
+        if(!empty($current_sql)) {
+            $pre_sql[] = $current_sql;
+        }
+    }
+
+    $sql = implode("\n UNION \n", $pre_sql);
 
-    $sql = "  SELECT c.contextlevel,
-                     c.instanceid AS instanceid
-              FROM {$CFG->prefix}context c
-              LEFT OUTER JOIN {$CFG->prefix}course_categories t
-                ON c.instanceid = t.id
-              WHERE t.id IS NULL AND c.contextlevel = " . CONTEXT_COURSECAT . "
-            UNION
-              SELECT c.contextlevel,
-                     c.instanceid
-              FROM {$CFG->prefix}context c
-              LEFT OUTER JOIN {$CFG->prefix}course t
-                ON c.instanceid = t.id
-              WHERE t.id IS NULL AND c.contextlevel = " . CONTEXT_COURSE . "
-            UNION
-              SELECT c.contextlevel,
-                     c.instanceid
-              FROM {$CFG->prefix}context c
-              LEFT OUTER JOIN {$CFG->prefix}course_modules t
-                ON c.instanceid = t.id
-              WHERE t.id IS NULL AND c.contextlevel = " . CONTEXT_MODULE . "
-            UNION
-              SELECT c.contextlevel,
-                     c.instanceid
-              FROM {$CFG->prefix}context c
-              LEFT OUTER JOIN {$CFG->prefix}user t
-                ON c.instanceid = t.id
-              WHERE t.id IS NULL AND c.contextlevel = " . CONTEXT_USER . "
-            UNION
-              SELECT c.contextlevel,
-                     c.instanceid
-              FROM {$CFG->prefix}context c
-              LEFT OUTER JOIN {$CFG->prefix}block_instance t
-                ON c.instanceid = t.id
-              WHERE t.id IS NULL AND c.contextlevel = " . CONTEXT_BLOCK . "
-           ";
     if ($rs = get_recordset_sql($sql)) {
         begin_sql();
         $tx = true;
@@ -2499,8 +3357,7 @@ function preload_course_contexts($courseid) {
  */
 function get_context_instance($contextlevel, $instance=0) {
 
-    global $context_cache, $context_cache_id, $CFG;
-    static $allowed_contexts = array(CONTEXT_SYSTEM, CONTEXT_USER, CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_MODULE, CONTEXT_BLOCK);
+    global $context_cache, $context_cache_id, $CFG, $context_levels;
 
     if ($contextlevel === 'clearcache') {
         // TODO: Remove for v2.0
@@ -2517,7 +3374,7 @@ function get_context_instance($contextlevel, $instance=0) {
     }
 
 /// check allowed context levels
-    if (!in_array($contextlevel, $allowed_contexts)) {
+    if (empty($context_levels[$contextlevel])) {
         // fatal error, code must be fixed - probably typo or switched parameters
         error('Error: get_context_instance() called with incorrect context level "'.s($contextlevel).'"');
     }
@@ -3430,85 +4287,13 @@ function capabilities_cleanup($component, $newcapdef=NULL) {
  * prints human readable context identifier.
  */
 function print_context_name($context, $withprefix = true, $short = false) {
+    global $context_levels;
 
-    $name = '';
-    switch ($context->contextlevel) {
-
-        case CONTEXT_SYSTEM: // by now it's a definite an inherit
-            $name = get_string('coresystem');
-            break;
-
-        case CONTEXT_USER:
-            if ($user = get_record('user', 'id', $context->instanceid)) {
-                if ($withprefix){
-                    $name = get_string('user').': ';
-                }
-                $name .= fullname($user);
-            }
-            break;
-
-        case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
-            if ($category = get_record('course_categories', 'id', $context->instanceid)) {
-                if ($withprefix){
-                    $name = get_string('category').': ';
-                }
-                $name .=format_string($category->name);
-            }
-            break;
-
-        case CONTEXT_COURSE: // 1 to 1 to course cat
-            if ($context->instanceid == SITEID) {
-                $name = get_string('frontpage', 'admin');
-            } else {
-                if ($course = get_record('course', 'id', $context->instanceid)) {
-                    if ($withprefix){
-                        $name = get_string('course').': ';
-                    }
-                    if (!$short){
-                        $name .= format_string($course->shortname);
-                    } else {
-                        $name .= format_string($course->fullname);
-                   }
-                }
-            }
-            break;
-
-        case CONTEXT_MODULE: // 1 to 1 to course
-            if ($cm = get_record('course_modules','id',$context->instanceid)) {
-                if ($module = get_record('modules','id',$cm->module)) {
-                    if ($mod = get_record($module->name, 'id', $cm->instance)) {
-                        if ($withprefix){
-                            $name = get_string('activitymodule').': ';
-                        }
-                        $name .= $mod->name;
-                    }
-                }
-            }
-            break;
-
-        case CONTEXT_BLOCK: // not necessarily 1 to 1 to course
-            if ($blockinstance = get_record('block_instance','id',$context->instanceid)) {
-                if ($block = get_record('block','id',$blockinstance->blockid)) {
-                    global $CFG;
-                    require_once("$CFG->dirroot/blocks/moodleblock.class.php");
-                    require_once("$CFG->dirroot/blocks/$block->name/block_$block->name.php");
-                    $blockname = "block_$block->name";
-                    if ($blockobject = new $blockname()) {
-                        if ($withprefix){
-                            $name = get_string('block').': ';
-                        }
-                        $name .= $blockobject->title;
-                    }
-                }
-            }
-            break;
-
-        default:
-            error ('This is an unknown context (' . $context->contextlevel . ') in print_context_name!');
-            return false;
-
+    if (!empty($context_levels[$context->contextlevel])) {
+        return $context_levels[$context->contextlevel]->print_context_name($context, $withprefix, $short);
+    } else {
+        error ('This is an unknown context (' . $context->contextlevel . ') in print_context_name!');
     }
-    return $name;
 }
 
 
@@ -3527,110 +4312,13 @@ function print_context_name($context, $withprefix = true, $short = false) {
  * `component` varchar(100) NOT NULL,
  */
 function fetch_context_capabilities($context) {
+    global $CFG, $context_levels;
 
-    global $CFG;
-
-    $sort = 'ORDER BY contextlevel,component,name';   // To group them sensibly for display
-
-    switch ($context->contextlevel) {
-
-        case CONTEXT_SYSTEM: // all
-            $SQL = "SELECT *
-                      FROM {$CFG->prefix}capabilities";
-        break;
-
-        case CONTEXT_USER:
-            $extracaps = array('moodle/grade:viewall');
-            foreach ($extracaps as $key=>$value) {
-                $extracaps[$key]= "'$value'";
-            }
-            $extra = implode(',', $extracaps);
-            $SQL = "SELECT *
-                      FROM {$CFG->prefix}capabilities
-                     WHERE contextlevel = ".CONTEXT_USER."
-                           OR name IN ($extra)";
-        break;
-
-        case CONTEXT_COURSECAT: // course category context and bellow
-            $SQL = "SELECT *
-                      FROM {$CFG->prefix}capabilities
-                     WHERE contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
-        break;
-
-        case CONTEXT_COURSE: // course context and bellow
-            $SQL = "SELECT *
-                      FROM {$CFG->prefix}capabilities
-                     WHERE contextlevel IN (".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
-        break;
-
-        case CONTEXT_MODULE: // mod caps
-            $cm = get_record('course_modules', 'id', $context->instanceid);
-            $module = get_record('modules', 'id', $cm->module);
-
-            $modfile = "$CFG->dirroot/mod/$module->name/lib.php";
-            if (file_exists($modfile)) {
-                include_once($modfile);
-                $modfunction = $module->name.'_get_extra_capabilities';
-                if (function_exists($modfunction)) {
-                    $extracaps = $modfunction();
-                }
-            }
-            if(empty($extracaps)) {
-                $extracaps = array();
-            }
-
-            // All modules allow viewhiddenactivities. This is so you can hide
-            // the module then override to allow specific roles to see it.
-            // The actual check is in course page so not module-specific
-            $extracaps[]="moodle/course:viewhiddenactivities";
-            if (count($extracaps) == 1) {
-                $extra = "OR name = '".reset($extracaps)."'";
-            } else {
-                foreach ($extracaps as $key=>$value) {
-                    $extracaps[$key]= "'$value'";
-                }
-                $extra = implode(',', $extracaps);
-                $extra = "OR name IN ($extra)";
-            }
-
-            $SQL = "SELECT *
-                      FROM {$CFG->prefix}capabilities
-                     WHERE (contextlevel = ".CONTEXT_MODULE."
-                           AND component = 'mod/$module->name')
-                           $extra";
-        break;
-
-        case CONTEXT_BLOCK: // block caps
-            $cb = get_record('block_instance', 'id', $context->instanceid);
-            $block = get_record('block', 'id', $cb->blockid);
-
-            $extra = "";
-            if ($blockinstance = block_instance($block->name)) {
-                if ($extracaps = $blockinstance->get_extra_capabilities()) {
-                    foreach ($extracaps as $key=>$value) {
-                        $extracaps[$key]= "'$value'";
-                    }
-                    $extra = implode(',', $extracaps);
-                    $extra = "OR name IN ($extra)";
-                }
-            }
-
-            $SQL = "SELECT *
-                      FROM {$CFG->prefix}capabilities
-                     WHERE (contextlevel = ".CONTEXT_BLOCK."
-                           AND component = 'block/$block->name')
-                           $extra";
-        break;
-
-        default:
+    if(!empty($context_levels[$context->contextlevel])) {
+        return $context_levels[$context->contextlevel]->fetch_context_capabilities($context);
+    } else {
         return false;
     }
-
-    if (!$records = get_records_sql($SQL.' '.$sort)) {
-        $records = array();
-    }
-
-    return $records;
 }
 
 
@@ -3742,81 +4430,12 @@ function is_inside_frontpage($context) {
  * @return array of child records
  */
 function get_child_contexts($context) {
+    global $CFG, $context_cache, $context_levels;
 
-    global $CFG, $context_cache;
-
-    // We *MUST* populate the context_cache as the callers
-    // will probably ask for the full record anyway soon after
-    // soon after calling us ;-)
-
-    switch ($context->contextlevel) {
-
-        case CONTEXT_BLOCK:
-            // No children.
-            return array();
-        break;
-
-        case CONTEXT_MODULE:
-            // No children.
-            return array();
-        break;
-
-        case CONTEXT_COURSE:
-            // Find
-            // - module instances - easy
-            // - blocks assigned to the course-view page explicitly - easy
-            $sql = " SELECT ctx.*
-                     FROM {$CFG->prefix}context ctx
-                     WHERE ctx.path LIKE '{$context->path}/%'
-                           AND ctx.contextlevel IN (".CONTEXT_MODULE.",".CONTEXT_BLOCK.")
-            ";
-            $rs  = get_recordset_sql($sql);
-            $records = array();
-            while ($rec = rs_fetch_next_record($rs)) {
-                $records[$rec->id] = $rec;
-                $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
-            }
-            rs_close($rs);
-            return $records;
-        break;
-
-        case CONTEXT_COURSECAT:
-            // Find
-            // - categories
-            // - courses
-            $sql = " SELECT ctx.*
-                     FROM {$CFG->prefix}context ctx
-                     WHERE ctx.path LIKE '{$context->path}/%'
-                           AND ctx.contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.")
-            ";
-            $rs  = get_recordset_sql($sql);
-            $records = array();
-            while ($rec = rs_fetch_next_record($rs)) {
-                $records[$rec->id] = $rec;
-                $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
-            }
-            rs_close($rs);
-            return $records;
-        break;
-
-        case CONTEXT_USER:
-            // No children.
-            return array();
-        break;
-
-        case CONTEXT_SYSTEM:
-            // Just get all the contexts except for CONTEXT_SYSTEM level
-            // and hope we don't OOM in the process - don't cache
-            $sql = 'SELECT c.*'.
-                     'FROM '.$CFG->prefix.'context c '.
-                    'WHERE contextlevel != '.CONTEXT_SYSTEM;
-
-            return get_records_sql($sql);
-        break;
-
-        default:
-            error('This is an unknown context (' . $context->contextlevel . ') in get_child_contexts!');
-        return false;
+    if(!empty($context_levels[$context->contextlevel])) {
+        return $context_levels[$context->contextlevel]->get_child_contexts($context);
+    } else {
+        error('This is an unknown context (' . $context->contextlevel . ') in get_child_contexts!');
     }
 }
 
@@ -3925,64 +4544,13 @@ function get_capability_string($capabilityname) {
  * @param $contextlevel
  */
 function get_component_string($component, $contextlevel) {
+    global $context_levels;
 
-    switch ($contextlevel) {
-
-        case CONTEXT_SYSTEM:
-            if (preg_match('|^enrol/|', $component)) {
-                $langname = str_replace('/', '_', $component);
-                $string = get_string('enrolname', $langname);
-            } else if (preg_match('|^block/|', $component)) {
-                $langname = str_replace('/', '_', $component);
-                $string = get_string('blockname', $langname);
-            } else if (preg_match('|^local|', $component)) {
-                $langname = str_replace('/', '_', $component);
-                $string = get_string('local');
-            } else if (preg_match('|^report/|', $component)) {
-                $string = get_string('reports');
-            } else {
-                $string = get_string('coresystem');
-            }
-        break;
-
-        case CONTEXT_USER:
-            $string = get_string('users');
-        break;
-
-        case CONTEXT_COURSECAT:
-            $string = get_string('categories');
-        break;
-
-        case CONTEXT_COURSE:
-            if (preg_match('|^gradeimport/|', $component)
-                || preg_match('|^gradeexport/|', $component)
-                || preg_match('|^gradereport/|', $component)) {
-                $string = get_string('gradebook', 'admin');
-            } else if (preg_match('|^coursereport/|', $component)) {
-                $string = get_string('coursereports');
-            } else {
-                $string = get_string('course');
-            }
-        break;
-
-        case CONTEXT_MODULE:
-            $string = get_string('modulename', basename($component));
-        break;
-
-        case CONTEXT_BLOCK:
-            if( $component == 'moodle' ){
-                $string = get_string('block');
-            }else{
-                $string = get_string('blockname', 'block_'.basename($component));
-            }
-        break;
-
-        default:
-            error ('This is an unknown context $contextlevel (' . $contextlevel . ') in get_component_string!');
-        return false;
-
+    if(!empty($context_levels[$contextlevel])) {
+        return $context_levels[$contextlevel]->get_component_string($component, $contextlevel);
+    } else {
+        error ('This is an unknown context $contextlevel (' . $contextlevel . ') in get_component_string!');
     }
-    return $string;
 }
 
 /**
@@ -5394,181 +5962,12 @@ function component_level_changed($cap, $comp, $contextlevel) {
  * @return void
  */
 function build_context_path($force=false, $feedback=false) {
-    global $CFG;
-    require_once($CFG->libdir.'/ddllib.php');
-
-    // System context
-    $sitectx = get_system_context(!$force);
-    $base    = '/'.$sitectx->id;
-
-    // Sitecourse
-    $sitecoursectx = get_record('context',
-                                'contextlevel', CONTEXT_COURSE,
-                                'instanceid', SITEID);
-    if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
-        set_field('context', 'path',  "$base/{$sitecoursectx->id}",
-                  'id', $sitecoursectx->id);
-        set_field('context', 'depth', 2,
-                  'id', $sitecoursectx->id);
-        $sitecoursectx = get_record('context',
-                                    'contextlevel', CONTEXT_COURSE,
-                                    'instanceid', SITEID);
-    }
-
-    $ctxemptyclause = " AND (ctx.path IS NULL
-                              OR ctx.depth=0) ";
-    $emptyclause    = " AND ({$CFG->prefix}context.path IS NULL
-                              OR {$CFG->prefix}context.depth=0) ";
-    if ($force) {
-        $ctxemptyclause = $emptyclause = '';
-    }
+    global $context_levels;
 
-    /* MDL-11347:
-     *  - mysql does not allow to use FROM in UPDATE statements
-     *  - using two tables after UPDATE works in mysql, but might give unexpected
-     *    results in pg 8 (depends on configuration)
-     *  - using table alias in UPDATE does not work in pg < 8.2
-     */
-    if ($CFG->dbfamily == 'mysql') {
-        $updatesql = "UPDATE {$CFG->prefix}context ct, {$CFG->prefix}context_temp temp
-                         SET ct.path  = temp.path,
-                             ct.depth = temp.depth
-                       WHERE ct.id = temp.id";
-    } else if ($CFG->dbfamily == 'oracle') {
-        $updatesql = "UPDATE {$CFG->prefix}context ct
-                         SET (ct.path, ct.depth) =
-                             (SELECT temp.path, temp.depth
-                                FROM {$CFG->prefix}context_temp temp
-                               WHERE temp.id=ct.id)
-                       WHERE EXISTS (SELECT 'x'
-                                       FROM {$CFG->prefix}context_temp temp
-                                       WHERE temp.id = ct.id)";
-    } else {
-        $updatesql = "UPDATE {$CFG->prefix}context
-                         SET path  = temp.path,
-                             depth = temp.depth
-                        FROM {$CFG->prefix}context_temp temp
-                       WHERE temp.id={$CFG->prefix}context.id";
-    }
-
-    $udelsql = "TRUNCATE TABLE {$CFG->prefix}context_temp";
-
-    // Top level categories
-    $sql = "UPDATE {$CFG->prefix}context
-               SET depth=2, path=" . sql_concat("'$base/'", 'id') . "
-             WHERE contextlevel=".CONTEXT_COURSECAT."
-                   AND EXISTS (SELECT 'x'
-                                 FROM {$CFG->prefix}course_categories cc
-                                WHERE cc.id = {$CFG->prefix}context.instanceid
-                                      AND cc.depth=1)
-                   $emptyclause";
-
-    execute_sql($sql, $feedback);
-
-    execute_sql($udelsql, $feedback);
-
-    // Deeper categories - one query per depthlevel
-    $maxdepth = get_field_sql("SELECT MAX(depth)
-                               FROM {$CFG->prefix}course_categories");
-    for ($n=2;$n<=$maxdepth;$n++) {
-        $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
-                SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", $n+1
-                  FROM {$CFG->prefix}context ctx
-                  JOIN {$CFG->prefix}course_categories c ON ctx.instanceid=c.id
-                  JOIN {$CFG->prefix}context pctx ON c.parent=pctx.instanceid
-                 WHERE ctx.contextlevel=".CONTEXT_COURSECAT."
-                       AND pctx.contextlevel=".CONTEXT_COURSECAT."
-                       AND c.depth=$n
-                       AND NOT EXISTS (SELECT 'x'
-                                       FROM {$CFG->prefix}context_temp temp
-                                       WHERE temp.id = ctx.id)
-                       $ctxemptyclause";
-        execute_sql($sql, $feedback);
-        
-        // this is needed after every loop
-        // MDL-11532
-        execute_sql($updatesql, $feedback);
-        execute_sql($udelsql, $feedback);
+    foreach($context_levels as $cl) {
+        $cl->build_context_path($force, $feedback);
     }
 
-    // Courses -- except sitecourse
-    $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
-            SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
-              FROM {$CFG->prefix}context ctx
-              JOIN {$CFG->prefix}course c ON ctx.instanceid=c.id
-              JOIN {$CFG->prefix}context pctx ON c.category=pctx.instanceid
-             WHERE ctx.contextlevel=".CONTEXT_COURSE."
-                   AND c.id!=".SITEID."
-                   AND pctx.contextlevel=".CONTEXT_COURSECAT."
-                       AND NOT EXISTS (SELECT 'x'
-                                       FROM {$CFG->prefix}context_temp temp
-                                       WHERE temp.id = ctx.id)
-                   $ctxemptyclause";
-    execute_sql($sql, $feedback);
-
-    execute_sql($updatesql, $feedback);
-    execute_sql($udelsql, $feedback);
-
-    // Module instances
-    $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
-            SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
-              FROM {$CFG->prefix}context ctx
-              JOIN {$CFG->prefix}course_modules cm ON ctx.instanceid=cm.id
-              JOIN {$CFG->prefix}context pctx ON cm.course=pctx.instanceid
-             WHERE ctx.contextlevel=".CONTEXT_MODULE."
-                   AND pctx.contextlevel=".CONTEXT_COURSE."
-                       AND NOT EXISTS (SELECT 'x'
-                                       FROM {$CFG->prefix}context_temp temp
-                                       WHERE temp.id = ctx.id)
-                   $ctxemptyclause";
-    execute_sql($sql, $feedback);
-
-    execute_sql($updatesql, $feedback);
-    execute_sql($udelsql, $feedback);
-
-    // Blocks - non-pinned course-view only
-    $sql = "INSERT INTO {$CFG->prefix}context_temp (id, path, depth)
-            SELECT ctx.id, ".sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
-              FROM {$CFG->prefix}context ctx
-              JOIN {$CFG->prefix}block_instance bi ON ctx.instanceid = bi.id
-              JOIN {$CFG->prefix}context pctx ON bi.pageid=pctx.instanceid
-             WHERE ctx.contextlevel=".CONTEXT_BLOCK."
-                   AND pctx.contextlevel=".CONTEXT_COURSE."
-                   AND bi.pagetype='course-view'
-                       AND NOT EXISTS (SELECT 'x'
-                                       FROM {$CFG->prefix}context_temp temp
-                                       WHERE temp.id = ctx.id)
-                   $ctxemptyclause";
-    execute_sql($sql, $feedback);
-
-    execute_sql($updatesql, $feedback);
-    execute_sql($udelsql, $feedback);
-
-    // Blocks - others
-    $sql = "UPDATE {$CFG->prefix}context
-               SET depth=2, path=".sql_concat("'$base/'", 'id')."
-             WHERE contextlevel=".CONTEXT_BLOCK."
-                   AND EXISTS (SELECT 'x'
-                                 FROM {$CFG->prefix}block_instance bi
-                                WHERE bi.id = {$CFG->prefix}context.instanceid
-                                      AND bi.pagetype!='course-view')
-                   $emptyclause ";
-    execute_sql($sql, $feedback);
-
-    // User
-    $sql = "UPDATE {$CFG->prefix}context
-               SET depth=2, path=".sql_concat("'$base/'", 'id')."
-             WHERE contextlevel=".CONTEXT_USER."
-                   AND EXISTS (SELECT 'x'
-                                 FROM {$CFG->prefix}user u
-                                WHERE u.id = {$CFG->prefix}context.instanceid)
-                   $emptyclause ";
-    execute_sql($sql, $feedback);
-
-    // Personal TODO
-
-    //TODO: fix group contexts
-
     // reset static course cache - it might have incorrect cached data
     global $context_cache, $context_cache_id;
     $context_cache    = array();

