// $Id: dumpont.java,v 1.20 2003/05/01 05:57:44 mdean Exp $


/**
 * print class and property hierarchies from an ontology.
 */
class dumpont
{
    static boolean html = true;
    static String hyperdaml = "http://www.daml.org/cgi-bin/hyperdaml";
    static boolean verbose = false;

    static java.util.Stack stack = new java.util.Stack();

    static java.util.Comparator comparator = new java.util.Comparator()
    {
	public int compare(Object o1, Object o2)
	{
	    return o1.toString().compareTo(o2.toString());
	}
	
	public boolean equals(Object comparator)
	{
	    return false;
	}
	};
    

    /**
     * information about a DAML Class
     */
    static class Class
    {
	static java.util.TreeMap classes = new java.util.TreeMap(comparator);
	NodeCenteredView.Node node;
	java.util.Vector subclasses = new java.util.Vector();
	java.util.Vector superclasses = new java.util.Vector();
	java.util.TreeSet properties = new java.util.TreeSet();
	java.util.TreeMap instances = new java.util.TreeMap(comparator);

	Class(NodeCenteredView.Node node)
	{
	    this.node = node;
	    classes.put(node, this);
	}

	void print(int depth)
	{
	    String classFragment = fragment(node);

	    if (html)
		{
		    System.out.println("<li>");
		    System.out.println("<a name=" + quoted(classFragment) + ">");
		}
	    else
		for (int i = 0; i < depth; i++)
		    System.out.println("  ");
	    System.out.print("<a href=" + quoted(hyperdaml + "?" + node) + ">" + classFragment + "</a>");

	    // check for cycles
	    if (stack.contains(this))
		{
		    System.out.println(" ... cycle ...");
		    return;
		}
	    stack.push(this);

	    // properties
	    System.out.print(" (");
	    java.util.Iterator iterator = properties.iterator();
	    boolean first = true;
	    while (iterator.hasNext())
		{
		    Object property = iterator.next();
		    if (! first)
			System.out.print(", ");
		    first = false;
		    if (html)
			{
			    String fragment = fragment(property);
			    System.out.print("<a href=" + quoted("#" + fragment) + ">" + fragment + "</a>");
			}
		    else
			System.out.print(property);
			
		}
	    System.out.println(")");

	    // recurse
	    iterator = subclasses.iterator();
	    java.util.Iterator instanceIterator = instances.values().iterator();
	    if (iterator.hasNext() 
		|| instanceIterator.hasNext()) 
		{
		    if (html)
			System.out.println("<ul>");
		    while (iterator.hasNext())
			{
			    Class child = (Class) iterator.next();
			    child.print(depth + 1);
			}
		    while (instanceIterator.hasNext())
			{
			    String instanceFragment = fragment(instanceIterator.next());
			    if (html)
				{
				    System.out.println("<li>");
				    System.out.println("<a name=" + quoted(instanceFragment) + ">");
				}
			    else
				for (int i = 0; i < depth; i++)
				    System.out.println("  ");
			    System.out.println("instance " + instanceFragment);
			}
		    if (html)
			System.out.println("</ul>");
		}

	    stack.pop();
	}
    }

    /**
     * information about a DAML Property
     */
    static class Property
    {
	static java.util.TreeMap properties = new java.util.TreeMap(comparator);
	NodeCenteredView.Node node;
	java.util.Vector subproperties = new java.util.Vector();
	java.util.Vector superproperties = new java.util.Vector();

	Property(NodeCenteredView.Node node)
	{
	    this.node = node;
	    properties.put(node, this);
	}

