/* This software was developed within the context of the project Metaphor for Science
   Museums (Mesmuses) in the framework of the Information Society Technology
   Programme, part of the Fifth Research And Technological Development
	Framework Programme of the European Community, under the Consortium
   Agreement dated <June 30, 2001>, between INRIA, Finsiel Spa, IMSS,
   Valoris , CSI, ICS-FORTH, ENSTB, EDW International.
*/

package gr.forth.ics.vrp.visualization;

import java.io.*;
import java.awt.*;
import java.util.*;
import gr.forth.ics.vrp.corevrp.broker.*;
import gr.forth.ics.vrp.corevrp.model.*;
import gr.forth.ics.vrp.corevrp.vocabulary.*;

/**
 *
 * @author Ta Tuan Anh
 * @version 2.5  (30 Januar 2003)
 */

public class SVGGenerator extends RDF_Visualization {

	public static int SVGWidth = 0;
	public static int SVGHeight = 0;
	public static final int MinClassRx = 50;
	public static final int ClassRy = 14;
	public static final int MinResourceWidth = 150;
	public static final int ResourceHeight = 25;
	public static final int MinFocusClassWidth = 150;
	public static final int MinFocusResourceWidth = 200;
	public static final int MinTreeWindowWidth = 150;
	public static int MaxTreeWindowWidth;
	public static int TreeWindowWidth;
	public static int TreeViewWidth;
	public static int TreeWindowHeight;
	public static int TreeViewHeight;
	public static int DesktopWindowWidth;
	public static int DesktopViewWidth;
	public static int DesktopWindowHeight;
	public static int DesktopViewHeight;

	public static final String ClassColor = "cyan";
	public static final String ResourceColor = "lime";
	public static final String PropertyColor = "royalblue";
	public static final String MetaColor = "springgreen";

	public static final String NoneTransitiveProperty = "mediumblue";
	public static final String TransitiveProperty = "magenta";

	public static final String NoneTransitiveClass = "slateblue";
	public static final String TransitiveClass = "hotpink";

	public static final String NoneTransitiveResource = "seagreen";
	public static final String TransitiveResource = "coral";

	ArrayList classList;
	ArrayList resourceList;
	ArrayList propertyList;

	private int path_counter; // variable for a counter of path

	public SVGGenerator(RDF_SemanticBroker broker)
	{
		super(broker);
		if (SVGWidth==0&&SVGHeight==0) setSVGSize(800, 600);
		classList = new ArrayList(broker.getAllClasses(true));
		if (classList.contains(rdfschema.Literal)) {
			System.out.println("CONTAINS");
		}  else {
			System.out.println("NOT CONTAINS");
		}
		resourceList = new ArrayList(broker.getAllResources(true));
		propertyList = new ArrayList(broker.getAllProperties(true));
	}

	public static void setSVGSize(int w, int h)
	{
		SVGWidth = w;
		if (SVGWidth < 600) SVGWidth = 600;
		SVGHeight = h;
		if (SVGHeight < 480) SVGHeight = 480;
		MaxTreeWindowWidth = SVGWidth/4;
		TreeWindowHeight = SVGHeight-30;
		TreeViewHeight = TreeWindowHeight-35;
		DesktopWindowHeight = SVGHeight-30;
		DesktopViewHeight = DesktopWindowHeight-10;
	}

	public static void setTreeWindowWidth(int w)
	{
		TreeWindowWidth = w;
		if (TreeWindowWidth > MaxTreeWindowWidth) TreeWindowWidth = MaxTreeWindowWidth;
		if (TreeWindowWidth < MinTreeWindowWidth) TreeWindowWidth = MinTreeWindowWidth;
		DesktopWindowWidth = SVGWidth - TreeWindowWidth;
		TreeViewWidth = TreeWindowWidth - 10;
		DesktopViewWidth = DesktopWindowWidth-10;
	}

	public void generate() throws IOException
	{
		path_counter = 1;
		println("<?xml version='1.0'?>");
		println("   <!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'");
        println("       'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>");
		println("<svg width='"+SVGWidth+"' height='"+SVGHeight+"' desktopview='none'>");
		printScripts();
		printTemplates();
		printTitleWindow();
		printTreeWindow();
		printDesktopWindow();
		println("</svg>");
	}

