/**
   * Format the to site email address.
   *
   * @param event The event that matched criteria to cause the notification.
   * @return the email address attribution for the site.
   */
  protected String getToSite(Event event) {
    Reference ref = EntityManager.newReference(event.getResource());

    // use either the configured site, or if not configured, the site (context) of the resource
    String siteId = (getSite() != null) ? getSite() : ref.getContext();

    // get a site title
    String title = siteId;
    String email = null;
    try {
      Site site = SiteService.getSite(siteId);
      title = site.getTitle();

      // check that the channel exists
      String channel = "/mailarchive/channel/" + siteId + "/main";
      EntityManager.newReference(channel);

      // find the alias for this site's mail channel
      List<Alias> all = AliasService.getAliases(channel);
      if (!all.isEmpty()) email = ((Alias) all.get(0)).getId();
    } catch (Exception ignore) {
    }

    // if for any reason we did not find an email, setup for the no-reply for email
    if (email == null) email = "no-reply";

    String rv =
        "\"" + title + "\" <" + email + "@" + ServerConfigurationService.getServerName() + ">";

    return rv;
  }
  @Override
  protected String plainTextContent(Event event) {
    StringBuilder buf = new StringBuilder();
    String newline = "\n\r";

    // get the message
    Reference ref = entityManager.newReference(event.getResource());
    AnnouncementMessage msg = (AnnouncementMessage) ref.getEntity();
    AnnouncementMessageHeader hdr = (AnnouncementMessageHeader) msg.getAnnouncementHeader();

    // use either the configured site, or if not configured, the site (context) of the resource
    String siteId = (getSite() != null) ? getSite() : ref.getContext();

    String url = ServerConfigurationService.getPortalUrl() + "/site/" + siteId;

    // get a site title
    String title = siteId;
    try {
      Site site = siteService.getSite(siteId);
      title = site.getTitle();
    } catch (Exception ignore) {

    }

    // Now build up the message text.
    if (AnnouncementService.SECURE_ANNC_ADD.equals(event.getEvent())) {
      buf.append(
          FormattedText.convertFormattedTextToPlaintext(
              rb.getFormattedMessage("noti.header.add", new Object[] {title, url})));

    } else {
      buf.append(
          FormattedText.convertFormattedTextToPlaintext(
              rb.getFormattedMessage("noti.header.update", new Object[] {title, url})));
    }

    buf.append(" " + rb.getString("at_date") + " ");
    buf.append(hdr.getDate().toStringLocalFull());
    buf.append(newline);
    buf.append(FormattedText.convertFormattedTextToPlaintext(msg.getBody()));
    buf.append(newline);

    // add any attachments
    List attachments = hdr.getAttachments();
    if (attachments.size() > 0) {
      buf.append(newline + rb.getString("Attachments") + newline);
      for (Iterator iAttachments = attachments.iterator(); iAttachments.hasNext(); ) {
        Reference attachment = (Reference) iAttachments.next();
        String attachmentTitle =
            attachment.getProperties().getPropertyFormatted(ResourceProperties.PROP_DISPLAY_NAME);
        buf.append(attachmentTitle + ": " + attachment.getUrl() + newline);
      }
    }

    return buf.toString();
  }
  /**
   * Format the announcement notification from address.
   *
   * @param event The event that matched criteria to cause the notification.
   * @return the announcement notification from address.
   */
  protected String getFromAddress(Event event) {
    Reference ref = EntityManager.newReference(event.getResource());

    // SAK-14831, yorkadam, make site title reflected in 'From:' name instead of default
    // ServerConfigurationService.getString("ui.service", "Sakai");
    String siteId = (getSite() != null) ? getSite() : ref.getContext();
    String title = "";
    try {
      Site site = SiteService.getSite(siteId);
      title = site.getTitle();
    } catch (Exception ignore) {
    }

    String userEmail = "no-reply@" + ServerConfigurationService.getServerName();
    String userDisplay = ServerConfigurationService.getString("ui.service", "Sakai");
    // String no_reply = "From: \"" + userDisplay + "\" <" + userEmail + ">";
    // String no_reply_withTitle = "From: \"" + title + "\" <" + userEmail + ">";
    String from = "From: Sakai"; // fallback value
    if (title != null && !title.equals("")) {
      from = "From: \"" + title + "\" <" + userEmail + ">";
    } else {
      String fromVal = getFrom(event); // should not return null but better safe than sorry
      if (fromVal != null) {
        from = fromVal;
      }
    }

    // get the message
    AnnouncementMessage msg = (AnnouncementMessage) ref.getEntity();
    String userId = msg.getAnnouncementHeader().getFrom().getDisplayId();

    // checks if "from" email id has to be included? and whether the notification is a delayed
    // notification?. SAK-13512
    // SAK-20988 - emailFromReplyable@org.sakaiproject.event.api.NotificationService is deprecated
    boolean notificationEmailFromReplyable =
        ServerConfigurationService.getBoolean("notify.email.from.replyable", false);
    if (notificationEmailFromReplyable && from.contains("no-reply@") && userId != null) {
      try {
        User u = UserDirectoryService.getUser(userId);
        userDisplay = u.getDisplayName();
        userEmail = u.getEmail();
        if ((userEmail != null) && (userEmail.trim().length()) == 0) userEmail = null;

      } catch (UserNotDefinedException e) {
      }

      // some fallback positions
      if (userEmail == null) userEmail = "no-reply@" + ServerConfigurationService.getServerName();
      if (userDisplay == null)
        userDisplay = ServerConfigurationService.getString("ui.service", "Sakai");
      from = "From: \"" + userDisplay + "\" <" + userEmail + ">";
    }

    return from;
  }
  /** @inheritDoc */
  protected String htmlContent(Event event) {
    StringBuilder buf = new StringBuilder();
    String newline = "<br />\n";

    // get the message
    Reference ref = EntityManager.newReference(event.getResource());
    AnnouncementMessage msg = (AnnouncementMessage) ref.getEntity();
    AnnouncementMessageHeader hdr = (AnnouncementMessageHeader) msg.getAnnouncementHeader();

    // use either the configured site, or if not configured, the site (context) of the resource
    String siteId = (getSite() != null) ? getSite() : ref.getContext();

    // get a site title
    String title = siteId;
    String url = ServerConfigurationService.getPortalUrl() + "/site/" + siteId;
    try {
      Site site = SiteService.getSite(siteId);
      title = site.getTitle();
      url = site.getUrl(); // Might have a better URL.
    } catch (Exception ignore) {
      M_log.warn("Failed to load site: " + siteId + " for: " + event.getResource());
    }

    // Now build up the message text.
    if (AnnouncementService.SECURE_ANNC_ADD.equals(event.getEvent())) {
      buf.append(rb.getFormattedMessage("noti.header.add", new Object[] {title, url}));
    } else {
      buf.append(rb.getFormattedMessage("noti.header.update", new Object[] {title, url}));
    }
    buf.append(" " + rb.getString("at_date") + " ");
    buf.append(hdr.getDate().toStringLocalFull());
    buf.append(newline);

    // add any attachments
    List<Reference> attachments = hdr.getAttachments();
    if (attachments.size() > 0) {
      buf.append(newline + rb.getString("Attachments") + newline);
      for (Iterator<Reference> iAttachments = attachments.iterator(); iAttachments.hasNext(); ) {
        Reference attachment = (Reference) iAttachments.next();
        String attachmentTitle =
            attachment.getProperties().getPropertyFormatted(ResourceProperties.PROP_DISPLAY_NAME);
        buf.append("<a href=\"" + attachment.getUrl() + "\">");
        buf.append(attachmentTitle);
        buf.append("</a>" + newline);
      }
    }

    return buf.toString();
  }
  public ContentResource wrap(final ContentResource content) {
    if (!isFiltered(content)) {
      return content;
    }
    Reference contentRef = entityManager.newReference(content.getReference());
    Reference siteRef = entityManager.newReference(contentRef.getContext());
    Entity entity = siteRef.getEntity();

    String addHtml = content.getProperties().getProperty(ResourceProperties.PROP_ADD_HTML);

    String skinRepo = getSkinRepo();
    String siteSkin = getSiteSkin(entity);

    final boolean detectHtml = addHtml == null || addHtml.equals("auto");
    String title = getTitle(content);
    final String header = MessageFormat.format(headerTemplate, skinRepo, siteSkin, title);
    final String footer = footerTemplate;

    return new WrappedContentResource(content, header, footer, detectHtml);
  }
  /**
   * Format the announcement notification subject line.
   *
   * @param event The event that matched criteria to cause the notification.
   * @return the announcement notification subject line.
   */
  protected String getSubject(Event event) {
    // get the message
    Reference ref = EntityManager.newReference(event.getResource());
    AnnouncementMessage msg = (AnnouncementMessage) ref.getEntity();
    AnnouncementMessageHeader hdr = (AnnouncementMessageHeader) msg.getAnnouncementHeader();

    // use either the configured site, or if not configured, the site (context) of the resource
    String siteId = (getSite() != null) ? getSite() : ref.getContext();

    // get a site title
    String title = siteId;
    try {
      Site site = SiteService.getSite(siteId);
      title = site.getTitle();
    } catch (Exception ignore) {
    }

    // use the message's subject
    return rb.getFormattedMessage("noti.subj", new Object[] {title, hdr.getSubject()});
  }
  /**
   * Format a to address, to the related site, but with no reply.
   *
   * @param event The event that matched criteria to cause the notification.
   * @return a to address, to the related site, but with no reply.
   */
  protected String getToSiteNoReply(Event event) {
    Reference ref = EntityManager.newReference(event.getResource());

    // use either the configured site, or if not configured, the site (context) of the resource
    String siteId = (getSite() != null) ? getSite() : ref.getContext();

    // get a site title
    String title = siteId;
    try {
      Site site = SiteService.getSite(siteId);
      title = site.getTitle();
    } catch (Exception ignore) {
    }

    return "\""
        + title
        + "\" <"
        + ServerConfigurationService.getString(
            "setup.request", "no-reply@" + ServerConfigurationService.getServerName())
        + ">";
  }
  /** @inheritDoc */
  protected List<User> getRecipients(Event event) {
    // get the resource reference
    Reference ref = EntityManager.newReference(event.getResource());

    // use either the configured site, or if not configured, the site (context) of the resource
    String siteId = (getSite() != null) ? getSite() : ref.getContext();

    // if the site is published, use the list of users who can SITE_VISIT the site,
    // else use the list of users who can SITE_VISIT_UNP the site.
    try {
      Site site = SiteService.getSite(siteId);
      String ability = SiteService.SITE_VISIT;
      if (!site.isPublished()) {
        ability = SiteService.SITE_VISIT_UNPUBLISHED;
      }

      // get the list of users who can do the right kind of visit
      List<User> users = SecurityService.unlockUsers(ability, ref.getReference());

      // get the list of users who have the appropriate access to the resource
      if (getResourceAbility() != null) {
        List<User> users2 = SecurityService.unlockUsers(getResourceAbility(), ref.getReference());

        // find intersection of users and user2
        users.retainAll(users2);
      }

      // only use direct site members for the base list of users
      refineToSiteMembers(users, site);

      // add any other users
      addSpecialRecipients(users, ref);

      return users;
    } catch (Exception any) {
      return new Vector<User>();
    }
  }