/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gagravarr.tika;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.sf.mpxj.Duration;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.Resource;
import net.sf.mpxj.ResourceAssignment;
import net.sf.mpxj.Task;

import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.XHTMLContentHandler;
import static org.apache.tika.utils.DateUtils.formatDate;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
 * Turns Microsoft Project files into Tika Metadata + XHTML
 */
public class ProjectFileProcessor {
    public static void parse(ProjectFile project, ContentHandler handler,
            Metadata metadata, ParseContext context)
            throws IOException, TikaException, SAXException {
       // To keep track of the resources that people claim
       Set<Integer> usedResources = new HashSet<Integer>();

       // Start our document
       XHTMLContentHandler xhtml =
               new XHTMLContentHandler(handler, metadata);
       xhtml.startDocument();

       // Walk the tree of tasks, printing them out
       xhtml.element("h2", "Tasks");
       handleTasks(project.getChildTasks(), xhtml, usedResources);

       // Find any un-used resources
       Set<Resource> spareResources = new HashSet<Resource>();
       for (Resource resource : project.getAllResources()) {
           if (! usedResources.contains(resource.getID())) {
               if (resource.getID() == 0 && resource.getName() == null) {
                   // Special case, skip this
               } else {
                   spareResources.add(resource);
               }
           }
       }

       // Print out any spare resources at the end
       if (! spareResources.isEmpty()) {
           xhtml.element("h2", "Un-Used Resources");
           xhtml.startElement("ul");
           for (Resource resource : spareResources) {
               String name = buildName("Resource", resource.getName(), resource.getID());
               xhtml.element("li", name);
           }
           xhtml.endElement("ul");
       }

       // Mark this as completed
       xhtml.endDocument();
    }
    
    protected static void handleTasks(List<Task> tasks, XHTMLContentHandler xhtml, 
            Set<Integer> usedResources) throws SAXException
    {
        xhtml.startElement("ol");
        for (Task task : tasks) {
            xhtml.startElement("li", "id", task.getID().toString());
            xhtml.startElement("div", "class", "task");

            // Name
            String name = buildName("Task", task.getName(), task.getID());
            xhtml.startElement("div", "class", "name");
            xhtml.element("b", name);
            xhtml.endElement("div");

            // Dates
            handleDates("Planned", task.getStart(), task.getFinish(), task.getDuration(), xhtml);
            handleDates("Actual", task.getActualStart(), task.getActualFinish(), task.getActualDuration(), xhtml);
            handleDates("Baseline", task.getBaselineStart(), task.getBaselineFinish(), task.getBaselineDuration(), xhtml);
            handleDates("Earliest", task.getEarlyStart(), task.getEarlyFinish(), null, xhtml);
            handleDates("Latest", task.getLateStart(), task.getLateFinish(), null, xhtml);

            // TODO Further information

            // Resources
            for (ResourceAssignment ra : task.getResourceAssignments()) {
                Resource resource = ra.getResource();
                if (resource != null) {
                    usedResources.add(resource.getID());

                    xhtml.startElement("div", "class", "resource");
                    xhtml.element("i", buildName("Resource", resource.getName(), resource.getID()));
                    xhtml.endElement("div");
                }
            }

            xhtml.endElement("div");

            // Do Child Tasks
            List<Task> childTasks = task.getChildTasks();
            if (childTasks != null && !childTasks.isEmpty()) {
                handleTasks(childTasks, xhtml, usedResources);
            }

            // Task complete
            xhtml.endElement("li");
        }
        xhtml.endElement("ol");
    }
    
    /**
     * Render a date range
     */
    protected static void handleDates(String what, Date start, Date finish,
            Duration duration, XHTMLContentHandler xhtml) throws SAXException {
        if (start == null && finish == null) {
            // Assume there's nothing there, and skip
            return;
        }

        String cls = what.toLowerCase() + "Dates";

        xhtml.startElement("div", "class", "fromTo " + cls);
        xhtml.characters(what);
        xhtml.characters(" from ");
        xhtml.characters(buildDate(start));
        xhtml.characters(" to ");
        xhtml.characters(buildDate(finish));

        if (duration != null) {
            // TODO Duration
        }

        xhtml.endElement("div");
    }

    protected static String buildName(String what, String name, Integer id) {
        if (name != null) {
            return name;
        }
        return "(" + what + " with ID " + id + ")";
    }
    protected static String buildDate(Date when) {
        if (when == null) {
            return "(unknown)";
        }
        return formatDate(when);
    }
}

@@ -1928,24 +1928,101 @@
 d resources%0A
+       // TODO Should we display all resources here instead, with notes etc?%0A
        Set%3CR
@@ -2068,24 +2068,24 @@
 esource%3E();%0A
-
        for (
@@ -3488,32 +3488,264 @@
 lement(%22div%22);%0A%0A
+            // Notes%0A            if (task.getNotes() != null) %7B%0A                xhtml.startElement(%22div%22, %22class%22, %22notes%22);%0A                xhtml.characters(task.getNotes());%0A                xhtml.endElement(%22div%22);%0A            %7D%0A%0A
             // D
@@ -4729,24 +4729,341 @@
 .getID()));%0A
+%0A                    // TODO What about Notes on the resource itself?%0A                    if (ra.getNotes() != null) %7B%0A                        xhtml.startElement(%22div%22, %22class%22, %22notes%22);%0A                        xhtml.characters(ra.getNotes());%0A                        xhtml.endElement(%22div%22);%0A                    %7D%0A%0A
             
@@ -6254,23 +6254,69 @@
 %22div%22);%0A
-
     %7D%0A%0A
+    // TODO Handler for Hyperlinks on things%0A%0A
     prot

Include notes, and add some TODOs for future things to cover