	private void printScripts() throws IOException
	{
		println("<!-- ECMAScript for SVG visualization -->");
		println("<script type='text/ecmascript'><![CDATA[");

		println("	function scroll(myview, dx, dy) {");
		println("		var box = myview.getAttribute('viewBox');");
		println("		var values = box.split(' ');");
		println("		var x = values[0];");
		println("		var y = values[1];");
		println("		var w = values[2];");
		println("		var h = values[3];");
		println("		var nx = eval(x+dx);");
		println("		if (eval(nx) < 0) nx = '0';");
		println("		var ny = eval(y+dy);");
		println("		if (eval(ny) < 0) ny = '0';");
		println("		if (nx!=x||ny!=y)");
		println("			myview.setAttribute('viewBox', nx+' '+ny+' '+w+' '+h);");
		println("	}");

		println("	function scrollto(myview, nx, ny) {");
		println("		var box = myview.getAttribute('viewBox');");
		println("		var values = box.split(' ');");
		println("		var x = values[0];");
		println("		var y = values[1];");
		println("		var w = values[2];");
		println("		var h = values[3];");
		println("		if (nx!=x||ny!=y)");
		println("			myview.setAttribute('viewBox', nx+' '+ny+' '+w+' '+h);");
		println("	}");

		println("	function scroll_desktop(evt) {");
		println("		var c = evt.target;");
		println("		var svgdoc = c.getOwnerDocument();");
		println("		var viewname=svgdoc.rootElement.getAttribute('desktopview');");
		println("		if (viewname!='none') {");
		println("			var desktopview = getView(svgdoc, viewname);");
		println("			var button=evt.target.getAttribute('xlink:href');");
		println("			if (button=='#up')");
		println("				scroll(desktopview, '+0', '-300');");
		println("			else if (button=='#down')");
		println("				scroll(desktopview, '+0', '+300');");
		println("			else if (button=='#left')");
		println("				scroll(desktopview, '-200', '+0');");
		println("			else if (button=='#right')");
		println("				scroll(desktopview, '+200', '+0');");
		println("			else if (button=='#coin')");
		println("				scrollto(desktopview, '0', '0');");
		println("		}");
		println("	}");

		println("	function scroll_tree(evt) {");
		println("		var c = evt.target;");
		println("		var svgdoc = c.getOwnerDocument();");
		println("		var treeview = getTreeView(svgdoc, 'ClassTree');");
		println("		if (treeview.getAttribute('display')=='none')");
		println("			treeview = getTreeView(svgdoc, 'PropertyTree');");
		println("		var button=evt.target.getAttribute('xlink:href');");
		println("		if (button=='#up')");
		println("			scroll(treeview, '+0', '-100');");
		println("		else if (button=='#down')");
		println("			scroll(treeview, '+0', '+100');");
		println("		else if (button=='#left')");
		println("			scroll(treeview, '-50', '+0');");
		println("		else if (button=='#right')");
		println("			scroll(treeview, '+50', '+0');");
		println("		else if (button=='#coin')");
		println("			scrollto(treeview, '0', '0');");
		println("	}");

		println("	function getTreeView(svgdoc, viewname) {");
		println("		var win;");
		println("		for (win=svgdoc.rootElement.firstChild; ;win=win.nextSibling) {");
		println("			if (win.tagName=='svg')");
		println("				if (win.getAttribute('id')=='TreeWindow') break;");
		println("		}");
		println("		var viewtag;");
		println("		for (viewtag = win.firstChild; ;viewtag = viewtag.nextSibling) {");
		println("			if (viewtag.tagName=='svg')");
		println("				if (viewtag.getAttribute('id')==viewname) break;");
		println("		}");
		println("		return viewtag;");
		println("	}");

		println("   function tree_view(evt) {");
		println("   	var c = evt.target;");
		println("		var svgdoc = c.getOwnerDocument();");
		println("		var link = c.getAttribute('xlink:href');");
		println("		var str = link.substring(1, link.length)+'Tree';");
		println("		var treeview = getTreeView(svgdoc, str);");
		println("		if (treeview.getAttribute('display')=='none') {");
		println("			var other;");
		println("			if (str=='ClassTree') other='PropertyTree';");
		println("			else other='ClassTree';");
		println("			getTreeView(svgdoc, other).setAttribute('display', 'none');");
		println("			treeview.setAttribute('display', 'inline');");
		println("		}");
		println("    }");

		println("	function getView(svgdoc, viewname) {");
		println("		var desktopwin;");
		println("		for (desktopwin=svgdoc.rootElement.firstChild; ;desktopwin=desktopwin.nextSibling) {");
		println("			if (desktopwin.tagName=='svg')");
		println("				if (desktopwin.getAttribute('id')=='DesktopWindow') break;");
		println("		}");
		println("		var viewtag;");
		println("		for (viewtag = desktopwin.firstChild; ;viewtag = viewtag.nextSibling) {");
		println("			if (viewtag.tagName=='svg')");
		println("				if (viewtag.getAttribute('id')==viewname) break;");
		println("		}");
		println("		return viewtag;");
		println("	}");

		println("   function view_click(evt) {");
		println("   	var c = evt.target;");
		println("		var svgdoc = c.getOwnerDocument();");
		println("		var viewname=svgdoc.rootElement.getAttribute('desktopview');");
		println("		if (viewname!='none') {");
		println("			getView(svgdoc, viewname).setAttribute('display', 'none');");
		println("		}");
		println("		var link = c.getAttribute('xlink:href');");
		println("		var str = 'view:'+link.substring(1, link.length);");
		println("		getView(svgdoc, str).setAttribute('display', 'inline');");
		println("		svgdoc.rootElement.setAttribute('desktopview', str);");
		println("    }");

		println("   function view2_click(evt) {");
		println("   	var c = evt.target;");
		println("		var svgdoc = c.getOwnerDocument();");
		println("		var viewname=svgdoc.rootElement.getAttribute('desktopview');");
		println("		if (viewname!='none') {");
		println("			getView(svgdoc, viewname).setAttribute('display', 'none');");
		println("		}");
		println("		var link = c.getAttribute('xlink:href');");
		println("		var str = 'view:'+link.substring(2, link.length);");
		println("		getView(svgdoc, str).setAttribute('display', 'inline');");
		println("		svgdoc.rootElement.setAttribute('desktopview', str);");
		println("    }");

		println("   function view3_click(evt) {");
		println("   	var c = evt.target;");
		println("		var svgdoc = c.getOwnerDocument();");
		println("		var viewname=svgdoc.rootElement.getAttribute('desktopview');");
		println("		if (viewname!='none') {");
		println("			getView(svgdoc, viewname).setAttribute('display', 'none');");
		println("		}");
		println("		link = c.getAttribute('viewID');");
		println("		getView(svgdoc, link).setAttribute('display', 'inline');");
		println("		svgdoc.rootElement.setAttribute('desktopview', link);");
		println("    }");

		println("	function open_tree(node) {");
		println("		if (node.getAttribute('state')=='close') {");
		println("		 	node.setAttribute('state', 'open');");
		println("			var y=0;");
		println("	  		for (var subnode=node.firstChild; ; subnode=subnode.nextSibling) {");
		println("	  			if (subnode.tagName=='g') {");
		println("					subnode.setAttribute('visibility', 'visible');");
		println("					y=y+15;");
		println("					subnode.setAttribute('transform', 'translate(10,'+y+')');");
		println("				}");
		println("				if (subnode==node.lastChild) break;");
		println("	  		}");
		println("			node.setAttribute('style','fill:red');");
		println("		}");
		println("	}");

		println("	function close_tree(node) {");
		println("		if (node.getAttribute('state')=='open') {");
		println("		 	node.setAttribute('state', 'close');");
		println("	  		for (var subnode=node.firstChild; ; subnode=subnode.nextSibling) {");
		println("	  			if (subnode.tagName=='g') {");
		println("					subnode.setAttribute('visibility', 'hidden');");
		println("					close_tree(subnode);");
		println("				}");
		println("				if (subnode==node.lastChild) break;");
		println("	  		}");
		println("			node.setAttribute('style','fill:green');");
		println("		}");
		println("	}");

		println("	function height_tree(node) {");
		println("		var y=15;");
		println("		if (node.getAttribute('state')=='open') {");
		println("	  		for (var subnode=node.firstChild; ; subnode=subnode.nextSibling) {");
		println("		  		if (subnode.tagName=='g') y=y+height_tree(subnode);");
		println("				if (subnode==node.lastChild) break;");
		println("			}");
		println("	  	}");
		println("		return y;");
		println("	}");

		println("	function arrange_tree(node) {");
		println("		var y = 15;");
		println("	  	for (var subnode=node.firstChild; ; subnode=subnode.nextSibling) {");
		println("	  		if (subnode.tagName=='g') {");
		println("	  			subnode.setAttribute('transform', 'translate(10,'+y+')');");
		println("				y=y+height_tree(subnode);");
		println("			}");
		println("			if (subnode==node.lastChild) break;");
		println("	  	}");
		println("		if (node.parentNode.tagName=='g') arrange_tree(node.parentNode);");
		println("	}");

		println("	function tree_click(evt) {");
		println("		var c = evt.target;");
		println("		var node=c.parentNode;");
		println("		if (node.getAttribute('state')=='open') {");
		println("			close_tree(node);");
		println("			arrange_tree(node.parentNode);");
		println("		}else");
		println("			if (node.getAttribute('state')=='close') {");
		println("				open_tree(node);");
		println("				arrange_tree(node.parentNode);");
		println("			}");
		println("	}");

		println("]]></script>");

	}
	private void printTemplates() throws IOException
	{
		println("<!-- Visualization templates -->");
		println("<defs>");

		println("	<filter id='Bevel' filterUnits='objectBoundingBox' x='-10%' y='-10%' ");
		println("			width='150%' height='150%'>");
		println("		<feGaussianBlur in='SourceAlpha' stdDeviation='3' result='blur'/>");
		println("		<feSpecularLighting in='blur' surfaceScale='5' specularConstant='0.5'");
		println("			specularExponent='10' result='specOut'");
		println("		 	style='lighting-color:white'>");
		println("			<fePointLight x='-5000' y='-10000' z='20000'/>");
		println("		</feSpecularLighting>");
		println("		<feComposite in='specOut' in2='SourceAlpha' operator='in' result='specOut2'/>");
		println("		<feComposite in='SourceGraphic' in2='specOut2' operator='arithmetic' k1='0'");
		println("			k2='1' k3='1' k4='0' result='litPaint'/>");
		println("	</filter>");

		println("	<marker id='marker:Triangle' viewBox='0 0 10 10' refX='10' refY='5'");
		println("		markerUnits='strokeWidth' markerWidth='6' markerHeight='4' orient='auto'>");
		println("		<path d='M0 0 L10 5 L0 10 z'/>");
		println("	</marker>");
		println("	<marker id='marker:Triangle-"+NoneTransitiveProperty+"' viewBox='0 0 10 10' refX='10' refY='5'");
		println("		markerUnits='strokeWidth' markerWidth='6' markerHeight='4' orient='auto'>");
		println("		<path d='M0 0 L10 5 L0 10' style='fill:none;stroke:"+NoneTransitiveProperty+"'/>");
		println("	</marker>");
		println("	<marker id='marker:Triangle-"+TransitiveProperty+"' viewBox='0 0 10 10' refX='10' refY='5'");
		println("		markerUnits='strokeWidth' markerWidth='6' markerHeight='4' orient='auto'>");
		println("		<path d='M0 0 L10 5 L0 10' style='fill:none;stroke:"+TransitiveProperty+"'/>");
		println("	</marker>");
		println("	<marker id='marker:Triangle-"+PropertyColor+"' viewBox='0 0 10 10' refX='10' refY='5'");
		println("		markerUnits='strokeWidth' markerWidth='6' markerHeight='4' orient='auto'>");
		println("		<path d='M0 0 L10 5 L0 10' style='fill:none;stroke:"+PropertyColor+"'/>");
		println("	</marker>");
		println("	<marker id='marker:Triangle2' viewBox='0 0 10 10' refX='10' refY='5'");
		println("		markerUnits='strokeWidth' markerWidth='6' markerHeight='4' orient='auto'>");
		println("		<path d='M0 0 L10 5 L0 10' style='fill:none;stroke:black'/>");
		println("	</marker>");

		println("	<polygon id='opencoin' points='0,0 10,5 0,10 3,5' ");
		println("			style='fill:blue;stroke:blue;stroke-width:1'/>");
		println("	<ellipse id='leafcoin' cx='5' cy='5' rx='3' ry='3' ");
		println("			style='fill:blue;stroke:blue;stroke-width:1'/>");

		println("	<g id='up'>");
		println("		<rect width='20' height='20' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<polygon transform='translate(5 5)' points='10,7 5,0 0,7 3,7 3,10 7,10 7,7'");
		println("			 style='fill:blue;stroke:blue;stroke-width:1'/>");
		println("	</g>");
		println("	<g id='down'>");
		println("		<rect width='20' height='20' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<polygon transform='translate(5 5)' points='10,3 5,10 0,3 3,3 3,0 7,0 7,3'");
		println("			 style='fill:blue;stroke:blue;stroke-width:1'/>");
		println("	</g>");
		println("	<g id='right'>");
		println("		<rect width='20' height='20' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<polygon transform='translate(5 5)' points='3,0 10,5 3,10 3,7 0,7 0,3 3,3'");
		println("			 style='fill:blue;stroke:blue;stroke-width:1'/>");
		println("		</g>");
		println("	<g id='left'>");
		println("		<rect width='20' height='20' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<polygon transform='translate(5 5)' points='7,0 0,5 7,10 7,7 10,7 10,3 7,3'");
		println("			 style='fill:blue;stroke:blue;stroke-width:1'/>");
		println("	</g>");
		println("	<g id='coin'>");
		println("		<rect width='20' height='20' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<polygon transform='translate(5 5)' points='7,0 0,0 0,7 2,5 5,8 8,5 5,2'");
		println("			 style='fill:blue;stroke:blue;stroke-width:1'/>");
		println("	</g>");

		printClassTemplates();
		printPropertyTemplates();
		printResourceTemplates();

		println("</defs>");
	}

	private int getLabelWidth(String label)
	{
		Font lf = new Font("Arial",Font.PLAIN,12);
		FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(lf);
		return fm.stringWidth(label);
	}
	private int getLabelWidth2(String label)
	{
		Font lf = new Font("Arial",Font.PLAIN,14);
		FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(lf);
		return fm.stringWidth(label);
	}

	private int getRx(RDF_Class cls)
	{
		int rx = getLabelWidth(broker.getLabelFor(cls))/2+5;
		if (rx < MinClassRx) rx = MinClassRx;
		return rx;
	}

	private void printClassTemplates() throws IOException
	{
		for (int i=0; i<classList.size(); i++)
		{
			RDF_Class cls = (RDF_Class) classList.get(i);
			// dont create template for attribute classes (literal, xml datatype)
			// if (broker.isAttributeClass(cls)) continue;
			String id = "C"+i;
			String label = broker.getLabelFor(cls);
			int rx = getRx(cls);

			println("	<text id='"+id+"' style='font-size:12;font-family:Arial'>"+label+"</text>");

			println("	<g id='_"+id+"'>");
			println("		<ellipse rx='"+rx+"' ry='"+ClassRy+"' style='fill:cyan;stroke-width:1;stroke:black;filter:url(#Bevel)'/>");
			println("		<use y='4' xlink:href='#"+id+"' style='text-anchor:middle;fill:black'/>");
			println("	</g>");
		}
	}

	private void printPropertyTemplates() throws IOException
	{
		for (int i=0; i<propertyList.size(); i++)
		{
			RDF_Property prop = (RDF_Property) propertyList.get(i);
			String id = "P"+i;
			String label = broker.getLabelFor(prop);

			println("	<text id='"+id+"' style='font-size:12;font-family:Arial'>"+label+"</text>");
		}
	}

	private int getWidth(RDF_Resource resrc)
	{
                int w = getLabelWidth(broker.getLabelFor(resrc))+10;
		if (w < MinResourceWidth) w = MinResourceWidth;
		return w;
	}

	private void printResourceTemplates() throws IOException
	{
		for (int i=0; i<resourceList.size(); i++)
		{
			RDF_Resource resrc = (RDF_Resource) resourceList.get(i);
			String id = "R"+i;
			String label = broker.getLabelFor(resrc);
			int w = getWidth(resrc);

			println("	<text id='"+id+"' style='font-size:12;font-family:Arial'>"+label+"</text>");

			println("	<g id='_"+id+"'>");
			println("		<rect width='"+w+"' height='"+ResourceHeight+"' style='fill:lime;stroke-width:1;stroke:black;filter:url(#Bevel)'/>");
			println("		<use x='"+w/2+"' y='18' xlink:href='#"+id+"' style='text-anchor:middle;fill:black'/>");
			println("	</g>");
		}
	}

