DueDateURLs.java

package edu.odu.cs.cowem.documents.urls;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;

/**
 * Implements URL rewriting in course documents.
 * 
 *  [text](due:) where text is a date/time in ISO 8601 format
 *           YYYY-MM-DDThh:mm, is formatted so a span of class
 *           date with a more conventional format, preceded by "Due: ".
 * 
 *  No support at the moment for time zones. May add that later.
 *  
 * @author zeil
 *
 */
public class DueDateURLs implements SpecialURL {
    
     
    /**
     * For logging error messages.
     */
    private static Logger logger 
       = LoggerFactory.getLogger(DueDateURLs.class);
    
    /**
     * Format used for rendering combined date-time attributes.
     */
    private static final DateTimeFormatter DT_ATTR_FORMAT 
        = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");


    /**
     * Create a URL rewriter.
     * 
     */
    public DueDateURLs() {
    }

 
	/**
	 * Checks to see if a linking element (a or img) uses a special
	 * protocol label and, if so, attempts to rewrite the element.
	 * 
     * @param link an element containing a URL
     * @param linkAttr name of the attribute containing the URL 
     * @return true if the element has been rewritten.
	 */
	@Override
	public final boolean applyTo(final Element link, final String linkAttr) {
	    String url = link.getAttribute(linkAttr);
	    if ("due:".equals(url)) {
	        String rawDateTime = link.getTextContent();
	        
	        String formattedDateTime = "";
	        String startTimeAttr = "";
	        String endTimeAttr = "";
	        ZoneId timeZone = ZoneId.systemDefault();

	        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
	        try {
	            LocalDateTime dateTime = LocalDateTime.parse(rawDateTime, 
	                    formatter);
	            DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern(
	                    "MM/dd/yyyy, h:mma z");
	            ZonedDateTime zdt  = ZonedDateTime.of(dateTime, timeZone);
	            formattedDateTime = "Due: " + outputFormat.format(zdt);
                startTimeAttr = DT_ATTR_FORMAT.format(zdt);
	            ZonedDateTime zedt = zdt.plusMinutes(1);
	            endTimeAttr = DT_ATTR_FORMAT.format(zedt);
                
	        } catch (DateTimeParseException ex) {
	            formattedDateTime = "";
	        }
            if (formattedDateTime.length() == 0) {
                formatter = DateTimeFormatter.ISO_LOCAL_DATE;
                try {
                    LocalDate date = LocalDate.parse(rawDateTime, 
                            formatter);
                    DateTimeFormatter outputFormat = 
                            DateTimeFormatter.ofPattern(
                               "MM/dd/yyyy");
                    formattedDateTime = "Due: " + outputFormat.format(date);
                    LocalDateTime dateTime = date.atTime(23,58,59);
                    ZonedDateTime zdt  = ZonedDateTime.of(dateTime, timeZone);
                    startTimeAttr = DT_ATTR_FORMAT.format(zdt);
                    ZonedDateTime zedt = zdt.plusMinutes(1);
                    endTimeAttr = DT_ATTR_FORMAT.format(zedt);
                            
                } catch (DateTimeParseException ex) {
                    formattedDateTime = "";
                }
            }
	        if (formattedDateTime.length() == 0) {
	            formatter = DateTimeFormatter.ISO_LOCAL_TIME;
	            try {
	                LocalTime time = LocalTime.parse(rawDateTime, 
	                        formatter);
	                DateTimeFormatter outputFormat = 
	                        DateTimeFormatter.ofPattern(
	                           "h:mma");
	                formattedDateTime = "Due: " + outputFormat.format(time);
	                        
	            } catch (DateTimeParseException ex) {
	                formattedDateTime = "";
	            }
	        }
	        if (formattedDateTime.length() > 0) {
	            Document doc = link.getOwnerDocument();
	            Element span = doc.createElement("span");
                NamedNodeMap attrs = link.getAttributes();
                for (int i = 0; i < attrs.getLength(); i++) {
                  Attr attr2 = (Attr) doc.importNode(attrs.item(i), true);
                  if (!attr2.getName().equals("href")) {
                      span.getAttributes().setNamedItem(attr2);
                  }
                }
                span.setAttribute("class", "date");
                if (startTimeAttr.length() > 0) {
                    span.setAttribute("startsAt", startTimeAttr);
                }
                if (endTimeAttr.length() > 0) {
                    span.setAttribute("endsAt", endTimeAttr);
                }
	            span.appendChild(doc.createTextNode(formattedDateTime));
	            link.getParentNode().replaceChild(span, link);
	            return true;
	        } else {
	            logger.warn("Unable to parse due date: " + rawDateTime);
	        }
	    }
	    return false;
	}
     	   	
     	    

}