/**********************************************************************
 * Copyright (c) 2008 CA Inc. and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * CA - Initial API and implementation
 *
 * $Id: GraphResponseOutputter.java,v 1.28 2008/09/03 08:55:13 lrichards Exp $
 **********************************************************************/

package org.eclipse.cosmos.internal.dr.drs.service.outputter;
	
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Iterator;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.cosmos.common.provisional.exceptions.CosmosException;
import org.eclipse.cosmos.internal.dr.drs.service.handler.common.ILogger;
import org.eclipse.cosmos.internal.dr.drs.service.handler.common.LoggerWrapper;
import org.eclipse.cosmos.internal.dr.drs.service.handler.common.XMLUtil;
import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.AbstractOutputter;
import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.IOutputterContext;
import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.IParameters;
import org.eclipse.cosmos.provisional.dr.ps.common.IConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class GraphResponseOutputter extends AbstractOutputter {

	public static final String XMLXTREAM="org.eclipse.cosmos.dr.drs.service.handler.xml.XMLStream";; //$NON-NLS-1$
	public static final String XML_NAMESPACE="http://cmdbf.org/schema/1-0-0/datamodel"; //$NON-NLS-1$

	private StringBuffer DetailBuffer = null;
	private StringBuffer ARTBuffer = null;
	private Vector<ItemData> _nodes = null;
	private Vector<ItemData> _edges = null;
	protected static ILogger logger = LoggerWrapper.getLogger(GraphResponseOutputter.class);
	
	private InternalUtility ut = null;
	protected String rootId;
	protected String rootDir;

	public GraphResponseOutputter() {
		ut = new InternalUtility();
		DetailBuffer = new StringBuffer();
		ARTBuffer = new StringBuffer();
		_nodes = new Vector<ItemData>();
		_edges = new Vector<ItemData>();
	}
	
	public void initalize(IOutputterContext context, IParameters parameters) throws Exception {
		this.rootDir = context.getRealPath(IConstants.QUERYREPO+File.separator + IConstants.RESPONSEDIR);		
		super.initalize(context, parameters);
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.cosmos.dr.drs.service.handler.sml.IOutputter#render(java.io.PrintWriter, java.util.Map)
	 * Entry point from the UI
	 *
	 */
	public void render(PrintWriter output, IParameters input) throws Exception {
		String queryResponse = input.getParameter("queryResponse"); //$NON-NLS-1$
		String historyId = input.getParameter("historyId"); //$NON-NLS-1$
		String uuid = input.getParameter("uuid"); //$NON-NLS-1$
		
		if (historyId != null){			
			queryResponse = null; 
			String historyFilename = rootDir+File.separator + uuid+File.separator+historyId+"."+IConstants.RESPONSEEXT; //$NON-NLS-1$
			File file = new File(historyFilename);
			if (file.exists()){
				StringBuffer buffer = new StringBuffer();
				FileInputStream fis = null;
//				ByteArrayOutputStream bos = null;
				try {
					fis = new FileInputStream(file);
//					bos = new ByteArrayOutputStream();
		
					int i;
					 
					while ((i = fis.read()) != -1)
					   buffer.append((char)i);
					 
					fis.close();
					 
				} finally {
			
					if (fis != null)
						fis.close();
			
				}
				queryResponse = buffer.toString();
			}
		}
		if (queryResponse != null){
			Element response = deserialize(queryResponse);
				
			GraphResponseOutputter local = new GraphResponseOutputter();
			local.render(output, response);
		}
	}

	protected Object getId(Object value){
		return idResolver.getId(value);
	}

	public void render(PrintWriter output, Element response) throws CosmosException {
		 StringBuffer buffer = new StringBuffer("{ items : ["); //$NON-NLS-1$
		 buffer.append(renderElements(response));
		 buffer.append("]}"); //$NON-NLS-1$
		 output.println(buffer.toString());
	}
	
	public Element deserialize(String xmlString) throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true);
		DocumentBuilder builder = factory.newDocumentBuilder();
		// Read the entire document into memory
		InputSource s = new InputSource(new StringReader(xmlString));  
		Document d = builder.parse(s);
		
		return d.getDocumentElement();
	}
	/* 
	 * Used by the entry point function called from the UI
	 * 
	 * Does not return anything, simply writes to the provided output stream
	 */
	public void render(PrintWriter pw, InputSource input) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true);
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			// Read the entire document into memory
			Document d = builder.parse(input);
			
			Element el = d.getDocumentElement();
						
			StringBuffer buffer = new StringBuffer("{ items : ["); //$NON-NLS-1$
			buffer.append(renderElements(el));
			buffer.append("]}"); //$NON-NLS-1$
			pw.println(buffer.toString());
		} catch (CosmosException e) {
			logger.error(e.getMessage(),e);
		} catch (ParserConfigurationException e) {
			logger.error(e.getMessage(), e);
		} catch (SAXException e) {
			logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	/* method to actually start doing the work, 
	 * takes an XML element 
	 * Adds bits bits for comboBox (Unique templateIds)
	 * top level table (Nodes and Edges)
	 * bottom level table (records)
	 * 
	 */
	
	protected StringBuffer renderElements(Element elem) throws CosmosException {
		StringBuffer buffer = new StringBuffer();
		StringBuffer fbuffer = new StringBuffer();
		NodeList nodes = elem.getElementsByTagNameNS(XML_NAMESPACE,"nodes"); //$NON-NLS-1$
		NodeList edges = elem.getElementsByTagNameNS(XML_NAMESPACE,"edges"); //$NON-NLS-1$
	
		fbuffer.append("{ Filter: 'All' }"); //$NON-NLS-1$
	
		ProcessNodes(nodes);
		ProcessEdges(edges);

		DumpNodesAndEdges(buffer);
		DumpFilterBuffer(fbuffer);
		
		buffer.append(fbuffer);
		buffer.append(DetailBuffer);
		buffer.append(ARTBuffer);
		return buffer;
	}
	
	/* 
	 * top level table - nodes from the XML query response
	 * walk through the nodelist, processing each node individually.
	 */
	
	protected boolean ProcessNodes(NodeList n) throws CosmosException {
		int i = 0;
		Element elem = null;
		
		for (i=0;i<n.getLength();i++) {
		  Node node = n.item(i);
		  if (node.getNodeType() == Element.ELEMENT_NODE) {
			  elem = (Element) node;
			  String t = elem.getAttribute("templateId"); //$NON-NLS-1$
			  ProcessNode(elem,t);
		  }
		}
	
		return (n.getLength() > 0);
	}
	
	/* 
	 *  process an individual node, which all it does is walk through the item
	 *  list and proces each item individually.
	 */
	
	protected void ProcessNode(Element n,String templateId) throws CosmosException
	{
		NodeList items = n.getElementsByTagNameNS(XML_NAMESPACE,"item"); //$NON-NLS-1$
		Element item = null;
		int i = 0;
		
		for (i=0;i<items.getLength();i++) {
			Node node = items.item(i);
			if (node.getNodeType() == Element.ELEMENT_NODE) {
				item = (Element) node;
				ProcessItem(item,templateId,(i == 0));
			}
		}
	}
	
	protected void EdgeInstance(Element item,ItemData I)
	{
		NodeList localId = null;
		NodeList Idl = null;
		NodeList mdrId = null;
		Node m = null;
		Node l = null;
		Element Id = null;
		String lidstr = null;
		String midstr = null;
		
		Idl = item.getElementsByTagNameNS(XML_NAMESPACE,"instanceId"); //$NON-NLS-1$
		if (Idl.getLength() > 0) {
			Id = (Element) Idl.item(0);
		
			localId = Id.getElementsByTagNameNS(XML_NAMESPACE,"localId"); //$NON-NLS-1$
			l = localId.item(0);
			lidstr = XMLUtil.extractText((Element) l);
			
			mdrId = Id.getElementsByTagNameNS(XML_NAMESPACE,"mdrId"); //$NON-NLS-1$
			m = mdrId.item(0);
			midstr = XMLUtil.extractText((Element) m);
					
			I.setMdrId(midstr);
			I.setEdgeId(lidstr);
		}
	}
	/* 
	 * process an item, because this is a node, there is no Edge or Target
	 * so there's just Source (processed by addNodeInstanceId()) for the top level table
	 * and the record (processed by addRecord()) for the bottom level table
	 */
	
	protected void ProcessItem(Element item,String templateId,boolean first) throws CosmosException
	{
		NodeList Idl = null;
		Node Id = null;
		NodeList records = null;
		Element record = null;
		NodeList arts = null;
		Element art = null;
		String tlidstr = null;
		String localId = null;
		int i = 0;
		boolean artdata = false;
	    ItemData I = null;
	    
	    if (first) 
	    	I = new ItemData(templateId);
	    else 
	    	I = new ItemData();
	    	    
		Idl = item.getElementsByTagNameNS(XML_NAMESPACE,"instanceId"); //$NON-NLS-1$
		if (Idl.getLength() > 0) {
			Id = Idl.item(0);
		
			if (Id.getNodeType() == Element.ELEMENT_NODE)
				localId = addNodeInstanceId(I,(Element) Id,templateId);
			addMdrId(I,(Element) Id);
			I.setEdgeId("");
		}
		else {
			CosmosException e = new CosmosException(Messages.getString("SpecViolation"));
			logger.error(e.getMessage(),e);
			throw e;
		}
		
		I.setTLSID(ut.getTLID());
		
		tlidstr = new String(templateId + ":" + localId); //$NON-NLS-1$
		ut.addTLIDMap(tlidstr);
						
		records = item.getElementsByTagNameNS(XML_NAMESPACE,"record"); //$NON-NLS-1$
		if (records != null) {
			for (i=0;i<records.getLength();i++) {
				Node node = records.item(i);
				if (node.getNodeType() == Element.ELEMENT_NODE) {
					record = (Element) node;
					addRecord(record,false);
				}
			}
		}
		arts = item.getElementsByTagNameNS(XML_NAMESPACE,"additionalRecordType"); //$NON-NLS-1$
		if (arts != null) {
			if (arts.getLength() == 0) 
				addArt(null,false);
			else {
				for (i=0;i<arts.getLength();i++) {
					Node node = arts.item(i);
					if (node.getNodeType() == Element.ELEMENT_NODE) {
						art = (Element) node;
						artdata = true;
						addArt(art,false);
					}
				}
			}
		}
		else
			addArt(null,false);
		
		ut.newTLID();
		I.setARTData(artdata);
			
		_nodes.add(I);
	}
	
	/* 
	 *  process an art bit
	 */
	
	public void addArt(Element art,boolean edge)
	{
		NodeList Id = null;
		Node n = null;
		String tmp = null;
		
		ARTBuffer.append(","); //$NON-NLS-1$
	
		ARTBuffer.append("{ NameSpace:'"); //$NON-NLS-1$
		if (art != null) {
			Id = art.getElementsByTagNameNS(XML_NAMESPACE,"namespace"); //$NON-NLS-1$
			n = Id.item(0);
			tmp = XMLUtil.extractText((Element) n);
			ARTBuffer.append(tmp);
		}
		
		ARTBuffer.append("', LocalName:'"); //$NON-NLS-1$
		if (art != null) {
			Id = art.getElementsByTagNameNS(XML_NAMESPACE,"localName"); //$NON-NLS-1$
			n = Id.item(0);
			tmp = XMLUtil.extractText((Element) n);
			ARTBuffer.append(tmp);
		}
		
		if (edge) 
			ARTBuffer.append("', TLSID:'', TLTID:'', CosmosId: '" + ut.getCosmosId() + "' "); //$NON-NLS-1$ //$NON-NLS-2$
		else 
			ARTBuffer.append("', TLSID: '" + ut.getTLID() + "', TLTID:'', CosmosId:'' "); //$NON-NLS-1$ //$NON-NLS-2$
		ARTBuffer.append("}"); //$NON-NLS-1$
	}
	
	/* 
	 * process a record, which includes a recordId, and some fields
	 * which are currently hard coded to be null - future enhancement to change this
	 * a cosmosId to link it with the top level table and the actual content
	 * which is processed by addContent()
	 */
	
	protected void addRecord(Element record,boolean edge)
	{
		NodeList Id = null;
		Node n = null;
		String tmp = null;
		
		if (DetailBuffer.length() > 0)
			DetailBuffer.append(","); //$NON-NLS-1$
		DetailBuffer.append("{ recordId:"); //$NON-NLS-1$
		
		Id = record.getElementsByTagNameNS(XML_NAMESPACE,"recordId"); //$NON-NLS-1$
		n = Id.item(0);
		tmp = XMLUtil.extractText((Element) n);
		DetailBuffer.append("'" + tmp + "', LastModified:'',BaseLineId:'', SnapShortId:'',Detail:'"); //$NON-NLS-1$ //$NON-NLS-2$
		
		addContent(record);
		if (edge) 
			DetailBuffer.append("', TLSID:'', TLTID:'', CosmosId: '" + ut.getCosmosId() + "' "); //$NON-NLS-1$ //$NON-NLS-2$
		else 
			DetailBuffer.append("', TLSID: '" + ut.getTLID() + "', TLTID:'" + ut.getTLID() + "', CosmosId:'' "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		DetailBuffer.append("}"); //$NON-NLS-1$
	}
	
	/* 
	 * process the node content which is raw XML
	 * does 2 things
	 * strips out the new lines from the string buffer that holds the generated XML text
	 * i.e. instead of 
	 * <student> 
	 *   Mike Lee
	 * </student>
	 * 
	 * its <student>Mike Lee</Student>
	 * 
	 * and translates < to &lt and > to &gr
	 */
	
	protected void addContent(Element record)
	{
		int i = 0;
		NodeList l = record.getChildNodes();
		StringBuffer nb = new StringBuffer();
		String tmp = null;
		int idx = 0;
				
		for (i=0;i<l.getLength();i++) {
			Node node = l.item(i);
			if (node.getNodeType() == Element.ELEMENT_NODE) {
				try {
					tmp = XMLUtil.xmlToString((Element) node);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
				idx = tmp.indexOf('>');
				idx += 2;
				nb = new StringBuffer();
				nb.append(tmp.substring(idx));
				
				NewTransformXML(nb);
				DetailBuffer.append(nb);
			}
		}
	}
	public void OldTransformXML(StringBuffer nb)
	{
		int i = 0;
		
		char ltb[];
		char gtb[];
		char hash[];
		char quot[], apos[], amp[];
		
		ltb = new char[4];
		gtb = new char[4];
		hash = new char[3];
		quot = new char[6];
		amp = new char[5];
	   	    
		ltb[0] = '&';
		ltb[1] = 'l';
		ltb[2] = 't';
		ltb[3] = ';';
		
		gtb[0] = '&';
		gtb[1] = 'g';
		gtb[2] = 't';
		gtb[3] = ';';
		
		amp[0] = '&';
		amp[1] = 'a';
		amp[2] = 'm';
		amp[3] = 'p';
		amp[4] = ';';
		
		quot[0] = '&';
		quot[1] = 'q';
		quot[2] = 'u';
		quot[3] = 'o';
		quot[4] = 't';
		quot[5] = ';';
		
		hash[0] = '%';
		hash[1] = '2';
		hash[2] = '3';
		
		for (i=0;i<nb.length();i++) {
			if (nb.charAt(i) == '<') {
				nb.deleteCharAt(i);
				nb.insert(i, ltb);
			}
			else if (nb.charAt(i) == '"') {
				nb.deleteCharAt(i);
				nb.insert(i, quot);
			}
			else if (nb.charAt(i) == 160) {
				nb.deleteCharAt(i);
				nb.insert(i," "); //$NON-NLS-1$
			}
			else if (nb.charAt(i) == '&') {
				nb.deleteCharAt(i);
				nb.insert(i, amp);
			}
			else if (nb.charAt(i) == '#') {
				nb.deleteCharAt(i);
				nb.insert(i, hash);
			}
			else if (nb.charAt(i) == '>') {
				if (i != nb.length()-2) {
  				  if ((nb.charAt(i+2) == '\n') ||(nb.charAt(i+2) == '\r') ){
  					  nb.deleteCharAt(i+2);
  				  }
				}
				
				if (i != nb.length()-1) {
  				  if ((nb.charAt(i+1) == '\n') ||(nb.charAt(i+1) == '\r') )
					nb.deleteCharAt(i+1);
  					 
				}
				nb.deleteCharAt(i);
				nb.insert(i, gtb);
			}
		}
		for (i=0;i<nb.length();i++) {
			if (nb.charAt(i) == '\r')
				nb.replace(i,i+1,"\\n"); //$NON-NLS-1$
			else if (nb.charAt(i) == '\n')
				nb.replace(i,i+1,"\\n"); //$NON-NLS-1$
			else if (nb.charAt(i) == '\'') {
            	nb.insert(i,"\\"); //$NON-NLS-1$
            	i++;
            }
        }
	}	
	public void NewTransformXML(StringBuffer nb)
	{
		int i = 0;
		
		char qt[];
				
		qt = new char[3];
	    		
		qt[0] = '%';
		qt[1] = '2';
		qt[2] = '2';
		for (i=0;i<nb.length();i++) {
			if (nb.charAt(i) == '"') {
				nb.deleteCharAt(i);
				nb.insert(i, qt);
			}
			else if (nb.charAt(i) == 160) {
				nb.deleteCharAt(i);
				nb.insert(i," "); //$NON-NLS-1$
			}
		}
		for (i=0;i<nb.length();i++) {
			if (nb.charAt(i) == '\r')
				nb.replace(i,i+1,"\\n"); //$NON-NLS-1$
			else if (nb.charAt(i) == '\n')
				nb.replace(i,i+1,"\\n"); //$NON-NLS-1$
			else if (nb.charAt(i) == '\'') {
            	nb.insert(i,"\\"); //$NON-NLS-1$
            	i++;
            }
        }
	}	 	
	/*
	 * adds localId (Source)
	 * also associates whatever is in templateId with the localId
	 * so there's a Map that says for example
	 * 'staff01' = 'Teachers'
	 * 
	 */
	protected String addNodeInstanceId(ItemData I,Element Id,String templateId) 
	{
		NodeList localId = null;
		NodeList mdrId = null;
		Node l = null;
		Node m = null;
		String tmp = null;
		String midstr = null;
		
		localId = Id.getElementsByTagNameNS(XML_NAMESPACE,"localId"); //$NON-NLS-1$
		l = localId.item(0);
		tmp = XMLUtil.extractText((Element) l);
		
		mdrId = Id.getElementsByTagNameNS(XML_NAMESPACE,"mdrId"); //$NON-NLS-1$
		m = mdrId.item(0);
		midstr = XMLUtil.extractText((Element) m);
		
		I.setSource(templateId + ":" + tmp); //$NON-NLS-1$
		
		ut.addTemplateIdMap(templateId,midstr,tmp);
				
		return tmp;
	}
	
	/* 
	 * processes the edges, which walks the list of edges and processes each of those individually.
	 */
	
	protected void ProcessEdge(Element e,String templateId) {
		NodeList rs = e.getElementsByTagNameNS(XML_NAMESPACE,"relationship"); //$NON-NLS-1$
		Element r = null;
		int i = 0;
				
		for (i=0;i<rs.getLength();i++) {
			Node node = rs.item(i);
			if (node.getNodeType() == Element.ELEMENT_NODE) {
				r = (Element) node;
				ProcessRelationship(r,templateId,(i == 0));
			}
		}
	}
	
	/*
	 * process an edge, which walks the list of relationships and processes each of thoes individually
	 */
	
	protected boolean ProcessEdges(NodeList e) {
		int i = 0;
		Element elem = null;
		
		
		for (i=0;i<e.getLength();i++) {
			Node node = e.item(i);
			if (node.getNodeType() == Element.ELEMENT_NODE) {
				elem = (Element) node;
			    String t = elem.getAttribute("templateId"); //$NON-NLS-1$
		   	    ProcessEdge(elem,t);
			}
		}
		return (e.getLength() > 0);
	}
	
	/* processes a relationship
	 * 
	 * a relationship has a Source, Target and a Record
	 * So each of these are processed in turn, the Source and Target are part of the top level table
	 * and the record is part of the bottom level table.
	 * 
	 * the addRecord() is the same method used by Node processing
	 * but the InstanceId is a little different as it has to retrieve info from the attrs map as oppose
	 * to put it in.
	 */
	
	protected void ProcessRelationship(Element r,String templateId,boolean first) {
		NodeList records = null;
		Element record = null;
		NodeList arts = null;
		Element art = null;
		NodeList sl = null;
		Node s = null;
		NodeList tl = null;
		Node t = null;
		int i = 0;
		String tlsid = null;
		String tltid = null;
		boolean artdata = false;
		ItemData I = null;
		
		if (first)
			I = new ItemData(templateId);
		else
			I = new ItemData();
		
		sl = r.getElementsByTagNameNS(XML_NAMESPACE,"source"); //$NON-NLS-1$
		s = sl.item(0);
		if (s.getNodeType() == Element.ELEMENT_NODE)
			tlsid = addEdgeInstanceId(I,(Element) s,"Source",true); //$NON-NLS-1$
		
		I.setEdge(templateId);
				
		tl = r.getElementsByTagNameNS(XML_NAMESPACE,"target"); //$NON-NLS-1$
		t = tl.item(0);
		if (t.getNodeType() == Element.ELEMENT_NODE)
			tltid = addEdgeInstanceId(I,(Element) t,"Target",false); //$NON-NLS-1$
				
		//I.setTLSID(Integer.valueOf(tlsid).intValue());
		//I.setTLTID(Integer.valueOf(tltid).intValue());
		I.setCosmosId(ut.getCosmosId());
		
	 EdgeInstance(r,I);
				
		records = r.getElementsByTagNameNS(XML_NAMESPACE,"record"); //$NON-NLS-1$

		if (records != null) {
			for (i=0;i<records.getLength();i++) {
				Node node = records.item(i);
				if (node.getNodeType() == Element.ELEMENT_NODE) {
					record = (Element) node;
					addRecord(record,true);
				}
			}
		}
		arts = r.getElementsByTagNameNS(XML_NAMESPACE,"additionalRecordType"); //$NON-NLS-1$
		if (arts != null) {
			if (arts.getLength() == 0) 
				addArt(null,true);
			else {
				for (i=0;i<arts.getLength();i++) {
					Node node = arts.item(i);
					if (node.getNodeType() == Element.ELEMENT_NODE) {
						art = (Element) node;
						artdata = true;
						addArt(art,true);
					}
				}
			}
		}
		else
			addArt(null,true);
		
		ut.newCosmosId();			
		I.setARTData(artdata);
		
		_edges.add(I);
	}

	/* 
	 * This is a multi purpose method used by the edge processing methods
	 * it adds the localId 
	 * 
	 * prefix can be 'Source' or 'Target'
	 * c is a boolean indicated whether or not a comma is needed after the entry
	 *
	 * also retrieved the mapping so if it gets 'staff01' it can then say for example
	 * 'Source: teachers:staff01'
	 */
	
	protected String addEdgeInstanceId(ItemData I,Element Id,String prefix,boolean src) 
	{
		NodeList localId = null;
		Node l = null;
		String tmp = null;
		NodeList mdrId = null;
		Node m = null;
		String midstr = null;
		
		String templateId = null;
		String tlidstr = null;

		localId = Id.getElementsByTagNameNS(XML_NAMESPACE,"localId"); //$NON-NLS-1$
		l = localId.item(0);
		tmp = XMLUtil.extractText((Element) l);
		
		mdrId = Id.getElementsByTagNameNS(XML_NAMESPACE,"mdrId"); //$NON-NLS-1$
		m = mdrId.item(0);
		midstr = XMLUtil.extractText((Element) m);
		
		templateId = ut.FindByValue(tmp,midstr);
		
		//tlidstr = new String(templateId + ":" + tmp); //$NON-NLS-1$
		tlidstr = new String(tmp);
		
		if (src)
			I.setSource(tlidstr);
		else
			I.setTarget(tlidstr);
		
		
		return ut.MapTLID(tlidstr);
	}
	
	/*
	 * adds MdrId found in the instanceId
	 * 
	 */
	
	protected void addMdrId(ItemData I,Element Id) 
	{
		NodeList mdrId = null;
		Node l = null;
		String tmp = null;
		
		mdrId = Id.getElementsByTagNameNS(XML_NAMESPACE,"mdrId"); //$NON-NLS-1$
		l = mdrId.item(0);
		tmp = XMLUtil.extractText((Element) l);
		I.setMdrId(tmp);
	}

	private void DumpNodesAndEdges(StringBuffer b)
	{
		// FilterDupNodes();
		boolean c = DumpList(_nodes,b,false);
		if (c)
			b.append(","); //$NON-NLS-1$
		c = DumpList(_edges,b,false);
		if (c)
			b.append(","); //$NON-NLS-1$
	}

	private void DumpFilterBuffer(StringBuffer b)
	{
		boolean n = DumpList(_nodes,b,true);
		boolean e = DumpList(_edges,b,true);
		if (e || n)
			b.append(","); //$NON-NLS-1$
	}
	private boolean DumpList(Vector v,StringBuffer b,boolean filter)
	{
		boolean ret = false;
		Iterator<ItemData> I = null;
		ItemData d = null;
				
		I = v.iterator();
		while (I.hasNext())
		{
			d = I.next();
			if (!filter && ret)
				b.append(","); //$NON-NLS-1$
			
			if (filter) {
				if (d.PrintForFilter(b))
					ret = true;
			}
			else {
				d.Print(b);
				ret = true;
			}
		}	
		return ret;
	}
	private void FilterDupNodes()
	{
		Iterator<ItemData> e = null;
		
		ItemData d = null;
		ItemData nd = null;
		
		e = _edges.iterator();
		
		while (e.hasNext())
		{
			d = e.next();
			nd = CheckNodeList(d.getSource());
			if (nd != null) 
				_nodes.remove(nd);
			
			nd = CheckNodeList(d.getTarget());
			if (nd != null) 
				_nodes.remove(nd);
		
		}
	}	
	private ItemData CheckNodeList(String Id)
	{
		Iterator<ItemData> n = null;
		n = _nodes.iterator();
		ItemData nd = null;
		
		while (n.hasNext())
		{
			nd = n.next();
			if (nd.getSource().equals(Id))
				return nd;
		}
		return null;
	}
}

/*
 * This class facilitates the mapping between templateId/localId and their associated records
 * which are displayed separated in the graph response viewer widget
 * in brief, nodes key on the TLID and edges key on cosmosId
 */

class InternalUtility {
	private int _cosmosId = 1;
	private int _TLID = 1;
	
	private Vector _mdrIds = null;
	private Vector _templateIds = null;
	private Vector _mapValues = null;
	private Vector _tlidm = null;
	private Vector _tlidv = null;

	public InternalUtility()
	{
		_cosmosId = 1;
		_TLID = 1;
		
		_mdrIds = new Vector();
		_templateIds = new Vector();
		_mapValues = new Vector();

		_tlidm = new Vector();
		_tlidv = new Vector();
	}
	
	int getCosmosId() { return _cosmosId; }
	void newCosmosId() { _cosmosId++; }
	
	int getTLID() { return _TLID; }
	void newTLID() { _TLID++; }
	
	/*
	 * lookup key by value
	 */
	
	public String FindByValue(String v,String mdrId) {
		String t = null;
		String m = null;
		String d = null;
		int i = 0;
		
		for (i=0;i<_templateIds.size();i++) {
			t = (String) _templateIds.get(i);
			m = (String) _mapValues.get(i);
			d = (String) _mdrIds.get(i);
			
			if (m.equals(v) && d.equals(mdrId)) 
					return t;
		}
		return null;
	}
	
	public String MapTLID(String v) {
		String t = null;
		String m = null;
		int i = 0;
		
		for (i=0;i<_tlidv.size();i++) {
			t = (String) _tlidv.get(i);
			m = (String) _tlidm.get(i);
				
			if (m.equals(v)) 
				return t;
		}
		return null;
	}
	
	public void addTemplateIdMap(String templateId,String mdrId,String localId) 
	{
		_mdrIds.add(mdrId);
		_templateIds.add(templateId);
		_mapValues.add(localId);
	}
	
	public void addTLIDMap(String tlid)
	{
		_tlidm.add(tlid);
		_tlidv.add(String.valueOf(_TLID));
	}
}

class ItemData
{
	private String _Source = null;
	private String _Edge = null;
	private String _Target = null;
	private int _TLSID = 0;
	private int _TLTID = 0;
	private int _CosmosId = 0;
	private String _MdrId = null;
	private boolean _ARTData = false;
	private String _templateId = null;
	private String _EdgeId = null;
	
	public ItemData() { /* nop */ }
	public ItemData(String tid) {
		_templateId = tid;
	}
	
	public void debug() {
		GraphResponseOutputter.logger.info("Source: " + _Source + " " + ((_templateId != null) ? _templateId : "**") + " " + ((_Target != null) ? _Target : "NT")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
	}
	String getSource() { return _Source; };
	String getEdge() { return _Edge; };
	String getTarget() { return _Target; };
	int getTLSID() { return _TLSID; };
	int getTLTID() { return _TLTID; };
	int getCosmosId() { return _CosmosId; };
	String getMdrId() { return _MdrId; };
	boolean getARTData() { return _ARTData; }
	String getEdgeId() { return _EdgeId; }
	
	void setSource(String s) { _Source = s; };
	void setEdge(String e) { _Edge = e; };
	void setTarget(String t) { _Target = t; };
	void setTLSID(int sid) { _TLSID = sid; };
	void setTLTID(int tid) { _TLTID = tid; };
	void setCosmosId(int c) { _CosmosId = c; };
	void setMdrId(String m) { _MdrId = m; };
	void setARTData(boolean a) { _ARTData = a; }
	void setEdgeId(String e) { _EdgeId = e; }
	
	boolean PrintForFilter(StringBuffer b) {
		if (_templateId != null) {
			if (_Edge == null)
				b.append(",{ Filter: 'Node: " + _templateId + "' }"); //$NON-NLS-1$ //$NON-NLS-2$
			else
				b.append(",{ Filter: 'Edge: " + _templateId + "' }"); //$NON-NLS-1$ //$NON-NLS-2$
			return true;
		}
		else
			return false;
	}
	
	void Print(StringBuffer b) { 
		b.append("{ Source:'" + _Source + "',"); //$NON-NLS-1$ //$NON-NLS-2$
		
		if (_Edge != null)
			b.append("Edge:'" + _Edge + "',"); //$NON-NLS-1$ //$NON-NLS-2$
		else
			b.append("Edge:'',"); //$NON-NLS-1$
		
		if (_Target != null)
			b.append("Target:'" + _Target + "',"); //$NON-NLS-1$ //$NON-NLS-2$
		else
			b.append("Target:'',"); //$NON-NLS-1$
		
		if (_TLSID > 0) 
			b.append("TLSID:'" + _TLSID + "', "); //$NON-NLS-1$ //$NON-NLS-2$
		else
			b.append("TLSID:'', "); //$NON-NLS-1$
		
		if (_TLTID > 0) 
			b.append("TLTID:'" + _TLTID + "',"); //$NON-NLS-1$ //$NON-NLS-2$
		else
			b.append("TLTID:'',"); //$NON-NLS-1$
		
		if (_CosmosId > 0)
			b.append("CosmosId:'" + _CosmosId + "', "); //$NON-NLS-1$ //$NON-NLS-2$
		else
			b.append("CosmosId:'', "); //$NON-NLS-1$
		
		b.append("MdrId:'" + _MdrId + "', "); //$NON-NLS-1$ //$NON-NLS-2$
	    if ((_EdgeId == null) || (_EdgeId.length() == 0))
	    	b.append("EdgeId:'', "); //$NON-NLS-1$ //$NON-NLS-2$
	    else
	    	b.append("EdgeId:'" + _EdgeId + "', "); //$NON-NLS-1$ //$NON-NLS-2$
		b.append("ARTData:'" + ((_ARTData) ? "Y" : "N") + "'}"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
	}
	
}