	private void printTitleWindow() throws IOException
	{
		println("<!-- Title window -->");

		println("<rect x='0' y='"+(SVGHeight-30)+"' width='"+SVGWidth+"' height='30'");
		println("	 style='fill:lightgray;stroke:grey;filter:url(#Bevel)'/>");

		String infor = broker.getNamespaceInfor();
		infor = "<![CDATA["+infor+"]]>";
		println("<svg id='TitleWindow' x='5' y='"+(SVGHeight-26)+"' width='"+(SVGWidth-10)+"' height='22'>");
		println("	<text y='16' style='fill:red;font-size:12;font-family:Arial'>");
		println("		"+infor);
		println("		<animate attributeName='x' attributeType='XML' 	from='"+(SVGWidth-10)+"' to='-"+getLabelWidth(infor)+"'");
		println("			begin='0s' dur='60s' fill='freeze' repeatCount='indefinite'/>");
		println("	</text>");
		println("</svg>");
	}

	private void printTreeNode(RDF_Class node, int y) throws IOException
	{
		String color;
		String state;
		String sym;
		String onclick;
		String vis = broker.isRootClass(node) ? "visible" : "hidden";
		String transform = y != 0 ? "transform='translate(10,"+y+")'" : "";
		if (broker.isLeafClass(node))
		{
			color = "red";
			state = "";
			sym = "#leafcoin";
			onclick = "";
		}else
		{
			color = "green";
			state = "state='close'";
			sym = "#opencoin";
			onclick = "onclick='tree_click(evt)'";
		}
		String id = "C"+classList.indexOf(node);
		println("		<g "+transform+" style='fill:"+color+"' visibility='"+vis+"' "+state+">");
		println("			<use xlink:href='"+sym+"' x='0' y='5' "+onclick+"/>");
		println("			<use xlink:href='#"+id+"' x='15' y='15' onclick='view_click(evt)'/>");
		for (Iterator i = broker.getSubClasses(node, false, true).iterator(); i.hasNext(); )
		{
			printTreeNode((RDF_Class)i.next(), 0);
		}
		println("		</g>");
	}

	private void printTreePropertyNode(RDF_Property node, int y) throws IOException
	{
		String color;
		String state;
		String sym;
		String onclick;
		String vis = broker.isRootProperty(node) ? "visible" : "hidden";
		String transform = y != 0 ? "transform='translate(10,"+y+")'" : "";
		if (broker.isLeafProperty(node))
		{
			color = "red";
			state = "";
			sym = "#leafcoin";
			onclick = "";
		}else
		{
			color = "green";
			state = "state='close'";
			sym = "#opencoin";
			onclick = "onclick='tree_click(evt)'";
		}
		String id = "P"+propertyList.indexOf(node);
		println("		<g "+transform+" style='fill:"+color+"' visibility='"+vis+"' "+state+">");
		println("			<use xlink:href='"+sym+"' x='0' y='5' "+onclick+"/>");
		println("			<use xlink:href='#"+id+"' x='15' y='15' onclick='view_click(evt)'/>");
		for (Iterator i = broker.getSubProperties(node, false, true).iterator(); i.hasNext(); )
		{
			printTreePropertyNode((RDF_Property)i.next(), 0);
		}
		println("		</g>");
	}

	private int getNodeWidth(RDF_Class node, int deep)
	{
		int w = getLabelWidth(broker.getLabelFor(node)) + deep*10 + 15;
		for (Iterator i = broker.getSubClasses(node, false, false).iterator(); i.hasNext(); )
		{
			int w1 = getNodeWidth((RDF_Class)i.next(), deep+1);
			if (w<w1) w=w1;
		}
		return w;
	}

	private void printTreeWindow() throws IOException
	{
		println("<!-- Tree window -->");

		int w = 0;
		ArrayList roots = new ArrayList();
		ArrayList schema = new ArrayList();
		for (Iterator i = broker.getRootClasses(true).iterator(); i.hasNext(); )
		{
			// dont show the tree view for the attribute classes and others
			// rdf:Resource can have sub classes
			RDF_Class cls = (RDF_Class)i.next();
			if (broker.isAttributeClass(cls)//||broker.isSchemaClass(cls)
			     ||(broker.isBasicResource(cls)&&broker.getSubClasses(cls, false, false).isEmpty()))
				continue;
			if (broker.isSchemaClass(cls)) schema.add(cls);
			else roots.add(cls);
		}
		for (Iterator i = roots.iterator(); i.hasNext(); )
		{
			int w1 = getNodeWidth((RDF_Class)i.next(), 1);
			if (w<w1) w = w1;
		}
		setTreeWindowWidth(w+10);

		println("<svg id='TreeWindow' x='0' y='0' width='"+TreeWindowWidth+"' height='"+TreeWindowHeight+"'>");
		println("<defs>");
		println("	<g id='Class'>");
		println("		<rect width='"+TreeWindowWidth/2+"' height='25' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<text x='"+TreeWindowWidth/4+"' y='16' style='text-anchor:middle;fill:blue;font-size:14;font-family:Arial'>Classes</text>");
		println("	</g>");
		println("	<g id='Property'>");
		println("		<rect width='"+TreeWindowWidth/2+"' height='25' style='fill:lightgrey;stroke:grey;filter:url(#Bevel)'/>");
		println("		<text x='"+TreeWindowWidth/4+"' y='16' style='text-anchor:middle;fill:blue;font-size:14;font-family:Arial'>Properties</text>");
		println("	</g>");
		println("</defs>");
		println("<rect x='0' y='0' width='"+TreeWindowWidth+"' height='"+TreeWindowHeight+"'");
		println("	 	style='fill:lightgray;stroke:grey;filter:url(#Bevel)'/>");
		println("<use xlink:href='#Class' x='0' y='0' onclick='tree_view(evt)'/>");
		println("<use xlink:href='#Property' x='"+(TreeWindowWidth/2)+"' y='0' onclick='tree_view(evt)'/>");
		println("<svg id='ClassTree' x='5' y='30' width='"+TreeViewWidth+"' height='"+TreeViewHeight+"'");
		println("		display='inline' viewBox='0 0 "+TreeViewWidth+" "+TreeViewHeight+"'>");
		println("	<g transform='translate(-10,-15)' state='open'>");
		println("	<g transform='translate(10,15)' state='open'>");
		println("		<text x='0' y='15' style='fill:blue;font-size:12;font-family:Arial'>All Classes:</text>");
		int y = 15;
		for (Iterator i = roots.iterator(); i.hasNext(); )
		{
			printTreeNode((RDF_Class)i.next(), y);
			y += 15;
		}
		println("	</g>");
		if (!schema.isEmpty())
		{
			y = (roots.size()+1)*15+15;
			println("	<g transform='translate(10,"+y+")' state='open'>");
			println("		<text x='0' y='15' style='fill:blue;font-size:12;font-family:Arial'>Meta Classes:</text>");
			y = 15;
			for (Iterator i = schema.iterator(); i.hasNext(); )
			{
				printTreeNode((RDF_Class)i.next(), y);
				y += 15;
			}
			println("	</g>");
		}
		println("	</g>");
		println("</svg>");

		println("<svg id='PropertyTree' x='5' y='30' width='"+TreeViewWidth+"' height='"+TreeViewHeight+"'");
		println("		display='none' viewBox='0 0 "+TreeViewWidth+" "+TreeViewHeight+"'>");
		println("	<g transform='translate(-10,-15)' state='open'>");
		println("	<g transform='translate(10,15)' state='open'>");
		println("		<text x='0' y='15' style='fill:blue;font-size:12;font-family:Arial'>All Properties:</text>");
		y = 15;
		for (Iterator i = broker.getRootProperties(true).iterator(); i.hasNext(); )
		{
			printTreePropertyNode((RDF_Property)i.next(), y);
			y += 15;
		}
		println("	</g>");
		println("	</g>");
		println("</svg>");

		println("<use xlink:href='#up' x='"+(TreeWindowWidth-20)+"' y='"+(TreeWindowHeight-60)+"' onclick='scroll_tree(evt)'/>");
		println("<use xlink:href='#down' x='"+(TreeWindowWidth-20)+"' y='"+(TreeWindowHeight-40)+"' onclick='scroll_tree(evt)'/>");
		println("<use xlink:href='#coin' x='"+(TreeWindowWidth-20)+"' y='"+(TreeWindowHeight-20)+"' onclick='scroll_tree(evt)'/>");
		println("<use xlink:href='#left' x='"+(TreeWindowWidth-60)+"' y='"+(TreeWindowHeight-20)+"' onclick='scroll_tree(evt)'/>");
		println("<use xlink:href='#right' x='"+(TreeWindowWidth-40)+"' y='"+(TreeWindowHeight-20)+"' onclick='scroll_tree(evt)'/>");
		println("</svg>");
	}

	private void printDesktopWindow() throws IOException
	{
		println("<!-- Desktop window -->");

		println("<svg id='DesktopWindow' x='"+(TreeWindowWidth)+"' y='0' width='"+DesktopWindowWidth+"' height='"+DesktopWindowHeight+"'>");
		println("<rect x='0' y='0' width='"+DesktopWindowWidth+"' height='"+DesktopWindowHeight+"'");
		println("	 style='fill:lightgray;stroke:grey;filter:url(#Bevel)'/>");
		printClassViews();
		printPropertyViews();
		printResourceViews();
		println("<use xlink:href='#up' x='"+(DesktopWindowWidth-20)+"' y='"+(DesktopWindowHeight-60)+"' onclick='scroll_desktop(evt)'/>");
		println("<use xlink:href='#down' x='"+(DesktopWindowWidth-20)+"' y='"+(DesktopWindowHeight-40)+"' onclick='scroll_desktop(evt)'/>");
		println("<use xlink:href='#coin' x='"+(DesktopWindowWidth-20)+"' y='"+(DesktopWindowHeight-20)+"' onclick='scroll_desktop(evt)'/>");
		println("<use xlink:href='#left' x='"+(DesktopWindowWidth-60)+"' y='"+(DesktopWindowHeight-20)+"' onclick='scroll_desktop(evt)'/>");
		println("<use xlink:href='#right' x='"+(DesktopWindowWidth-40)+"' y='"+(DesktopWindowHeight-20)+"' onclick='scroll_desktop(evt)'/>");
		println("</svg>");
	}

