content: /******************************************************************************
  * Copyright 2013-2016 LASIGE                                                  *
  *                                                                             *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may     *
  * not use this file except in compliance with the License. You may obtain a   *
  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0           *
  *                                                                             *
  * Unless required by applicable law or agreed to in writing, software         *
  * distributed under the License is distributed on an "AS IS" BASIS,           *
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.    *
  * See the License for the specific language governing permissions and         *
  * limitations under the License.                                              *
  *                                                                             *
  *******************************************************************************
  * Displays a mapping graphically, and shows detailed information about it.    *
  *                                                                             *
  * @author Daniel Faria, Catia Pesquita & Catarina Martins                     *
  ******************************************************************************/
  package aml.ui;
   
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.Dimension;
  import java.awt.FlowLayout;
  import java.awt.GraphicsEnvironment;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.Set;
  import java.util.Vector;
  
  import javax.swing.BoxLayout;
  import javax.swing.JButton;
  import javax.swing.JCheckBox;
  import javax.swing.JDialog;
  import javax.swing.JLabel;
  import javax.swing.JMenu;
  import javax.swing.JMenuBar;
  import javax.swing.JMenuItem;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTabbedPane;
  import javax.swing.SwingConstants;
  import javax.swing.border.BevelBorder;
  import javax.swing.border.TitledBorder;
  
  import org.gephi.graph.api.DirectedGraph;
  import org.gephi.graph.api.Edge;
  import org.gephi.graph.api.GraphController;
  import org.gephi.graph.api.GraphModel;
  import org.gephi.graph.api.Node;
  import org.gephi.layout.plugin.force.StepDisplacement;
  import org.gephi.layout.plugin.force.yifanHu.YifanHuLayout;
  import org.gephi.layout.plugin.labelAdjust.LabelAdjust;
  import org.gephi.preview.api.PreviewController;
  import org.gephi.preview.api.PreviewModel;
  import org.gephi.preview.api.PreviewProperty;
  import org.gephi.preview.api.ProcessingTarget;
  import org.gephi.preview.api.RenderTarget;
  import org.gephi.preview.types.DependantColor;
  import org.gephi.preview.types.DependantOriginalColor;
  import org.gephi.preview.types.EdgeColor;
  import org.gephi.project.api.ProjectController;
  import org.openide.util.Lookup;
  
  import aml.AML;
  import aml.filter.QualityFlagger;
  import aml.filter.RepairMap;
  import aml.match.Alignment;
  import aml.match.Mapping;
  import aml.ontology.Lexicon;
  import aml.ontology.Ontology;
  import aml.ontology.RelationshipMap;
  import aml.ontology.URIMap;
  import aml.ontology.ValueMap;
  import aml.settings.LexicalType;
  import aml.settings.MappingRelation;
  import aml.settings.MappingStatus;
  import aml.util.Table2Set;
  import processing.core.PApplet;
  import aml.settings.EntityType;
   
  
  public class ViewMapping extends JDialog implements ActionListener
  {
  	
  //Attributes
  	
  	//Constants
  	private static final long serialVersionUID = 4516245633857479148L;
    	private static final int MAX_RETRIES = 5;
    	
    	//Ontology and Alignment attributes
  	private AML aml;
  	private URIMap uris;
  	private RelationshipMap rm;
  	private Ontology source, target;
    	private Alignment a;
  	private int mapping, sourceId, targetId;
  	private Mapping m;
  	private EntityType t;
  
  	//Dimensions
  	private int width;
  	private int height;
  	
  	//Components
  	private JMenuBar menu;
  	private JMenu view;
  	private JMenuItem next, previous, options, redraw;
  	private JTabbedPane tabbedPane;
  	private PApplet mappingViewer;
  	private JPanel details, conflicts, sourcePanel, targetPanel;
  	private Vector<JCheckBox> check;
  	private Vector<Mapping> mappings;
  	private Vector<MappingButton> mappingButtons;
  	private Vector<JLabel> labels;
  	private JButton reset, setCorrect, setIncorrect;
  	
  	//Graph components
  	private GraphModel model;
    	private DirectedGraph directedGraph;
    	private HashSet<Integer> nodes;
    	private Table2Set<Integer,Integer> edges;
    	private int classDistance;
    	private float[] sourceColor, targetColor;
  
  //Constructors
    	
      public ViewMapping()
      {
          super();
          //Set the size & colors
          GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
  		Dimension screenSize = env.getMaximumWindowBounds().getSize();
  		width = screenSize.width;
  		height = screenSize.height;
       	this.setMinimumSize(new Dimension((int)(width*0.9),(int)(height*0.9)));
       	this.setPreferredSize(new Dimension((int)(width*0.9),(int)(height*0.9)));
  		sourceColor = new float[3];
  		AMLColor.BLUE.getRGBColorComponents(sourceColor);
  		targetColor = new float[3];
  		AMLColor.BROWN.getRGBColorComponents(targetColor);
  		
       	//Get the ontologies and alignment
       	aml = AML.getInstance();
  		source = aml.getSource();
  		target = aml.getTarget();
  		uris = aml.getURIMap();
          rm = aml.getRelationshipMap();
          
          //Setup the menu bar
          menu = new JMenuBar();
          view = new JMenu("View");
          next = new JMenuItem("Next Mapping");
          next.addActionListener(this);
          view.add(next);
          previous = new JMenuItem("Previous Mapping");
          previous.addActionListener(this);
          view.add(previous);
          view.addSeparator();
          redraw = new JMenuItem("Refresh");
          redraw.addActionListener(this);
          view.add(redraw);
          view.addSeparator();
          options = new JMenuItem("Graph Options");
          options.addActionListener(this);
          view.add(options);
          menu.add(view);
          this.setJMenuBar(menu);
          
          refresh();
      }
      
  //Public Methods
      
  	@Override
  	public void actionPerformed(ActionEvent e)
  	{
  		Object b = e.getSource();
  		if(b == redraw)
  		{
  			this.refresh();			
  		}
  		else if(b == next)
  		{
  			mapping++;
  			if(mapping >= a.size())
  				aml.goTo(0);
  			else
  				aml.goTo(mapping);
  			this.refresh();			
  		}
  		else if(b == previous)
  		{
  			mapping--;
  			if(mapping < 0)
  				aml.goTo(a.size() - 1);
  			else
  				aml.goTo(mapping);
  			this.refresh();
  		}
  		else if(b == options)
  		{
  			String lang = aml.getLabelLanguage();
  			boolean anc = aml.showAncestors();
  			boolean des = aml.showDescendants();
  			int cls = aml.getClassDistance();
  			int ind = aml.getIndividualDistance();
  			new ViewOptions();
  			if(!lang.equals(aml.getLabelLanguage()) ||
  					anc != aml.showAncestors() ||
  					des != aml.showDescendants() ||
  					cls != aml.getClassDistance() ||
  					ind != aml.getIndividualDistance())
  				this.refresh();
  		}
  		else if(b == reset)
  		{
  			for(int i = 0; i < check.size(); i++)
  			{
  				if(check.get(i).isSelected())
  				{
  					Mapping n = mappings.get(i);
  					check.get(i).setSelected(false);
  					if(n.getStatus().equals(MappingStatus.UNKNOWN))
  						continue;
  					int index = a.getIndex(n.getSourceId(),n.getTargetId());
  					a.get(index).setStatus(MappingStatus.UNKNOWN);
  					aml.refreshMapping(index);
  					mappingButtons.get(i).refresh();
  				}
  			}
  		}
  		else if(b == setCorrect)
  		{
  			for(int i = 0; i < check.size(); i++)
  			{
  				if(check.get(i).isSelected())
  				{
  					Mapping n = mappings.get(i);
  					check.get(i).setSelected(false);
  					if(n.getStatus().equals(MappingStatus.CORRECT))
  						continue;
  					int index = a.getIndex(n.getSourceId(),n.getTargetId());
  					a.get(index).setStatus(MappingStatus.CORRECT);
  					aml.refreshMapping(index);
  					mappingButtons.get(i).refresh();
  				}
  			}
  		}
  		else if(b == setIncorrect)
  		{
  			for(int i = 0; i < check.size(); i++)
  			{
  				if(check.get(i).isSelected())
  				{
  					Mapping n = mappings.get(i);
  					check.get(i).setSelected(false);
  					if(n.getStatus().equals(MappingStatus.INCORRECT))
  						continue;
  					int index = a.getIndex(n.getSourceId(),n.getTargetId());
  					a.get(index).setStatus(MappingStatus.INCORRECT);
  					aml.refreshMapping(index);
  					mappingButtons.get(i).refresh();
  				}
  			}
  		}
  		else
  		{
  			int index = mappingButtons.indexOf(b);
  			if(index > -1)
  			{
  				Mapping n = mappings.get(index);
  				index = a.getIndex(n.getSourceId(),n.getTargetId());
  				aml.goTo(index);
  				refresh();
  			}
  		}		
  	}
  
  //Private Methods
      
  	private void refresh()
  	{
  		a = aml.getAlignment();
  		mapping = aml.getActiveMapping();
          m = a.get(mapping);
          sourceId = m.getSourceId();
          targetId = m.getTargetId();
          t = uris.getType(sourceId);
          
          //Set the title and modality
          this.setTitle(m.toGUI());
  		this.setModalityType(ModalityType.APPLICATION_MODAL);
  
          //Setup the Tabbed Pane
          tabbedPane = new JTabbedPane();
          tabbedPane.setBackground(AMLColor.WHITE);
  
          //Add the graph
          buildGraph();
          if(mappingViewer != null)
          {
          	tabbedPane.addTab("Graph View", mappingViewer);
          	mappingViewer.mouseClicked();
          }
          else
          	tabbedPane.addTab("Graph View", new JPanel());
          JLabel lab1 = new JLabel("Graph View",SwingConstants.CENTER);
          lab1.setPreferredSize(new Dimension(120, 15));
          tabbedPane.setTabComponentAt(0, lab1);
          //Add the details
          buildDetailPanel();
          tabbedPane.addTab("Details", details);
          JLabel lab2 = new JLabel("Details",SwingConstants.CENTER);
          lab2.setPreferredSize(new Dimension(120, 15));
          tabbedPane.setTabComponentAt(1, lab2);
          //Add the issues
          buildConflictPanel();
          tabbedPane.addTab("Status & Conflicts", conflicts);
          JLabel lab3 = new JLabel("Status & Conflicts",SwingConstants.CENTER);
          lab3.setPreferredSize(new Dimension(120, 15));
          tabbedPane.setTabComponentAt(2, lab3);
          
          //Set the tabbed pane as the content pane
  		setContentPane(tabbedPane);
  		
  		//Wrap up
  		this.pack();
  		GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment();
  		int left = g.getCenterPoint().x - (int)(this.getPreferredSize().width / 2);
  		this.setLocation(left, 0);
          this.setVisible(true);
  	}
  	
      //Builds the Mapping graph using the Gephi Toolkit
  	private void buildGraph()
  	{
  		//Initialize a project and therefore a workspace
  		ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
  		pc.newProject();
  		//Initialize the graph-building variables
  		GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
  		model = graphController.getModel();
  		directedGraph = model.getDirectedGraph();
  		//Initialize the node sets (which don't include the starting nodes)
  		nodes = new HashSet<Integer>();
  		edges = new Table2Set<Integer,Integer>();
  		//Get the maximum distance
  		classDistance = aml.getClassDistance();
  		
  		//Add the starting source and target nodes to the graph
  		addNode(sourceId,8);
  		addNode(targetId,8);
  		//And the mapping between them
  		addMapping(sourceId,targetId);
  		//Add all ancestors and descendants as per the view parameters
  		if(aml.showAncestors())
  		{
  			addAncestors(sourceId);
  			addAncestors(targetId);
  		}
  		if(aml.showDescendants())
  		{
  			addDescendants(sourceId);
  			addDescendants(targetId);
  		}
  		if(t.equals(EntityType.INDIVIDUAL))
  			addInstancedClasses();
  		else if(t.equals(EntityType.CLASS))
  		{
  			addEquiv(sourceId);
  			addEquiv(targetId);
  		}
  		//Add all additional mappings of the initial nodes
  		addOtherMappings(sourceId,targetId);
  		//Now find if there are any mappings between the node sets and add them
  		addAllMappings();
  		//Finally, render the graph
  		renderGraph();
  	}
  	
  	//Builds the details panel
  	private void buildDetailPanel()
  	{
  		//Setup the panels
  		details = new JPanel();
  		details.setLayout(new BoxLayout(details, BoxLayout.Y_AXIS));
  		JPanel topFiller = new JPanel();
  		topFiller.setPreferredSize(new Dimension(topFiller.getPreferredSize().width,10));
  		topFiller.setMaximumSize(new Dimension(topFiller.getMaximumSize().width,10));
  		details.add(topFiller);
  		
  		if(t.equals(EntityType.CLASS))
  		{
  			sourcePanel = buildClassDetailPanel(sourceId);
  			sourcePanel.setBorder(new TitledBorder("Source Class:"));
  			targetPanel = buildClassDetailPanel(targetId);
  			targetPanel.setBorder(new TitledBorder("Target Class:"));
  		}
  		else if(t.equals(EntityType.INDIVIDUAL))
  		{
  			sourcePanel = buildIndivDetailPanel(sourceId);
  			sourcePanel.setBorder(new TitledBorder("Source Individual:"));
  			targetPanel = buildIndivDetailPanel(targetId);
  			targetPanel.setBorder(new TitledBorder("Target Individual:"));
  		}
  		else
  		{
  			sourcePanel = buildPropDetailPanel(sourceId);
  			sourcePanel.setBorder(new TitledBorder("Source Property:"));
  			targetPanel = buildPropDetailPanel(targetId);
  			targetPanel.setBorder(new TitledBorder("Target Property:"));
  		}
  		
  		//Set the sizes of the subpanels and add them to the details panel
  		sourcePanel.setPreferredSize(new Dimension((int)(width*0.85),sourcePanel.getPreferredSize().height));
  		sourcePanel.setMaximumSize(new Dimension((int)(width*0.85),sourcePanel.getPreferredSize().height));
  		details.add(sourcePanel);
  		JPanel midFiller1 = new JPanel();
  		midFiller1.setPreferredSize(new Dimension(midFiller1.getPreferredSize().width,10));
  		midFiller1.setMaximumSize(new Dimension(midFiller1.getMaximumSize().width,10));
  		details.add(midFiller1);
  		targetPanel.setPreferredSize(new Dimension((int)(width*0.85),targetPanel.getPreferredSize().height));
  		targetPanel.setMaximumSize(new Dimension((int)(width*0.85),targetPanel.getPreferredSize().height));
  		details.add(targetPanel);
  		JPanel midFiller2 = new JPanel();
  		midFiller2.setPreferredSize(new Dimension(midFiller2.getPreferredSize().width,10));
  		midFiller2.setMaximumSize(new Dimension(midFiller2.getMaximumSize().width,10));
  		details.add(midFiller2);
  		//Initialize and construct the mapping panel
  		JPanel mappingPanel = new JPanel();
  		mappingPanel.setLayout(new BoxLayout(mappingPanel, BoxLayout.Y_AXIS));
  		mappingPanel.setBorder(new TitledBorder("Mapping:"));
          JLabel type = new JLabel("<html>Type: <i>" + t + " Mapping</i></html>");
  		mappingPanel.add(type);
          JLabel sim = new JLabel("<html>Final Similarity: <i>" + m.getSimilarityPercent() + "</i></html>");
          mappingPanel.add(sim);
          if(t.equals(EntityType.CLASS))
          {
  	        QualityFlagger qf = aml.getQualityFlagger();
  	        if(qf != null)
  	        {
  	        	Vector<String> labels = qf.getLabels();
  	        	for(int i = 0; i < labels.size(); i++)
  	        	{
  	        		JLabel simQ = new JLabel("<html>" + labels.get(i) + "<i>" +
  	        				qf.getSimilarityPercent(sourceId,targetId,i) + "</i></html>");
  	        		mappingPanel.add(simQ);
  	        	}
  	        }
          }
  		//Set its size and add it to the details panel
  		mappingPanel.setPreferredSize(new Dimension((int)(width*0.85),mappingPanel.getPreferredSize().height));
  		mappingPanel.setMaximumSize(new Dimension((int)(width*0.85),mappingPanel.getPreferredSize().height));
  		details.add(mappingPanel);
  		JPanel bottomFiller = new JPanel();
  		details.add(bottomFiller);
  	}
  	
  	//Builds the conflict panel
  	private void buildConflictPanel()
  	{
  		conflicts = new JPanel();
  		conflicts.setLayout(new BoxLayout(conflicts, BoxLayout.Y_AXIS));
  		
  		//The header button panel
  		setCorrect = new JButton("Set Correct");
  		setCorrect.setBackground(AMLColor.GREEN);
  		setCorrect.setPreferredSize(new Dimension(110,28));
  		setCorrect.addActionListener(this);
  		reset = new JButton("Reset");
  		reset.setBackground(AMLColor.GRAY);
  		reset.setPreferredSize(new Dimension(110,28));
  		reset.addActionListener(this);
  		setIncorrect = new JButton("Set Incorrect");
  		setIncorrect.setBackground(AMLColor.RED);
  		setIncorrect.setPreferredSize(new Dimension(110,28));
  		setIncorrect.addActionListener(this);
  		JPanel sub = new JPanel();
  		sub.setBorder(new BevelBorder(1));
  		sub.add(setCorrect);
  		sub.add(reset);
  		sub.add(setIncorrect);
  		JPanel headerPanel = new JPanel(new FlowLayout());
  		headerPanel.setMaximumSize(new Dimension((int)(width*0.9),40));
  		headerPanel.add(sub);
  		conflicts.add(headerPanel);
  		
  		JPanel mappingPanel = new JPanel();
  		mappingPanel.setLayout(new BoxLayout(mappingPanel, BoxLayout.Y_AXIS));
  		check = new Vector<JCheckBox>();
  		mappingButtons = new Vector<MappingButton>();
  		mappings = new Vector<Mapping>();
  		labels = new Vector<JLabel>();
  		
  		mappings.add(m);
  		labels.add(new JLabel("[Active Mapping]"));
  		for(Mapping n : a.getConflicts(m))
  		{
  			mappings.add(n);
  			labels.add(new JLabel("[Cardinality Conflict]"));
  		}
  		RepairMap rMap = aml.getRepairMap();
  		if(rMap != null)
  		{
  			for(Mapping n : rMap.getConflictMappings(m))
  			{
  				if(!mappings.contains(n))
  				{
  					mappings.add(n);
  					labels.add(new JLabel("[Coherence Conflict]"));
  				}
  				else
  				{
  					labels.get(mappings.indexOf(n)).setText("[Cardinality & Coherence Conflict]");
  				}
  			}
  		}
  		for(int i = 0; i < mappings.size(); i++)
  		{
  			JCheckBox c = new JCheckBox(""); 
  			check.add(c);
  			MappingButton b = new MappingButton(mappings.get(i));
  			mappingButtons.add(b);
  			if(!mappings.get(i).equals(m))
  				b.addActionListener(this);
  			JPanel subPanel = new JPanel(new BorderLayout());
  			subPanel.add(c,BorderLayout.LINE_START);
  			JPanel subSubPanel = new JPanel(new BorderLayout());
  			subSubPanel.add(b,BorderLayout.LINE_START);
  			subSubPanel.add(labels.get(i), BorderLayout.CENTER);
  			subPanel.add(subSubPanel, BorderLayout.CENTER);
  			subPanel.setMaximumSize(new Dimension(subPanel.getMaximumSize().width,28));
  			subPanel.setPreferredSize(new Dimension(subPanel.getPreferredSize().width,28));
  			mappingPanel.add(subPanel);
  		}		
  		JPanel filler = new JPanel();
  		mappingPanel.add(filler);
  		JScrollPane scrollPane = new JScrollPane(mappingPanel);
  		scrollPane.setBorder(new BevelBorder(1));
  		conflicts.add(scrollPane);
  	}
  
  //Auxiliary Methods for buildGraph()
  	
  	//Adds all mappings between listed nodes to the graph
  	private void addAllMappings()
  	{
  		if(a == null)
  			return;
  		for(int i : nodes)
  		{
  			for(int j : a.getSourceMappings(i))
  				if(nodes.contains(j))
  					addMapping(i, j);
  			for(int j : a.getTargetMappings(i))
  				if(nodes.contains(j))
  					addMapping(j, i);
  		}
  	}
  	
  	//Adds all ancestors of the given entity to the graph
  	private void addAncestors(int id)
  	{
  		HashSet<Integer> ancestors = new HashSet<Integer>();
  		ancestors.add(id);
  		HashSet<Integer> descendants;
  		if(t.equals(EntityType.CLASS))
  		{
  			for(int i = 0; i < classDistance; i++)
  			{
  				descendants = new HashSet<Integer>(ancestors);
  				ancestors = new HashSet<Integer>();
  				for(int j : descendants)
  				{
  					Set<Integer> parents = rm.getParents(j);
  					for(int k : parents)
  					{
  						if(directedGraph.getNode("" + k) == null)
  							addNode(k, 6);
  						if(!edges.contains(j,k) && !edges.contains(k,j))
  							addEdge(j, k, rm.getRelationship(j, k).getProperty());
  					}
  					ancestors.addAll(parents);
  				}
  				nodes.addAll(ancestors);
  			}
  		}
  		else if(t.equals(EntityType.INDIVIDUAL))
  		{
  			for(int k : rm.getIndividualActiveRelations(id))
  			{
  				Set<Integer> rels = rm.getIndividualProperties(id, k);
  				if(rels.size() > 0)
  				{
  					if(directedGraph.getNode("" + k) == null)
  						addNode(k, 6);
  					if(!edges.contains(id,k) && !edges.contains(k,id))
  						addEdge(id, k, rels.iterator().next());
  				}
  				nodes.add(k);
  			}
  		}
  	}
  	
  	//Adds all descendants of the given entity to the graph
  	private void addDescendants(int id)
  	{
  		HashSet<Integer> descendants = new HashSet<Integer>();
  		descendants.add(id);
  		HashSet<Integer> ancestors;
  		if(t.equals(EntityType.CLASS))
  		{
  			for(int i = 0; i < classDistance; i++)
  			{
  				ancestors = new HashSet<Integer>(descendants);
  				descendants = new HashSet<Integer>();
  				for(int j : ancestors)
  				{
  					Set<Integer> children = rm.getChildren(j);
  					for(int k : children)
  					{
  						if(directedGraph.getNode("" + k) == null)
  							addNode(k, 6);
  						if(!edges.contains(j,k) && !edges.contains(k,j))
  							addEdge(k, j, rm.getRelationship(k, j).getProperty());
  					}
  					descendants.addAll(children);
  				}
  				nodes.addAll(descendants);
  			}
  		}
  	}
  	
  	//Adds an anonymous edge between two entities to the graph (for subclass relations)
  	private void addEdge(int child, int parent)
  	{
  		edges.add(child, parent);
  		Node c = directedGraph.getNode("" + child);
  		Node p = directedGraph.getNode("" + parent);
  		Edge e = model.factory().newEdge(c, p, 3, true);
  		if(source.contains(child) && !target.contains(child))
  			e.getEdgeData().setColor(sourceColor[0], sourceColor[1], sourceColor[2]);
  		else if(!source.contains(child) && target.contains(child))
  			e.getEdgeData().setColor(targetColor[0], targetColor[1], targetColor[2]);
  		directedGraph.addEdge(e);
  	}
  	
  	//Adds an edge between two entities to the graph with the given property's label
  	private void addEdge(int child, int parent, int prop)
  	{
  		edges.add(child, parent);
  		Node c = directedGraph.getNode("" + child);
  		Node p = directedGraph.getNode("" + parent);
  		Edge e = model.factory().newEdge(c, p, 3, true);
  		if(source.contains(child))
  		{
  			if(prop > -1)
  				e.getEdgeData().setLabel(source.getName(prop));
  			if(!target.contains(child))
  				e.getEdgeData().setColor(sourceColor[0], sourceColor[1], sourceColor[2]);
  		}
  		else if(target.contains(child))
  		{
  			if(prop > -1)
  				e.getEdgeData().setLabel(target.getName(prop));
  			e.getEdgeData().setColor(targetColor[0], targetColor[1], targetColor[2]);
  		}
  		directedGraph.addEdge(e);
  		if(rm.isSymmetric(prop) || (prop == -1 && rm.getDistance(child, parent) == 0))
  		{
  			Edge f = model.factory().newEdge(p, c, 3, true);
  			f.getEdgeData().setColor(sourceColor[0], sourceColor[1], sourceColor[2]);
  			directedGraph.addEdge(f);
  		}
  	}
  	
  	//Adds an edge between two entities to the graph with the given label
  	private void addEdge(int child, int parent, String label)
  	{
  		edges.add(child, parent);
  		Node c = directedGraph.getNode("" + child);
  		Node p = directedGraph.getNode("" + parent);
  		Edge e = model.factory().newEdge(c, p, 3, true);
  		if(source.contains(child) && !target.contains(child))
  			e.getEdgeData().setColor(sourceColor[0], sourceColor[1], sourceColor[2]);
  		else if(!source.contains(child) && target.contains(child))
  			e.getEdgeData().setColor(targetColor[0], targetColor[1], targetColor[2]);
  		e.getEdgeData().setLabel(label);
  		directedGraph.addEdge(e);
  	}
  	
  	//Adds all equivalent classes of the given class to the graph
  	private void addEquiv(int id)
  	{
  		Set<Integer> eq = rm.getEquivalences(id);
  		for(int i : eq)
  		{
  			if(directedGraph.getNode("" + i) == null)
  				addNode(i, 6);
  			addEdge(i, id);
  		}
  		nodes.addAll(eq);
  	}
  	
  	//Adds all classes instanced by the listed individuals to the graph
  	//plus their ancestors up to the classDistance limit
  	private void addInstancedClasses()
  	{
  		Set<Integer> classes = new HashSet<Integer>();
  		Set<Integer> individuals = new HashSet<Integer>(nodes);
  		for(int i : individuals)
  		{
  			for(int c : rm.getIndividualClasses(i))
  			{
  				nodes.add(c);
  				classes.add(c);
  				if(directedGraph.getNode("" + c) == null)
  					addNode(c,10);
  				if(!edges.contains(i,c) && !edges.contains(c,i))
  					addEdge(i, c, "instanceOf");
  			}
  		}
  		HashSet<Integer> ancestors = new HashSet<Integer>(classes);
  		HashSet<Integer> descendants;
  		for(int i = 0; i < classDistance; i++)
  		{
  			descendants = new HashSet<Integer>(ancestors);
  			ancestors = new HashSet<Integer>();
  			for(int j : descendants)
  			{
  				Set<Integer> parents = rm.getParents(j);
  				for(int k : parents)
  				{
  					if(directedGraph.getNode("" + k) == null)
  						addNode(k,10);
  					if(!edges.contains(j,k) && !edges.contains(k,j))
  						addEdge(j, k);
  				}
  				ancestors.addAll(parents);
  			}
  			nodes.addAll(ancestors);
  		}
  	}
  	
  	//Adds a mapping between two classes to the graph
  	private void addMapping(int sId, int tId)
  	{
  		Node n1 = directedGraph.getNode("" + sId);
  		Node n2 = directedGraph.getNode("" + tId);
  		if(directedGraph.getEdge(n1,n2) != null)
  			return;
  		MappingRelation r = a.getRelationship(sId,tId);
  		MappingStatus s = a.get(sId,tId).getStatus();
  		float[] edgeColor = new float[3];
  		if(s.equals(MappingStatus.CORRECT))
  			edgeColor = Color.GREEN.getRGBColorComponents(edgeColor);
  		else if(s.equals(MappingStatus.INCORRECT))
  			edgeColor = Color.RED.getRGBColorComponents(edgeColor);
  		else if(s.equals(MappingStatus.FLAGGED))
  			edgeColor = Color.ORANGE.getRGBColorComponents(edgeColor);
  		else
  			edgeColor = Color.GRAY.getRGBColorComponents(edgeColor);
  		if(!r.equals(MappingRelation.SUPERCLASS))
  		{
  			Edge e1 = model.factory().newEdge(n1, n2, 3, true);
  			e1.getEdgeData().setColor(edgeColor[0], edgeColor[1], edgeColor[2]);
  			e1.getEdgeData().setLabel(a.getSimilarityPercent(sId,tId));
  			directedGraph.addEdge(e1);
  		}
  		if(!r.equals(MappingRelation.SUBCLASS))
  		{
  			Edge e2 = model.factory().newEdge(n2, n1, 3, true);
  			e2.getEdgeData().setColor(edgeColor[0], edgeColor[1], edgeColor[2]);
  			if(r.equals(MappingRelation.SUPERCLASS))
  				e2.getEdgeData().setLabel(a.getSimilarityPercent(sId,tId));
  			directedGraph.addEdge(e2);
  		}
  	}
  	
  	//Adds a node to the graph
  	private void addNode(int id, int size)
  	{
  		Node n = model.factory().newNode("" + id);
  		if(source.contains(id))
  		{
  			n.getNodeData().setLabel(source.getName(id));
  			if(!target.contains(id))
  				n.getNodeData().setColor(sourceColor[0], sourceColor[1], sourceColor[2]);
  		}
  		else if(target.contains(id))
  		{
  			n.getNodeData().setLabel(target.getName(id));
  			n.getNodeData().setColor(targetColor[0], targetColor[1], targetColor[2]);			
  		}
  		n.getNodeData().setSize(size);
  		directedGraph.addNode(n);
  	}
  	
  	//Adds other entities mapped to the entities in the central mapping
  	private void addOtherMappings(int sId, int tId)
  	{
  		Set<Integer> sourceMappings = a.getSourceMappings(sId);
  		for(Integer i : sourceMappings)
  		{
  			if(i == tId)
  				continue;
  			if(!nodes.contains(i))
  			{
  				nodes.add(i);
  				addNode(i,6);
  			}
  			addMapping(sId,i);
  			if(aml.showAncestors())
  				addAncestors(i);
  			if(aml.showDescendants())
  				addDescendants(i);
  		}
  		Set<Integer> targetMappings = a.getTargetMappings(tId);
  		for(Integer i : targetMappings)
  		{
  			if(i == sId)
  				continue;
  			if(!nodes.contains(i))
  			{
  				nodes.add(i);
  				addNode(i,6);
  			}
  			addMapping(i,tId);
  			if(AML.getInstance().showAncestors())
  				addAncestors(i);
  			if(AML.getInstance().showDescendants())
  				addDescendants(i);
  		}
  	}
  	
  	//Graph rendering procedure with placement heuristic
  	private void renderGraph()
  	{
  		//Finally, try to render the graph
  		for(int i = 0; i < MAX_RETRIES; i++)
  		{
  			try
  			{
  				//Run YifanHuLayout for 100 passes - The layout always takes the current visible view
  				YifanHuLayout layout = new YifanHuLayout(null, new StepDisplacement(1f));
  				layout.setGraphModel(model);
  				layout.resetPropertiesValues();
  				layout.setOptimalDistance(300f);
  				layout.setBarnesHutTheta(0.2f);
  				layout.initAlgo();
  				for (int j = 0; j < 100 && layout.canAlgo(); j++)
  					layout.goAlgo();
  			
  				//Run LabelAdjust to stop labels from overlapping
  				LabelAdjust labela = new LabelAdjust(null);
  				labela.resetPropertiesValues();
  				labela.initAlgo();
  				for (int j = 0; j < 30 && labela.canAlgo(); j++)
  					labela.goAlgo();
  				
  				//Initialize and configure preview
  				PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class);
  				PreviewModel previewModel = previewController.getModel();
  				//Configure node labels
  				previewModel.getProperties().putValue(PreviewProperty.SHOW_NODE_LABELS, true);
  				previewModel.getProperties().putValue(PreviewProperty.NODE_LABEL_OUTLINE_COLOR, new DependantColor(AMLColor.WHITE));
  				previewModel.getProperties().putValue(PreviewProperty.NODE_LABEL_OUTLINE_SIZE, 5f);
  				previewModel.getProperties().putValue(PreviewProperty.NODE_LABEL_COLOR, new DependantOriginalColor(AMLColor.BLACK));
  				//Configure edges
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_CURVED, false);
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_OPACITY, 100);
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_RADIUS, 5f);
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_COLOR, new EdgeColor(EdgeColor.Mode.ORIGINAL));
  				//Configure edge labels
  				previewModel.getProperties().putValue(PreviewProperty.SHOW_EDGE_LABELS, true);
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_LABEL_COLOR, new DependantOriginalColor(AMLColor.DARK_GRAY));
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_LABEL_OUTLINE_COLOR, new DependantColor(AMLColor.WHITE));
  				previewModel.getProperties().putValue(PreviewProperty.EDGE_LABEL_OUTLINE_SIZE, 2f);
  				//Configure background color
  				previewModel.getProperties().putValue(PreviewProperty.BACKGROUND_COLOR, AMLColor.WHITE);
  				previewController.refreshPreview();
  				//Initialize the processing target and the PApplet
  				ProcessingTarget target = (ProcessingTarget) previewController.getRenderTarget(RenderTarget.PROCESSING_TARGET);
  				mappingViewer = target.getApplet();
  				mappingViewer.init();
  				//Refresh the preview and reset the zoom
  				previewController.render(target);
  				target.refresh();
  				target.resetZoom();
  				//If successful, return
  				return;
  			}
  			catch(Exception e)
  			{
  				//Otherwise keep trying
  				continue;
  			}
  		}
  		//If not successful after the retry limit, set mappingViewer to null
  		mappingViewer = null;
  	}
  	
  //Auxiliary Methods for buildDetailPanel()
  	
  	private JPanel buildClassDetailPanel(int id)
  	{
  		JPanel p = new JPanel();
  		p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
  
  		Ontology o;
  		if(source.contains(id))
  			o = source;
  		else
  			o = target;
  		Lexicon lex = o.getLexicon();
  		
  		//Get the local name
          JLabel localName = new JLabel("<html>Local Name: <i>" +
          		uris.getLocalName(id) + "</i></html>");
          p.add(localName);
          //Labels
          String lab = "<html>Label(s): ";
          Set<String> names = lex.getNames(id,LexicalType.LABEL);
  		for(String s : names)
  			lab += "<i>" + s + "</i>; ";
  		if(names.size() == 0)
  			lab += "N/A</html>";
  		else
  			lab = lab.substring(0, lab.length()-2) + "</html>";
          JLabel label = new JLabel(lab);
          p.add(label);
          //Synonyms
          names = lex.getNames(id,LexicalType.EXACT_SYNONYM);
  		if(names.size() > 0)
  		{
  	        lab = "<html>Exact Synonyms(s): ";
  			for(String s : names)
  				lab += "<i>" + s + "</i>; ";
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  	        JLabel exact = new JLabel(lab);
  	        p.add(exact);
  		}
          names = lex.getNames(id,LexicalType.OTHER_SYNONYM);
  		if(names.size() > 0)
  		{
  	        lab = "<html>Other Synonyms(s): ";
  			for(String s : names)
  				lab += "<i>" + s + "</i>; ";
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  	        JLabel other = new JLabel(lab);
  	        p.add(other);
  		}
          //Formulas
          names = lex.getNames(id,LexicalType.FORMULA);
  		if(names.size() > 0)
  		{
  	        lab = "<html>Formula(s): ";
  			for(String s : names)
  				lab += "<i>" + s + "</i>; ";
  				lab = lab.substring(0, lab.length()-2) + "</html>";
  	        JLabel form = new JLabel(lab);
  	        p.add(form);
  		}
  		
  		//High Level Ancestors
  		Set<Integer> highSet = rm.getHighLevelAncestors(id);
  		lab = "<html>Ontology Branch(es): ";
  		for(Integer i : highSet)
  			lab += "<i>" + o.getName(i) + "</i>; ";
  		if(highSet.size() == 0)
  			lab += "N/A</html>";
  		else
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  		JLabel high = new JLabel(lab);
  		p.add(high);
  		
  		//Parents
  		Set<Integer> parents = rm.getParents(id);
  		Table2Set<Integer,Integer> relParents = new Table2Set<Integer,Integer>();
  		for(Integer i : parents)
  			relParents.add(rm.getRelationship(id, i).getProperty(), i);
  		Vector<Integer> rels = new Vector<Integer>(relParents.keySet());
  		Collections.sort(rels);
  		for(Integer r : rels)
  		{
  			if(r == -1)
  				lab = "<html>subClassOf: ";
  			else
  				lab = "<html>" + o.getName(r) + ": ";
  			for(Integer a : relParents.get(r))
  				lab += "<i>" + o.getName(a) + "</i>; ";
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  			JLabel ancs = new JLabel(lab);
  			p.add(ancs);
  		}
  		
  		//And Disjoints
  		Set<Integer> disjointSetSource = rm.getDisjointTransitive(id);
  		if(disjointSetSource.size() != 0)
  		{
  			lab = "<html>disjointWith: ";
  			for(Integer i : disjointSetSource)
  				lab += "<i>" + o.getName(i) + "</i>; ";
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  			JLabel disjointsS = new JLabel(lab);
  			p.add(disjointsS);
  		}
  		if(o.isObsoleteClass(id))
  		{
  			JLabel obsS = new JLabel("<html><b><font color=\"red\"> Obsolete Class!</font></b></html>");
  			p.add(obsS);
  		}
  		return p;
  	}
  	
  	private JPanel buildIndivDetailPanel(int id)
  	{
  		JPanel p = new JPanel();
  		p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
  		
  		Ontology o;
  		if(source.contains(id))
  			o = source;
  		else
  			o = target;
  		//Get the local name
          JLabel localName = new JLabel("<html>Local Name: <i>" +
          		uris.getLocalName(id) + "</i></html>");
          p.add(localName);
          //Labels
          String lab = "<html>Label: " + o.getName(id);
          JLabel label = new JLabel(lab);
          p.add(label);
  		
  		//Classes
  		Set<Integer> classes = rm.getIndividualClasses(id);
  		lab = "<html>instanceOf: ";
  		for(Integer i : classes)
  			lab += "<i>" + o.getName(i) + "</i>; ";
  		if(classes.size() == 0)
  			lab += "N/A</html>";
  		else
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  		JLabel high = new JLabel(lab);
  		p.add(high);
  		
  		//Relations
  		Table2Set<String,String> relMap = new Table2Set<String,String>();
  		for(Integer i : rm.getIndividualActiveRelations(id))
  			for(Integer j : rm.getIndividualProperties(id, i))
  				relMap.add(o.getName(j),o.getName(i));
  		Vector<String> rels = new Vector<String>(relMap.keySet());
  		Collections.sort(rels);
  		for(String r : rels)
  		{
  			lab = "<html>" + r + ": ";
  			for(String s : relMap.get(r))
  				lab += "<i>" + s + "</i>; ";
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  			JLabel ancs = new JLabel(lab);
  			p.add(ancs);
  		}
  		
  		//Data Properties
  		ValueMap vm = o.getValueMap();
  		for(Integer v : vm.getProperties(id))
  		{
  			lab = "<html>" + o.getName(v) + ": ";
  			for(String s : vm.getValues(id, v))
  				lab += "<i>" + s + "</i>; ";
  			lab = lab.substring(0, lab.length()-2) + "</html>";
  			JLabel ancs = new JLabel(lab);
  			p.add(ancs);
  		}
  		return p;
  	}
  	
  	private JPanel buildPropDetailPanel(int id)
  	{
  		JPanel p = new JPanel();
  		p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
  
  		Ontology o;
  		if(source.contains(id))
  			o = source;
  		else
  			o = target;
  		Lexicon lex = o.getLexicon();
  		
  		//Get the local name
          JLabel localName = new JLabel("<html>Local Name: <i>" +
          		uris.getLocalName(id) + "</i></html>");
          p.add(localName);
          //Labels
          String lab = "<html>Label(s): ";
          Set<String> names = lex.getNames(id,LexicalType.LABEL);
  		for(String s : names)
  			lab += "<i>" + s + "</i>; ";
  		if(names.size() == 0)
  			lab += "N/A</html>";
  		else
  			lab = lab.substring(0, lab.length()-2) + "</html>";
          JLabel label = new JLabel(lab);
          p.add(label);
          
  		if(t.equals(EntityType.OBJECT))
  		{
  			Set<Integer> domain = rm.getDomains(id);
  			lab = "<html>Domain: ";
  			for(Integer i : domain)
  				lab += "<i>" + o.getName(i) + "</i>; ";
  			if(domain.size() > 0)
  				lab = lab.substring(0, lab.length()-2) + "</html>";
  			else
  				lab += "N/A</html>";
  			JLabel domainS = new JLabel(lab);
  			p.add(domainS);
  			
  			Set<Integer> range = rm.getObjectRanges(id);
  			lab = "<html>Range: ";
  			for(Integer i : range)
  				lab += "<i>" + o.getName(i) + "</i>; ";
  			if(range.size() > 0)
  				lab = lab.substring(0, lab.length()-2) + "</html>";
  			else
  				lab += "N/A</html>";
  			JLabel rangeS = new JLabel(lab);
  			p.add(rangeS);
  			if(rm.isFunctional(id))
  			{
  				JLabel funS = new JLabel("Functional Property");
  				p.add(funS);
  			}
  		}
  		else if(t.equals(EntityType.DATA))
  		{
  			Set<Integer> domain = rm.getDomains(id);
  			lab = "<html>Domain: ";
  			for(Integer i : domain)
  				lab += "<i>" + o.getName(i) + "</i>; ";
  			if(domain.size() > 0)
  				lab = lab.substring(0, lab.length()-2) + "</html>";
  			else
  				lab += "N/A</html>";
  			JLabel domainS = new JLabel(lab);
  			p.add(domainS);
  			
  			Set<String> range = rm.getDataRanges(id);
  			lab = "Range: ";
  			for(String s : range)
  				lab += "<i>" + s + "</i>; ";
  			if(range.size() > 0)
  				lab = lab.substring(0, lab.length()-2) + "</html>";
  			else
  				lab += "N/A</html>";
  			JLabel rangeS = new JLabel(lab);
  			p.add(rangeS);
  			if(rm.isFunctional(id))
  			{
  				JLabel funS = new JLabel("Functional Property");
  				p.add(funS);
  			}
  		}
  		return p;
  	}
  }