diff --git a/lib/accesslib.php b/lib/accesslib.php
index b5d8014..3b2dc67 100644
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -317,6 +317,987 @@ $ACCESSLIB_PRIVATE->preloadedcourses = array(); // Used in preload_course_contex
 $ACCESSLIB_PRIVATE->capabilities     = null; // detailed information about the capabilities
 
 /**
+ * Abstract class for context levels.  The context level classes encapsulate
+ * context level-specific logic.
+ */
+abstract class context_level_base {
+    /**
+     * The numeric value for the context level.  Used by cleanup_contexts_sql.
+     */
+    protected $level;
+
+    /**
+     * Primary table used for the data records represented by this context
+     * level, or null if there is no table.  Used by cleanup_contexts_sql.
+     */
+    protected $table = null;
+
+    private static $allcontextlevels;
+
+    /**
+     * Returns an array of all the context levels defined in the system.
+     *
+     * @return array
+     */
+    static function get_all_context_levels() {
+        if (!isset(context_level_base::$allcontextlevels)) {
+            context_level_base::$allcontextlevels =
+                array(
+                    CONTEXT_SYSTEM      => new context_level_system(),
+                    CONTEXT_USER        => new context_level_user(),
+                    CONTEXT_COURSECAT   => new context_level_coursecat(),
+                    CONTEXT_COURSE      => new context_level_course(),
+                    CONTEXT_MODULE      => new context_level_module(),
+                    CONTEXT_BLOCK       => new context_level_block(),
+                    );
+        }
+
+        return context_level_base::$allcontextlevels;
+    }
+
+    /**
+     * Returns the context level object for the specified context level.
+     *
+     * @param int $level
+     * @return mixed
+     */
+    static function get_context_level($level) {
+        // make sure $all_context_levels is loaded
+        context_level_base::get_all_context_levels();
+
+        if (is_object($level)) {
+            // if $level is a context object
+            $level = $level->contextlevel;
+        }
+
+        return context_level_base::$allcontextlevels[$level];
+    }
+
+    /**
+     * Determines whether the specified context level is a valid level.
+     *
+     * @param int $level
+     * @return bool
+     */
+    static function context_level_exists($level) {
+        // make sure $all_context_levels is loaded
+        context_level_base::get_all_context_levels();
+
+        if (is_object($level)) {
+            // if $level is a context object
+            $level = $level->contextlevel;
+        }
+
+        return isset(context_level_base::$allcontextlevels[$level]);
+    }
+
+    /**
+     * @return string the name for this type of context.
+     */
+    abstract public function get_contextlevel_name();
+
+    /**
+     * Retrieves information for an instance necessary for creating a new
+     * context instance.  (Used by create_context.)
+     *
+     * @param int $instanceid
+     *
+     * @return array (boolean instance OK, string base path, int base depth,
+     * string error message)
+     */
+    abstract public function get_context_info($instanceid, $strictness);
+
+    /**
+     * Prints human readable context identifier.
+     *
+     * @param object $context the context.
+     * @param boolean $withprefix whether to prefix the name of the context with the
+     *      type of context, e.g. User, Course, Forum, etc.
+     * @param boolean $short whether to user the short name of the thing. Only applies
+     *      to course contexts
+     * @return string the human readable context name.
+     */
+    abstract public function print_context_name($context, $withprefix = true, $short = false);
+
+    /**
+     * Get a URL for a context, if there is a natural one. For example, for
+     * CONTEXT_COURSE, this is the course page. For CONTEXT_USER it is the
+     * user profile page.
+     *
+     * @param object $context the context.
+     * @return moodle_url
+     */
+    abstract public function get_context_url($context);
+
+    /**
+     * 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,
+     *
+     * @global object
+     * @param object context
+     * @return array
+     */
+    public function fetch_context_capabilities($context) {
+        global $DB;
+
+        $sort = 'ORDER BY contextlevel,component,name';    // To group them sensibly for display
+
+        list($SQL, $params) = $this->fetch_context_capabilities_sql($context);
+
+        if (!$records = $DB->get_records_sql($SQL.' '.$sort, $params)) {
+            $records = array();
+        }
+
+        return $records;
+    }
+
+    /**
+     * sql for the removal of stale contexts
+     *
+     * @return string
+     */
+    public function cleanup_contexts_sql() {
+        global $CFG;
+
+        if (empty($this->table)) {
+            return null;
+        }
+
+        $sql = " SELECT c.contextlevel,
+                        c.instanceid
+                 FROM {context} c
+                 LEFT OUTER JOIN {{$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 array - $sql and $params
+     */
+    abstract protected function fetch_context_capabilities_sql($context);
+
+    /**
+     * Recursive function which, given a context, finds 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);
+
+    /**
+     * Populate context.path and context.depth where missing.
+     *
+     * @param string $base base path for top-level context
+     * @param string $emptyclause clause to filter out the records that should
+     * not be updated.  $a in the string should be replaced by the table name
+     * or alias for the context table.
+     */
+    abstract public function build_context_path($base, $emptyclause);
+
+    /**
+     * Flush the contents of the context_temp table to the context table, and
+     * reset context_temp to empty.
+     */
+    static protected function flush_context_temp() {
+        global $DB;
+
+        static $updatesql;
+
+        if (!isset($updatesql)) {
+            /* 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
+             *
+             * Different code for each database - mostly for performance reasons
+             */
+            $dbfamily = $DB->get_dbfamily();
+            if ($dbfamily == 'mysql') {
+                $updatesql = "UPDATE {context} ct, {context_temp} temp
+                                 SET ct.path  = temp.path,
+                                     ct.depth = temp.depth
+                               WHERE ct.id = temp.id";
+            } else if ($dbfamily == 'oracle') {
+                $updatesql = "UPDATE {context} ct
+                                 SET (ct.path, ct.depth) =
+                                     (SELECT temp.path, temp.depth
+                                        FROM {context_temp} temp
+                                       WHERE temp.id=ct.id)
+                               WHERE EXISTS (SELECT 'x'
+                                             FROM {context_temp} temp
+                                             WHERE temp.id = ct.id)";
+            } else if ($dbfamily == 'postgres' or $dbfamily == 'mssql') {
+                $updatesql = "UPDATE {context}
+                                 SET path  = temp.path,
+                                     depth = temp.depth
+                                FROM {context_temp} temp
+                               WHERE temp.id={context}.id";
+            } else {
+                // sqlite and others
+                $updatesql = "UPDATE {context}
+                                 SET path  = (SELECT path FROM {context_temp} WHERE id = {context}.id),
+                                     depth = (SELECT depth FROM {context_temp} WHERE id = {context}.id)
+                               WHERE id IN (SELECT id FROM {context_temp})";
+            }
+        }
+
+        $DB->execute($updatesql);
+        $DB->delete_records('context_temp');
+    }
+}
+
+/**
+ * Class representing the system context level.
+ */
+class context_level_system extends context_level_base {
+    public function get_context_info($instanceid, $strictness) {
+        return array(false, '', 1, ''); // this should never be called
+    }
+
+    public function get_contextlevel_name() {
+        return get_string('coresystem');
+    }
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        return get_string('coresystem');
+    }
+
+    public function get_context_url($context) {
+        return null;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        $SQL = "SELECT *
+                  FROM {capabilities}";
+
+        return array($SQL, array());
+    }
+
+    public function get_child_contexts($context) {
+        global $DB;
+
+        $array = array();
+
+        // 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 {context} c
+                 WHERE contextlevel != ".CONTEXT_SYSTEM;
+
+        $records = $DB->get_records_sql($sql);
+        foreach ($records as $rec) {
+            $array[$rec->id] = $rec;
+        }
+        return $array;
+    }
+
+    public function build_context_path($base, $emptyclause) {
+        global $DB;
+
+        // Sitecourse
+        $sitecoursectx = $DB->get_record('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>SITEID));
+        if (!$emptyclause || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
+            $DB->set_field('context', 'path',  "$base/{$sitecoursectx->id}", array('id'=>$sitecoursectx->id));
+            $DB->set_field('context', 'depth', 2, array('id'=>$sitecoursectx->id));
+            $sitecoursectx = $DB->get_record('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>SITEID));
+        }
+    }
+}
+
+/**
+ * Class representing the user context level.
+ */
+class context_level_user extends context_level_base {
+    protected $level = CONTEXT_USER;
+    protected $table = 'user';
+
+    public function get_context_info($instanceid, $strictness) {
+        $basepath  = '/' . SYSCONTEXTID;
+        $basedepth = 1;
+        $result = true;
+        $error_message = null;
+
+        return array($result, $basepath, $basedepth, $error_message);
+    }
+
+    public function get_contextlevel_name() {
+        return get_string('user');
+    }
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        global $DB;
+
+        $name = '';
+        $user = $DB->get_record('user', array('id'=>$context->instanceid));
+
+        if (!empty($user)) {
+            if ($withprefix){
+                $name = get_string('user').': ';
+            }
+            $name .= fullname($user);
+        }
+
+        return $name;
+    }
+
+    public function get_context_url($context) {
+        global $CFG, $COURSE;
+
+        if ($COURSE->id == SITEID) {
+            $url = new moodle_url('/user/profile.php', array('id'=>$context->instanceid));
+        } else {
+            $url = new moodle_url('/user/view.php', array('id'=>$context->instanceid, 'courseid'=>$COURSE->id));
+        }
+        return $url;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $DB;
+
+        $extracaps = array('moodle/grade:viewall');
+        list($extra, $params) = $DB->get_in_or_equal($extracaps, SQL_PARAMS_NAMED, 'cap');
+        $SQL = "SELECT *
+                  FROM {capabilities}
+                 WHERE contextlevel = ".CONTEXT_USER."
+                       OR name $extra";
+
+        return array($SQL, $params);
+    }
+
+    public function get_child_contexts($context) {
+        global $DB, $ACCESSLIB_PRIVATE;
+
+        $array = array();
+        $cache = $ACCESSLIB_PRIVATE->contexcache;
+
+        // Find
+        // - blocks under this context path.
+        $sql = " SELECT ctx.*
+                       FROM {context} ctx
+                      WHERE ctx.path LIKE ?
+                            AND ctx.contextlevel = ".CONTEXT_BLOCK;
+        $params = array("{$context->path}/%", $context->instanceid);
+        $records = $DB->get_recordset_sql($sql, $params);
+        foreach ($records as $rec) {
+            $cache->add($rec);
+            $array[$rec->id] = $rec;
+        }
+        return $array;
+    }
+
+    public function build_context_path($base, $emptyclause) {
+        global $DB;
+
+        $a = '{context}';
+        eval('$emptyclause = "'.$emptyclause.'";');
+
+        // User
+        $sql = "UPDATE {context}
+                   SET depth=2, path=".$DB->sql_concat("'$base/'", 'id')."
+                 WHERE contextlevel=".CONTEXT_USER."
+                       AND EXISTS (SELECT 'x'
+                                     FROM {user} u
+                                    WHERE u.id = {context}.instanceid)
+                       $emptyclause ";
+        $DB->execute($sql);
+    }
+}
+
+/**
+ * Class representing the course category context level.
+ */
+class context_level_coursecat extends context_level_base {
+    protected $level = CONTEXT_COURSECAT;
+    protected $table = 'course_categories';
+
+    public function get_context_info($instanceid, $strictness) {
+        global $DB;
+
+        $basepath  = '/' . SYSCONTEXTID;
+        $basedepth = 1;
+        $result = true;
+        $error_message = null;
+
+        $sql = "SELECT ctx.path, ctx.depth
+                  FROM {context}           ctx
+                  JOIN {course_categories} cc
+                       ON (cc.parent=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSECAT.")
+                 WHERE cc.id=?";
+        $params = array($instanceid);
+        if ($p = $DB->get_record_sql($sql, $params)) {
+            $basepath  = $p->path;
+            $basedepth = $p->depth;
+        } else if ($category = $DB->get_record('course_categories', array('id'=>$instanceid), '*', $strictness)) {
+            if (empty($category->parent)) {
+                // ok - this is a top category
+            } else if ($parent = get_context_instance(CONTEXT_COURSECAT, $category->parent)) {
+                $basepath  = $parent->path;
+                $basedepth = $parent->depth;
+            } else {
+                // wrong parent category - no big deal, this can be fixed later
+                $basepath  = null;
+                $basedepth = 0;
+            }
+        } else {
+            // incorrect category id
+            $error_message = "incorrect course category id ($instanceid)";
+            $result = false;
+        }
+
+        return array($result, $basepath, $basedepth, $error_message);
+    }
+
+    public function get_contextlevel_name() {
+        return get_string('category');
+    }
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        global $DB;
+
+        $name = '';
+
+        if ($category = $DB->get_record('course_categories', array('id'=>$context->instanceid))) {
+            if ($withprefix){
+                $name = get_string('category').': ';
+            }
+            $name .=format_string($category->name);
+        }
+
+        return $name;
+    }
+
+    public function get_context_url($context) {
+        global $CFG;
+
+        return new moodle_url('/course/category.php', array('id'=>$context->instanceid));
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        $SQL = "SELECT *
+                  FROM {capabilities}
+                 WHERE contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
+
+        return array($SQL, array());
+    }
+
+    public function get_child_contexts($context) {
+        global $DB, $ACCESSLIB_PRIVATE;
+
+        $array = array();
+        $cache = $ACCESSLIB_PRIVATE->contexcache;
+
+        // Find
+        // - categories
+        // - courses
+        $sql = " SELECT ctx.*
+                       FROM {context} ctx
+                      WHERE ctx.path LIKE ?
+                            AND ctx.contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.")";
+        $params = array("{$context->path}/%");
+        $records = $DB->get_recordset_sql($sql, $params);
+        foreach ($records as $rec) {
+            $cache->add($rec);
+            $array[$rec->id] = $rec;
+        }
+        return $array;
+    }
+
+    public function build_context_path($base, $emptyclause) {
+        global $DB;
+
+        $a = 'ctx';
+        eval('$ctxemptyclause = "'.$emptyclause.'";');
+        $a = '{context}';
+        eval('$emptyclause = "'.$emptyclause.'";');
+
+        // Top level categories
+        $sql = "UPDATE {context}
+                   SET depth=2, path=" . $DB->sql_concat("'$base/'", 'id') . "
+                 WHERE contextlevel=".CONTEXT_COURSECAT."
+                       AND EXISTS (SELECT 'x'
+                                     FROM {course_categories} cc
+                                    WHERE cc.id = {context}.instanceid
+                                          AND cc.depth=1)
+                       $emptyclause";
+
+        $DB->execute($sql);
+
+        // Deeper categories - one query per depthlevel
+        $maxdepth = $DB->get_field_sql("SELECT MAX(depth)
+                                          FROM {course_categories}");
+        for ($n=2;$n<=$maxdepth;$n++) {
+            $sql = "INSERT INTO {context_temp} (id, path, depth)
+                    SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", $n+1
+                      FROM {context} ctx
+                      JOIN {course_categories} c ON ctx.instanceid=c.id
+                      JOIN {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 {context_temp} temp
+                                           WHERE temp.id = ctx.id)
+                           $ctxemptyclause";
+            $DB->execute($sql);
+
+            // this is needed after every loop
+            // MDL-11532
+            context_level_base::flush_context_temp();
+        }
+
+    }
+}
+
+/**
+ * Class representing the course context level.
+ */
+class context_level_course extends context_level_base {
+    protected $level = CONTEXT_COURSE;
+    protected $table = 'course';
+
+    public function get_context_info($instanceid, $strictness) {
+        global $DB;
+
+        $basepath  = '/' . SYSCONTEXTID;
+        $basedepth = 1;
+        $result = true;
+        $error_message = null;
+
+        $sql = "SELECT ctx.path, ctx.depth
+                  FROM {context} ctx
+                  JOIN {course}  c
+                       ON (c.category=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSECAT.")
+                 WHERE c.id=? AND c.id !=" . SITEID;
+        $params = array($instanceid);
+        if ($p = $DB->get_record_sql($sql, $params, '*', $strictness)) {
+            $basepath  = $p->path;
+            $basedepth = $p->depth;
+        } else if ($course = $DB->get_record('course', array('id'=>$instanceid))) {
+            if ($course->id == SITEID) {
+                //ok - no parent category
+            } else if ($parent = get_context_instance(CONTEXT_COURSECAT, $course->category)) {
+                $basepath  = $parent->path;
+                $basedepth = $parent->depth;
+            } else {
+                // wrong parent category of course - no big deal, this can be fixed later
+                $basepath  = null;
+                $basedepth = 0;
+            }
+        } else if ($instanceid == SITEID) {
+            // no errors for missing site course during installation
+            return false;
+        } else {
+            // incorrect course id
+            $error_message = "incorrect course id ($instanceid)";
+            $result = false;
+        }
+
+        return array($result, $basepath, $basedepth, $error_message);
+    }
+
+    public function get_contextlevel_name() {
+        return get_string('course');
+    }
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        if ($context->instanceid == SITEID) {
+            $name = get_string('frontpage', 'admin');
+        } else {
+            global $DB;
+            if ($course = $DB->get_record('course', array('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 get_context_url($context) {
+        global $CFG;
+
+        if ($context->instanceid != SITEID) {
+            return new moodle_url('/course/view.php', array('id'=>$context->instanceid));
+        }
+        return null;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        $SQL = "SELECT *
+                  FROM {capabilities}
+                 WHERE contextlevel IN (".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
+
+        return array($SQL, array());
+    }
+
+    public function get_child_contexts($context) {
+        global $DB, $ACCESSLIB_PRIVATE;
+
+        $array = array();
+        $cache = $ACCESSLIB_PRIVATE->contexcache;
+
+        // Find
+        // - modules and blocks under this context path.
+        $sql = " SELECT ctx.*
+                   FROM {context} ctx
+                  WHERE ctx.path LIKE ?
+                        AND ctx.contextlevel IN (".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
+        $params = array("{$context->path}/%", $context->instanceid);
+        $records = $DB->get_recordset_sql($sql, $params);
+        foreach ($records as $rec) {
+            $cache->add($rec);
+            $array[$rec->id] = $rec;
+        }
+        return $array;
+    }
+
+    public function build_context_path($base, $emptyclause) {
+        global $DB;
+
+        $a = 'ctx';
+        eval('$ctxemptyclause = "'.$emptyclause.'";');
+
+        // Courses -- except sitecourse
+        $sql = "INSERT INTO {context_temp} (id, path, depth)
+                SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
+                  FROM {context} ctx
+                  JOIN {course} c ON ctx.instanceid=c.id
+                  JOIN {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 {context_temp} temp
+                                           WHERE temp.id = ctx.id)
+                       $ctxemptyclause";
+        $DB->execute($sql);
+
+        context_level_base::flush_context_temp();
+    }
+}
+
+/**
+ * Class representing the module context level.
+ */
+class context_level_module extends context_level_base {
+    protected $level = CONTEXT_MODULE;
+    protected $table = 'course_modules';
+
+    public function get_context_info($instanceid, $strictness) {
+        global $DB;
+
+        $basepath  = '/' . SYSCONTEXTID;
+        $basedepth = 1;
+        $result = true;
+        $error_message = null;
+
+        $sql = "SELECT ctx.path, ctx.depth
+                  FROM {context}        ctx
+                  JOIN {course_modules} cm
+                       ON (cm.course=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
+                 WHERE cm.id=?";
+        $params = array($instanceid);
+        if ($p = $DB->get_record_sql($sql, $params)) {
+            $basepath  = $p->path;
+            $basedepth = $p->depth;
+        } else if ($cm = $DB->get_record('course_modules', array('id'=>$instanceid), '*', $strictness)) {
+            if ($parent = get_context_instance(CONTEXT_COURSE, $cm->course, $strictness)) {
+                $basepath  = $parent->path;
+                $basedepth = $parent->depth;
+            } else {
+                // course does not exist - modules can not exist without a course
+                $error_message = "course does not exist ($cm->course) - modules can not exist without a course";
+                $result = false;
+            }
+        } else {
+            // cm does not exist
+            $error_message = "cm with id $instanceid does not exist";
+            $result = false;
+        }
+
+        return array($result, $basepath, $basedepth, $error_message);
+    }
+
+    public function get_contextlevel_name() {
+        return get_string('activitymodule');
+    }
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        global $DB;
+
+        $name = '';
+
+        if ($cm = $DB->get_record_sql('SELECT cm.*, md.name AS modname FROM {course_modules} cm ' .
+                'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?', array($context->instanceid))) {
+            if ($mod = $DB->get_record($cm->modname, array('id' => $cm->instance))) {
+                if ($withprefix){
+                    $name = get_string('activitymodule').': ';
+                }
+                $name .= $mod->name;
+            }
+        }
+
+        return $name;
+    }
+
+    public function get_context_url($context) {
+        global $CFG, $DB;
+
+        if ($modname = $DB->get_field_sql('SELECT md.name AS modname FROM {course_modules} cm ' .
+                'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?', array($context->instanceid))) {
+            return new moodle_url('/mod/' . $modname . '/view.php', array('id'=>$context->instanceid));
+        }
+        return null;
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $CFG, $DB;
+
+        $cm = $DB->get_record('course_modules', array('id'=>$context->instanceid));
+        $module = $DB->get_record('modules', array('id'=>$cm->module));
+
+            $subcaps = array();
+            $subpluginsfile = "$CFG->dirroot/mod/$module->name/db/subplugins.php";
+            if (file_exists($subpluginsfile)) {
+                $subplugins = array();  // should be redefined in the file
+                include($subpluginsfile);
+                if (!empty($subplugins)) {
+                    foreach (array_keys($subplugins) as $subplugintype) {
+                        foreach (array_keys(get_plugin_list($subplugintype)) as $subpluginname) {
+                            $subcaps = array_merge($subcaps, array_keys(load_capability_def($subplugintype.'_'.$subpluginname)));
+                        }
+                    }
+                }
+            }
+
+        $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();
+        }
+
+            $extracaps = array_merge($subcaps, $extracaps);
+
+        // 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";
+        list($extra, $params) = $DB->get_in_or_equal(
+            $extracaps, SQL_PARAMS_NAMED, 'cap0');
+        $extra = "OR name $extra";
+
+        $SQL = "SELECT *
+                  FROM {capabilities}
+                 WHERE (contextlevel = ".CONTEXT_MODULE."
+                       AND component = :component)
+                       $extra";
+        $params['component'] = "mod_$module->name";
+
+        return array($SQL, $params);
+    }
+
+    public function get_child_contexts($context) {
+        global $DB, $ACCESSLIB_PRIVATE;
+
+        $array = array();
+        $cache = $ACCESSLIB_PRIVATE->contexcache;
+
+        // Find
+        // - blocks under this context path.
+        $sql = " SELECT ctx.*
+                       FROM {context} ctx
+                      WHERE ctx.path LIKE ?
+                            AND ctx.contextlevel = ".CONTEXT_BLOCK;
+        $params = array("{$context->path}/%", $context->instanceid);
+        $records = $DB->get_recordset_sql($sql, $params);
+        foreach ($records as $rec) {
+            $cache->add($rec);
+            $array[$rec->id] = $rec;
+        }
+        return $array;
+    }
+
+    public function build_context_path($base, $emptyclause) {
+        global $DB;
+
+        $a = 'ctx';
+        eval('$ctxemptyclause = "'.$emptyclause.'";');
+
+        // Module instances
+        $sql = "INSERT INTO {context_temp} (id, path, depth)
+                SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
+                  FROM {context} ctx
+                  JOIN {course_modules} cm ON ctx.instanceid=cm.id
+                  JOIN {context} pctx ON cm.course=pctx.instanceid
+                 WHERE ctx.contextlevel=".CONTEXT_MODULE."
+                       AND pctx.contextlevel=".CONTEXT_COURSE."
+                           AND NOT EXISTS (SELECT 'x'
+                                           FROM {context_temp} temp
+                                           WHERE temp.id = ctx.id)
+                       $ctxemptyclause";
+        $DB->execute($sql);
+
+        context_level_base::flush_context_temp();
+    }
+}
+
+/**
+ * Class representing the block context level.
+ */
+class context_level_block extends context_level_base {
+    protected $level = CONTEXT_BLOCK;
+    protected $table = 'block_instances';
+
+    public function get_context_info($instanceid, $strictness) {
+        global $DB;
+
+        $basepath  = '/' . SYSCONTEXTID;
+        $basedepth = 1;
+        $result = true;
+        $error_message = null;
+
+        $sql = "SELECT ctx.path, ctx.depth
+                  FROM {context} ctx
+                  JOIN {block_instances} bi ON (bi.parentcontextid=ctx.id)
+                 WHERE bi.id = ?";
+        $params = array($instanceid, CONTEXT_COURSE);
+        if ($p = $DB->get_record_sql($sql, $params, '*', $strictness)) {
+            $basepath  = $p->path;
+            $basedepth = $p->depth;
+        } else {
+            // block does not exist
+            $error_message = 'block or parent context does not exist';
+            $result = false;
+        }
+
+        return array($result, $basepath, $basedepth, $error_message);
+    }
+
+    public function get_contextlevel_name() {
+        return get_string('block');
+    }
+
+    public function print_context_name($context, $withprefix = true, $short = false) {
+        global $DB;
+
+        $name = '';
+
+        if ($blockinstance = $DB->get_record('block_instances', array('id'=>$context->instanceid))) {
+            global $CFG;
+            require_once("$CFG->dirroot/blocks/moodleblock.class.php");
+            require_once("$CFG->dirroot/blocks/$blockinstance->blockname/block_$blockinstance->blockname.php");
+            $blockname = "block_$blockinstance->blockname";
+            if ($blockobject = new $blockname()) {
+                if ($withprefix){
+                    $name = get_string('block').': ';
+                }
+                $name .= $blockobject->title;
+            }
+        }
+
+        return $name;
+    }
+
+    public function get_context_url($context) {
+        $parentcontexts = get_parent_contexts($context, false);
+        $parent = reset($parentcontexts);
+        $parent = get_context_instance_by_id($parent);
+        return get_context_url($parent);
+    }
+
+    public function fetch_context_capabilities_sql($context) {
+        global $DB;
+
+        $bi = $DB->get_record('block_instances', array('id' => $context->instanceid));
+
+        $extra = '';
+        $extracaps = block_method_result($bi->blockname, 'get_extra_capabilities');
+        if ($extracaps) {
+            list($extra, $params) = $DB->get_in_or_equal($extracaps, SQL_PARAMS_NAMED, 'cap');
+            $extra = "OR name $extra";
+        }
+
+        $SQL = "SELECT *
+                  FROM {capabilities}
+                 WHERE (contextlevel = ".CONTEXT_BLOCK."
+                       AND component = :component)
+                       $extra";
+        $params['component'] = 'block_' . $bi->blockname;
+
+        return array($SQL, $params);
+    }
+
+    public function get_child_contexts($context) {
+        //no children by default
+        return array();
+    }
+
+    public function build_context_path($base, $emptyclause) {
+        global $DB;
+
+        $a = 'ctx';
+        eval('$ctxemptyclause = "'.$emptyclause.'";');
+
+    // pctx.path IS NOT NULL prevents fatal problems with broken block instances that point to invalid context parent
+        $sql = "INSERT INTO {context_temp} (id, path, depth)
+            SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
+              FROM {context} ctx
+              JOIN {block_instances} bi ON ctx.instanceid = bi.id
+              JOIN {context} pctx ON bi.parentcontextid = pctx.id
+             WHERE ctx.contextlevel=".CONTEXT_BLOCK."
+                   AND pctx.path IS NOT NULL
+                   AND NOT EXISTS (SELECT 'x'
+                                   FROM {context_temp} temp
+                                   WHERE temp.id = ctx.id)
+                   $ctxemptyclause";
+        $DB->execute($sql);
+
+        context_level_base::flush_context_temp();
+    }
+}
+
+/**
  * Clears accesslib's private caches. ONLY BE USED BY UNIT TESTS
  *
  * This method should ONLY BE USED BY UNIT TESTS. It clears all of
@@ -1765,111 +2800,7 @@ function create_context($contextlevel, $instanceid, $strictness = IGNORE_MISSING
     $result = true;
     $error_message = null;
 
-    switch ($contextlevel) {
-        case CONTEXT_COURSECAT:
-            $sql = "SELECT ctx.path, ctx.depth
-                      FROM {context}           ctx
-                      JOIN {course_categories} cc
-                           ON (cc.parent=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSECAT.")
-                     WHERE cc.id=?";
-            $params = array($instanceid);
-            if ($p = $DB->get_record_sql($sql, $params)) {
-                $basepath  = $p->path;
-                $basedepth = $p->depth;
-            } else if ($category = $DB->get_record('course_categories', array('id'=>$instanceid), '*', $strictness)) {
-                if (empty($category->parent)) {
-                    // ok - this is a top category
-                } else if ($parent = get_context_instance(CONTEXT_COURSECAT, $category->parent)) {
-                    $basepath  = $parent->path;
-                    $basedepth = $parent->depth;
-                } else {
-                    // wrong parent category - no big deal, this can be fixed later
-                    $basepath  = null;
-                    $basedepth = 0;
-                }
-            } else {
-                // incorrect category id
-                $error_message = "incorrect course category id ($instanceid)";
-                $result = false;
-            }
-            break;
-
-        case CONTEXT_COURSE:
-            $sql = "SELECT ctx.path, ctx.depth
-                      FROM {context} ctx
-                      JOIN {course}  c
-                           ON (c.category=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSECAT.")
-                     WHERE c.id=? AND c.id !=" . SITEID;
-            $params = array($instanceid);
-            if ($p = $DB->get_record_sql($sql, $params)) {
-                $basepath  = $p->path;
-                $basedepth = $p->depth;
-            } else if ($course = $DB->get_record('course', array('id'=>$instanceid), '*', $strictness)) {
-                if ($course->id == SITEID) {
-                    //ok - no parent category
-                } else if ($parent = get_context_instance(CONTEXT_COURSECAT, $course->category)) {
-                    $basepath  = $parent->path;
-                    $basedepth = $parent->depth;
-                } else {
-                    // wrong parent category of course - no big deal, this can be fixed later
-                    $basepath  = null;
-                    $basedepth = 0;
-                }
-            } else if ($instanceid == SITEID) {
-                // no errors for missing site course during installation
-                return false;
-            } else {
-                // incorrect course id
-                $error_message = "incorrect course id ($instanceid)";
-                $result = false;
-            }
-            break;
-
-        case CONTEXT_MODULE:
-            $sql = "SELECT ctx.path, ctx.depth
-                      FROM {context}        ctx
-                      JOIN {course_modules} cm
-                           ON (cm.course=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
-                     WHERE cm.id=?";
-            $params = array($instanceid);
-            if ($p = $DB->get_record_sql($sql, $params)) {
-                $basepath  = $p->path;
-                $basedepth = $p->depth;
-            } else if ($cm = $DB->get_record('course_modules', array('id'=>$instanceid), '*', $strictness)) {
-                if ($parent = get_context_instance(CONTEXT_COURSE, $cm->course, $strictness)) {
-                    $basepath  = $parent->path;
-                    $basedepth = $parent->depth;
-                } else {
-                    // course does not exist - modules can not exist without a course
-                    $error_message = "course does not exist ($cm->course) - modules can not exist without a course";
-                    $result = false;
-                }
-            } else {
-                // cm does not exist
-                $error_message = "cm with id $instanceid does not exist";
-                $result = false;
-            }
-            break;
-
-        case CONTEXT_BLOCK:
-            $sql = "SELECT ctx.path, ctx.depth
-                      FROM {context} ctx
-                      JOIN {block_instances} bi ON (bi.parentcontextid=ctx.id)
-                     WHERE bi.id = ?";
-            $params = array($instanceid, CONTEXT_COURSE);
-            if ($p = $DB->get_record_sql($sql, $params, '*', $strictness)) {
-                $basepath  = $p->path;
-                $basedepth = $p->depth;
-            } else {
-                // block does not exist
-                $error_message = 'block or parent context does not exist';
-                $result = false;
-            }
-            break;
-        case CONTEXT_USER:
-            // default to basepath
-            break;
-    }
+    list($result, $basepath, $basedepth, $error_message) = context_level_base::get_context_level($contextlevel)->get_context_info($instanceid, $strictness);
 
     // if grandparents unknown, maybe rebuild_context_path() will solve it later
     if ($basedepth != 0) {
@@ -2089,41 +3020,20 @@ function create_contexts($contextlevel = null, $buildpaths = true) {
 function cleanup_contexts() {
     global $DB;
 
-    $sql = "  SELECT c.contextlevel,
-                     c.instanceid AS instanceid
-                FROM {context} c
-                LEFT OUTER JOIN {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 {context} c
-                LEFT OUTER JOIN {course} t
-                     ON c.instanceid = t.id
-               WHERE t.id IS NULL AND c.contextlevel = ".CONTEXT_COURSE."
-            UNION
-              SELECT c.contextlevel,
-                     c.instanceid
-                FROM {context} c
-                LEFT OUTER JOIN {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 {context} c
-                LEFT OUTER JOIN {user} t
-                     ON c.instanceid = t.id
-               WHERE t.id IS NULL AND c.contextlevel = ".CONTEXT_USER."
-            UNION
-              SELECT c.contextlevel,
-                     c.instanceid
-                FROM {context} c
-                LEFT OUTER JOIN {block_instances} t
-                     ON c.instanceid = t.id
-               WHERE t.id IS NULL AND c.contextlevel = ".CONTEXT_BLOCK."
-           ";
+    // context class will contain function with the sql returned
+    // iterate over all the contexts to generate the sql
+
+    $sqlarray = array();
+
+    foreach(context_level_base::get_all_context_levels() as $cl) {
+        $currentsql = $cl->cleanup_contexts_sql();
+
+        if(!empty($currentsql)) {
+            $sqlarray[] = $currentsql;
+        }
+    }
+
+    $sql = implode("\n UNION \n", $sqlarray);
 
     // transactions used only for performance reasons here
     $transaction = $DB->start_delegated_transaction();
@@ -2190,7 +3100,6 @@ function preload_course_contexts($courseid) {
  */
 function get_context_instance($contextlevel, $instance = 0, $strictness = IGNORE_MISSING) {
     global $DB, $ACCESSLIB_PRIVATE;
-    static $allowed_contexts = array(CONTEXT_SYSTEM, CONTEXT_USER, CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_MODULE, CONTEXT_BLOCK);
 
 /// System context has special cache
     if ($contextlevel == CONTEXT_SYSTEM) {
@@ -2198,7 +3107,7 @@ function get_context_instance($contextlevel, $instance = 0, $strictness = IGNORE
     }
 
 /// check allowed context levels
-    if (!in_array($contextlevel, $allowed_contexts)) {
+    if (!context_level_base::context_level_exists($contextlevel)) {
         // fatal error, code must be fixed - probably typo or switched parameters
         print_error('invalidcourselevel');
     }
@@ -3530,18 +4483,7 @@ function capabilities_cleanup($component, $newcapdef = null) {
  * @return string the name for this type of context.
  */
 function get_contextlevel_name($contextlevel) {
-    static $strcontextlevels = null;
-    if (is_null($strcontextlevels)) {
-        $strcontextlevels = array(
-            CONTEXT_SYSTEM    => get_string('coresystem'),
-            CONTEXT_USER      => get_string('user'),
-            CONTEXT_COURSECAT => get_string('category'),
-            CONTEXT_COURSE    => get_string('course'),
-            CONTEXT_MODULE    => get_string('activitymodule'),
-            CONTEXT_BLOCK     => get_string('block')
-        );
-    }
-    return $strcontextlevels[$contextlevel];
+    return context_level_base::get_context_level($contextlevel)->get_contextlevel_name();
 }
 
 /**
@@ -3555,83 +4497,13 @@ function get_contextlevel_name($contextlevel) {
  * @return string the human readable context name.
  */
 function print_context_name($context, $withprefix = true, $short = false) {
-    global $DB;
-
-    $name = '';
-    switch ($context->contextlevel) {
-
-        case CONTEXT_SYSTEM:
-            $name = get_string('coresystem');
-            break;
-
-        case CONTEXT_USER:
-            if ($user = $DB->get_record('user', array('id'=>$context->instanceid))) {
-                if ($withprefix){
-                    $name = get_string('user').': ';
-                }
-                $name .= fullname($user);
-            }
-            break;
-
-        case CONTEXT_COURSECAT:
-            if ($category = $DB->get_record('course_categories', array('id'=>$context->instanceid))) {
-                if ($withprefix){
-                    $name = get_string('category').': ';
-                }
-                $name .=format_string($category->name);
-            }
-            break;
-
-        case CONTEXT_COURSE:
-            if ($context->instanceid == SITEID) {
-                $name = get_string('frontpage', 'admin');
-            } else {
-                if ($course = $DB->get_record('course', array('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:
-            if ($cm = $DB->get_record_sql('SELECT cm.*, md.name AS modname FROM {course_modules} cm ' .
-                    'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?', array($context->instanceid))) {
-                if ($mod = $DB->get_record($cm->modname, array('id' => $cm->instance))) {
-                        if ($withprefix){
-                        $name = get_string('modulename', $cm->modname).': ';
-                        }
-                        $name .= $mod->name;
-                    }
-                }
-            break;
-
-        case CONTEXT_BLOCK:
-            if ($blockinstance = $DB->get_record('block_instances', array('id'=>$context->instanceid))) {
-                global $CFG;
-                require_once("$CFG->dirroot/blocks/moodleblock.class.php");
-                require_once("$CFG->dirroot/blocks/$blockinstance->blockname/block_$blockinstance->blockname.php");
-                $blockname = "block_$blockinstance->blockname";
-                if ($blockobject = new $blockname()) {
-                    if ($withprefix){
-                        $name = get_string('block').': ';
-                    }
-                    $name .= $blockobject->title;
-                }
-            }
-            break;
-
-        default:
-            print_error('unknowncontext');
-            return false;
+    if (context_level_base::context_level_exists($context)) {
+        $context_level = context_level_base::get_context_level($context);
+        return $context_level->print_context_name($context, $withprefix, $short);
+    } else {
+        print_error('unknowncontext');
+        return false;
     }
-
-    return $name;
 }
 
 /**
@@ -3643,38 +4515,12 @@ function print_context_name($context, $withprefix = true, $short = false) {
  * @return moodle_url
  */
 function get_context_url($context) {
-    global $COURSE, $DB;
-
-    switch ($context->contextlevel) {
-        case CONTEXT_USER:
-            if ($COURSE->id == SITEID) {
-                $url = new moodle_url('/user/profile.php', array('id'=>$context->instanceid));
-            } else {
-                $url = new moodle_url('/user/view.php', array('id'=>$context->instanceid, 'courseid'=>$COURSE->id));
-            }
-            return $url;;
-
-        case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
-            return new moodle_url('/course/category.php', array('id'=>$context->instanceid));
-
-        case CONTEXT_COURSE: // 1 to 1 to course cat
-            if ($context->instanceid != SITEID) {
-                return new moodle_url('/course/view.php', array('id'=>$context->instanceid));
-            }
-            break;
-
-        case CONTEXT_MODULE: // 1 to 1 to course
-            if ($modname = $DB->get_field_sql('SELECT md.name AS modname FROM {course_modules} cm ' .
-                    'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?', array($context->instanceid))) {
-                return new moodle_url('/mod/' . $modname . '/view.php', array('id'=>$context->instanceid));
-            }
-            break;
-
-        case CONTEXT_BLOCK:
-            $parentcontexts = get_parent_contexts($context, false);
-            $parent = reset($parentcontexts);
-            $parent = get_context_instance_by_id($parent);
-            return get_context_url($parent);
+    if(context_level_base::context_level_exists($context)) {
+        $context_level = context_level_base::get_context_level($context);
+        $rv = $context_level->get_context_url($context);
+        if ($rv != null) {
+            return $rv;
+        }
     }
 
     return new moodle_url('/');
@@ -3726,115 +4572,12 @@ function get_capability_docs_link($capability) {
  * @return array
  */
 function fetch_context_capabilities($context) {
-    global $DB, $CFG;
-
-    $sort = 'ORDER BY contextlevel,component,name';   // To group them sensibly for display
-
-    $params = array();
-
-    switch ($context->contextlevel) {
-
-        case CONTEXT_SYSTEM: // all
-            $SQL = "SELECT *
-                      FROM {capabilities}";
-        break;
-
-        case CONTEXT_USER:
-            $extracaps = array('moodle/grade:viewall');
-            list($extra, $params) = $DB->get_in_or_equal($extracaps, SQL_PARAMS_NAMED, 'cap');
-            $SQL = "SELECT *
-                      FROM {capabilities}
-                     WHERE contextlevel = ".CONTEXT_USER."
-                           OR name $extra";
-        break;
-
-        case CONTEXT_COURSECAT: // course category context and bellow
-            $SQL = "SELECT *
-                      FROM {capabilities}
-                     WHERE contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
-        break;
-
-        case CONTEXT_COURSE: // course context and bellow
-            $SQL = "SELECT *
-                      FROM {capabilities}
-                     WHERE contextlevel IN (".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
-        break;
-
-        case CONTEXT_MODULE: // mod caps
-            $cm = $DB->get_record('course_modules', array('id'=>$context->instanceid));
-            $module = $DB->get_record('modules', array('id'=>$cm->module));
-
-            $subcaps = array();
-            $subpluginsfile = "$CFG->dirroot/mod/$module->name/db/subplugins.php";
-            if (file_exists($subpluginsfile)) {
-                $subplugins = array();  // should be redefined in the file
-                include($subpluginsfile);
-                if (!empty($subplugins)) {
-                    foreach (array_keys($subplugins) as $subplugintype) {
-                        foreach (array_keys(get_plugin_list($subplugintype)) as $subpluginname) {
-                            $subcaps = array_merge($subcaps, array_keys(load_capability_def($subplugintype.'_'.$subpluginname)));
-                        }
-                    }
-                }
-            }
-
-            $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();
-            }
-
-            $extracaps = array_merge($subcaps, $extracaps);
-
-            // 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";
-            list($extra, $params) = $DB->get_in_or_equal(
-                $extracaps, SQL_PARAMS_NAMED, 'cap0');
-            $extra = "OR name $extra";
-
-            $SQL = "SELECT *
-                      FROM {capabilities}
-                     WHERE (contextlevel = ".CONTEXT_MODULE."
-                           AND component = :component)
-                           $extra";
-            $params['component'] = "mod_$module->name";
-        break;
-
-        case CONTEXT_BLOCK: // block caps
-            $bi = $DB->get_record('block_instances', array('id' => $context->instanceid));
-
-            $extra = '';
-            $extracaps = block_method_result($bi->blockname, 'get_extra_capabilities');
-            if ($extracaps) {
-                list($extra, $params) = $DB->get_in_or_equal($extracaps, SQL_PARAMS_NAMED, 'cap');
-                $extra = "OR name $extra";
-            }
-
-            $SQL = "SELECT *
-                      FROM {capabilities}
-                     WHERE (contextlevel = ".CONTEXT_BLOCK."
-                           AND component = :component)
-                           $extra";
-            $params['component'] = 'block_' . $bi->blockname;
-        break;
-
-        default:
+    if(context_level_base::context_level_exists($context)) {
+        $context_level = context_level_base::get_context_level($context);
+        return $context_level->fetch_context_capabilities($context);
+    } else {
         return false;
     }
-
-    if (!$records = $DB->get_records_sql($SQL.' '.$sort, $params)) {
-        $records = array();
-    }
-
-    return $records;
 }
 
 
@@ -4031,101 +4774,13 @@ function get_sorted_contexts($select, $params = array()) {
  * @return array Array of child records
  */
 function get_child_contexts($context) {
-
-    global $DB, $ACCESSLIB_PRIVATE;
-
-    // We *MUST* populate the context_cache as the callers
-    // will probably ask for the full record anyway soon after
-    // soon after calling us ;-)
-
-    $array = array();
-    $cache = $ACCESSLIB_PRIVATE->contexcache;
-
-    switch ($context->contextlevel) {
-
-        case CONTEXT_BLOCK:
-            // No children.
-        break;
-
-        case CONTEXT_MODULE:
-            // Find
-            // - blocks under this context path.
-            $sql = " SELECT ctx.*
-                       FROM {context} ctx
-                      WHERE ctx.path LIKE ?
-                            AND ctx.contextlevel = ".CONTEXT_BLOCK;
-            $params = array("{$context->path}/%", $context->instanceid);
-            $records = $DB->get_recordset_sql($sql, $params);
-            foreach ($records as $rec) {
-                $cache->add($rec);
-                $array[$rec->id] = $rec;
-            }
-            break;
-
-        case CONTEXT_COURSE:
-            // Find
-            // - modules and blocks under this context path.
-            $sql = " SELECT ctx.*
-                       FROM {context} ctx
-                      WHERE ctx.path LIKE ?
-                            AND ctx.contextlevel IN (".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
-            $params = array("{$context->path}/%", $context->instanceid);
-            $records = $DB->get_recordset_sql($sql, $params);
-            foreach ($records as $rec) {
-                $cache->add($rec);
-                $array[$rec->id] = $rec;
-            }
-        break;
-
-        case CONTEXT_COURSECAT:
-            // Find
-            // - categories
-            // - courses
-            $sql = " SELECT ctx.*
-                       FROM {context} ctx
-                      WHERE ctx.path LIKE ?
-                            AND ctx.contextlevel IN (".CONTEXT_COURSECAT.",".CONTEXT_COURSE.")";
-            $params = array("{$context->path}/%");
-            $records = $DB->get_recordset_sql($sql, $params);
-            foreach ($records as $rec) {
-                $cache->add($rec);
-                $array[$rec->id] = $rec;
-            }
-        break;
-
-        case CONTEXT_USER:
-            // Find
-            // - blocks under this context path.
-            $sql = " SELECT ctx.*
-                       FROM {context} ctx
-                      WHERE ctx.path LIKE ?
-                            AND ctx.contextlevel = ".CONTEXT_BLOCK;
-            $params = array("{$context->path}/%", $context->instanceid);
-            $records = $DB->get_recordset_sql($sql, $params);
-            foreach ($records as $rec) {
-                $cache->add($rec);
-                $array[$rec->id] = $rec;
-            }
-            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 {context} c
-                     WHERE contextlevel != ".CONTEXT_SYSTEM;
-
-            $records = $DB->get_records_sql($sql);
-            foreach ($records as $rec) {
-                $array[$rec->id] = $rec;
-            }
-        break;
-
-        default:
-            print_error('unknowcontext', '', '', $context->contextlevel);
-            return false;
+    if(context_level_base::context_level_exists($context)) {
+        $context_level = context_level_base::get_context_level($context);
+        return $context_level->get_child_contexts($context);
+    } else {
+        print_error('unknowcontext', '', '', $context->contextlevel);
+        return false;
     }
-    return $array;
 }
 
 
@@ -5704,165 +6359,21 @@ function rebuild_contexts(array $fixcontexts) {
  * @param bool $force force a complete rebuild of the path and depth fields, defaults to false
  */
 function build_context_path($force = false) {
-    global $CFG, $DB, $ACCESSLIB_PRIVATE;
-
+    global $ACCESSLIB_PRIVATE;
     // System context
     $sitectx = get_system_context(!$force);
     $base    = '/'.$sitectx->id;
 
-    // Sitecourse
-    $sitecoursectx = $DB->get_record('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>SITEID));
-    if ($force || $sitecoursectx->path !== "$base/{$sitecoursectx->id}") {
-        $DB->set_field('context', 'path',  "$base/{$sitecoursectx->id}", array('id'=>$sitecoursectx->id));
-        $DB->set_field('context', 'depth', 2, array('id'=>$sitecoursectx->id));
-        $sitecoursectx = $DB->get_record('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>SITEID));
-    }
-
-    $ctxemptyclause = " AND (ctx.path IS NULL
-                              OR ctx.depth=0) ";
-    $emptyclause    = " AND ({context}.path IS NULL
-                              OR {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
-     *
-     * Different code for each database - mostly for performance reasons
-     */
-    $dbfamily = $DB->get_dbfamily();
-    if ($dbfamily == 'mysql') {
-        $updatesql = "UPDATE {context} ct, {context_temp} temp
-                         SET ct.path  = temp.path,
-                             ct.depth = temp.depth
-                       WHERE ct.id = temp.id";
-    } else if ($dbfamily == 'oracle') {
-        $updatesql = "UPDATE {context} ct
-                         SET (ct.path, ct.depth) =
-                             (SELECT temp.path, temp.depth
-                                FROM {context_temp} temp
-                               WHERE temp.id=ct.id)
-                       WHERE EXISTS (SELECT 'x'
-                                       FROM {context_temp} temp
-                                       WHERE temp.id = ct.id)";
-    } else if ($dbfamily == 'postgres' or $dbfamily == 'mssql') {
-        $updatesql = "UPDATE {context}
-                         SET path  = temp.path,
-                             depth = temp.depth
-                        FROM {context_temp} temp
-                       WHERE temp.id={context}.id";
     } else {
-        // sqlite and others
-        $updatesql = "UPDATE {context}
-                         SET path  = (SELECT path FROM {context_temp} WHERE id = {context}.id),
-                             depth = (SELECT depth FROM {context_temp} WHERE id = {context}.id)
-                         WHERE id IN (SELECT id FROM {context_temp})";
+        $emptyclause    = ' AND ({$a}.path IS NULL OR {$a}.depth=0) ';
     }
 
-    // Top level categories
-    $sql = "UPDATE {context}
-               SET depth=2, path=" . $DB->sql_concat("'$base/'", 'id') . "
-             WHERE contextlevel=".CONTEXT_COURSECAT."
-                   AND EXISTS (SELECT 'x'
-                                 FROM {course_categories} cc
-                                WHERE cc.id = {context}.instanceid
-                                      AND cc.depth=1)
-                   $emptyclause";
-
-    $DB->execute($sql);
-    $DB->delete_records('context_temp');
-
-    // Deeper categories - one query per depthlevel
-    $maxdepth = $DB->get_field_sql("SELECT MAX(depth)
-                               FROM {course_categories}");
-    for ($n=2; $n<=$maxdepth; $n++) {
-        $sql = "INSERT INTO {context_temp} (id, path, depth)
-                SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", $n+1
-                  FROM {context} ctx
-                  JOIN {course_categories} c ON ctx.instanceid=c.id
-                  JOIN {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 {context_temp} temp
-                                       WHERE temp.id = ctx.id)
-                       $ctxemptyclause";
-        $DB->execute($sql);
-
-        // this is needed after every loop
-        // MDL-11532
-        $DB->execute($updatesql);
-        $DB->delete_records('context_temp');
+    foreach(context_level_base::get_all_context_levels() as $cl) {
+        $cl->build_context_path($base, $emptyclause);
     }
 
-    // Courses -- except sitecourse
-    $sql = "INSERT INTO {context_temp} (id, path, depth)
-            SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
-              FROM {context} ctx
-              JOIN {course} c ON ctx.instanceid=c.id
-              JOIN {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 {context_temp} temp
-                                       WHERE temp.id = ctx.id)
-                   $ctxemptyclause";
-    $DB->execute($sql);
-
-    $DB->execute($updatesql);
-    $DB->delete_records('context_temp');
-
-    // Module instances
-    $sql = "INSERT INTO {context_temp} (id, path, depth)
-            SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
-              FROM {context} ctx
-              JOIN {course_modules} cm ON ctx.instanceid=cm.id
-              JOIN {context} pctx ON cm.course=pctx.instanceid
-             WHERE ctx.contextlevel=".CONTEXT_MODULE."
-                   AND pctx.contextlevel=".CONTEXT_COURSE."
-                       AND NOT EXISTS (SELECT 'x'
-                                       FROM {context_temp} temp
-                                       WHERE temp.id = ctx.id)
-                   $ctxemptyclause";
-    $DB->execute($sql);
-
-    $DB->execute($updatesql);
-    $DB->delete_records('context_temp');
-
-    // User
-    $sql = "UPDATE {context}
-               SET depth=2, path=".$DB->sql_concat("'$base/'", 'id')."
-             WHERE contextlevel=".CONTEXT_USER."
-                   AND EXISTS (SELECT 'x'
-                                 FROM {user} u
-                                WHERE u.id = {context}.instanceid)
-                   $emptyclause ";
-    $DB->execute($sql);
-
-    // Blocks
-    // pctx.path IS NOT NULL prevents fatal problems with broken block instances that point to invalid context parent
-    $sql = "INSERT INTO {context_temp} (id, path, depth)
-            SELECT ctx.id, ".$DB->sql_concat('pctx.path', "'/'", 'ctx.id').", pctx.depth+1
-              FROM {context} ctx
-              JOIN {block_instances} bi ON ctx.instanceid = bi.id
-              JOIN {context} pctx ON bi.parentcontextid = pctx.id
-             WHERE ctx.contextlevel=".CONTEXT_BLOCK."
-                   AND pctx.path IS NOT NULL
-                   AND NOT EXISTS (SELECT 'x'
-                                   FROM {context_temp} temp
-                                   WHERE temp.id = ctx.id)
-                   $ctxemptyclause";
-    $DB->execute($sql);
-
-    $DB->execute($updatesql);
-    $DB->delete_records('context_temp');
-
     // reset static course cache - it might have incorrect cached data
     $ACCESSLIB_PRIVATE->contexcache->reset();
 }