	private void printClassViews() throws IOException
	{
		for (int i=0; i<classList.size(); i++)
		{
			RDF_Class cls = (RDF_Class) classList.get(i);
			String id = "C"+i;
			printClassView(id, cls);
		}
	}

	private class PropertyArc {
		public RDF_Class rdf_class;
		public RDF_Property rdf_property;

		public PropertyArc(RDF_Class cls, RDF_Property prop)
		{
			rdf_class = cls;
			rdf_property = prop;
		}
		public String getPropertyLabel()
		{
			return broker.getLabelFor(rdf_property);
		}
		public String getClassLabel()
		{
			return broker.getLabelFor(rdf_class);
		}
		public String getAttributeLabel()
		{
			String str = getPropertyLabel()+" -> ";
			if (rdf_class != null)
				str += broker.getLabelFor(rdf_class);
			else
				str += "no range constraint";
			return str;
		}

		public boolean isDefinedWithDomain(RDF_Class cls)
		{
			return rdf_property.getdomain().contains(cls);
		}
		public boolean isDefinedWithRange(RDF_Class cls)
		{
			return rdf_property.getrange().contains(cls);
		}
	}

	private class SizeComparator implements Comparator {
		public int compare(Object o1, Object o2)
		{
			int w1 = getLabelWidth(((PropertyArc)o1).getClassLabel());
			int w2 = getLabelWidth(((PropertyArc)o2).getClassLabel());
			return (w1<w2) ? -1 : 1;
		}
		public boolean equals(Object obj)
		{
			return false;
		}
	}

	private void printClassView(String id, RDF_Class cls) throws IOException
	{
		// layout parameters
		int c_w; // center width
		int c_h; // center height
		int t_w; // top width
		int t_h; // top height
		int b_w; // bottom width
		int b_h; // bottom height
		int l_w; // left width
		int l_h; // left height
		int r_w; // right width
		int r_h; // right height
		int width; // view width

		Collection outProps = broker.getPropertiesWithDomain(cls, true);
		Collection inProps = broker.getPropertiesWithRange(cls, true);
		Collection supers = broker.getSuperClasses(cls, false, false);
		Collection subs = broker.getSubClasses(cls, false, false);

		/* getting in/out classes and properties (arcs) */
		SizeComparator comparator = new SizeComparator();
		TreeSet outArcs = new TreeSet(comparator);
		TreeSet inArcs = new TreeSet(comparator);
//		ArrayList selfArcs = new ArrayList(); don't use self arc
		ArrayList attributes = new ArrayList();

		String comment = "";
		for (Iterator i=cls.getcomment().iterator(); i.hasNext(); ){
			if (!comment.equals("")) comment += ". ";
				comment += ((Literal)i.next()).getvalue();
		}

		for (Iterator i=outProps.iterator(); i.hasNext(); )
		{
			// get ranges of properties
			RDF_Property prop = (RDF_Property)i.next();
			Collection range = broker.getRangeOfProperty(prop, false, false);
			if (range.isEmpty())
				attributes.add(new PropertyArc(null, prop));
			for (Iterator k=range.iterator(); k.hasNext(); )
			{
				RDF_Class c = (RDF_Class)k.next();
				PropertyArc arc = new PropertyArc(c, prop);
				if (broker.isAttributeClass(c)) attributes.add(arc);
				//else if (range==cls) selfArcs.add(arc);
					 else outArcs.add(arc);
			}

		}
		// only in for other classes
		for (Iterator i=inProps.iterator(); i.hasNext(); )
		{
			// get ranges of properties
			RDF_Property prop = (RDF_Property)i.next();
			for (Iterator k=broker.getDomainOfProperty(prop, false, false).iterator(); k.hasNext(); )
			{
				RDF_Class domain = (RDF_Class)k.next();
				if(domain!=cls)
					inArcs.add(new PropertyArc(domain, prop));
			}
		}

		//System.out.println("in:"+inProps.size()+" "+inArcs.size()+"  out:"+outProps.size()+" "+outArcs.size());

		// calculating parameters
		c_h = 45+attributes.size()*15;
		String label=broker.getLabelFor(cls); // focus class label
		c_w = getLabelWidth2(label);
		// check also for metaclass
		for (Iterator i=attributes.iterator(); i.hasNext(); )
		{
			int w = getLabelWidth(((PropertyArc)i.next()).getAttributeLabel());
			if (c_w<w) c_w=w;
		}
		c_w += 10;
		if (c_w<MinFocusClassWidth) c_w = MinFocusClassWidth;

		// distance bw class symbols = 35
		l_h = 35*inArcs.size();
		l_w = 0;
		int count = 0;
		for (Iterator i=inArcs.iterator(); i.hasNext(); )
		{
			count++;
			int w = getRx(((PropertyArc)i.next()).rdf_class)*2;
			if (count*35/2-c_h/2<100) w += 100;
			if (l_w<w) l_w=w;
		}
		l_w += 10;

		r_h = 35*outArcs.size();
		r_w = 0;
		count = 0;
		for (Iterator i=outArcs.iterator(); i.hasNext(); )
		{
			count++;
			int w = getRx(((PropertyArc)i.next()).rdf_class)*2;
			if (count*35/2-c_h/2<100) w += 100;
			if (r_w<w) r_w=w;
		}
		r_w += 10;

		int c_x; // x center
		if (l_w+c_w+r_w<DesktopViewWidth)
		{
			width = DesktopViewWidth;
			if (l_w+c_w/2<=width/2&&r_w+c_w/2<=width/2)
				c_x = width/2;
			else
			 	c_x = l_w+(width-l_w-r_w)/2;
		}else
		{
			width=l_w+c_w+r_w;
			c_x = l_w+c_w/2;
		}

		t_w = 0;
		t_h = 35;
		for (Iterator i=supers.iterator(); i.hasNext(); )
		{
			int w = getRx((RDF_Class)i.next())*2;
			t_w += w+10;
			if (t_w>width-10)
			{
				t_h+=35;
				t_w = 0;
			}
		}
		if (supers.isEmpty()) t_h = 10;
		else t_h += 20;

		// comment on the top
		if (!comment.equals("")) t_h += 50;

		b_w = 0;
		b_h = 35;
		for (Iterator i=subs.iterator(); i.hasNext(); )
		{
			int w = getRx((RDF_Class)i.next())*2;
			b_w += w+10;
			if (b_w>width-10)
			{
				b_h+=35;
				b_w = 0;
			}
		}
		if (subs.isEmpty()) b_h = 10;
		else b_h += 20;

		int c_y; // y center

		int mh; // minimum height of the middle box
		c_y = t_h+Math.max(l_h, r_h)/2;
		mh = t_h + c_h/2;
		if (!supers.isEmpty()) mh += 100;
		if (c_y < mh) c_y = mh;
		else mh = c_y;
		mh += Math.max(l_h, r_h)/2;
		int temp = c_h/2;
		if (!subs.isEmpty()) temp += 100;
		if (mh<c_y+temp) mh = c_y+temp;
		mh -= t_h;

		int x, y, x1, y1, x2, y2; // tempo variable

		println("	<svg id='view:"+id+"' x='5' y='5' width='"+DesktopViewWidth+"' height='"+DesktopViewHeight+"'");
		println("			display='none' viewBox='0 0 "+DesktopViewWidth+" "+DesktopViewHeight+"'>");

		// comment
		if (!comment.equals(""))
		{
			comment = "<![CDATA["+comment+"]]>";
			println("		<rect x='0' y='5' width='"+width+"' height='40'");
			println("			 style='fill:lightgreen;stroke:lightgreen;filter:url(#Bevel)'/>");
			println("		<svg x='5' y='5' width='"+(width-10)+"' height='40'>");
			println("			<text x='0' y='15' style='fill:black;font-size:12;");
			println("				font-family:Arial'>Comment:</text>");
			println("			<text y='30' style='fill:red;font-size:12;font-family:Arial'>");
			println("				"+comment);
			println("				<animate attributeName='x' attributeType='XML' 	from='"+(width-10)+"' to='-"+getLabelWidth(comment)+"'");
			println("					begin='0s' dur='60s' fill='freeze' repeatCount='indefinite'/>");
			println("			</text>");
			println("		</svg>");
		}

		// focus class
		String meta = "";
		String ref = "";
		String color = "grey";
		if (broker.isMetaClass(cls)) meta = "Meta-class";
		else if (broker.isPropertyClass(cls)) meta = "Meta-Property";
		else // none-schema class
		{
			RDF_Class metacls = broker.getMetaClass(cls);
		 	if (metacls!=null)
			{
				meta = broker.getLabelFor(metacls);
				color = MetaColor;
				ref = "viewID='view:C"+classList.indexOf(metacls)+"' onclick='view3_click(evt)'";
			}/*else
				meta = "Modeling-primitive";*/
		}
		println("		<g transform='translate("+(c_x-c_w/2)+","+(c_y-c_h/2)+")'>");
		println("			<rect  width='"+c_w+"' height='"+c_h+"' rx='10'");
		println("				 style='fill:yellow;stroke:black;stroke-width:1;filter:url(#Bevel)'/>");
		println("			<text x='"+c_w/2+"' y='20' style='text-anchor:middle;fill:black;");
		println("				 font-size:14;font-family:Arial'>"+label+"</text>");
		println("			<text x='"+c_w/2+"' y='35' style='text-anchor:middle;fill:"+color+";");
		println("				 font-size:12;font-family:Arial' "+ref+">("+meta+")</text>");
		println("			<line x1='0' y1='40' x2='"+c_w+"' y2='40'");
		println("				 	style='fill:none;stroke:grey;stroke-width:1'/>");
		y = 55;
		for (Iterator i=attributes.iterator(); i.hasNext();)
		{
			PropertyArc arc = (PropertyArc)i.next();
			color = arc.isDefinedWithDomain(cls) ? NoneTransitiveProperty : TransitiveProperty;
			String onclick = "viewID='view:P"+propertyList.indexOf(arc.rdf_property)+"' onclick='view3_click(evt)'";
			println("			<text x='5' y='"+y+"' style='fill:"+color+";font-size:12;");
			println("					font-family:Arial' "+onclick+">"+arc.getAttributeLabel()+"</text>");
			y += 15;
		}
		println("		</g>");

		// super class
		if (supers.size()>0)
		{
			int height = t_h-10;
			y = 5;
			if (!comment.equals(""))
			{
				height -= 50;
				y += 50;
			}
			println("		<rect x='0' y='"+y+"' width='"+width+"' height='"+height+"'");
			println("			 style='fill:yellow;stroke:yellow;filter:url(#Bevel)'/>");
			y = t_h-28;
			ArrayList line = new ArrayList();
			t_w = 0;
			for (Iterator i=supers.iterator(); i.hasNext(); )
			{
				RDF_Class c = (RDF_Class)i.next();
				int w = getRx(c)*2;
				if (t_w+w+10>width-10)
				{
					/* print current line */
					printClassLine(line, y, t_w, width);
					line.clear();
					t_w = w;
					y -= 35;
				}else t_w += w+10;
				line.add(c);
			}
			printClassLine(line, y, t_w, width);
			x1 = c_x; y1 = c_y - c_h/2;
			x2 = width/2; y2 = t_h-5;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2'/>");
			if (x2 < x1)
			{
				path_counter++;
				println("		<path id='p"+path_counter+"' d='M"+x2+" "+y2+" L"+x1+" "+y1+"'");
				println("			 style='fill:none;stroke:none'/>");
			}
			println("		<text style='text-anchor:middle;font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='50%'>");
			println("				rdfs:subClassOf");
			println("			</textPath>");
			println("		</text>");
			path_counter++;
		}

		// sub class
		if (subs.size()>0)
		{
			y = t_h+mh+5;
			println("		<rect x='0' y='"+y+"' width='"+width+"' height='"+(b_h-10)+"'");
			println("			 style='fill:yellow;stroke:yellow;filter:url(#Bevel)'/>");
			y = t_h+mh+28;
			ArrayList line = new ArrayList();
			b_w = 0;
			for (Iterator i=subs.iterator(); i.hasNext(); )
			{
				RDF_Class c = (RDF_Class)i.next();
				int w = getRx(c)*2;
				if (b_w+w+10>width-10)
				{
					/* print current line */
					printClassLine(line, y, b_w, width);
					line.clear();
					b_w = w;
					y += 35;
				}else b_w += w+10;
				line.add(c);
			}
			printClassLine(line, y, b_w, width);
			x1 = width/2; y1 = t_h+mh+5;
			x2 = c_x; y2 = c_y+c_h/2;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2'/>");
			if (x2 < x1)
			{
				path_counter++;
				println("		<path id='p"+path_counter+"' d='M"+x2+" "+y2+" L"+x1+" "+y1+"'");
				println("			 style='fill:none;stroke:none'/>");
			}
			println("		<text style='text-anchor:middle;font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='50%'>");
			println("				rdfs:subClassOf");
			println("			</textPath>");
			println("		</text>");
			path_counter++;
		}

		// in class
		y = c_y;
		if (inArcs.size()%2==0) y -= 17;
		int yinc = 35;
		for (Iterator i=inArcs.iterator(); i.hasNext();)
		{
			PropertyArc arc = (PropertyArc)i.next();
			int w = getRx(arc.rdf_class)*2;
			x = 10+w/2;
			color = arc.isDefinedWithRange(cls) ? NoneTransitiveProperty : TransitiveProperty;
			ref = "C"+classList.indexOf(arc.rdf_class);
			println("		<use x='"+x+"' y='"+y+"' xlink:href='#_"+ref+"' onclick='view2_click(evt)'/>");

			String onclick = "viewID='view:P"+propertyList.indexOf(arc.rdf_property)+"' onclick='view3_click(evt)'";

			x1 = 10+w; y1 = y;
			Point[] points = Clipping.getClipped(x1, y1, c_x, c_y, c_x-c_w/2, c_x+c_w/2, c_y-c_h/2, c_y+c_h/2);
			// it must be clipped
			if (points[0].x==c_x&&points[0].y==c_y)
			{
				x2 = points[1].x; y2 = points[1].y;
			}else
			{
				x2 = points[0].x; y2 = points[0].y;
			}
			int l = (int) Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
			int k = (getLabelWidth(arc.getPropertyLabel())+l)*25/l;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle-"+color+");fill:none;stroke:"+color+";stroke-width:2'/>");
			println("		<text style='text-anchor:middle;fill:"+color+";font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='"+k+"%' "+onclick+">");
			println("			"+arc.getPropertyLabel()+"");
			println("			</textPath>");
			println("		</text>");
			path_counter++;
			y += yinc;
			if (yinc>0) yinc = -(yinc+35);
			else yinc = -yinc+35;
		}

