/**
  * Display a post. This method is used for:
  * - The normal HTML display of a post
  * - HTML email of a post
  * - Text-only email of a post
  * These are all combined in one method since ordinarily they change at
  * the same time (i.e. if adding/hiding information it is usually added to
  * or hidden from all views).
  *
  * $options is an associative array from a forum_post::OPTION_xx constant.
  * All available options are always set - if they were not set by
  * the user, they will have been set to false before this call happens,
  * so there is no need to use empty() or isset().
  *
  * Options are as follows. These are available in email mode:
  *
  * OPTION_TIME_ZONE (int) - Moodle time zone
  * OPTION_VIEW_FULL_NAMES (bool) - If user is allowed to see full names
  * OPTION_EMAIL (bool) - True if this is an email (false = standard view)
  * OPTION_DIGEST (bool) - True if this is part of an email digest
  * OPTION_COMMAND_REPLY (bool) - True if 'Reply' link should be displayed
  *   (available in email too)
  *
  * These options only apply in non-email usage:
  *
  * OPTION_SUMMARY (bool) - True if the entire post should not be displayed,
  *   only a short summary
  * OPTION_NO_COMMANDS (bool) - True if this post is being printed on its own
  * OPTION_COMMAND_EDIT (bool) - Display 'Edit' command
  * OPTION_COMMAND_DELETE (bool) - Display 'Edit' command
  * OPTION_COMMAND_SPLIT (bool) - Display 'Split' command
  * OPTION_RATINGS_VIEW (bool) - True to display current ratings
  * OPTION_RATINGS_EDIT (bool) - True to display ratings edit combo
  * OPTION_LEAVE_DIV_OPEN (bool) - True to not close post div (means that
  *   child posts can be added within).
  * OPTION_EXPANDED (bool) - True to show full post, otherwise abbreviate
  * OPTION_DISCUSSION_SUBJECT (bool) - If true, and only IF post is a 
  *   discussion root, includes subject (HTML, shortened as it would be for
  *   header display) as a hidden field.
  *
  * @param forum_post $post Post object
  * @param bool $html True if using HTML, false to output in plain text
  * @param array $options Associative array of name=>option, as above
  * @return string HTML or text of post
  */
 public function display_post($post, $html, $options)
 {
     global $CFG, $USER, $THEME;
     $discussion = $post->get_discussion();
     $expanded = $options[forum_post::OPTION_EXPANDED];
     $export = $options[forum_post::OPTION_EXPORT];
     $email = $options[forum_post::OPTION_EMAIL];
     // When posts are deleted we hide a lot of info - except when the person
     // viewing it has the ability to view deleted posts.
     $deletedhide = $post->get_deleted() && !$options[forum_post::OPTION_VIEW_DELETED_INFO];
     // Hide deleted messages if they have no replies
     if ($deletedhide && !$email && !$post->has_children()) {
         // note: !email check is to deal with posts that are deleted
         // between when the mail list finds them, and when it sends out
         // mail. It would be confusing to send out a blank email so let's
         // not do that. Also, ->has_children() is not safe to call during
         // email processing because it doesn't load the whole discussion.
         return '';
     }
     // Save some bandwidth by not sending link full paths except in emails
     if ($options[forum_post::OPTION_FULL_ADDRESSES]) {
         $linkprefix = $CFG->wwwroot . '/mod/forumng/';
     } else {
         $linkprefix = '';
     }
     $postnumber = ($options[forum_post::OPTION_NO_COMMANDS] || $email) && !$options[forum_post::OPTION_VISIBLE_POST_NUMBERS] ? '' : $post->get_number();
     $lf = "\n";
     // Initialise result
     $out = '';
     if ($html) {
         if ($export) {
             $out .= '<hr />';
         }
         // Basic intro
         $classes = $expanded ? ' forumng-full' : ' forumng-short';
         $classes .= $post->is_important() ? ' forumng-important' : '';
         $classes .= !$email && !$options[forum_post::OPTION_UNREAD_NOT_HIGHLIGHTED] && $post->is_unread() ? ' forumng-unread' : ' forumng-read';
         $classes .= $post->get_deleted() ? ' forumng-deleted' : '';
         $classes .= ' forumng-p' . $postnumber;
         $out .= $lf . '<div class="forumng-post' . $classes . '"><a id="p' . $post->get_id() . '"></a>';
         if ($options[forum_post::OPTION_FIRST_UNREAD]) {
             $out .= '<a id="firstunread"></a>';
         }
         // Theme hooks
         if (!empty($THEME->forumng_post_hooks)) {
             for ($i = 1; $i <= $THEME->forumng_post_hooks; $i++) {
                 $out .= '<div class="forumng-' . $i . '"></div>';
             }
         }
     }
     if ($html || $options[forum_post::OPTION_VISIBLE_POST_NUMBERS]) {
         // Accessible text giving post a number so we can make links unique
         // etc.
         if ($postnumber) {
             $data = new stdClass();
             $data->num = $postnumber;
             if ($post->get_parent()) {
                 if ($html) {
                     $data->parent = '<a class="forumng-parentlink" href="#p' . $post->get_parent()->get_id() . '">' . $post->get_parent()->get_number() . '</a>';
                 } else {
                     $data->parent = $post->get_parent()->get_number();
                 }
                 $data->info = '';
                 if ($post->is_unread()) {
                     $data->info = get_string('postinfo_unread', 'forumng');
                 }
                 if (!$expanded) {
                     $data->info .= ' ' . get_string('postinfo_short', 'forumng');
                 }
                 if ($post->get_deleted()) {
                     $data->info .= ' ' . get_string('postinfo_deleted', 'forumng');
                 }
                 $data->info = trim($data->info);
                 if ($data->info) {
                     $data->info = ' (' . $data->info . ')';
                 }
                 $info = get_string('postnumreply', 'forumng', $data);
             } else {
                 $info = get_string('postnum', 'forumng', $data);
             }
             if ($options[forum_post::OPTION_VISIBLE_POST_NUMBERS]) {
                 if (!$html) {
                     $out .= "## " . $info . "\n";
                 }
             }
         }
     }
     // Discussion subject (root only)
     if ($options[forum_post::OPTION_DISCUSSION_SUBJECT] && $post->is_root_post()) {
         $out .= '<input type="hidden" name="discussion_subject" value="' . shorten_text(htmlspecialchars($post->get_subject())) . '" />';
     }
     // Pictures (HTML version only)
     if ($html && !$export && $options[forum_post::OPTION_USER_IMAGE]) {
         $out .= $lf . '<div class="forumng-pic">';
         // User picture
         $out .= $deletedhide ? '' : $post->display_user_picture();
         // Group pictures if any - only for expanded version
         if ($expanded) {
             $grouppics = $post->display_group_pictures();
             if ($grouppics) {
                 $out .= '<div class="forumng-grouppicss">' . $grouppics . '</div>';
             }
         }
         $out .= '</div>';
     }
     // Link used to expand post
     $expandlink = '';
     if (!$expanded && !$deletedhide) {
         $expandlink = '&nbsp;[<a class="forumng-expandlink" ' . 'href="' . $linkprefix . 'discuss.php?' . $discussion->get_link_params(forum::PARAM_HTML) . '&amp;expand=1#p' . $post->get_id() . '">' . get_string('expandall', 'forumng') . '</a>] <img src="' . $CFG->pixpath . '/spacer.gif" width="16" height="16" alt="" />';
     }
     // Byline
     $by = new stdClass();
     $by->name = $deletedhide ? '' : fullname($post->get_user(), $options[forum_post::OPTION_VIEW_FULL_NAMES]);
     $by->date = $deletedhide ? '' : userdate($post->get_created(), get_string('strftimedatetime', 'langconfig'), $options[forum_post::OPTION_TIME_ZONE]);
     if ($html) {
         $out .= $lf . '<div class="forumng-info"><h2 class="forumng-author">';
         $out .= $post->is_important() ? '<img src="' . $CFG->modpixpath . '/forumng/exclamation_mark.gif" alt="' . get_string('important', 'forumng') . '" ' . 'title = "' . get_string('important', 'forumng') . '"/>' : '';
         if ($export) {
             $out .= $by->name;
         } else {
             $out .= '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $post->get_user()->id . ($post->get_forum()->is_shared() ? '' : '&amp;course=' . $post->get_forum()->get_course_id()) . '">' . $by->name . '</a>';
         }
         if ($postnumber) {
             if ($options[forum_post::OPTION_VISIBLE_POST_NUMBERS]) {
                 $out .= '<span class="accesshide" style="position:static"> ' . $info . ' </span>';
             } else {
                 $out .= '<span class="accesshide"> ' . $info . ' </span>';
             }
         }
         $out .= $deletedhide ? '' : '</h2> <span class="forumng-separator">&#x2022;</span> ';
         $out .= '<span class="forumng-date">' . $by->date . '</span>';
         if ($edituser = $post->get_edit_user()) {
             $out .= ' <span class="forumng-separator">&#x2022;</span> ' . '<span class="forumng-edit">';
             $edit = new stdClass();
             $edit->date = userdate($post->get_modified(), get_string('strftimedatetime', 'langconfig'), $options[forum_post::OPTION_TIME_ZONE]);
             $edit->name = fullname($edituser, $options[forum_post::OPTION_VIEW_FULL_NAMES]);
             if ($edituser->id == $post->get_user()->id) {
                 $out .= get_string('editbyself', 'forumng', $edit->date);
             } else {
                 $out .= get_string('editbyother', 'forumng', $edit);
             }
             if ($options[forum_post::OPTION_COMMAND_HISTORY]) {
                 $out .= ' (<a href="history.php?' . $post->get_link_params(forum::PARAM_HTML) . '">' . get_string('history', 'forumng') . '</a>)';
             }
             $out .= '</span>';
         }
         if ($options[forum_post::OPTION_SELECTABLE]) {
             $out .= ' &#x2022; <input type="checkbox" name="selectp' . $post->get_id() . '" id="id_selectp' . $post->get_id() . '" /><label class="accesshide" for="id_selectp' . $post->get_id() . '">' . get_string('selectlabel', 'forumng', $postnumber) . '</label>';
         }
         if ($options[forum_post::OPTION_FLAG_CONTROL]) {
             $out .= '<div class="forumng-flag">' . '<input type="image" title="' . get_string($post->is_flagged() ? 'clearflag' : 'setflag', 'forumng') . '" src="' . $CFG->modpixpath . '/forumng/flag.' . ($post->is_flagged() ? 'on' : 'off') . '.png" alt="' . get_string($post->is_flagged() ? 'flagon' : 'flagoff', 'forumng') . '" name="action.flag.p_' . $post->get_id() . '.timeread_' . $options[forum_post::OPTION_READ_TIME] . '.flag_' . ($post->is_flagged() ? 0 : 1) . '"/></div>';
         }
         $out .= '</div>';
     } else {
         $out .= $by->name . ' - ' . $by->date . $lf;
         $out .= forum_cron::EMAIL_DIVIDER;
     }
     if ($post->get_deleted()) {
         $out .= '<p class="forumng-deleted-info"><strong>' . get_string('deletedpost', 'forumng') . '</strong> ';
         if ($deletedhide) {
             $out .= get_string($post->get_delete_user()->id == $post->get_user()->id ? 'deletedbyauthor' : 'deletedbymoderator', 'forumng', userdate($post->get_deleted()));
         } else {
             $a = new stdClass();
             $a->date = userdate($post->get_deleted());
             $a->user = '******' . $CFG->wwwroot . '/user/view.php?id=' . $post->get_delete_user()->id . '&amp;course=' . $post->get_forum()->get_course_id() . '">' . fullname($post->get_delete_user(), $options[forum_post::OPTION_VIEW_FULL_NAMES]) . '</a>';
             $out .= get_string('deletedbyuser', 'forumng', $a);
         }
         $out .= '</p>';
     }
     // Get subject. This may make a db query when showing a single post
     // (which includes parent subject).
     if ($options[forum_post::OPTION_EMAIL] || $options[forum_post::OPTION_NO_COMMANDS]) {
         $subject = $post->get_effective_subject(true);
     } else {
         $subject = $post->get_subject();
     }
     // Otherwise, subject is only displayed if it has changed
     if ($subject !== null && $expanded && !$deletedhide) {
         if ($html) {
             $out .= $lf . '<h3 class="forumng-subject">';
             if ($options[forum_post::OPTION_DIGEST]) {
                 // Digest contains link to original post
                 $out .= '<a href="' . $linkprefix . 'discuss.php?' . $discussion->get_link_params(forum::PARAM_HTML) . '#p' . $post->get_id() . '">' . format_string($subject) . '</a>';
             } else {
                 $out .= format_string($subject);
             }
             $out .= '</h3>';
         } else {
             $out .= format_string($subject, true);
             if ($options[forum_post::OPTION_DIGEST]) {
                 // Link to original post
                 $out .= " <{$linkprefix}discuss.php?" . $discussion->get_link_params(forum::PARAM_HTML) . $discussion->get_id() . '#p' . $post->get_id() . '>';
             }
             $out .= $lf;
         }
     }
     // Get content of actual message in HTML
     if ($html) {
         $textoptions = new stdClass();
         // Don't put a <p> tag round post
         $textoptions->para = false;
         // Does not indicate that we trust the text, only that the
         // TRUSTTEXT marker is supported.
         $textoptions->trusttext = true;
         $message = format_text($post->get_message(), $post->get_format(), $textoptions, $post->get_forum()->get_course_id());
         if (!$expanded && !$deletedhide) {
             // When not expanded and no subject, we include a summary of the
             // message
             $stripped = strip_tags(preg_replace('~<script.*?</script>~s', '', $message));
             $messagetosummarise = $subject !== null ? '<h3>' . $subject . '</h3>&nbsp;' . $stripped : $stripped;
             $summary = self::nice_shorten_text($messagetosummarise, 50);
             $out .= $lf . '<div class="forumng-summary"><div class="forumng-text">' . $summary . '</div> ' . $expandlink . '</div>';
         }
     }
     // Start of post main section
     if ($expanded && !$deletedhide) {
         if ($html) {
             $out .= '<div class="forumng-postmain">';
         }
         // Attachments
         $attachments = $post->get_attachment_names();
         if (count($attachments)) {
             if ($html) {
                 $out .= $lf . '<ul class="forumng-attachments">';
             }
             if (count($attachments) == 1) {
                 $attachmentlabel = get_string('attachment', 'forumng');
             } else {
                 $attachmentlabel = get_string('attachments', 'forumng');
             }
             $out .= '<span class="accesshide">' . $attachmentlabel . '</span>';
             foreach ($attachments as $attachment) {
                 if ($html) {
                     require_once $CFG->libdir . '/filelib.php';
                     $iconsrc = $CFG->pixpath . '/f/' . mimeinfo('icon', $attachment);
                     $alt = get_mimetype_description(mimeinfo('type', $attachment));
                     $out .= '<li><a href="' . $linkprefix . 'attachment.php?' . $post->get_link_params(forum::PARAM_HTML) . '&amp;file=' . $attachment . '">' . '<img src="' . $iconsrc . '" alt="' . $alt . '" /> <span>' . htmlspecialchars($attachment) . '</span></a></li>';
                 } else {
                     // Right-align the entry to 70 characters
                     $padding = 70 - strlen($attachment);
                     if ($padding > 0) {
                         $out .= str_repeat(' ', $padding);
                     }
                     // Add filename
                     $out .= $attachment . $lf;
                 }
             }
             if ($html) {
                 $out .= '</ul>' . $lf;
             } else {
                 $out .= $lf;
                 // Extra line break after attachments
             }
         }
         // Display actual content
         if ($html) {
             if ($options[forum_post::OPTION_PRINTABLE_VERSION]) {
                 $message = preg_replace('~<a[^>]*\\shref\\s*=\\s*[\'"](http:.*?)[\'"][^>]*>' . '(?!(http:|www\\.)).*?</a>~', "\$0 [\$1]", $message);
             }
             $out .= $lf . '<div class="forumng-message">' . $message . '</div>';
         } else {
             $out .= format_text_email(trusttext_strip($post->get_message()), $post->get_format());
             $out .= "\n\n";
         }
         if ($html) {
             $out .= $lf . '<div class="forumng-postfooter">';
         }
         // Ratings
         $ratings = '';
         $ratingclasses = '';
         if ($options[forum_post::OPTION_RATINGS_VIEW]) {
             $ratingclasses .= ' forumng-canview';
             if ($post->get_num_ratings() >= $post->get_forum()->get_rating_threshold()) {
                 if ($html) {
                     $ratings .= '<div class="forumng-rating">';
                     $a = new stdClass();
                     $a->avg = '<strong id="rating_for_' . $post->get_id() . '">' . $post->get_average_rating(true) . '</strong>';
                     $a->num = '<span class="forumng-count">' . $post->get_num_ratings() . '</span>';
                     $ratings .= get_string('averagerating', 'forumng', $a);
                     $ratings .= '</div>';
                 } else {
                     $ratings .= strip_tags($post->get_average_rating(true));
                 }
             }
         }
         if ($options[forum_post::OPTION_RATINGS_EDIT] && $html) {
             $ratingclasses .= ' forumng-canedit';
             $ratings .= '<div class="forumng-editrating">' . get_string('yourrating', 'forumng') . ' ';
             $ratings .= choose_from_menu($post->get_forum()->get_rating_options(), 'rating' . $post->get_id(), $post->get_own_rating(), '-', '', forum_post::NO_RATING, true);
             $ratings .= '</div>';
         }
         if ($ratings) {
             $out .= '<div class="forumng-ratings' . $ratingclasses . '">' . $ratings . '</div>';
         }
         // Commands at bottom of mail
         if (class_exists('ouflags') && ou_get_is_mobile_from_cookies()) {
             $mobileclass = ' class="forumng-mobilepost-link"';
         } else {
             $mobileclass = '';
         }
         if ($html) {
             $commands = '';
             $expires = $post->can_ignore_edit_time_limit() ? '' : '&amp;expires=' . ($post->get_edit_time_limit() - time());
             // Jump box
             if ($options[forum_post::OPTION_JUMP_PREVIOUS] || $options[forum_post::OPTION_JUMP_NEXT] || $options[forum_post::OPTION_JUMP_PARENT]) {
                 $commands .= '<li class="forumng-jumpto">' . get_string('jumpto', 'forumng');
                 if ($nextid = $options[forum_post::OPTION_JUMP_NEXT]) {
                     $commands .= ' <a href="#p' . $nextid . '" class="forumng-next">' . get_string('jumpnext', 'forumng') . '</a>';
                 }
                 if ($pid = $options[forum_post::OPTION_JUMP_PREVIOUS]) {
                     if ($nextid) {
                         $commands .= ' (<a href="#p' . $pid . '" class="forumng-prev">' . get_string('jumppreviousboth', 'forumng') . '</a>)';
                     } else {
                         $commands .= ' <a href="#p' . $pid . '" class="forumng-prev">' . get_string('jumpprevious', 'forumng') . '</a>';
                     }
                 }
                 if ($parentid = $options[forum_post::OPTION_JUMP_PARENT]) {
                     $commands .= ' <a href="#p' . $parentid . '" class="forumng-parent">' . get_string('jumpparent', 'forumng') . '</a>';
                 }
                 $commands .= '</li>';
             }
             //Direct link
             if ($options[forum_post::OPTION_COMMAND_DIRECTLINK]) {
                 $commands .= '<li class="forumng-permalink"><a href="discuss.php?' . $discussion->get_link_params(forum::PARAM_HTML) . '#p' . $post->get_id() . '" title="' . get_string('directlinktitle', 'forumng') . '">' . get_string('directlink', 'forumng', $postnumber) . '</a></li>';
             }
             // Alert link
             if ($options[forum_post::OPTION_COMMAND_REPORT]) {
                 $commands .= '<li><a href="' . $linkprefix . 'alert.php?' . $post->get_link_params(forum::PARAM_HTML) . '" title="' . get_string('alert_linktitle', 'forumng') . '">' . get_string('alert_link', 'forumng', $postnumber) . '</a></li>';
             }
             // Split link
             if ($options[forum_post::OPTION_COMMAND_SPLIT]) {
                 $commands .= '<li class="forumng-split"><a href="' . $linkprefix . 'splitpost.php?' . $post->get_link_params(forum::PARAM_HTML) . '">' . get_string('split', 'forumng', $postnumber) . '</a></li>';
             }
             // Delete link
             if ($options[forum_post::OPTION_COMMAND_DELETE]) {
                 $commands .= '<li><a' . $mobileclass . ' href="' . $linkprefix . 'deletepost.php?' . $post->get_link_params(forum::PARAM_HTML) . $expires . '">' . get_string('delete', 'forumng', $postnumber) . '</a></li>';
             }
             // Undelete link
             if ($options[forum_post::OPTION_COMMAND_UNDELETE]) {
                 $commands .= '<li><a href="' . $linkprefix . 'deletepost.php?' . $post->get_link_params(forum::PARAM_HTML) . '&amp;delete=0">' . get_string('undelete', 'forumng', $postnumber) . '</a></li>';
             }
             // Edit link
             if ($options[forum_post::OPTION_COMMAND_EDIT]) {
                 $commands .= '<li><a' . $mobileclass . ' href="' . $linkprefix . 'editpost.php?' . $post->get_link_params(forum::PARAM_HTML) . $expires . '">' . get_string('edit', 'forumng', $postnumber) . '</a></li>';
             }
             // Reply link
             if ($options[forum_post::OPTION_COMMAND_REPLY]) {
                 $commands .= '<li class="forumng-replylink"><a' . $mobileclass . ' href="' . $linkprefix . 'editpost.php?replyto=' . $post->get_id() . $post->get_forum()->get_clone_param(forum::PARAM_HTML) . '">' . get_string('reply', 'forumng', $postnumber) . '</a></li>';
             }
             if ($commands) {
                 $out .= $lf . '<ul class="forumng-commands">' . $commands . '</ul>';
             }
         } else {
             // Reply link
             if ($options[forum_post::OPTION_COMMAND_REPLY]) {
                 $out .= forum_cron::EMAIL_DIVIDER;
                 if ($options[forum_post::OPTION_EMAIL]) {
                     $course = $post->get_forum()->get_course();
                     $out .= get_string("postmailinfo", "forumng", $course->shortname) . $lf;
                 }
                 $out .= "{$linkprefix}editpost.php?replyto=" . $post->get_id() . $post->get_forum()->get_clone_param(forum::PARAM_PLAIN) . $lf;
             }
             // Only the reply command is available in text mode
         }
         // End of post footer and main section
         if ($html) {
             $out .= '</div></div>';
         }
     }
     // End of post div
     if ($html) {
         $out .= '<div class="forumng-endpost"></div></div>';
         if ($export) {
             $out .= '<br /><br />';
         }
     }
     return $out;
 }