// $Id: NodeCenteredView.java,v 1.7 2001/04/26 04:01:04 mdean Exp $


class NodeCenteredView
{
    static org.w3c.rdf.util.RDFFactory factory = new org.w3c.rdf.util.RDFFactoryImpl();
    org.w3c.rdf.model.Model model;
    
    class Node
	implements java.lang.Comparable
    {
	org.w3c.rdf.model.Resource resource;
	org.w3c.rdf.model.Model incoming = factory.createModel();
	org.w3c.rdf.model.Model outgoing = factory.createModel();

	Node(org.w3c.rdf.model.Resource resource)
	{
	    this.resource = resource;
	}

	public int compareTo(Object object)
	{
	    return resource.toString().compareTo(((Node) object).resource.toString());
	}

	private org.w3c.rdf.model.Statement findAnyStatement(org.w3c.rdf.model.Model model,
							     String predicate)
	    throws Exception
	{
	    String match = "#" + predicate;

	    for (java.util.Enumeration en = model.elements(); en.hasMoreElements();)
		{
		    org.w3c.rdf.model.Statement statement = (org.w3c.rdf.model.Statement) en.nextElement();
		    String thisPredicate = statement.predicate().toString();
		    if (thisPredicate.endsWith(match))
			return statement;
		}

	    return null;
	}

	/**
	 * returns a single Value (a NodeCenteredView.Node or a String)
	 * based on the specified path expression.  If no such path is 
	 * found, null is returned.
	 */
	Object findAny(String path)
	    throws Exception
	{
	    Object retval = null;
	    org.w3c.rdf.model.Statement statement;

	    // parse path
	    int end;
	    for (end = 1; end < path.length(); end++)
		{
		    if ((path.charAt(end) == '<')
			|| (path.charAt(end) == '>'))
			break;
		}
	    String predicate = path.substring(1, end);

	    if (path.charAt(0) == '<')
		{
		    statement = findAnyStatement(incoming,
						 predicate);
		    if (statement != null)
			retval = statement.subject();
		}
	    else if (path.charAt(0) == '>')
		{
		    statement = findAnyStatement(outgoing,
						 predicate);
		    if (statement != null)
			retval = statement.object();
		}

	    // convert
	    if (retval instanceof org.w3c.rdf.model.Resource)
		retval = getNode((org.w3c.rdf.model.Resource) retval);
	    else if (retval instanceof org.w3c.rdf.model.Literal)
		retval = retval.toString();

	    // process any continuation
	    if ((retval != null) 
		&& (end < path.length()))
		{
		    retval = ((Node) retval).findAny(path.substring(end));
		}
	    
	    return retval;
	}

	private void findAllInternal(String path,
				     java.util.Vector retval)
	    throws org.w3c.rdf.model.ModelException
	{
	    // parse path
	    int end;
	    for (end = 1; end < path.length(); end++)
		{
		    if ((path.charAt(end) == '<')
			|| (path.charAt(end) == '>'))
			break;
		}
	    String predicate = path.substring(1, end);
	    String match = "#" + predicate;

	    org.w3c.rdf.model.Model model = (path.charAt(0) == '<') ? incoming : outgoing;
	    for (java.util.Enumeration en = model.elements(); en.hasMoreElements();)
		{
		    org.w3c.rdf.model.Statement statement = (org.w3c.rdf.model.Statement) en.nextElement();
		    String thisPredicate = statement.predicate().toString();
		    if (thisPredicate.endsWith(match))
			{
			    Object value = (path.charAt(0) == '<') ? statement.subject() : statement.object();
			    
			    // convert
			    if (value instanceof org.w3c.rdf.model.Resource)
				value = getNode((org.w3c.rdf.model.Resource) value);
			    else if (value instanceof org.w3c.rdf.model.Literal)
				value = value.toString();

			    // process any continuation
			    if (end < path.length())
				{
				    ((Node) value).findAllInternal(path.substring(end),
								   retval);
				}
			    else
				{
				    retval.add(value);
				}
			}
		}
	}

	/**
	 * returns a (possibly empty) Vector of
	 * NodeCenteredView.Node or String
	 * based on the specified path expression.
	 */
	java.util.Vector findAll(String path)
	    throws Exception
	{
	    java.util.Vector retval = new java.util.Vector();
	    findAllInternal(path,
			    retval);
	    return retval;
	}

	public String toString()
	{
	    return resource.toString();
	}
    }

    /**
     * map from org.w3c.rdf.model.Resource to Node
     */
    java.util.Hashtable nodes = new java.util.Hashtable();
	
    Node getNode(org.w3c.rdf.model.Resource resource,
		 boolean create)
    {
	Node retval = (Node) nodes.get(resource);
	if ((retval == null) && create)
	    {
		retval = new Node(resource);
		nodes.put(resource, retval);
	    }
	return retval;
    }

    Node getNode(org.w3c.rdf.model.Resource resource)
    {
	return getNode(resource, false);
    }

    NodeCenteredView(org.w3c.rdf.model.Model model)
	throws org.w3c.rdf.model.ModelException
    {
	this.model = model;

	for (java.util.Enumeration en = model.elements(); en.hasMoreElements();)
	    {
		org.w3c.rdf.model.Statement statement = (org.w3c.rdf.model.Statement) en.nextElement();
		org.w3c.rdf.model.Resource subject = statement.subject();
		org.w3c.rdf.model.RDFNode object = statement.object();
		
		Node subjectNode = getNode(subject, true);
		subjectNode.outgoing.add(statement);

		if (object instanceof org.w3c.rdf.model.Resource)
		    {
			Node objectNode = getNode((org.w3c.rdf.model.Resource) object, true);
			objectNode.incoming.add(statement);
		    }
	    }
    }

    /**
     * return all instances of the specified class.
     */
    java.util.Vector allInstances(String cl)
	throws Exception
    {
	java.util.Vector retval = new java.util.Vector();

	cl = "#" + cl;

	for (java.util.Enumeration en = model.elements(); en.hasMoreElements();)
	    {
		org.w3c.rdf.model.Statement statement = (org.w3c.rdf.model.Statement) en.nextElement();
		if (statement.predicate().equals(org.w3c.rdf.vocabulary.rdf_syntax_19990222.RDF.type))
		    {
			if (statement.object().getLabel().endsWith(cl))
			    retval.add(nodes.get(statement.subject()));
		    }
	    }

	return retval;
    }
}



