// $Id: genhtml.java,v 1.17 2005/04/07 18:34:15 mdean Exp $


public class genhtml
{
    static class Day
	implements Comparable
    {
	com.hp.hpl.mesa.rdf.jena.model.Resource day;
	java.util.Date start;
	
	Day(com.hp.hpl.mesa.rdf.jena.model.Model model,
	    com.hp.hpl.mesa.rdf.jena.model.Resource day)
	    throws Exception
	{
	    this.day = day;
	    start = org.exolab.castor.types.TimeInstant.parseRecurringDuration(itinerary2map.getValue(model, day, agenda_ont.start).toString()).toDate();
	    // adjust for org.exolab.castor.types.X.toDate localization
	    calendar.setTime(start);
	    start = new java.util.Date(start.getTime() - calendar.get(java.util.Calendar.ZONE_OFFSET) - calendar.get(java.util.Calendar.DST_OFFSET));
	}
	
	public int compareTo(Object object)
	{
	    return start.compareTo(((Day) object).start);
	}
    }

    static final java.util.Calendar calendar = java.util.Calendar.getInstance();
    static final java.text.DateFormat dateFormat = new java.text.SimpleDateFormat("EEEE, d MMMM yyyy");
    static final java.text.DateFormat timeFormat = new java.text.SimpleDateFormat("HHmm");
    static final java.text.DateFormat monthAndYearFormat = new java.text.SimpleDateFormat("MMMM yyyy");
    static final java.text.DateFormat dayAndMonthFormat = new java.text.SimpleDateFormat("d MMMM");
    static final java.text.DateFormat yearFormat = new java.text.SimpleDateFormat("yyyy");
    static final java.text.DateFormat dayMonthYearFormat = new java.text.SimpleDateFormat("d MMMM yyyy");

    static com.hp.hpl.jena.daml.DAMLProperty email = null;
    static com.hp.hpl.jena.daml.DAMLProperty homePage = null;
    static com.hp.hpl.jena.daml.DAMLProperty name = null;

    static String getOptionalLiteral(com.hp.hpl.mesa.rdf.jena.model.Model model,
				     com.hp.hpl.mesa.rdf.jena.model.Resource subject,
				     com.hp.hpl.mesa.rdf.jena.model.Property property)
	throws itinerary2map.BadCardinality,
	       Exception
    {
	String retval;
	com.hp.hpl.mesa.rdf.jena.model.NodeIterator nodeIterator = model.listObjectsOfProperty(subject, property);
	if (! nodeIterator.hasNext())
	    return null;
	retval = nodeIterator.next().toString();
	if (nodeIterator.hasNext())
	    throw new itinerary2map.BadCardinality(subject, property);
	nodeIterator.close();
	return retval;
    }

    static String getOptionalLiteral(com.hp.hpl.jena.daml.DAMLInstance instance,
				     com.hp.hpl.mesa.rdf.jena.model.Property property)
	throws Exception
    {
	// instance.getPropertyValue(property) doesn't use samePropertyAs

	java.util.Iterator iterator = instance.getAll(property, false);
	if (iterator.hasNext())
	    return iterator.next().toString();
	else
	    return null;
    }

    static String optionalLink(String text,
			       String href)
    {
	if (href == null)
	    return text;
	else
	    return "<a href=\"" + href + "\">" + text + "</a>";
    }

    static String indent(int depth)
    {
	String retval = "";
	for (int i = 0; i < depth; i++)
	    retval += "&nbsp;&nbsp;";
	return retval;
    }

    /**
     * return the total duration for the specified block hierarchy
     */
    static long blockDuration(com.hp.hpl.jena.daml.DAMLModel model,
			      com.hp.hpl.jena.daml.DAMLInstance block)
	throws Exception
    {
	long retval = 0;
	
	// iterate over items
	com.hp.hpl.jena.daml.DAMLList items = (com.hp.hpl.jena.daml.DAMLList) itinerary2map.getValue(model,
												     block,
												     agenda_ont.items);
	java.util.Iterator iterator = items.getAll();
	while (iterator.hasNext())
	    {
		com.hp.hpl.jena.daml.DAMLInstance item = (com.hp.hpl.jena.daml.DAMLInstance) iterator.next();
		String duration = getOptionalLiteral(model,
						     item,
						     agenda_ont.duration);
		if (duration == null)
		    {
			// assume it's a subblock
			retval += blockDuration(model,
						item);
		    }
		else
		    retval += org.exolab.castor.types.TimeDuration.parseTimeDuration(duration).toLong();
	    }

	return retval;
    }

