/**
  * Renders HTML to display one course module in a course section
  *
  * This includes link, content, availability, completion info and additional information
  * that module type wants to display (i.e. number of unread forum posts)
  *
  * This function calls:
  * {@link core_course_renderer::course_section_cm_name()}
  * {@link cm_info::get_after_link()}
  * {@link core_course_renderer::course_section_cm_text()}
  * {@link core_course_renderer::course_section_cm_availability()}
  * {@link core_course_renderer::course_section_cm_completion()}
  * {@link course_get_cm_edit_actions()}
  * {@link core_course_renderer::course_section_cm_edit_actions()}
  *
  * @param \stdClass $course
  * @param \completion_info $completioninfo
  * @param \cm_info $mod
  * @param int|null $sectionreturn
  * @param array $displayoptions
  * @return string
  */
 public function course_section_cm($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array())
 {
     global $COURSE;
     $output = '';
     // We return empty string (because course module will not be displayed at all)
     // if:
     // 1) The activity is not visible to users
     // and
     // 2) The 'availableinfo' is empty, i.e. the activity was
     // hidden in a way that leaves no info, such as using the
     // eye icon.
     if (!$mod->uservisible && empty($mod->availableinfo)) {
         return $output;
     }
     $output .= '<div class="asset-wrapper">';
     // TODO - add if can edit.
     // Drop section notice.
     $output .= '<a class="snap-move-note" href="#">' . get_string('movehere', 'theme_snap') . '</a>';
     // Start the div for the activity content.
     $output .= "<div class='activityinstance'>";
     // Display the link to the module (or do nothing if module has no url).
     $cmname = $this->course_section_cm_name($mod, $displayoptions);
     $assetlink = '';
     // SHAME - For moodles ajax show/hide call to work it needs activityinstance > a to add a class of dimmed to.
     // This dimmed class is of course inaccessible junk.
     if (!empty($cmname)) {
         $assetlink = '<a></a><h4 class="snap-asset-link">' . $cmname . '</h4>';
     }
     // Asset content.
     $contentpart = $this->course_section_cm_text($mod, $displayoptions);
     // Activity/resource type.
     $snapmodtype = $this->get_mod_type($mod)[0];
     $assetmeta = "<span class='snap-assettype'>" . $snapmodtype . "</span>";
     // Groups, Restriction and all that jazz metadata.
     // Completion tracking.
     $completiontracking = $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions);
     // Due date, feedback available and all the nice snap things.
     $snapcompletiondata = $this->module_meta_html($mod);
     $assetcompletionmeta = "<div class='snap-completion-meta'>" . $completiontracking . $snapcompletiondata . "</div>";
     // Draft status - always output, shown via css of parent.
     $assetrestrictions = "<div class='draft-tag text text-warning'>" . get_string('draft', 'theme_snap') . "</div>";
     $canmanagegroups = has_capability('moodle/course:managegroups', context_course::instance($mod->course));
     if ($canmanagegroups && $mod->effectivegroupmode != NOGROUPS) {
         if ($mod->effectivegroupmode == VISIBLEGROUPS) {
             $groupinfo = get_string('groupsvisible');
         } else {
             if ($mod->effectivegroupmode == SEPARATEGROUPS) {
                 $groupinfo = get_string('groupsseparate');
             }
         }
         $assetrestrictions .= "<div class='text'>{$groupinfo}</div>";
     }
     // TODO - ask what this is...
     if (!empty($mod->groupingid) && $canmanagegroups) {
         // Grouping label.
         $groupings = groups_get_all_groupings($mod->course);
         $assetrestrictions .= "<div class='text text-danger'>" . format_string($groupings[$mod->groupingid]->name) . "</div>";
         // TBD - add a title to show this is the Grouping...
     }
     $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $mod->context);
     // If the module isn't available, or we are a teacher (can view hidden activities) then get availability
     // info.
     $availabilityinfo = '';
     if (!$mod->available || $canviewhidden) {
         $availabilityinfo = $this->course_section_cm_availability($mod, $displayoptions);
     }
     if ($availabilityinfo !== '') {
         $conditionalinfo = get_string('conditional', 'theme_snap');
         $assetrestrictions .= "<div class='text text-danger'>{$conditionalinfo}.{$availabilityinfo}</div>";
     }
     $assetrestrictions = "<div class='snap-restrictions-meta'>{$assetrestrictions}</div>";
     $assetmeta .= $assetcompletionmeta . $assetrestrictions;
     // Build output.
     $postcontent = '<div class="snap-asset-meta" data-cmid="' . $mod->id . '">' . $mod->afterlink . $assetmeta . '</div>';
     $output .= $assetlink . $contentpart . $postcontent;
     // Bail at this point if we aren't using a supported format. (Folder view is only partially supported).
     $supported = ['folderview', 'topics', 'weeks', 'site'];
     if (!in_array($COURSE->format, $supported)) {
         return parent::course_section_cm($course, $completioninfo, $mod, $sectionreturn, $displayoptions) . $assetmeta;
     }
     // Build up edit actions.
     $actions = '';
     $actionsadvanced = array();
     $coursecontext = context_course::instance($mod->course);
     $modcontext = context_module::instance($mod->id);
     $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
     if (has_capability('moodle/course:update', $modcontext)) {
         $str = get_strings(array('delete', 'move', 'duplicate', 'hide', 'show', 'roles'), 'moodle');
         // TODO - add snap strings here.
         // Move, Edit, Delete.
         if (has_capability('moodle/course:manageactivities', $modcontext)) {
             $movealt = get_string('move', 'theme_snap', $mod->get_formatted_name());
             $moveicon = "<img title='{$movealt}' aria-hidden='true' class='svg-icon' src='" . $this->output->pix_url('move', 'theme') . "' />";
             $editalt = get_string('edit', 'theme_snap', $mod->get_formatted_name());
             $editicon = "<img title='{$editalt}' alt='{$editalt}' class='svg-icon' src='" . $this->output->pix_url('edit', 'theme') . "'/>";
             $actions .= "<input id='snap-move-mod-{$mod->id}' class='js-snap-asset-move sr-only' type='checkbox'><label class='snap-asset-move' for='snap-move-mod-{$mod->id}'><span class='sr-only'>{$movealt}</span>{$moveicon}</label>";
             $actions .= "<a class='snap-edit-asset' href='" . new moodle_url($baseurl, array('update' => $mod->id)) . "'>{$editicon}</a>";
             $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('delete' => $mod->id)) . "'>{$str->delete}</a>";
         }
         // Hide/Show.
         if (has_capability('moodle/course:activityvisibility', $modcontext)) {
             $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('hide' => $mod->id)) . "' class='editing_hide js_snap_hide'>{$str->hide}</a>";
             $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('show' => $mod->id)) . "' class='editing_show js_snap_show'>{$str->show}</a>";
             // AX click to change.
         }
         // Duplicate.
         $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport');
         if (has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2) && plugin_supports('mod', $mod->modname, 'duplicate', true)) {
             $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('duplicate' => $mod->id)) . "' class='js_snap_duplicate'>{$str->duplicate}</a>";
         }
         // Asign roles.
         if (has_capability('moodle/role:assign', $modcontext)) {
             $actionsadvanced[] = "<a href='" . new moodle_url('/admin/roles/assign.php', array('contextid' => $modcontext->id)) . "'>{$str->roles}</a>";
         }
         // Give local plugins a chance to add icons.
         $localplugins = array();
         foreach (get_plugin_list_with_function('local', 'extend_module_editing_buttons') as $function) {
             $localplugins = array_merge($localplugins, $function($mod));
         }
         // TODO - pld string is far too long....
         $locallinks = '';
         foreach ($localplugins as $localplugin) {
             $url = $localplugin->url;
             $text = $localplugin->text;
             $class = $localplugin->attributes['class'];
             $actionsadvanced[] = "<a href='{$url}' class='{$class}'>{$text}</a>";
         }
     }
     $advancedactions = '';
     if (!empty($actionsadvanced)) {
         $moreicon = "<img title='" . get_string('more', 'theme_snap') . "' alt='" . get_string('more', 'theme_snap') . "' class='svg-icon' src='" . $this->output->pix_url('more', 'theme') . "'/>";
         $advancedactions = "<div class='dropdown snap-edit-more-dropdown'>\n                      <a href='#' class='dropdown-toggle snap-edit-asset-more' data-toggle='dropdown' aria-expanded='false' aria-haspopup='true'>{$moreicon}</a>\n                      <ul class='dropdown-menu'>";
         foreach ($actionsadvanced as $action) {
             $advancedactions .= "<li>{$action}</li>";
         }
         $advancedactions .= "</ul></div>";
     }
     // Add actions menu.
     if ($actions) {
         $output .= "<div class='snap-asset-actions' role='region' aria-label='actions'>";
         $output .= $actions . $advancedactions;
         $output .= "</div>";
     }
     $output .= "</div>";
     // Close .activityinstance.
     $output .= "</div>";
     // Close .asset-wrapper.
     return $output;
 }