	void print(int depth)
	{
	    String propertyFragment = fragment(node);

	    if (html)
		{
		    System.out.println("<li>");
		    System.out.println("<a name=" + quoted(propertyFragment) + ">");
		}
	    else
		for (int i = 0; i < depth; i++)
		    System.out.println("  ");
	    System.out.print("<a href=" + quoted(hyperdaml + "?" + node) + ">" + propertyFragment + "</a>");

	    // check for cycles
	    if (stack.contains(this))
		{
		    System.out.println(" ... cycle ...");
		    return;
		}
	    stack.push(this);

	    System.out.println();

	    // recurse
	    java.util.Iterator iterator = subproperties.iterator();
	    if (iterator.hasNext()) 
		{
		    if (html)
			System.out.println("<ul>");
		    while (iterator.hasNext())
			{
			    Property child = (Property) iterator.next();
			    child.print(depth + 1);
			}
		    if (html)
			System.out.println("</ul>");
		}

	    stack.pop();
	}
    }

    static NodeCenteredView ncv;

    static String quoted(String string)
    {
	return '"' + string + '"';
    }

    static String fragment(Object object)
    {
	String uri = object.toString();
	int pound = uri.lastIndexOf('#');
	return (pound == (-1)) ? uri : uri.substring(pound + 1);
    }

    static void printHeader(String header)
    {
	if (html)
	    System.out.print("<h2>");
	System.out.print(header);
	if (html)
	    System.out.print("</h2>");
	System.out.println();
    }

    static void warn(String warning)
    {
	if (verbose)
	    System.err.println(warning);
    }

    static void usage()
    {
	System.err.println("Usage:  [-verbose] [-hyperdaml uri] <daml-uri>");
	System.exit(1);
    }