    static void processItems(com.hp.hpl.jena.daml.DAMLModel model,
			     com.hp.hpl.jena.daml.DAMLList items,
			     java.util.Date time,
			     int depth)
	throws Exception
    {
	java.util.Iterator iterator = items.getAll();
	while (iterator.hasNext())
	    {
		com.hp.hpl.jena.daml.DAMLInstance item = (com.hp.hpl.jena.daml.DAMLInstance) iterator.next();
		com.hp.hpl.mesa.rdf.jena.model.Resource type = (com.hp.hpl.mesa.rdf.jena.model.Resource) itinerary2map.getValue(model,
																item,
																com.hp.hpl.mesa.rdf.jena.vocabulary.RDF.type);
		long duration = 0;
		try {
		    duration = org.exolab.castor.types.TimeDuration.parseTimeDuration(itinerary2map.getValue(model, item, agenda_ont.duration).toString()).toLong();
		} catch (Exception e) {
		    // XXX
		}
		java.util.Date endTime = new java.util.Date(time.getTime() + duration);
		String theme = getOptionalLiteral(model, item, agenda_ont.theme);

		if (item.hasRDFType(agenda_ont.Day))
		    {
			System.err.println("Day may not be nested");
		    }
		else if (item.hasRDFType(agenda_ont.Block))
		    {
			long thisBlockDuration = blockDuration(model,
							       item);
			java.util.Date blockEndTime = new java.util.Date(time.getTime() + thisBlockDuration);
			System.out.println("<tr>");
			System.out.println("  <td width=70>" + timeFormat.format(time) + "-" + timeFormat.format(blockEndTime) + "</td>");
			System.out.println("  <td colspan=2><i>" + indent(depth) + theme + "</i></td>");
			System.out.println("</tr>");
			processItems(model,
				     (com.hp.hpl.jena.daml.DAMLList) itinerary2map.getValue(model,
											    item,
											    agenda_ont.items),
				     time,
				     depth + 1);
			endTime = blockEndTime;
		    }
		else if (item.hasRDFType(agenda_ont.Talk))
		    {
			String title = itinerary2map.getValue(model,
							      item,
							      agenda_ont.title).toString();
			String uri = getOptionalLiteral(model,
							item,
							agenda_ont.uri);
			com.hp.hpl.jena.daml.DAMLInstance speaker = (com.hp.hpl.jena.daml.DAMLInstance) itinerary2map.getValue(model,
															       item,
															       agenda_ont.speaker);
			String speakerName = getOptionalLiteral(speaker,
								name);
			String speakerOrganization = getOptionalLiteral(speaker,
									agenda_ont.organization);
			String speakerLink = getOptionalLiteral(speaker,
								homePage);
			String speakerEmail = getOptionalLiteral(speaker,
								 email);
			if ((speakerLink == null)
			    && speakerEmail != null)
			    speakerLink = "mailto:" + speakerEmail;
			System.out.println("<tr>");
			System.out.println("  <td>" + timeFormat.format(time) + "-" + timeFormat.format(endTime) + "</td>");
			System.out.println("  <td>" + indent(depth) + optionalLink(title, uri) + "</td>");
			System.out.println("  <td>" + optionalLink(speakerName, speakerLink) + ", " + speakerOrganization + "</td>");
			System.out.println("</tr>");
		    }
		else if (item.hasRDFType(agenda_ont.Break))
		    {
			if (theme == null)
			    theme = "Break";
			System.out.println("<tr>");
			System.out.println("  <td>" + timeFormat.format(time) + "-" + timeFormat.format(endTime) + "</td>");
			System.out.println("  <td colspan=2>" + indent(depth) + theme + "</td>");
			System.out.println("</tr>");
		    }
		else
		    System.err.println("unexpected type " + type + " for item");
		
		time = endTime;
	    }
    }
    
    static void usage()
    {
	System.err.println("Usage:  uri");
	System.exit(1);
    }