		// out class
		y = c_y;
		if (outArcs.size()%2==0) y -= 17;
		yinc = 35;
		for (Iterator i=outArcs.iterator(); i.hasNext();)
		{
			PropertyArc arc = (PropertyArc)i.next();
			int w = getRx(arc.rdf_class)*2;
			x = width-10-w/2;
			color = arc.isDefinedWithDomain(cls) ? NoneTransitiveProperty : TransitiveProperty;
			ref = "C"+classList.indexOf(arc.rdf_class);
			println("		<use x='"+x+"' y='"+y+"' xlink:href='#_"+ref+"' onclick='view2_click(evt)'/>");

			String onclick = "viewID='view:P"+propertyList.indexOf(arc.rdf_property)+"' onclick='view3_click(evt)'";

			x2 = width-10-w; y2 = y;
			Point[] points = Clipping.getClipped(x2, y2, c_x, c_y, c_x-c_w/2, c_x+c_w/2, c_y-c_h/2, c_y+c_h/2);
			// it must be clipped
			if (points[0].x==c_x&&points[0].y==c_y)
			{
				x1 = points[1].x; y1 = points[1].y;
			}else
			{
				x1 = points[0].x; y1 = points[0].y;
			}
			int l = (int) Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
			int k = (getLabelWidth(arc.getPropertyLabel())+l)*25/l;
			if (k<50) k=100-k;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle-"+color+");fill:none;stroke:"+color+";stroke-width:2'/>");
			println("		<text style='text-anchor:middle;fill:"+color+";font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='"+k+"%' "+onclick+">");
			println("			"+arc.getPropertyLabel()+"");
			println("			</textPath>");
			println("		</text>");
			path_counter++;