    public static void main(String args[])
	throws Exception
    {
	// parse arguments
	String daml = null;
	for (int i = 0; i < args.length; i++)
	    {
		String arg = args[i];

		if (arg.charAt(0) == '-')
		    {
			if (arg.equals("-verbose"))
			    verbose = true;
			else if (arg.equals("-hyperdaml"))
			    {
				if ((i+1) > args.length)
				    usage();
				hyperdaml = args[++i];
			    }
			else
			    usage();
		    }
		else
		    daml = arg;
	    }
	if (daml == null)
	    usage();

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

	// load DAML
	org.w3c.rdf.util.RDFFactory factory = new org.w3c.rdf.util.RDFFactoryImpl();
	org.w3c.rdf.model.Model model = factory.createModel();
	org.w3c.rdf.util.RDFUtil.parse(daml, factory.createParser(), model);
	ncv = new NodeCenteredView(model);

	// collect Class hierarchy
	java.util.Vector classNodes = ncv.allInstances("Class");
	java.util.Iterator iterator = classNodes.iterator();
	while (iterator.hasNext())
	    {
		NodeCenteredView.Node node = (NodeCenteredView.Node) iterator.next();
		new Class(node);
	    }
	java.util.Collection sortedClasses = Class.classes.values();

	// assign sub/superclasses
	iterator = sortedClasses.iterator();
	while (iterator.hasNext())
	    {
		Class child = (Class) iterator.next();
		java.util.Vector subclasses = child.node.findAll(">subClassOf");
		java.util.Iterator parentIterator = subclasses.iterator();
		while (parentIterator.hasNext())
		    {
			NodeCenteredView.Node parentNode = (NodeCenteredView.Node) parentIterator.next();
			Class parent = (Class) Class.classes.get(parentNode);
			if (parent == null)
			    warn("unknown superclass " + parentNode);
			else
			    {
				parent.subclasses.add(child);
				child.superclasses.add(parent);
			    }
		    }
	    }

	// collect properties
	java.util.Vector propertyNodes = ncv.allInstances("Property");
	propertyNodes.addAll(ncv.allInstances("DatatypeProperty"));
	propertyNodes.addAll(ncv.allInstances("ObjectProperty"));
	propertyNodes.addAll(ncv.allInstances("TransitiveProperty"));
	propertyNodes.addAll(ncv.allInstances("SymmetricProperty"));
	propertyNodes.addAll(ncv.allInstances("UnambiguousProperty"));
	propertyNodes.addAll(ncv.allInstances("UniqueProperty"));
	propertyNodes.addAll(ncv.allInstances("FunctionalProperty"));
	propertyNodes.addAll(ncv.allInstances("InverseFunctionalProperty"));
	iterator = propertyNodes.iterator();
	while (iterator.hasNext())
	    {
		NodeCenteredView.Node node = (NodeCenteredView.Node) iterator.next();
		new Property(node);
	    }
	java.util.Collection sortedProperties = Property.properties.values();

	// assign sub/superproperties
	iterator = sortedProperties.iterator();
	while (iterator.hasNext())
	    {
		Property child = (Property) iterator.next();
		java.util.Vector subproperties = child.node.findAll(">subPropertyOf");
		java.util.Iterator parentIterator = subproperties.iterator();
		while (parentIterator.hasNext())
		    {
			NodeCenteredView.Node parentNode = (NodeCenteredView.Node) parentIterator.next();
			Property parent = (Property) Property.properties.get(parentNode);
			if (parent == null)
			    warn("unknown superproperty " + parentNode);
			else
			    {
				parent.subproperties.add(child);
				child.superproperties.add(parent);
			    }
		    }
	    }

	// assign properties based on domain
	iterator = propertyNodes.iterator();
	while (iterator.hasNext())
	    {
		NodeCenteredView.Node property = (NodeCenteredView.Node) iterator.next();
		java.util.Vector domains = property.findAll(">domain");
		java.util.Iterator domainIterator = domains.iterator();
		while (domainIterator.hasNext())
		    {
			Object domain = domainIterator.next();
			Class cl = (Class) Class.classes.get(domain);
			if (cl == null)
			    warn("unknown domain class " + domain);
			else
			    cl.properties.add(property);
		    }
	    }

	// assign properties based on restrictions
	iterator = sortedClasses.iterator();
	while (iterator.hasNext())
	    {
		Class cl = (Class) iterator.next();

		cl.properties.addAll((java.util.Vector) cl.node.findAll(">subClassOf>onProperty"));
		cl.properties.addAll((java.util.Vector) cl.node.findAll(">restrictedBy>onProperty"));
	    }

	// assign instances to their types
	iterator = ncv.nodes.values().iterator();
	while (iterator.hasNext())
	    {
		NodeCenteredView.Node node = (NodeCenteredView.Node) iterator.next();
		java.util.Vector types = node.findAll(">type");
		java.util.Iterator typeIterator = types.iterator();
		while (typeIterator.hasNext())
		    {
			NodeCenteredView.Node typeNode = (NodeCenteredView.Node) typeIterator.next();
			String type = typeNode.toString();
			if ((type.endsWith("#Class"))
			    || (type.endsWith("#Property"))
			    || (type.endsWith("#DatatypeProperty"))
			    || (type.endsWith("#ObjectProperty"))
			    || (type.endsWith("#TransitiveProperty"))
			    || (type.endsWith("#SymmetricProperty"))
			    || (type.endsWith("#UnambiguousProperty"))
			    || (type.endsWith("#UniqueProperty"))
			    || (type.endsWith("#FunctionalProperty"))
			    || (type.endsWith("#InverseFunctionalProperty"))
			    || (type.endsWith("#Ontology"))
			    || (type.endsWith("#Restriction")))
			    {
				// nothing
			    }
			else
			    {
				Class cl = (Class) Class.classes.get(typeNode);
				if (cl == null)
                                    warn("unknown type class " + typeNode);
				else
				    cl.instances.put(node, node);
			    }
		    }
	    }

	// print Classes
	iterator = sortedClasses.iterator();
	printHeader("Class Hierarchy");
	if (html)
	    {
		System.out.println("<ul>");
	    }
	while (iterator.hasNext())
	    {
		Class cl = (Class) iterator.next();
		if (cl.superclasses.size() == 0) // root
		    cl.print(1);
	    }
	if (html)
	    System.out.println("</ul>");

	// print Properties
	iterator = sortedProperties.iterator();
	printHeader("Property Hierarchy");
	if (html)
	    {
		System.out.println("<ul>");
	    }
	while (iterator.hasNext())
	    {
		Property property = (Property) iterator.next();
		if (property.superproperties.size() == 0) // root
		    property.print(1);
	    }
	if (html)
	    System.out.println("</ul>");
    }
}