    public static void main(String args[])
	throws Exception
    {
	// parse arguments
	if (args.length != 1)
	    usage();
	String uri = args[0];

	// strip form input prefix
	if (uri.startsWith("uri="))
	    uri = java.net.URLDecoder.decode(uri.substring(4));

	com.hp.hpl.jena.daml.DAMLModel model = new com.hp.hpl.jena.daml.common.DAMLModelImpl();
	model.setUseEquivalence(true);

	// load ontology
	model.read("file:agenda-ont.daml", "http://www.daml.org/2001/10/agenda/agenda-ont", null);
	// model.read("file:../researchers/researchers-ont.daml", "http://www.daml.org/researchers-ont", null); // XXX
	// model.read("file:../researchers/researchers.daml", "http://www.daml.org/researchers.daml", null); // XXX

	// load agenda
	model.read(uri, uri, null);

	// agenda_ont. properties don't have sameProperties
	email = model.createDAMLProperty("http://www.daml.org/2001/10/agenda/agenda-ont#email");
	name = model.createDAMLProperty("http://www.daml.org/2001/10/agenda/agenda-ont#name");
	homePage = model.createDAMLProperty("http://www.daml.org/2001/10/agenda/agenda-ont#homePage");

	com.hp.hpl.jena.daml.DAMLInstance meeting = null;
	// com.hp.hpl.mesa.rdf.jena.model.Resource meeting = null;
	java.util.Iterator iterator = model.listDAMLInstances();
	while (iterator.hasNext())
	    {
		com.hp.hpl.jena.daml.DAMLInstance instance = (com.hp.hpl.jena.daml.DAMLInstance) iterator.next();
		if (instance.hasRDFType(agenda_ont.Meeting))
		    {
			meeting = instance;
			break;
		    }
	    }
	if (meeting == null)
	    {
		com.hp.hpl.mesa.rdf.jena.model.ResIterator resources = model.listSubjectsWithProperty(com.hp.hpl.mesa.rdf.jena.vocabulary.RDF.type,
												      agenda_ont.Meeting);
		if (resources.hasNext())
		    meeting = (com.hp.hpl.jena.daml.DAMLInstance) resources.next();
	    }
	if (meeting == null)
	    {
		System.err.println("no " + agenda_ont.Meeting + " found");
		return;
	    }

	// get days
	java.util.TreeSet days = new java.util.TreeSet();
	// com.hp.hpl.mesa.rdf.jena.model.NodeIterator days = meeting.getPropertyValues(agenda_ont.day);
	com.hp.hpl.mesa.rdf.jena.model.NodeIterator dayNodes = model.listObjectsOfProperty(meeting,
											   agenda_ont.day);
	while (dayNodes.hasNext())
	    {
		days.add(new Day(model,
				 (com.hp.hpl.mesa.rdf.jena.model.Resource) dayNodes.next()));
	    }
	if (days.size() == 0)
	    {
		System.err.println("no " + agenda_ont.Day + " found");
		return;
	    }

	// heading
	String title = itinerary2map.getValue(model, meeting, agenda_ont.name).toString();
	String location = itinerary2map.getValue(model, meeting, agenda_ont.location).toString();
	System.out.println("<title>" + title + "</title>");
	System.out.println("<h1>" + title + "</h1>");

	// date range
	java.util.Date firstDate = ((Day) days.first()).start;
	java.util.Date lastDate = ((Day) days.last()).start;
	java.util.Calendar first = java.util.Calendar.getInstance();
	java.util.Calendar last = java.util.Calendar.getInstance();
	first.setTime(firstDate);
	last.setTime(lastDate);
	
	if (days.size() == 1)
	    {
		System.out.println(dayMonthYearFormat.format(firstDate));
	    }
	else if ((first.get(java.util.Calendar.MONTH) == last.get(java.util.Calendar.MONTH))
		 && (first.get(java.util.Calendar.YEAR) == last.get(java.util.Calendar.YEAR)))
	    {
		System.out.println(first.get(java.util.Calendar.DATE) + " - " + last.get(java.util.Calendar.DATE) + " " + monthAndYearFormat.format(firstDate));
	    }
	else if (first.get(java.util.Calendar.YEAR) == last.get(java.util.Calendar.YEAR))
	    {
		System.out.println(dayAndMonthFormat.format(firstDate) + " - " + dayAndMonthFormat.format(lastDate) + " " + yearFormat.format(firstDate));
	    }
	else
	    {
		System.out.println(dayMonthYearFormat.format(firstDate) + " - " + dayMonthYearFormat.format(lastDate));
	    }

	// location
	System.out.println("<br>");
	System.out.println(location);

	System.out.println("<table border='0'>");

	java.util.Iterator daysIterator = days.iterator();
	while (daysIterator.hasNext())
	    {
		// com.hp.hpl.jena.daml.DAMLInstance day = (com.hp.hpl.jena.daml.DAMLInstance) daysIterator.next();
		Day day = (Day) daysIterator.next();
		// print date
		System.out.println("<tr>");
		System.out.println("  <td colspan=3><br><b>" + dateFormat.format(day.start) + "</b></td>");
		System.out.println("</tr>");

		// iterate over daml:List
		processItems(model,
			     (com.hp.hpl.jena.daml.DAMLList) itinerary2map.getValue(model,
										    day.day,
										    agenda_ont.items),
			     day.start,
			     0);
	    }

	System.out.println("</table>");
	System.out.println("<p>");
	System.out.println("<hr>");
	System.out.println("<address>generated from <a href=\"" + uri + "\">" + uri + "</a> on " + new java.util.Date() + " using <a href='http://www.daml.org/2001/10/agenda/'>DAML Agenda</a></address>");
    }
}