			y += yinc;
			if (yinc>0) yinc = -(yinc+35);
			else yinc = -yinc+35;
		}

		if (!broker.isSchemaClass(cls)&&!broker.isAttributeClass(cls))
		{
		// instances
		Collection resrcs = broker.getInstanceResources(cls, true, true);
		Collection dresrcs = broker.getInstanceResources(cls, false, true);

		x=0; y=t_h+mh+b_h+10;

		int maxw = 1;
		int h;
		int colnum=0;
		int linenum = 0;
		if (resrcs.size()!=0)
		{
			for (Iterator i=resrcs.iterator(); i.hasNext(); )
			{
				int w = getWidth((RDF_Resource)i.next());
				if (maxw < w) maxw = w;
			}
			if (width<maxw) width = maxw;
			colnum = width/maxw;
			linenum = resrcs.size()/colnum;
			if (resrcs.size()%colnum != 0) linenum++;
			h = 15*linenum+5;
		}else h = 20;

		String title = "Resource Instances";
		if (broker.isContainerClass(cls))
			title = "Container Instances";
		else if (broker.isStatementClass(cls))
			title = "Reified Statements";

		println("		<g transform='translate("+x+","+y+")'>");
		println("			<rect x='0' y='0' width='"+width+"' height='30' style='fill:limegreen;filter:url(#Bevel)'/>");
		println("			<text x='"+(width/2)+"' y='20' style='text-anchor:middle;font-size:14;font-family:Arial'>"+title+"</text>");
		println("			<rect x='0' y='30' width='"+width+"' height='"+h+"' style='fill:beige'/>");

		int col = 0;
		int line = 1;
		for (Iterator i=resrcs.iterator(); i.hasNext(); )
		{
			x1 = col*maxw+5;
			y1 = 15*line+30;
			RDF_Resource resrc = (RDF_Resource)i.next();
			color = dresrcs.contains(resrc) ? NoneTransitiveResource : TransitiveResource;
			ref = "R"+resourceList.indexOf(resrc);
			println("			<use x='"+x1+"' y='"+y1+"' xlink:href='#"+ref+"' style='fill:"+color+"' onclick='view_click(evt)'/>");
			line++;
			if (line>linenum)
			{
				line = 1;
				col++;
			}
		}
		println("		</g>");
		}else if (broker.isMetaClass(cls))
		{
		// instance classes
		Collection instances = broker.getClassesOfMetaclass(cls, true);

		x=0; y=t_h+mh+b_h+10;

		int maxw = 1;
		int h;
		int colnum=0;
		int linenum = 0;
		if (instances.size()!=0)
		{
			for (Iterator i=instances.iterator(); i.hasNext(); )
			{
				int w = getRx((RDF_Class)i.next())*2;
				if (maxw < w) maxw = w;
			}
			if (width<maxw) width = maxw;
			colnum = width/maxw;
			linenum = instances.size()/colnum;
			if (instances.size()%colnum != 0) linenum++;
			h = 15*linenum+5;
		}else h = 20;

		println("		<g transform='translate("+x+","+y+")'>");
		println("			<rect x='0' y='0' width='"+width+"' height='30' style='fill:lime;filter:url(#Bevel)'/>");
		println("			<text x='"+(width/2)+"' y='20' style='text-anchor:middle;font-size:14;font-family:Arial'>Class Instances</text>");
		println("			<rect x='0' y='30' width='"+width+"' height='"+h+"' style='fill:beige'/>");

		int col = 0;
		int line = 1;
		for (Iterator i=instances.iterator(); i.hasNext(); )
		{
			x1 = col*maxw+5;
			y1 = 15*line+30;
			ref = "C"+classList.indexOf(i.next());
			println("			<use x='"+x1+"' y='"+y1+"' xlink:href='#"+ref+"' style='fill:"+NoneTransitiveClass+"' onclick='view_click(evt)'/>");
			line++;
			if (line>linenum)
			{
				line = 1;
				col++;
			}
		}
		println("		</g>");
		}else if (broker.isPropertyClass(cls))
		{
		// property class
		Collection props = broker.getPropertiesOfClass(cls, true);

		x=0; y=t_h+mh+b_h+10;

		int maxw = 1;
		int h;
		int colnum=0;
		int linenum = 0;
		if (props.size()!=0)
		{
			for (Iterator i=props.iterator(); i.hasNext(); )
			{
				label = broker.getLabelFor((RDF_Property)i.next());
				int w = getLabelWidth(label)+10;
				if (maxw < w) maxw = w;
			}
			if (width<maxw) width = maxw;
			colnum = width/maxw;
			linenum = props.size()/colnum;
			if (props.size()%colnum != 0) linenum++;
			h = 15*linenum+5;
		}else h = 20;

		println("		<g transform='translate("+x+","+y+")'>");
		println("			<rect x='0' y='0' width='"+width+"' height='30' style='fill:lime;filter:url(#Bevel)'/>");
		println("			<text x='"+(width/2)+"' y='20' style='text-anchor:middle;font-size:14;font-family:Arial'>Property Instances</text>");
		println("			<rect x='0' y='30' width='"+width+"' height='"+h+"' style='fill:beige'/>");

		int col = 0;
		int line = 1;
		for (Iterator i=props.iterator(); i.hasNext(); )
		{
			x1 = col*maxw+5;
			y1 = 15*line+30;
			ref = "P"+propertyList.indexOf(i.next());
			println("			<use x='"+x1+"' y='"+y1+"' style='fill:"+NoneTransitiveProperty+"' xlink:href='#"+ref+"' onclick='view_click(evt)'/>");
			line++;
			if (line>linenum)
			{
				line = 1;
				col++;
			}
		}
		println("		</g>");
		}

		println("	</svg>");
	}

	private void printClassLine(Collection line, int y, int w, int vw) throws IOException
	{
		int x = (vw-w)/2;
		for (Iterator i=line.iterator(); i.hasNext(); )
		{
			RDF_Class c = (RDF_Class)i.next();
			int cw = getRx(c)*2;
			String ref = "C"+classList.indexOf(c);
			println("		<use x='"+(x+cw/2)+"' y='"+y+"' xlink:href='#_"+ref+"' onclick='view2_click(evt)'/>");
			x += (cw+10);
		}
	}

	private void printPropertyViews() throws IOException
	{
		for (int i=0; i<propertyList.size(); i++)
		{
			RDF_Property prop = (RDF_Property) propertyList.get(i);
			String id = "P"+i;
			printPropertyView(id, prop);
		}
	}

	private void printPropertyView(String id, RDF_Property prop) throws IOException
	{

		Collection domain = broker.getDomainOfProperty(prop, true, false);
		Collection range = broker.getRangeOfProperty(prop, true, false);
		Collection supers = broker.getSuperProperties(prop, false, true);
		Collection subs = broker.getSubProperties(prop, false, true);

		String comment = "";
		for (Iterator i=prop.getcomment().iterator(); i.hasNext(); )
		{
			if (!comment.equals("")) comment += ". ";
			comment += ((Literal)i.next()).getvalue();
		}

		// layout parameters
		int c_h; // center height
		int t_h; // top height
		int b_h; // bottom height
		int width; // width

		width = DesktopViewWidth*4/5;

		t_h = 20+supers.size()*15;
		if (!comment.equals("")) t_h += 50;
		b_h = 20+subs.size()*15;

		int maxw1 = 1;
		int colnum1=0;
		int linenum1 = 0;
		for (Iterator i=domain.iterator(); i.hasNext(); )
		{
			int w = getRx((RDF_Class)i.next())*2;
			if (maxw1 < w) maxw1 = w;
		}
		int maxw2 = 1;
		int colnum2=0;
		int linenum2 = 0;
		for (Iterator i=range.iterator(); i.hasNext(); )
		{
			int w = getRx((RDF_Class)i.next())*2;
			if (maxw2 < w) maxw2 = w;
		}
		if (width<maxw1*2+20) width = maxw1*2+20;
		if (width<maxw2*2+20) width = maxw2*2+20;

		colnum1 = (width/2-10)/maxw1;
		if (colnum1==0) colnum1 = 1;
		linenum1 = domain.size()/colnum1;
		if (domain.size()%colnum1 != 0) linenum1++;
		if (linenum1==0) linenum1 = 1;

		colnum2 = (width/2-10)/maxw2;
		if (colnum2==0) colnum2 = 1;
		linenum2 = range.size()/colnum2;
		if (range.size()%colnum2 != 0) linenum2++;
		if (linenum2==0) linenum2 = 1;

		int linenum = (linenum1>linenum2) ? linenum1 : linenum2;
		c_h = 65 +  linenum*15;

		int c_x =  (width<=DesktopViewWidth) ? DesktopViewWidth/2 : width/2;
		int c_y = t_h+c_h/2;
		if (!supers.isEmpty()) c_y += 120;

		int x, y, x1, y1, x2, y2; // tempo variable

		println("	<svg id='view:"+id+"' display='none' viewBox='0 0 "+DesktopViewWidth+" "+DesktopViewHeight+"'>");

		// comment
		if (!comment.equals(""))
		{
			comment = "<![CDATA["+comment+"]]>";
			println("		<rect x='"+(c_x-width/2)+"' y='5' width='"+width+"' height='40'");
			println("			 style='fill:lightgreen;stroke:lightgreen;filter:url(#Bevel)'/>");
			println("		<svg x='"+(c_x-width/2+5)+"' y='5' width='"+(width-10)+"' height='40'>");
			println("			<text x='0' y='15' style='fill:black;font-size:12;");
			println("				font-family:Arial'>Comment:</text>");
			println("			<text y='30' style='fill:red;font-size:12;font-family:Arial'>");
			println("				"+comment);
			println("				<animate attributeName='x' attributeType='XML' 	from='"+(width-10)+"' to='-"+getLabelWidth(comment)+"'");
			println("					begin='0s' dur='60s' fill='freeze' repeatCount='indefinite'/>");
			println("			</text>");
			println("		</svg>");
		}

		// focus
		String label = broker.getLabelFor(prop);
		String meta = "";
		String ref = "";
		String color = "grey";
		RDF_Class metacls = broker.getClassTypeOfProperty(prop);
		if (metacls!=null)
		{
			meta = broker.getLabelFor(metacls);
			color = MetaColor;
			ref = "viewID='view:C"+classList.indexOf(metacls)+"' onclick='view3_click(evt)'";
		}/*else
			meta = "Model primitive";*/

		println("		<g transform='translate("+(c_x-width/2)+","+(c_y-c_h/2)+")'>");
		println("			<rect  width='"+width+"' height='"+c_h+"'");
		println("				 style='fill:yellow;stroke:black;stroke-width:1;filter:url(#Bevel)'/>");
		println("			<text x='"+width/2+"' y='20' style='text-anchor:middle;fill:black;");
		println("				 font-size:14;font-family:Arial'>"+label+"</text>");
		println("			<text x='"+width/2+"' y='35' style='text-anchor:middle;fill:"+color+";");
		println("				 font-size:12;font-family:Arial' "+ref+">("+meta+")</text>");
		println("			<line x1='0' y1='40' x2='"+width+"' y2='40'");
		println("				 	style='fill:none;stroke:grey;stroke-width:1'/>");
		println("			<line x1='"+width/2+"' y1='40' x2='"+width/2+"' y2='"+c_h+"'");
		println("				 	style='fill:none;stroke:grey;stroke-width:1'/>");
		println("			<text x='"+width/4+"' y='55' style='fill:black;text-anchor:middle;");
		println("				 font-size:12;font-family:Arial'>Domain</text>");
		y = 55;
		int col = 0;
		int line = 1;
		for (Iterator i=domain.iterator(); i.hasNext(); )
		{
			x1 = col*maxw1+10;
			y1 = 15*line+y;
			RDF_Class cls = (RDF_Class)i.next();
			ref = "C"+classList.indexOf(cls);
			color = prop.getdomain().contains(cls) ? NoneTransitiveClass : TransitiveClass;
			println("			<use x='"+x1+"' y='"+y1+"' xlink:href='#"+ref+"' style='fill:"+color+"' onclick='view_click(evt)'/>");
			line++;
			if (line>linenum)
			{
				line = 1;
				col++;
			}
		}
		println("			<text x='"+(width*3/4)+"' y='55' style='fill:black;text-anchor:middle;");
		println("				 font-size:12;font-family:Arial'>Range</text>");
		y = 55;
		col = 0;
		line = 1;
		for (Iterator i=range.iterator(); i.hasNext(); )
		{
			x1 = col*maxw2+width/2+10;
			y1 = 15*line+y;
			RDF_Class cls = (RDF_Class)i.next();
			ref = "C"+classList.indexOf(cls);
			color = prop.getrange().contains(cls) ? NoneTransitiveClass : TransitiveClass;

			println("			<use x='"+x1+"' y='"+y1+"' xlink:href='#"+ref+"' style='fill:"+color+"' onclick='view_click(evt)'/>");
			line++;
			if (line>linenum)
			{
				line = 1;
				col++;
			}
		}
		println("		</g>");

		// super property
		if (supers.size()>0)
		{
			int height = t_h-10;
			y = 5;
			if (!comment.equals(""))
			{
				height -= 50;
				y += 50;
			}
			println("		<rect x='"+(c_x-width/2)+"' y='"+y+"' width='"+width+"' height='"+(height)+"'");
			println("			 style='fill:yellow;stroke:yellow;filter:url(#Bevel)'/>");
			y += 15;
			for (Iterator i=supers.iterator(); i.hasNext(); )
			{
				RDF_Property p = (RDF_Property)i.next();
				ref = "P"+propertyList.indexOf(p);
				println("		<use x='"+c_x+"' y='"+y+"' style='text-anchor:middle;fill:"+NoneTransitiveProperty+"' xlink:href='#"+ref+"' onclick='view_click(evt)'/>");
				y += 15;
			}
			x1 = c_x; y1 = c_y - c_h/2;
			x2 = c_x; y2 = t_h-5;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2'/>");
			println("		<text style='text-anchor:middle;font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='50%'>");
			println("				rdfs:subPropertyOf");
			println("			</textPath>");
			println("		</text>");
			path_counter++;
		}

		// sub property
		if (subs.size()>0)
		{
			y = c_y + c_h/2 + 125;
			println("		<rect x='"+(c_x-width/2)+"' y='"+y+"' width='"+width+"' height='"+(b_h-10)+"'");
			println("			 style='fill:yellow;stroke:yellow;filter:url(#Bevel)'/>");
			y += 15;
			for (Iterator i=subs.iterator(); i.hasNext(); )
			{
				RDF_Property p = (RDF_Property)i.next();
				ref = "P"+propertyList.indexOf(p);
				println("		<use x='"+c_x+"' y='"+y+"' style='text-anchor:middle;fill:"+NoneTransitiveProperty+"' xlink:href='#"+ref+"' onclick='view_click(evt)'/>");
				y += 15;
			}
			x1 = c_x; y1 = c_y + c_h/2 + 125;
			x2 = c_x; y2 = c_y+c_h/2;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2'/>");
			println("		<text style='text-anchor:middle;font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='50%'>");
			println("				rdfs:subPropertyOf");
			println("			</textPath>");
			println("		</text>");
			path_counter++;
		}

		println("	</svg>");
	}

	private void printResourceViews() throws IOException
	{
		for (int i=0; i<resourceList.size(); i++)
		{
			RDF_Resource resrc = (RDF_Resource) resourceList.get(i);
			String id = "R"+i;
			printResourceView(id, resrc);
		}
	}

	private class LinkArc {
		public RDF_Resource rdf_resource;
		public RDF_Property rdf_property;

		public LinkArc(RDF_Resource resrc, RDF_Property prop)
		{
			rdf_resource = resrc;
			rdf_property = prop;
		}
		public String getPropertyLabel()
		{
			return broker.getLabelFor(rdf_property);
		}
		public String getResourceLabel()
		{
			return broker.getLabelFor(rdf_resource);
		}
		public String getResourceVizID()
		{
			return "R"+resourceList.indexOf(rdf_resource);
		}
	}

	private class SizeComparator2 implements Comparator {
		public int compare(Object o1, Object o2)
		{
			int w1 = getLabelWidth(((LinkArc)o1).getResourceLabel());
			int w2 = getLabelWidth(((LinkArc)o2).getResourceLabel());
			return (w1<w2) ? -1 : 1;
		}
		public boolean equals(Object obj)
		{
			return false;
		}
	}

	private void printResourceView(String id, RDF_Resource resrc) throws IOException
	{

		HashMap outLinks = broker.getLinksWithSubject(resrc);
		HashMap inLinks = broker.getLinksWithObject(resrc);
		Collection types = broker.getClassTypes(resrc, true);

		// getting in/out links (arcs)
		SizeComparator2 comparator = new SizeComparator2();
		TreeSet outArcs = new TreeSet(comparator);
		TreeSet inArcs = new TreeSet(comparator);
		ArrayList attributes = new ArrayList();

		String label = broker.getLabelFor(resrc);

		// check if resource is a container

		if (resrc instanceof RDF_Container)
		{
			label = "Container: "+label;
			int count = 1;
			for (Iterator i=((RDF_Container)resrc).getmember().iterator(); i.hasNext(); )
			{
				Object mem = i.next();
				RDF_Resource r = null;
                                if (mem instanceof RDF_Resource) r = (RDF_Resource)mem;
				if (r!=null) mem = broker.getLabelFor(r);
				attributes.add(count+". "+mem);
				count++;
			}
		}
		// check if resource is a statement
		if (resrc instanceof RDF_Statement)
		{
			label = "Statement: "+label;
			Object o = ((RDF_Statement)resrc).getsubject();
                        RDF_Resource r = null;
                        String s = "";
                        if (o instanceof RDF_Resource) r = (RDF_Resource)o;
			if (r!=null) s = broker.getLabelFor(r);
			attributes.add("Subject: "+s);
			o = ((RDF_Statement)resrc).getpredicate();
			r=(RDF_Resource)o;
			if (r!=null) s = broker.getLabelFor(r);
			attributes.add("Predicate: "+s);
			Object obj = ((RDF_Statement)resrc).getobject();
			// obj must be Literal or Resource
			if (obj instanceof Literal)
				s = ((Literal)obj).getvalue();
			else s = ((Resource)obj).getID();
			attributes.add("Object: "+s);
		}

		for (Iterator i=outLinks.keySet().iterator(); i.hasNext(); )
		{
			Link link = (Link)i.next();
			RDF_Property prop = (RDF_Property) outLinks.get(link);
			Object obj = link.getobject();
			// obj must be Literal or Resource
			if (obj instanceof Literal)
				attributes.add(broker.getLabelFor(prop)+" = "+((Literal)obj).getvalue());
			else
			{
                                RDF_Resource res = null;
				if (obj instanceof RDF_Resource) res = (RDF_Resource)obj;
				outArcs.add(new LinkArc(res, prop));
			}
		}
		for (Iterator i=inLinks.keySet().iterator(); i.hasNext(); )
		{
			Link link = (Link)i.next();
			RDF_Property prop = (RDF_Property) inLinks.get(link);
                        // !!! change need to be done here !!!
			Object obj = "test";
			// obj must be String
			RDF_Resource res = broker.getResourceByID((String)obj);
			inArcs.add(new LinkArc(res, prop));
		}

		// layout parameters
		int c_w; // center width
		int c_h; // center height
		int t_w; // top width
		int t_h; // top height
		int l_w; // left width
		int l_h; // left height
		int r_w; // right width
		int r_h; // right height
		int width; // view width

		c_h = 30+attributes.size()*15;
		c_w = getLabelWidth(label);
		for (Iterator i=attributes.iterator(); i.hasNext(); )
		{
			int w = getLabelWidth((String)i.next());
			if (c_w<w) c_w=w;
		}
		c_w += 10;
		if (c_w<MinFocusResourceWidth) c_w = MinFocusResourceWidth;

		if (inArcs.isEmpty())
		{
			l_w = 0;l_h = 0;
		}else {
			l_w = getWidth(((LinkArc)inArcs.toArray()[inArcs.size()-1]).rdf_resource)+10;
			l_h = (inArcs.size()+1)/2*35+50;
		}


		if (outArcs.isEmpty())
		{
			 r_w = 0; r_h = 0;
		}else {
			r_w = getWidth(((LinkArc)outArcs.toArray()[outArcs.size()-1]).rdf_resource)+10;
			r_h = (outArcs.size())/2*35+50;
		}

		int c_x; // x center
		if (l_w+c_w+r_w<DesktopViewWidth)
		{
			width = DesktopViewWidth;
			if (l_w+c_w/2<=width/2&&r_w+c_w/2<=width/2)
				c_x = width/2;
			else
			 	c_x = l_w+(width-l_w-r_w)/2;
		}else
		{
			width=l_w+c_w+r_w;
			c_x = l_w+c_w/2;
		}

		t_w = 0;
		t_h = 35;
		for (Iterator i=types.iterator(); i.hasNext(); )
		{
			int w = getRx((RDF_Class)i.next())*2;
			t_w += w+10;
			if (t_w>width-10)
			{
				t_h+=35;
				t_w = 0;
			}
		}
		t_h += 20;

		int c_y; // y center
		int mh = Math.max(l_h, r_h);
		if (mh < 100) mh=100;
		c_y = t_h+mh+c_h/2;

		int x, y, x1, y1, x2, y2; // tempo variable

		println("	<svg id='view:"+id+"' display='none' viewBox='0 0 "+DesktopViewWidth+" "+DesktopViewHeight+"'>");

		// types
		if (types.size()>0)
		{
			println("		<rect x='0' y='5' width='"+width+"' height='"+(t_h-10)+"'");
			println("			 style='fill:yellow;stroke:yellow;filter:url(#Bevel)'/>");
			y = t_h-28;
			ArrayList line = new ArrayList();
			t_w = 0;
			for (Iterator i=types.iterator(); i.hasNext(); )
			{
				RDF_Class c = (RDF_Class)i.next();
				int w = getRx(c)*2;
				if (t_w+w+10>width-10)
				{
					/* print current line */
					printClassLine(line, y, t_w, width);
					line.clear();
					t_w = w;
					y -= 35;
				}else t_w += w+10;
				line.add(c);
			}
			printClassLine(line, y, t_w, width);
			x1 = c_x; y1 = c_y - c_h/2;
			x2 = width/2; y2 = t_h-5;
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='stroke-dasharray:5,3;marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2'/>");
			if (x2 < x1)
			{
				path_counter++;
				println("		<path id='p"+path_counter+"' d='M"+x2+" "+y2+" L"+x1+" "+y1+"'");
				println("			 style='fill:none;stroke:none'/>");
			}
			println("		<text style='text-anchor:middle;font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='50%'>");
			println("				rdf:type");
			println("			</textPath>");
			println("		</text>");
			path_counter++;
		}

		// focus resource
		println("		<g transform='translate("+(c_x-c_w/2)+", "+(c_y-c_h/2)+")'>");
		println("			<rect width='"+c_w+"' height='"+c_h+"'");
		println("				 style='fill:yellow;stroke:black;stroke-width:1'/>");
		println("			<text x='"+c_w/2+"' y='18' style='text-anchor:middle'>"+label+"</text>");
		println("			<line x1='0' y1='25' x2='"+c_w+"' y2='25'");
		println("				 style='fill:none;stroke:grey;stroke-width:1'/>");
		int yinc = 40;
		for (Iterator i=attributes.iterator(); i.hasNext(); )
		{
			println("			<text x='5' y='"+yinc+"' style='font-size:12;font-family:Arial'>"+(String)i.next()+"</text>");
			yinc += 15;
		}
		println("		</g>");

		// in resource
		y = c_y-c_h/2-80;
		yinc = c_h+130;
		x = 10;
		for (Iterator i=inArcs.iterator(); i.hasNext();)
		{
			LinkArc arc = (LinkArc)i.next();
			String ref = "R"+resourceList.indexOf(arc.rdf_resource);
			println("		<use x='"+x+"' y='"+y+"' xlink:href='#_"+ref+"' onclick='view2_click(evt)'/>");

			x1 = 10+getWidth(arc.rdf_resource); y1 = y+12;
			Point[] points = Clipping.getClipped(x1, y1, c_x, c_y, c_x-c_w/2, c_x+c_w/2, c_y-c_h/2, c_y+c_h/2);
			// it must be clipped
			if (points[0].x==c_x&&points[0].y==c_y)
			{
				x2 = points[1].x; y2 = points[1].y;
			}else
			{
				x2 = points[0].x; y2 = points[0].y;
			}
			int l = (int) Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
			int k = (getLabelWidth(arc.getPropertyLabel())+l)*25/l;
			String onclick = "viewID='view:P"+propertyList.indexOf(arc.rdf_property)+"' onclick='view3_click(evt)'";
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle-"+PropertyColor+");fill:none;stroke:"+PropertyColor+";stroke-width:2'/>");
			println("		<text style='text-anchor:middle;fill:"+PropertyColor+";font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='"+k+"%' "+onclick+">");
			println("			"+arc.getPropertyLabel()+"");
			println("			</textPath>");
			println("		</text>");
			path_counter++;

			y += yinc;
			if (yinc>0) yinc = -(yinc+35);
			else yinc = -yinc+35;
		}

		// out resource
		y = c_y+c_h/2+50;
		yinc = -c_h-130;

		for (Iterator i=outArcs.iterator(); i.hasNext();)
		{
			LinkArc arc = (LinkArc)i.next();
			String ref = "R"+resourceList.indexOf(arc.rdf_resource);
			x = width-getWidth(arc.rdf_resource)-10;
			println("		<use x='"+x+"' y='"+y+"' xlink:href='#_"+ref+"' onclick='view2_click(evt)'/>");

			x2 = x; y2 = y+12;
			Point[] points = Clipping.getClipped(x2, y2, c_x, c_y, c_x-c_w/2, c_x+c_w/2, c_y-c_h/2, c_y+c_h/2);
			// it must be clipped
			if (points[0].x==c_x&&points[0].y==c_y)
			{
				x1 = points[1].x; y1 = points[1].y;
			}else
			{
				x1 = points[0].x; y1 = points[0].y;
			}
			int l = (int) Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
			int k = (getLabelWidth(arc.getPropertyLabel())+l)*25/l;
			if (k<50) k=100-k;
			String onclick = "viewID='view:P"+propertyList.indexOf(arc.rdf_property)+"' onclick='view3_click(evt)'";
			println("		<path id='p"+path_counter+"' d='M"+x1+" "+y1+" L"+x2+" "+y2+"'");
			println("			 style='marker-end:url(#marker:Triangle-"+PropertyColor+");fill:none;stroke:"+PropertyColor+";stroke-width:2'/>");
			println("		<text style='text-anchor:middle;fill:"+PropertyColor+";font-size:12;font-family:Arial'>");
			println("			<textPath xlink:href='#p"+path_counter+"' startOffset='"+k+"%' "+onclick+">");
			println("			"+arc.getPropertyLabel()+"");
			println("			</textPath>");
			println("		</text>");
			path_counter++;

			y += yinc;
			if (yinc>0) yinc = -(yinc+35);
			else yinc = -yinc+35;
		}

		println("	</svg>");
	}

/*	private class LinkArc {
		public RDF_Resource rdf_resource;
		public RDF_Property rdf_property;
		public RDF_Class    rdf_class;
		public RDF_Class 	center_class;

		public LinkArc(RDF_Resource resrc, RDF_Property prop, RDF_Class cls)
		{
			rdf_resource = resrc;
			rdf_property = prop;
			rdf_class = cls;
		}
		public String getPropertyLabel()
		{
			return broker.getLabelFor(rdf_property);
		}
		public String getResourceLabel()
		{
			return broker.getLabelFor(rdf_resource);
		}
		public String getResourceVizID()
		{
			return "R"+resourceList.indexOf(rdf_resource);
		}
	}

	private class SizeComparator2 implements Comparator {
		public int compare(Object o1, Object o2)
		{
			int w1 = getLabelWidth(((LinkArc)o1).getResourceLabel());
			int w2 = getLabelWidth(((LinkArc)o2).getResourceLabel());
			return (w1<w2) ? -1 : 1;
		}
		public boolean equals(Object obj)
		{
			return false;
		}
	}

	private void printResourceView(String id, RDF_Resource resrc) throws IOException
	{

		HashMap outLinks = broker.getLinksWithSubject(resrc);
		HashMap inLinks = broker.getLinksWithObject(resrc);
		Collection types = broker.getClassTypes(resrc, true);

		// getting in/out links (arcs)
		SizeComparator2 comparator = new SizeComparator2();
		TreeSet outArcs = new TreeSet(comparator);
		TreeSet inArcs = new TreeSet(comparator);
		ArrayList attributes = new ArrayList();


		for (Iterator i=outLinks.keySet().iterator(); i.hasNext(); )
		{
			Link link = (Link)i.next();
			RDF_Property prop = (RDF_Property) outLinks.get(link);
			Object obj = link.getobject();
			// obj must be Literal or String
			if (obj instanceof Literal)
				attributes.add(broker.getLabelFor(prop)+" = "+((Literal)obj).getvalue());
			else
			{
				RDF_Resource res = broker.getResourceByID((String)obj);
				// get type of this resource;
				RDF_Class cls = null;
				for (Iterator k=broker.getClassTypes(res, false).iterator(); k.hasNext(); )
				{
					cls = (RDF_Class)k.next();
					// transitive properties
					if (broker.getPropertiesWithRange(cls, true).contains(prop)) break;
				}
				outArcs.add(new LinkArc(res, prop, cls));
			}
		}
		for (Iterator i=inLinks.keySet().iterator(); i.hasNext(); )
		{
			Link link = (Link)i.next();
			RDF_Property prop = (RDF_Property) inLinks.get(link);
			Object obj = link.getsubject();
			// obj must be String
			RDF_Resource res = broker.getResourceByID((String)obj);
			// get type of this resource;
			RDF_Class cls = null;
			for (Iterator k=broker.getClassTypes(res, false).iterator(); k.hasNext(); )
			{
				cls = (RDF_Class)k.next();
				// transitive properties
				if (broker.getPropertiesWithDomain(cls, true).contains(prop)) break;
			}
			inArcs.add(new LinkArc(res, prop, cls));
		}

		ArrayList inClasses = new ArrayList();
		ArrayList outClasses = new ArrayList();

		for (Iterator i=types.iterator(); i.hasNext(); )
		{
			RDF_Class cls = (RDF_Class)i.next();
			Collection props = broker.getPropertiesWithDomain(cls, true);
			for (Iterator k=outArcs.iterator(); k.hasNext(); )
			{
				LinkArc arc = (LinkArc)k.next();
				if (props.contains(arc.rdf_property))
				{
					arc.center_class = cls;
					outClasses.add(arc.rdf_class);
				}
			}
			props = broker.getPropertiesWithRange(cls, true);
			for (Iterator k=inArcs.iterator(); k.hasNext(); )
			{
				LinkArc arc = (LinkArc)k.next();
				if (props.contains(arc.rdf_property))
				{
					arc.center_class = cls;
					inClasses.add(arc.rdf_class);
				}
			}
		}

		// layout parameters
		int c_w; // center width
		int c_h; // center height
		int t_w; // top width
		int t_h; // top height
		int b_w; // bottom width
		int b_h; // bottom height
		int l_w; // left width
		int l_h; // left height
		int r_w; // right width
		int r_h; // right height
		int width; // view width

		println("	<svg id='view:"+id+"' display='none' viewBox='0 0 "+DesktopViewWidth+" "+DesktopViewHeight+"'>");




	<!-- schema layer -->
	<!-- classes of the focus resource -->
 	<use x="230" y="30" xlink:href="#_Sculpture" onclick="view2_click(evt)"/>
	<use x="350" y="60" xlink:href="#_ExtResource" onclick="view2_click(evt)"/>
	<!-- in classes -->
<use x="70" y="30" xlink:href="#_Sculptor" onclick="view2_click(evt)"/>
	<path id="path:82" d="M120 30 L172 30"
			 style="marker-end:url(#marker:Triangle-blue);fill:none;stroke:blue;stroke-width:2"/>
	<text style="text-anchor:middle;fill:blue;font-size:12;font-family:Arial">
		<textPath xlink:href="#path:82" startOffset="50%">	sculpts</textPath>
	</text>
	<!-- out classes -->
	<use x="450" y="30" xlink:href="#_Museum" onclick="view2_click(evt)"/>
	<path id="path:64" d="M280 30 L392 30"
			 style="marker-end:url(#marker:Triangle-red);fill:none;stroke:red;stroke-width:2"/>
	<text style="text-anchor:middle;fill:red;font-size:12;font-family:Arial">
		<textPath xlink:href="#path:64" startOffset="50%">exhibited</textPath>
	</text>
	<!-- rdf:type, connection of the two layers -->
	<path d="M300 150 L230 48"
		 style="stroke-dasharray:3,3;
				marker-end:url(#marker:Triangle-cyan);fill:none;stroke:cyan;stroke-width:1"/>
	<path d="M300 150 L350 78"
		style="stroke-dasharray:3,3;
				marker-end:url(#marker:Triangle-cyan);fill:none;stroke:cyan;stroke-width:1"/>
	<path d="M140 80 L70 48"
		 style="stroke-dasharray:3,3;
				marker-end:url(#marker:Triangle-cyan);fill:none;stroke:cyan;stroke-width:1"/>
	<path d="M370 250 L450 48"
		 style="stroke-dasharray:3,3;
				marker-end:url(#marker:Triangle-cyan);fill:none;stroke:cyan;stroke-width:1"/>
	<!-- resource description layer -->
	<!-- the focus resource -->
	<g transform="translate(150, 150)">
		<rect width="300" height="45"
			 style="fill:yellow;stroke:black;stroke-width:1"/>
		<use x="150" y="18" xlink:href="#r15" style="text-anchor:middle"/>
		<line x1="0" y1="25" x2="300" y2="25"
			 style="fill:none;stroke:black;stroke-width:1"/>
		<text x="5" y="40" style="font-size:12;font-family:Arial">title = "Crucifixion"</text>
	</g>
	<!-- in resources -->
	<use x="20" y="80" xlink:href="#_r4" onclick="view2_click(evt)"/>
	<path id="path:36" d="M150 105 L250 145"
		 style="marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2"/>
	<text style="text-anchor:middle;fill:black;font-size:12;font-family:Arial">
		<textPath xlink:href="#path:36" startOffset="50%">sculpts	</textPath>
	</text>
	<!-- out resources -->
	<use x="250" y="250" xlink:href="#_r14" onclick="view2_click(evt)"/>
	<path id="path:37" d="M300 195 L350 245"
		 style="marker-end:url(#marker:Triangle);fill:none;stroke:black;stroke-width:2"/>
	<text style="text-anchor:middle;fill:black;font-size:12;font-family:Arial">
		<textPath xlink:href="#path:37" startOffset="50%">exhibited</textPath>
	</text>
		println("	</svg>");
	}*/
}