DCR.js

// +--------------------------------------------------------------------------+ \\
// ¦ DCR 1.0 - DCR Graphs Library, All Copy Rights Reserved by DCRSolutions   ¦ \\
// +--------------------------------------------------------------------------¦ \\
// ¦ Author Shahzad Mirza, DCRSolutions, TEO                                  ¦ \\
// +--------------------------------------------------------------------------+ \\
/* Main DCR Library Function 
* @example
*	<!doctype html>
*	<html>
*	<head>
*	    <meta charset="utf-8">
*	    <title>Demo App</title>
*	</head>
*	<body>
*	    <script src="jquery.js"></script>
*	    <script src="xml2json.js"></script>
*	    <script src="DCR.js"></script>	
*	    <script>
*		// We can create Apps with the DCR library and can fill out the missing functionalities of DCR Library with these Apps.
* 		//Example plugin to display Events by Roles in list items fashion
* 		;(function (DCR) {
*			DCR.fn.showEventsByRoles = function (reqContainer) {
*				$('#'+reqContainer).append('<h4>Roles</h4>');
*				var outPut = '<ul>';
*				for (var i = 0; i < this.Roles.length; i++) {
*					var curRoleNEvents = this.getEventsByRole(this.Roles[i]);
*					outPut += '<li>'+this.Roles[i]+'</li>';
*					if(curRoleNEvents.length>0){
*						outPut += '<ul>';
*						for (var j = 0; j < curRoleNEvents.length; j++) {
*							outPut += '<li>'+curRoleNEvents[j].custom.label+'</li>';
*						};
*						outPut += '</ul>';
*					}
*				};
*				outPut += '</ul>';
*				$('#'+reqContainer).append(outPut);
*			}
*		})(DCR)
*		// Basic Demo application HTML structure and how to include the Library files:
*		$(document).ready(function () {
*	 		var myApp = new DCR();
* 			
*			$('#loadGraph').on('click', function () {
*				var fileXML = $('#xmlInput').val();
*				if(fileXML==" " || fileXML == ""){
*					alert('Invalid Input');
*					return;
*				}
*				myApp.loadXML(fileXML).showEventsByRoles("result");
*				//graph will reset first by default by this function just in case user clicks several time
*				//so each time new graph is to be laoded properly
*			});
*	    })
*	 
*	    </script>
*		<textarea id="xmlInput"></textarea>
*		<input type="submit" id="loadGraph" value="Load DCR Graph" />
*		<div id="result"></div>
*	</body>
*	</html>
 */
(function (window, fun) {
    // AMD support
    if (typeof define === "function" && define.amd) {
        // Define as an anonymous module
        define([], function() {
            return fun(window);
        });
    } else {
        // DCR adds itself to window
        fun(window);
    }
}(window, function (window) {

		/** global functions */
		/** This function will find distance between two points, will return the distance as Number. This function is used in the DCR to create connections mostly.
		*
		* @function lineDistance
		*
		* @param {object} point1 First Point containing x and y location
		* @param {object} point2 Second Point containing x and y location
		*
		* @example lineDistance({'x':10, 'y':10}, {'x':20, 'y':20});
		* // returns 14.142135623730951
		*
		* @returns {Number} Returns the distance between two points.
		*/
		lineDistance = function( point1, point2 ) {
			var xs = 0;
			var ys = 0;
			 
			xs = point2.x - point1.x;
			xs = xs * xs;
			 
			ys = point2.y - point1.y;
			ys = ys * ys;
			 
			return Math.sqrt( xs + ys );
		}

		//this function gets a point on the line at and distance provided in as d
		getPointOnLine = function (P1, P2, d, LStart) {
			var mag = lineDistance(P1, P2); 
			if(mag===0){
				mag = 0.5;
			}
			if(LStart==true){
				d = -mag-d;
			}
			var P3x = P2.x + d * (P2.x - P1.x) / mag;
			var P3y = P2.y + d * (P2.y - P1.y) / mag;
			//console.clear();
			//console.log(P3x+'------'+P3y);

			return {x:P3x, y:P3y};
		}

		//this function gets middle point on the line and returns the distance
		getMiddlePointOnLine = function (P1, P2){
			var xd = P1.x - P2.x;
			var yd = P1.y - P2.y;
			return Math.sqrt(xd * xd + yd * yd);
		}
		toNumber = function (n) {
		   var nStr = (n + ""); 
		   if(nStr.indexOf(".") > -1) 
		      nStr = nStr.replace(".","").replace(/\d+$/, function(m){ return --m; });
		   return nStr.replace(/(\d+)e\+?(\d+)/, function(m, g1, g2){
		      return g1 + new Array(+g2).join("0") + "";
		   })
		}
    
		replaceSlashes = function (str) {
			return (str + '').replace(/\\/g, '\\\\');
		}

		fixSlashes = function (str) {
			//'\\'.replace(/\\/g, '&#92;');
			return (str + '').replace(/\\\\/g, '\\');
		}
		isInteger = function (num) {
			  return (num ^ 0) === num;
		}

		isDate = function(date) {
		    return (new Date(date) !== "Invalid Date") && !isNaN(new Date(date));
		}

		//http://stackoverflow.com/questions/770523/escaping-strings-in-javascript
		addSlashes = function(str) {
		    return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
		}

		/** This function will convert a string to XML friendly version by converting the potential HTML tags to thier unicodes, it is used with the htmlEncode Function
		*
		* @function htmlEscape
		*
		* @param {string} str String to esape the HTML tags
		*
		* @example htmlEscape('<div>test</div>');
		* //returns "&lt;div&gt;test&lt;/div&gt;"
		*
		* @returns {string} Returns the escaped string.
		*/
		htmlEscape = function(str) {
		    return String(str)
		    		.replace(/&/g, '&amp;')
		            .replace(/"/g, '&quot;')
		            //.replace(/'/g, '&#39;')
		            .replace(/'/g, '&apos;')
		            .replace(/</g, '&lt;')
		            .replace(/>/g, '&gt;')
		}

		htmlEscapeEntity = function (str) {
		    return String(str)
		            .replace(/&/g, '&#38;')
		            .replace(/"/g, '&#34;')
		            .replace(/'/g, '&#39;')
		            .replace(/</g, "&#60;")
		            .replace(/>/g, '&#62;')
		}

		/** This function will Encode an HTML string to XML friendly version, it is used with the htmlEncode Function, it create a in-memory div, set it's inner text(which jQuery automatically encodes) then grab the encoded contents back out.  The div never exists on the page.
		*
		* @function htmlEncode
		*
		* @param {string} value String HTML to be Encoded
		*
		* @example htmlEncode('<div>test</div>');
		* //returns "&lt;div&gt;test&lt;/div&gt;"
		*
		* @see {@link htmlEscape} for further information.
		*
		* @returns {string} Returns the Encoded string.
		*/
		htmlEncode = function(value){
		  //console.log($('<div/>').text(value).html());
		  value = $('<div/>').text(value).text();
		  value = htmlEscape(value);
		  return value;//$('<div/>').text(value).html();
		}

		/** This function will Decode a string to HTML friendly version.
		* @function htmlDecode
		*
		* @param {string} value String HTML to be Encoded
		*
		* @example htmlDecode("&lt;div&gt;test&lt;/div&gt;");
		* //returns '<div>test</div>'
		*
		* @returns {string} Returns the Decode string as HTML.
		*/
		htmlDecode = function (value){
			//console.log($('<div/>').html(value).text());
		  return $('<div/>').html(value).text();
		}

		//converting events to objects/json
		function parseXML( events){
			var arr = [];
			var skipElements = [];
			var fragmentElements = [];
			//setting up parentId on each event
			$(events).each(function(index, el){
				var curType = el.getAttribute("type");

				if($(el).attr('parentId')==undefined || el.parentNode.nodeName == 'event'){
					$(el).attr('parentId',el.parentNode.getAttribute('id'));
					$(el).attr('parentGUID',el.parentNode.getAttribute('guid'));
				}
				if((curType=="form" && el.getAttribute("referId")!=undefined) || ((curType=="form" || curType=="subprocess") && el.getAttribute("fragmentId")!=undefined && el.getElementsByTagName("dcrgraph").length>0)){
					//if referred event, remove all of its childs from events array
					$(el).find("events event").each(function (idx, elx) {
						skipElements.push(elx)
					})
				}

				
				//console.log(el);
				if($.inArray(el, skipElements)<0){
					//if this is form element then don't process it now
					arr.push($.xml2json(el))
				}
				
			});

			return arr;
		}

		//same as events converting function but generic
		xmlToJsonArray = function (obj){
			var arr = [];
			$(obj).each(function(index, el){
					if(!this.hasAttribute('type')){
						this.setAttribute('type', this.nodeName);
					}
					this.setAttribute('nodeType', this.nodeName);
					arr.push($.xml2json(this));
			});
			return arr;
			
		}

		/** Function to convert a string to XML document format.
		*
		* @function stringToXML
		*
		* @param {string} oString - String to be converted as XML document
		*
		* @example stringToXML('<div>test</div>');
		* //returns and XML document
		*
		* @returns {XML} Returns the string as an XML document.
		*/
		stringToXML = function (oString) {
			//code for IE
			if (window.ActiveXObject) {
				var oXML = new ActiveXObject("Microsoft.XMLDOM"); oXML.loadXML(oString);
				return oXML;
			}
			// code for Chrome, Safari, Firefox, Opera, etc.
			else {
				return (new DOMParser()).parseFromString(oString, "text/xml");
			}
		}


		//function to sort array of objects based on the attr to sort provided
		sortArray = function (prop, arr, isNumber) {
		    prop = prop.split('.');
		    var len = prop.length;

		    arr.sort(function (a, b) {
		        var i = 0;
		        while (i < len) {
		            a = a[prop[i]];
		            b = b[prop[i]];
		            i++;
		        }

		        if (isNumber) {
		            a = parseInt(a, 0);
		            b = parseInt(b, 0);
		        }else{
		        	a = a.toLowerCase();
		        	b = b.toLowerCase();
		        }

		        if (a < b) {
		            return -1;
		        } else if (a > b) {
		            return 1;
		        } else {
		            return 0;
		        }
		    });
		    return arr;
		}



		/** Function to convert an XML document format to string. 
		*
		* @function XMLtoString
		*
		* @param {string} oXML - XML to be converted as string.
		*
		* @returns {string} Returns the XML document as string.
		*/
		XMLtoString = function (oXML) {
			return new XMLSerializer().serializeToString(oXML);
		}

		/** Function to get a value of an attibute's value in the URL.
		*
		* @function getQueryVariable
		*
		* @param {string|number} variable - A variable to found its value.
		*
		* @returns {string|number} Returns the value of an attribute passed.
		*/
		getQueryVariable = function (variable) {
	    	var query = window.location.search.substring(1);
	         var vars = query.split("&");
	         for (var i=0;i<vars.length;i++) {
	                 var pair = vars[i].split("=");
	                 if(pair[0] == variable){return pair[1];}
	         }
	         return(false);
	    };

	    /** Function to check if item exists in and array of objects based on the property provided.
		*
		* @function checkForMatch
		*
		* @param {array} array Array in which the item should be looked for
		* @param {string} propertyToMatch Item to be matched
		* @param {string} valueToMatch Item to be matched with
		* @param {boolean} lowerCase Check if the values to be matched should both be compared in lowercase or not
		*
		* @returns {integer} Returns returns the index of the element, if element not found then returns -1.
		*/
		checkForMatch = function (array, propertyToMatch, valueToMatch, lowerCase){
			if(lowerCase==true){
				 for(var i = 0; i < array.length; i++){
		        	if(array[i][propertyToMatch].toLowerCase() == valueToMatch.toLowerCase())
		            return i;
		    	}
		    }else{
		    	for(var i = 0; i < array.length; i++){
			        if(array[i][propertyToMatch] == valueToMatch)
			            return i;
			    }
		    }
		    return -1;
		}

		/** Function to return value of Object
		*
		* @function getPropValue
		*
		* @param {array} array Array in which the item should be looked for
		* @param {string} propertyToMatch Item to be matched
		*
		* @returns {any} Returns value of property.
		*/
		getPropValue = function(obj, key) {
			return key.split(".").reduce(function(o, x) {
				return (typeof o == "undefined" || o === null || 0 === undefined) ? undefined : o[x];
			}, obj);
		}

		hasProp = function(obj, key) {
			return key.split(".").every(function(x) {
				if(typeof obj != "object" || obj === null || obj === undefined || ! x in obj)
					return false;
				obj = obj[x];
				return true;
			});
		}

		function checkPath(base, path) {
			var current = base;
			var components = path.split(".");
			for (var i = 0; i < components.length; i++) {
				if ((typeof current !== "object") || (!current.hasOwnProperty(components[i]))) {
					return false;
				}
				current = current[components[i]];
			}
			return true;
		}
		

		//function to find and event in the DCR graphXML, graphXML should be in XML format
		findInXML = function (eventId, graphXML){
			var curGraph = new DCR();
			return curGraph.loadXML(graphXML).getById(eventId)
		}


		/*function calculateNLevels(childEvent, conEvent){

			//set the +1 to N level of the child as of container event
			//setting the child event nLevel to the one of the parent level +1
			childEvent.nLevel = parseInt(conEvent.nLevel + 1);

		}*/

	    /** Main DCR Class, This will return a new instance of the Graph Class. This new object will be used for creating, editing or using the DCR graphs. This is added in to the Window context to be used and extended by user in plugins
		* @class DCR
		* @example var myApp = new DCR();	
		* @returns {object} Returns an object of Graph Class.
		*/
        function D() {
            return new D._Graph;
        }

        D.about = {
	        version: 1.1,
	        details: "DCR Core Library",
	        author: "Shahzad Mirza",
	        created: "January 2015",
	        updated: "19 August 2020"
	    };

	    D.toString = function () {
	        return  "You are using DCR Library "+ D.about.version + " by " + D.about.author;
	    };

		/**
		* Core Class to handle the Graph Operations.            
		* This will be returned by the main DCR function to be utilized by the users or apps.
		* Graph Prototype will have the most common graph related functions, such as load/write XML
		* users can extend this class prototype in plugins.
		* 
		* @class Graph
		* @property {string}  XML               - Stores the XML of the graph.
		* @property {array}  Events       - Stores all the events of graph as objects of Element Class.
		* @property {array}  ExternalEvents         - Stores all external events of graph while loading the XML of the graph, its items are in XML format.
		* @property {array}  Processes      - Stores all the Processes of graph as objects of Element Class.
		* @property {array}  Parents - Stores Parent elements of graph as objects of Element Class.
		* @property {array}  Childs - Stores all Child elements of graph as an array which has child object (instance of Element Class) on 0 index and a string id of its parent object on index 1.
		* @property {array}  Connections - Array to store All Connections of graph as objects of Connection Class.
		* @property {array}  AllConnections - This array is used as temporary container to store all the connections from XML on loading for supporting Nesting levels.
		* @property {array}  Roles - Array to store All Roles of graph in string format.
		* @property {array}  Groups - Array to store All Groups of graph in string format.
		* @property {array}  AllParameters - This array is used for temporary purposes on loading the graph XML to store all the parameters of the graph supporting Nesting levels.
		* @property {array}  Parameters - Array to store All the Unique Parameters of graph as an object {id: "a", type: "variable", value: "10"}.
		* @property {array}  AllParametersSim - This array is used for temporary purposes on loading the graph XML to storing all the parameters of simulation in the graph supporting Nesting levels.
		* @property {array}  ParametersSim - Array to store All the Unique Parameters for simulation of graph as an object {id: "a", type: "variable", value: "10"}.
		* @property {array}  EventTypes - Stores Event Types of graph as strings.
		* @property {string}  Title - Contains the Title of Graph.
		* @property {string}  Description - Contains Description for the Graph.
		* @property {string}  Documentation - Contains Documentation for the Graph.
		* @property {number}  ZoomLevel - An integer of values -9 to 9 ranging (10% to 190%).
		* @property {number}  FilterLevel - Array to store All Connections of graph.
		* @property {array}  FilterRoles - Array to store All Roles in string format for filteration of graph.
		* @property {array}  FilterGroups - Array to store All Groups in string format for filteration of graph.
		* @property {number}  eCount - Contains Events count.
		* @property {number}  pCount - Contains Processes count.
		* @property {array}  ProcessedPs - Temporary container used in loading of graph XML so once traversed processes are not traversed again.
		* @property {array}  ProcessedProcesses - Temporary container used in writing of graph XML so once XML of processes is writter they are not used again as recursive functions are used for supporting N level of nesting.
		* @property {array}  ProcessedEvents - Temporary container used in writing of graph XML so once XML of Events is written they are not used again as recursive functions are used for supporting N level of nesting.
		* @property {array}  AllSharedEvents - While witing XML shared events are stored in this array to be used later.
		*
		* @returns {object} Returns Graph Object.
		*/
	    var Graph = function () {

	    	//Graph globals
		    this.XML = null,
		    this.CurrentEl = null,
		    this.CurrentREl = null, //to store the cur relation selected
			this.Events = [],
			this.ReferredEvents = [],
			this.ExternalEvents = [],
			this.Processes = [],
			this.ReferredPros = [],
			this.ReferredForms = [],
			this.Fragments = [],
			this.Parents = [],
			this.Childs = [],
			this.Connections = [],
			this.AllConnections = [],//temporary holds the connection until all the elements of graph are loaded
			this.ReferredCons = [],//referredConnections of the graph
			this.Highlights = [], //graph highlighted text if any
			this.HighlightLayers = [], //graph highlighted layers if any
			/* Graph resources*/
			this.Roles = [],
			this.ReferredRoles = [],
			this.Groups = [],
			this.ReferredGroups = [],
			this.AllParameters = [], //this will store all the prams of graph
			this.Parameters = [], //this will store all unique prams of graph
			this.GlobalStore = [], //this will store all unique prams of graph
			this.ReferredParams = [], //this will store all unique prams of graph
			this.EventTypes = [],
			this.ReferredEventTypes = [],
			this.Phases = [],
			this.ReferredPhases = [],
			/* Graph related properties*/
			this.Title = "DCR",
			this.Description = "DCR Process",
			this.Documentation = "",
			this.Language = "en-US", //code for languages
			this.Domain = "process", //standard, legal, process, other
			this.ZoomLevel = 0, //this is the current Zoom level of graph
			this.MinZoom = -9, 
			this.MaxZoom = 9, 
			this.FilterLevel = -1, //this is the current Selection filter level //graphFilterLevel
			this.InsightFilter = false, // show insight Fitler Events
			this.FilterRoles = [],
			this.FilterGroups = [],
			this.FilterPhases = [],
			this.GlobalFilter = true,
			this.Exercise = false,
			this.SendText = '',
			this.CancelText = '',
			this.HideCancel = false,
			this.FormShowInitialPhase = 1,
			//basic counters
			this.eCount = this.Events.length,
			this.pCount = this.getProcessCount();
			this.fCount = this.getFormCount();
	    	//graph other globals
	    	this.ProcessedPs = [], //used in loading of the XML graph
	    	this.ProcessedProcesses = [], //used in writing the XML of graph
	    	this.ProcessedReferGraphs = [], //used in writing the XML of graph
			this.ProcessedEvents = [], //used in writing the XML of graph
			this.AllSharedEvents = [], //used in writing the XML of graph, to be used for execution log
			this.FormGroupStyle = "Normal",
            		this.FormLayoutStyle = "Horizontal",
			this.DataTypesStatus = "hide", //show, hide
			this.GlobalMarking = {}, //global markings
			this.BG = "#ffffff",
			this.ProsDisabled = false, //boolean used to identify if processes in graph are disabled or not
			this.Disabled = false, //boolean used to identify if the graph is to be disabled for editing or not
			this.LogContainer = []; //array to store changes of graph for revision history
			this.Simulation = {}; //object to store main simulation of graph
			this.Time = null; //object to store time related info of graph simulation
			this.DeadLine = null; //object to store time related info of graph simulation
			this.Delay = null; //object to store time related info of graph simulation
			this.Keywords = []; //to store keywords of graph
			this.Type = '0',
			this.Options = {
				labels : {
					activity : 'Activity',
					process : 'Process'
				}
			}
	    }

	    D._Graph = Graph;

	    var conproto = D.con = {};

	    /**
		* Main Connection Class, it will be used to create connection b/w Events or Events to Multi Instance Processes
		* 
		* @class Connection
		*
		* @property {object}  graph               - Main Graph Object.
		* @property {object}  from               - Stores the connection from object which is instance of Element class.
		* @property {object}  to       - Stores the connection to object which is instance of Element class.
		* @property {string}  type         - Stores the type of connection as string.
		* @property {string}  guard         - Stores Guard for the connection as string.
		* @property {number}  level         - Stores filter level of the connection greater than or equal to Zero.
		* @property {string}  desc         - Stores description of the connection as string.
		*
		* @param {object}  graph               - A graph object of the current application is passed so it can be used to update the garph easily.
		* @param {object}  from               - An element object is passed as source element from where connection will originate.
		* @param {object}  to       - An element object is passed as target element to where connection will end up.
		* @param {string}  type         - Connection type is passed as string so a connection can be identified, possible values are 'condition', 'response', 'include', 'exclude', 'milestone', 'spawn', 'coresponse', update.
		* @param {string}  guard         - Guard for the connection as string.
		* @param {number}  level         - filter level of the connection greater than or equal to Zero.
		* @param {string}  desc         - Description of the connection as string.
		*
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'}).connectTo(myApp.createEvent({'id':'Exit'}), 'condition');
		* //this will create an Event Element with Enter Id and will create a condition relation from this element to another new Exit element
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'}).connectFrom(myApp.createEvent({'id':'Exit'}), 'condition');
		* //this will create an Event Element with Enter Id and will create a condition relation from another Exit element to this Enter
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'}).createConnection(myApp.createEvent({'id':'Exit'}), 'condition', true);
		* //this will create an Event Element with Enter Id and will create a condition relation from another Exit element to this Enter
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'});
		* myApp.createEvent({'id':'Exit'});
		* myApp.createConnection(myApp.getById('Enter'), myApp.getById('Exit'), 'response');
		* //this will create an Event Element Enter and Exit, then we can use the app to create a response connection between two by finding them by their Ids.
		*
		* @returns {object} Returns Connection Object.
		*/
        var Connection = function (graph, from, to, color, type, guard, level, desc, time, groups, strong, link, businessRule, valueExpression) {
        	//setting some basic objects for element
        	this.guid = GUID();
        	this.graph = graph; 
        	this.from = from;
        	this.to = to;
        	this.type = type;
        	this.level = parseInt(level) || 0;
        	this.description = desc || '';	
        	this.guard = guard || '';
        	this.valueExpression = valueExpression || '';
			this.time = time || '';
			this.link = link || ''; // if any link already exists then set it up
			this.strong = strong || false // if a strong relation, as we need to link it with its pair: for strong condition: condition +  milestone
			this.businessRule = businessRule || false

			// this is a linked strong relation
			if(this.strong==true && this.link.trim().length==0){
				this.link = this.getId(); // get current relation id
			}

        	if(groups != undefined && groups.length>0){
				var curGroups = groups.toString().split(',');
				var elGroups = [];
				for (var i = 0; i < curGroups.length; i++) {
					var index = checkForMatch(this.graph.Groups, 'title', curGroups[i]);
					if(index>=0){
						elGroups.push(this.graph.Groups[index]);
					}else{
						var newGroup = {'id': GUID(), 'title':curGroups[i], 'sequence':0, 'description': ''};
						this.graph.Groups.push(newGroup);
						elGroups.push(newGroup);
					}
				};
				this.groups = elGroups; elGroups = [];
			}else{
				this.groups = [];
			}

        	if(color==undefined || color.length<1){
        		switch(this.type){
	        		case 'condition':
	        			this.color = '#FFA500';
	        			break;
	        		case 'response':	
	        			this.color = '#1E90FF';
	        			break;
					case 'coresponse':	
	        			this.color = '#795548';
	        			break;
	        		case 'include':
	        			this.color = '#29A81A';
	        			break;
	        		case 'exclude':
	        			this.color = 'red';
	        			break;
	        		case 'milestone':
	        			this.color = '#BC1AF2';
	        			break;
	        		case 'update':
	        			this.color = '#b0bfc3';
	        			break;
	        		case 'spawn':
	        			this.color = '#334960';
	        			break;
	        		default:
	        			this.color = 'black';
	        			break;
	        	}	
        	}else{
        		this.color = color;
        	}


        	//get the obj and set its properties accordingly	
			//for(var k in objAttrs) this[k]=objAttrs[k];
        	
        }

        Connection.prototype = conproto;
	    conproto.constructor = Connection;


        //function to check if the curConenction is a referred connection based on the events data
		conproto.isReferCon =  function () {
		    for(var i =0 ; i<this.graph.Connections.length; i++){
		      if(this.graph.Connections[i].guid == this.guid){
		        if(this.graph.Connections[i].from.isReferEvent()==true && this.graph.Connections[i].to.isReferEvent()==true){
		         return true;
		        }
		      }
		    }

		    return false;
		}

		conproto.remove =  function () {
		    //see if the item is a refer item child then don't allow delte on this.
		    if(this.isReferCon()==true){
		      alert('This operation is not allowed for referred element');
		      return false;
		    }

		    if(this.graph.Connections.indexOf(this)!= -1){
				// remove connection sibling first and then remove connection
				var sibling = this.hasSibling()
				if(sibling){ sibling.remove() }
				removeHighlights(this.graph, this);
				this.graph.Connections.splice(this.graph.Connections.indexOf(this), 1);
			}

		    return true;
		}

		// function to find siblings for strong relations and to check if there is any missing sibling connection
		conproto.hasSibling = function (strong) {
			var self = this,
				link = this.link || this.getId(),
				type = strong && this.type=='milestone'? 'condition': strong && this.type=='exclude'? 'include' : this.type; // if this is sibling and has strong then then for it
			return this.graph.Connections.find(function (con) {
				return con.link == link && con.type == type && con!=self;
			})
		}
		
		// check if current connection is sibling
		conproto.isSibling = function () {
			return (this.type == 'milestone' && typeof this.link !='undefined' && this.link.trim().length>0) || (this.type == 'exclude' && typeof this.link !='undefined' && this.link.trim().length>0)? true: false;
		}
		
		// check if current connection has strong sibling
		conproto.isOrphanSibling = function () {
			return this.isSibling() && !this.hasSibling(true)? true: false;
		}

		function removeHighlights(graph, item) {
			//remove any associated highlights
			graph.Highlights = graph.Highlights.filter(function (el) {
				//remove the items from highlight
				el.items = el.items.filter(function (elx) {
					return elx!=item
				})
				//if no item associated then remove highlight or if item is comment as comments don't have any items associated to them
				return el.items.length>0 || el.type === "comment";
			})
		}
		
		
		conproto.getId =  function (fullPath) {
			if(fullPath==true) return this.from.getPath() +"--"+ this.type +"--"+ this.to.getPath()
		    return this.from.id +"--"+ this.type +"--"+ this.to.id
		}

		var highlightproto = D.highlight = {};

	    /**
		* Main Highlight Class, it will be used to create highlights for DCR
		* 
		* @class Highlight
		*
		* @property {string}  guid               - Unique GUID for highlight.
		* @property {Graph}  graph               - Main Graph Object.
		* @property {string}  type         - Stores the type of highlight as string, default type will be `activity` if none provide, others can be: 'role', 'relation', 'suggestion', 'alias', 'comment', 'note'.
		* @property {array}  items         - Stores items of the highlight with which the it is associated with, e-g `Element`, `Connection` or Roles object.
		* @property {array}  layers         - Stores layers of the highlight with ranges of the selection in that layer associated with highlight e-g: { layer: HighlightLayer, ranges: [HighlighterRange]}
		* @property {array}  attrs         - Stores any custom attributes to be added for nodes of the Highlight { name: NAME OF ATTRIBUTE, value: VALUE OF ATTRIBUTE}
		*
		* @param {Graph}  graph               - A graph object of the current application is passed so it can be used to update the garph easily.
		* @param {object}  props               - An object is passed with basic or updates to basic properties of the highlight object.
		*
		*
		* @returns {Highlight} Returns Highlight Object.
		*/
        var Highlight = function (graph, props) {
			//setting some basic objects for element
			var self = this;
        	this.guid = GUID();
			this.graph = graph; 
        	this.type = 'activity'; 
			this.items = [];
			this.layers = [];
			this.attrs = [];
        			
			//get the obj and set its properties accordingly	
			for(var k in props) this[k]=props[k];

			//TODO: for now we will use default layer, but when layers are implemented we need to handle accordingly
			if(this.layers!=undefined && this.layers.layer!=undefined){
				if(!Array.isArray(this.layers.layer)){
					//if it is not an array then make it an array
					this.layers.layer = [this.layers.layer];
				}
				this.layers = this.layers.layer.map(function (layer) {
					//check if those layers exist in the graph
					var index = checkForMatch(graph.HighlightLayers, 'name', layer.name) // TODO: need to escape name if that is required from user
					if(index>-1){
						//set ranges for those layers
						var currentLayer = {
							layer: graph.HighlightLayers[index],
							ranges: []
						}
						setHighlightRanges(self, currentLayer, layer.ranges)
						return currentLayer;
					}
				})	
			}else if(this.layers!=undefined && Array.isArray(this.layers)){
				//get the default layer for the graph and add the highlights there,
				// TODO: need to update the code to support adding items to other layer, when layers are implemented.
				var defaultLayer = graph.getDefaultHighlightLayer();
				if(defaultLayer!=undefined){
					var hasLayer = getLayerInHighlight(this, defaultLayer);
					if(!hasLayer){
						var currentLayer = {
							layer: defaultLayer,
							ranges: []
						}
						this.layers.push(currentLayer)
						//check if ranges have been passed then add those ranges in this layer
						setHighlightRanges(this, currentLayer, this.ranges)
					}
				}
			}else{
				this.layers = [];
			}
			
			
			if(this.items!=undefined && this.items.item!=undefined){
				if(!Array.isArray(this.items.item)){
					//if it is not an array then make it an array
					this.items.item = [this.items.item];
				}
				this.items = this.items.item.map(function (item) {
					//find the item in graph and add it to highlight
					if(item.id == undefined || item.id == "undefined" || typeof item.id == undefined){
						console.warn("undefined item id provided for highlight item ", item)
						return "undefined";
					}
					return item.id
				}).filter(function (item) {
					return item!=="undefined" //remove any items which have undefined id
				})
				
			}else if(this.items!=undefined && !Array.isArray(this.items)){
				this.items = []
			}
				
		}
		
		function setHighlightRanges(highlight, layer, ranges) {
			if(ranges!=undefined && ranges.range!=undefined){
				if(!Array.isArray(ranges.range)){
					//if it is not an array then make it an array
					ranges.range = [ranges.range];
				}
				ranges.range.map(function (range) {
					//find the item in graph and add it to highlight
					addHighlightRange(highlight, layer, range)
				})
				
			}else if(ranges!=undefined && Array.isArray(ranges)){
				ranges.map(function (range) {
					//find the item in graph and add it to highlight
					addHighlightRange(highlight, layer, range)
				})
			}
		}

        Highlight.prototype = highlightproto;
		highlightproto.constructor = Highlight;

		function getLayerInHighlight(highlight, layer) {
			return highlight.layers.find(function (item) {
				return item.layer.name == layer.name // TODO: need to escape name if that is required from user
			})
		}
		
		// Functions for Highlight, like add/update/remove etc
		// TODO: APIs for highlights
		/* 
			Content
				deleteText
				getContents
				getLength
				getText
				insertEmbed
				insertText
				setContents
				setText
				updateContents

			Selection
				getBounds
				getSelection
				setSelection
		*/

		function addHighlightRange(highlight, layer, range){
			if(typeof layer !== 'undefined'){
				var range = new HighlightRange(highlight, range);
				layer.ranges.push(range)
				return range;
			}else{
				events.fire("error", {
					message: "Something went wrong while adding Highlight Range", 
					module: "DCR", 
					fileName: "DCR.js",
					functionName: "addHighlightRange",
					parameters: JSON.stringify({highlight: highlight, layer: layer, range: range})
				})
			}
		}

		/** Add a range to Highlight
	    *
	    * @memberof Highlight 
	    * @method addRange 
		*
		* @param {HighlightLayer}  layer       - A `HighlightLayer` object is required to add the range to that layer for current Highlight
		* @param {object}  range               - An object containing range details e-g: {start = null; end = null; text = null}
	    *
		* @returns {Highlight} Returns an object of `Highlight` Class.
	    */
		highlightproto.addRange = function (layer, range, returnRange) {
			//if layer then check if that layer exisit for highlight, else use defualt layer
			var hasLayer = getLayerInHighlight(this, layer);
			if (!hasLayer) {
				hasLayer = {
					layer: layer,
					ranges: []
				};
				this.layers.push(hasLayer);
			}
			if(hasLayer.ranges !=undefined && Array.isArray(hasLayer.ranges)){
				var range = addHighlightRange(this, hasLayer, range)
			}
			return returnRange ? range : this;
		}



		function removeHighlightRange(highlight, layer, range){
			if(typeof layer !== 'undefined'){
				var index = layer.ranges.indexOf(range);
				if (index !== -1) {
					layer.ranges.splice(index, 1);
				}				
			}else{
				events.fire("error", {
					message: "Something went wrong while removing Highlight Range", 
					module: "DCR", 
					fileName: "DCR.js",
					functionName: "removeHighlightRange",
					parameters: JSON.stringify({highlight: highlight, layer: layer, range: range})
				})
			}
		}

		/** Remove a range from Highlight
	    *
	    * @memberof Highlight 
	    * @method removeRange 
		*
		* @param {HighlightLayer}  layer       - A `HighlightLayer` object is required to add the range to that layer for current Highlight
		* @param {object}  range               - An object containing range details e-g: {start = null; end = null; text = null}
	    *
		* @returns {Highlight} Returns an object of `Highlight` Class.
	    */
		highlightproto.removeRange = function (layer, range) {
			//if layer then check if that layer exisit for highlight, else use defualt layer
			var hasLayer = getLayerInHighlight(this, layer);
			if(hasLayer && hasLayer.ranges !=undefined && Array.isArray(hasLayer.ranges)){
				removeHighlightRange(this, hasLayer, range)
			}
			return this;
		}

		/** Add an item to Highlight
	    *
	    * @memberof Highlight 
	    * @method addItem 
		*
		* @param {object}  item               - An object either of Class `Element`, `Connection` or Roles of graph is to be passed.
	    *
		* @returns {Highlight} Returns an object of `Highlight` Class.
	    */
		highlightproto.addItem = function (item) {
			if(this.items !=undefined && Array.isArray(this.items)){
				this.items.indexOf(item)<0? this.items.push(item): null
			}
			return this;
		}
		
		/** Removes an item from Highlight, if there is no item then the Highlight is removed from Graph Highlights.
	    *
	    * @memberof Highlight 
	    * @method removeItem 
		*
		* @param {object}  item       - An object either of Class `Element`, `Connection` or Roles of graph is to be passed.
	    *
		* @returns {Highlight} Returns an object of `Highlight` Class.
	    */
		highlightproto.removeItem = function (item) {
			removeHighlights(this.graph, item)
			return this;
		}

		//TODO: if we want to remove associated items as well, we have pass removeItems= true
		/** Remove Highlight from graph Highlights
	    *
	    * @memberof Highlight 
	    * @method remove 
		*
		* @param {bool}  removeItems       - TODO: If we want to remove associated items as well, we have pass removeItems= true.
	    *
		* @returns {bool} Always returns true.
	    */
		highlightproto.remove = function (removeItems) {
			var self = this;
			this.graph.Highlights = this.graph.Highlights.filter(function (el) {
				return el!=self
			})
			return true;
		}
		
		/** Get the Id of the items in Highlight
	    *
	    * @memberof Highlight 
	    * @method getItemId 
		*
		* @param {object}  item       - An object either of Class `Element`, `Connection` or Roles of graph is to be passed.
	    *
		* @returns {string} Returns id of the item or undefined.
	    */
		highlightproto.getItemId = function (item) {
			if(item==undefined || item == null) return;
			var itemId = undefined;
			switch (this.type) {
				case 'activity':
					itemId = item.id
					break;
				case 'role':
					itemId = replaceSlashes(htmlEncode(item.title))
					break;
				case 'relation':
					itemId = item.getId()
					break;
				default:
					break;
			}
			return itemId;
		}
		

		var highlightrangeproto = D.highlightrange = {};

		/**
		* Main Highlight Range Class, it will be used to create ranges for highlights in DCR
		* 
		* @class HighlightRange
		*
		* @property {string}  guid                - Unique GUID for range.
		* @property {Highlight}  highlight        - `Highlight` object with which the range is associated with.
		* @property {number}  start               - Stores start index of range from text.
		* @property {number}  end       		  - Stores end index of range from text.
		* @property {string}  text        		  - Stores Text for the highlight as string.
		*
		* @param {Highlight}  highlight               - A graph object of the current application is passed so it can be used to update the garph easily.
		* @param {object}  props               - An object is passed with basic or updates to basic properties of the range object, currently we don't mutate the props but in future it will be supported.
		*
		*
		* @returns {HighlightRange} Returns `HighlightRange` Object.
		*/
		var HighlightRange = function (highlight, props) {
        	//setting some basic objects for element
        	this.guid = GUID();
			this.highlight = highlight || null; 
        	this.text = props.text? props.text: '';
			this.start = props.start && !isNaN(parseInt(props.start))? parseInt(props.start): 0;
			this.end = props.end && !isNaN(parseInt(props.end))? parseInt(props.end): this.text.length; 

			//TODO: get the obj and set its properties accordingly	
			// for(var k in props) this[k]=props[k];

		}
		
		HighlightRange.prototype = highlightrangeproto;
		highlightrangeproto.constructor = HighlightRange;

		/** Updates start/End positions for a range
	    *
	    * @memberof HighlightRange 
	    * @method updatePosition 
		*
		* @param {object}  positions       - An object with positions is to be passed, e-g: {start = null; end = null;}.
	    *
		* @returns {HighlightRange} Returns an object of `HighlightRange` Class.
	    */
		highlightrangeproto.updatePosition = function (positions) {
			this.start = positions.start;
			this.end = positions.end;
			return this;
		}
		
		/** Get postion of a range containing start and end value of the range.
	    *
	    * @memberof HighlightRange 
	    * @method getPosition 
		*
		* @returns {object} Returns an object with postions of a range.
	    */
		highlightrangeproto.getPosition = function () {
			return {start: this.start, end: this.end};
		}


		var highlightlayerproto = D.highlightlayer = {};

		/**
		* Main HighlightLayer Class, it will be used to create layers for Highlights in DCR
		* 
		* @class HighlightLayer
		*
		* @property {string}  guid        - Unique GUID for highlight layer.
		* @property {Graph}  graph        - Main Graph Object.
		* @property {string}  type        - Store layer type, will have several layers of Highlighted text in graph, e-g: - the law, the process description (default), the best practice etc.
		* @property {string}  text        - Stores Text for the layer as string, which will be null by default.
		* @property {string}  name        - Stores Name of the layer, default name will be called 'decription'.
		*
		* @param {Graph}  graph           - A graph object of the current application is passed so it can be used to update the garph easily.
		* @param {object}  props          - An object is passed with basic or updates to basic properties of the layer object.
		*
		*
		* @returns {HighlightLayer} Returns `HighlightLayer` Object.
		*/
        var HighlightLayer = function (graph, props) {
        	//setting some basic objects for element
        	this.guid = GUID();
			this.graph = graph; 
			this.type = 'default'; 
			this.default = false; //sets the default layer
			this.text = null; //text to be marked
        	this.name = 'description'; //name of layer
        			
			//get the obj and set its properties accordingly	
			for(var k in props) this[k]=props[k];
        	
        }

        HighlightLayer.prototype = highlightlayerproto;
		highlightlayerproto.constructor = HighlightLayer;

		/** Set the Highlight layer as default, will unset default value for all other layers
	    *
	    * @memberof HighlightLayer 
	    * @method setAsDefault 
		*
	    *
		* @returns {HighlightLayer} Returns an object of `HighlightLayer` Class.
	    */
		highlightlayerproto.setAsDefault = function () {
			this.graph.HighlightLayers = this.graph.HighlightLayers.map(function (el) {
				el.default = false
				return el;
			})
			this.default = true;
			return this;
		}

		/** Remove Highlight layer
	    *
	    * @memberof HighlightLayer 
	    * @method remove 
		*
	    * @example var myApp = new DCR();
		* myApp.addHighlightLayer({
                name: 'New Layer',
                text: 'some layer text'
            })
		* myApp.HighlightLayers[0].remove(); // this will remove the Highlight Layer selected from graph Layers array, i-e 1st layer in the array
		*	
		* @returns {boolean} Returns true or false based on operation success.
	    */
		highlightlayerproto.remove = function () {

			var _this = this;

			// we can't remove all layers, there must be atleast 1 layer
			if (_this.graph.HighlightLayers.length<2) {
				return false; 
			}

			// if we have to remove Highlights as well
			if (_this.getHighlights()) {
				_this.removeHighlights()
			}

			_this.graph.HighlightLayers = _this.graph.HighlightLayers.filter(function (el) {
				return el!=_this;
			})

			// if removed layer was default then, we need to make 1st layer final
			if (_this.graph.HighlightLayers.length>0 && _this.default == true) {
				_this.graph.HighlightLayers[0].default = true
			}

			return true;
		}

		/** Remove Highlights related to a layer of graph.
		 * 
		 * @memberof HighlightLayer 
	     * @method removeHighlights
		 * 
		 * @example var myApp = new DCR();
		 * myApp.addHighlightLayer({
				name: 'New Layer',
				text: 'some layer text'
			})
		 * myApp.addHighlight({layers: [myApp.HighlightLayers[0]]}) // adds the highlight to layer
		 * myApp.HighlightLayers[0].removeHighlights(); // this will remove the Highlights of Layer
		 * 
		 */
		highlightlayerproto.removeHighlights = function(){
			var _this = this
			_this.graph.Highlights = _this.graph.Highlights.map(function (item) {
				// remove this layer from highlights
				item.layers = item.layers.filter(function (layerItem) {
					return layerItem.layer!= _this;
				})
				return item
			}).filter(function (item) { // if highlight doesn't have any layer then remove it
				return item.layers.length>0
			})
		}

		/** Get Highlights related to a layer of graph.
		 * 
		 * @memberof HighlightLayer 
	     * @method getHighlights 
		 * 
		 * @returns {array} - An array of graph Highlights.
		 * 
		 */
		highlightlayerproto.getHighlights = function(){
			var _this = this
			return _this.graph.Highlights.filter(function (item) {
				return item.layers.find(function (layerItem) {
					return layerItem.layer == _this
				});
			})
		}

		// TODO: highlight layer remove function, no such requirement at the moment

	    //elemet proto and el object
	    var elproto = D.el = {};
	    var graphproto;

	    /**
		* Main Element Class, it will be used to create Events or Processes 
		* 
		* @class Element
		*
		* @param {object}  graph               - A graph object of the current application is passed so it can be used to update the garph easily.
		* @param {object}  objAttrs               - These are the main object attributes provided by user they can be custom but XML writing for custum attributes is not supported by CORE library yet.
		* @param {boolean}  isProcess       - This is used to create either an event or a processes possible values can be true, false.
		*
		* @property {object}  graph               - Contains the main Graph instance to be used for the operation on the Element.
		* @property {string}  id               - Contains the id of the Element.
		* @property {number}  nLevel               - Contains the nesting level of the Element.
		* @property {object}  runtimes               - Contains the run times information of the Element.
		* @property {boolean}  runtimes.executed               - Defines Executed property of Element, if true is stored then Element will be recognized as an Executed event.
		* @property {boolean}  runtimes.included               - Defines Included property of Element, if true is stored then Element will be recognized as an Included event, else Excluded event.
		* @property {boolean}  runtimes.pending               - Defines Pending property of Element, if true is stored then Element will be recognized as an Pending event, which makes its priority high in simulation.
		* @property {enum}  scope               - Contains scope of the Element, default is "private". Element can also be set a "shared", this is used in creating the connections from with in process to outer scope.
		* @property {string}  sharedId               - if an Element is shared then its id is stored here to be used in generating the XML.
		* @property {enum}  type               - Stores the type of Element, i-e "event" or "process" .
		* @property {object}  custom       - Stores all the custom properties of the Elements stored in the custom section of the standard DCR XML structure.
		* @property {object}  custom.visualization         - Stores the visual information of the Element including dimensions and locations.
		* @property {object}  custom.visualization.dimension        - Stores the dimension of the Element as an object.
		* @property {number}  custom.visualization.dimension.width        - Stores width of the Element.
		* @property {number}  custom.visualization.dimension.height        - Stores height of the Element.
		* @property {object}  custom.visualization.location      - Stores the cordinates of the Element.
		* @property {number}  custom.visualization.location.xLoc      - Stores the value of x axis of the Element.
		* @property {number}  custom.visualization.location.yLoc      - Stores the value of y axis of the Element.
		* @property {string}  custom.label        - Stores the label of the Element.
		* @property {string}  custom.eventDescription        - Stores the description of the Element.
		* @property {string}  custom.eventType        - Stores activity type of the Element associated to it in graph.
		* @property {array}   custom.groups        - Stores all the groups associated to the Element.
		* @property {array}   custom.roles        - Stores all the roles associated to the Element.
		* @property {number}  custom.level        - Stores the filter level value of the Element.
		*
		* @returns {object} Returns Element Object.
		*/
        var Element = function (graph, objAttrs, isProcess, isForm, isRefer, isFragment) {

        	//setting some basic objects for element
        	this.graph = graph;	

        	var defaultColors = {
									bg : '#f9f7ed',
									textStroke : '#000000',
									stroke : '#cccccc'
								}
			
			/* TODO: disabled form colors, remove in future
			if(isForm==true){
				defaultColors = {
					bg : '#b1ea98',
					textStroke : '#000000',
					stroke : '#6aa84f'
				}
			}else*/ if(isProcess==true){
				defaultColors = {
					bg : '#83c5ff',
					textStroke : '#000000',
					stroke : '#4da1e8'
				}
			} 					
			var defaultLocation = {
									xLoc : 100,
									yLoc : 100
								},
			defaultDimension = {
							width: 100,
							height : 100
						};

			var eventDefaults = {
					visualization : {
						location : defaultLocation,
						colors : defaultColors,
						dimension : defaultDimension
					},
					groups : [],
					roles : [],
					phases : [],
					interfaces : [],
					interfaceType: null,
					level : 0,
					label : 'Add title',
					costs : 0,
					eventDescription : '',
					purpose : '',
					insight: {
						use: false,
						deadlineExpression: ''
					},
					guide : '',
					eventData : {
							dataType : {
								sequence : 0,
								width : 'medium',
								height : 'medium',
								min : 0,
								max : 255,
								placeholder : undefined,
								hintText : undefined,
								default : false,
								type : undefined, 
								rules : []
							}
					},
					parentObj : null,
					actionType : 'Execute'
				};

			this.custom = eventDefaults;

			//get the obj and set its properties accordingly	
			for(var k in objAttrs) this[k]=objAttrs[k];


			//setting up default labels for activity or the processes 

        	var tempLabel = 'Activity '
        	if(isProcess==true){
        		var curID = graph.getNewID(true);
        		if(isRefer==true){
        			this.isRefer = true;
				    this.multiInstance = false;
				    this.referId =  objAttrs.graphID ? objAttrs.graphID : null;
					this.dcrgraph = objAttrs.graphXML ? objAttrs.graphXML : null; 
        		}
				var tempLabel = curID.label;

				//setting this as process
				this.baseType = 'process';
				if(this.dcrgraph!=undefined){
					//this.dcrgraph = new Graph().loadXML(XMLtoString(objAttrs.dcrgraph));
				}
				if(this.multiInstance=="false" || this.multiInstance==false || isForm==true){
					this.multiInstance = false;
				}else{
					this.multiInstance = true;
				}

				if(this.parentPro==undefined || this.parentPro==null){
					this.parentPro = 'root';
				}
				
			}else{
				if(isForm==true){
					var curID = graph.getNewID(false);
					// TODO: need to remove this once and for all once fragments are fully settled in
        			// this.isRefer = true;
				    // this.referId =  objAttrs.graphID ? objAttrs.graphID : null;
					// this.dcrgraph = objAttrs.graphXML ? objAttrs.graphXML : null; 
					// this.isDynamicForm = isDynamicForm(this)
					this.type = 'form'
        		}else{
					var curID = graph.getNewID();
					if(isFragment){
						this.type = 'subprocess'
					}
        		}
				
				if(isFragment){
					this.fragmentId = objAttrs.fragmentId!=undefined ? objAttrs.fragmentId : null;
				}
				var tempLabel = curID.label;

				var types = ["nesting", "subprocess", "form", "transactional_subprocess"]
				if(types.indexOf(this.type) == -1){
					this.type = 'default';
				}


				if(this.actionType==undefined || this.actionType!='Open'){
					this.actionType = 'Execute'
				}

				this.baseType = 'event'
				
			}

			// if form then add these properties
			if(this.type == 'form' || isForm == true){
				this.cancelText = objAttrs.cancelText ? fixSlashes(objAttrs.cancelText) : '';
				this.sendText = objAttrs.sendText ? fixSlashes(objAttrs.sendText) : '';
				this.hideCancel = objAttrs.hideCancel && objAttrs.hideCancel == "true" ? true : false;
				this.formShowInitialPhase = objAttrs.formShowInitialPhase && objAttrs.formShowInitialPhase == "2" ? 2 : 1;
			}

			if(this.computation!=undefined){
				this.computation = fixSlashes(this.computation);
			}else{
				this.computation = ''
			}
			
			if(!this.dmnXML){
				this.dmnXML = '';
			}
			
			if(this.interfaceType && (this.interfaceType=="inner" || this.interfaceType=="outer")){
				this.interfaceType = this.interfaceType;
			}else{
				this.interfaceType = null
			}
			
			if(this.commonId && this.commonId=="true"){
				this.commonId = true;
			}else{
				this.commonId = false;
			}

			if(typeof this.defaultValue!='undefined' && this.defaultValue!=undefined){
				this.defaultValue.value = fixSlashes(this.defaultValue.value);
			}else{
				this.defaultValue = null
			}


			//setting the Event data Type of Event
			if(this.custom.eventData != undefined && this.custom.eventData.dataType != undefined){
				var curDataType = {};
				for(var m in this.custom.eventData.dataType) curDataType[m] = this.custom.eventData.dataType[m];
				var dataType = this.custom.eventData.dataType = curDataType;

				dataType.type = dataType.text;

				dataType.toString = function () {
					return  this.type;
				};

				if(dataType.type=='undefined'){
						dataType.type = undefined;
				}

				if(dataType.type!=undefined){
					dataType.type = dataType.type.toLowerCase();
				}
				
				//fetch the data from the data type
				if(dataType.sequence!=undefined && parseInt(dataType.sequence)>0){
					//setting the event form Sequence no
					dataType.sequence = parseInt(dataType.sequence);
				}else{
					//setting the event form Sequence no
					dataType.sequence = eventDefaults.eventData.dataType.sequence;
				}

				if(dataType.width==undefined){
					dataType.width = eventDefaults.eventData.dataType.width;
				}

				if(dataType.min==''){
					dataType.min = eventDefaults.eventData.dataType.min;
				} else {
				    if (dataType.type != 'date' && dataType.type != 'datetime') {
				        if (dataType.type == 'float') {
				            dataType.min = parseFloat(dataType.min);
				        }
				        else{
				            dataType.min = parseInt(dataType.min);
				        }
				        
				    }
					
				}

				if(dataType.max==''){
					dataType.max = eventDefaults.eventData.dataType.max;
				}else{
				    if (dataType.type != 'date' && dataType.type != 'datetime') {
				        if (dataType.type == 'float') {
				            dataType.max = parseFloat(dataType.max);
				        }
				        else {
				            dataType.max = parseInt(dataType.max);
				        }
				    }
				}

				if(dataType.type==='bool'){
					this.custom.eventData.dataType.default = dataType.default=="true"?true:false;
				}else if(dataType.type==='label' && this.custom.eventData.dataType.default !=undefined){
					this.custom.eventData.dataType.default = htmlEncode(this.custom.eventData.dataType.default)
				}

				//console.log('----////------------')
				//console.log(this.custom.eventData)
				var curItemRules = [];
				if(this.custom.eventData.validationRules!=undefined && this.custom.eventData.validationRules.rule!=undefined){
					var curRules = this.custom.eventData.validationRules.rule;

					if(Array.isArray(curRules)==false){
						curRules = [curRules]
					}

					for (var i = 0; i < curRules.length; i++) {
						var curParameters = [];
						var curRule = curRules[i];
						var curRuleParamters = [];

						if(curRule.parameters!=undefined && curRule.parameters.parameter!=undefined){
							var curParameters = curRule.parameters.parameter;

							if(Array.isArray(curParameters)==false){
								curRuleParamters = [curParameters]
							}

							for (var j = 0; j < curParameters.length; j++) {
								if(curParameters[j].required=="true"){
									curParameters[j].required = true
								}else{
									curParameters[j].required = false;
								}
								curRuleParamters.push(curParameters[j])
							};
						}
						

						curRule.parameters = curRuleParamters;
						curItemRules.push(curRule)
					};

					// {id:ruleId, details: curRule, customMessage: customMessage, parameters: ruleParams }
					
				}

				this.custom.eventData.dataType.rules = curItemRules;
				//console.log(curItemRules);

			}else{
				//setting the event data type
				this.custom.eventData = eventDefaults.eventData;
			}

			if(this.custom.sequence!=undefined && parseInt(this.custom.sequence)>=0){
				this.custom.sequence = parseInt(this.custom.sequence);
			}else{
				this.custom.sequence = this.graph.getMaxSequence() + 1;
			}
			//test ? expression1 : expression2	

			this.id = objAttrs.id ? objAttrs.id : curID.id;
			this.guid = objAttrs.guid ? objAttrs.guid : GUID();
			this.oriId = objAttrs.oriId ? objAttrs.oriId : this.id;

			this.custom.label = objAttrs.custom ? (objAttrs.custom.label ? objAttrs.custom.label : tempLabel) : tempLabel;

			this.runtimes = objAttrs.runtimes || {included:true, pending:false, executed: false };
			this.nLevel = 0;
			//this.isShared = false;
			this.sharedId = '';

			///storing the event description
			if(this.custom.eventDescription ==undefined || this.custom.eventDescription.length<1 ){
				this.custom.eventDescription = ''
			}

			if(this.custom.purpose ==undefined || this.custom.purpose.length<1 ){
				this.custom.purpose = ''
			}

			if(this.custom.guide ==undefined || this.custom.guide.length<1 ){
				this.custom.guide = ''
			}
			
			if(this.custom.insight ==undefined ){
				this.custom.insight = {
					use: false,
					deadlineExpression: ''
				}
			}else{
				this.custom.insight.use = this.custom.insight.use=="true"? true: false;
				this.custom.insight.deadlineExpression = typeof this.custom.insight.deadlineExpression !='undefined' && this.custom.insight.deadlineExpression.length>0? fixSlashes(this.custom.insight.deadlineExpression): '';
			}

			// check if resouces are available, also check if user id is available
			var props = ['id', 'message', 'value'];
			this.precondition = props.reduce(function(obj, key){ 
				obj[key] = obj[key]!= undefined? fixSlashes(obj[key]): ''; 
				return obj
			}, (this.precondition || {}))
			
			if(this.custom.costs !=undefined && isInteger(parseInt(this.custom.costs))==true){
				this.custom.costs = toNumber(this.custom.costs);
			}else{
				this.custom.costs = 0;
			}

			//setting the Filter Level of Event also checking if any value exists and it is integer or not
			if(this.custom.level!=undefined && parseInt(this.custom.level)>0 && this.custom.level == parseInt(this.custom.level)){
				this.custom.level = parseInt(this.custom.level);
			}else{
				this.custom.level = 1;
			}

			//if this has a parent id then put it in childs
			if(this.parentId && this.parentId.length>0 && this.parentGUID!=undefined&& this.parentGUID.length>0){
				//put it in the childs array
				graph.Childs.push(this);

				var curGUID = this.parentGUID;

				this.parentObj = $.grep(graph.Events, function(obj){
					return obj.guid == curGUID;
				});

				if(this.parentObj.length<1){
					this.parentObj = $.grep(graph.Processes, function(obj){
						return obj.guid == curGUID;
					});
					if(this.parentObj.length>0){
						this.parentObj = this.parentObj[0];
					}else{
						this.parentObj = null;
					}
				}else{
					this.parentObj = this.parentObj[0];
				}

			}else{
				this.parentObj = null;
			}

			//getting the event refer type and setting boolean to it
			if(this.isRefer != undefined && (this.isRefer=='true' || this.isRefer==true)){
				this.isRefer = true;
			}else{
				this.isRefer = false;
			}

			//getting the event Roles and setting em to event data
			if(this.custom.roles != undefined && this.custom.roles.role != undefined && this.custom.roles.role.length >0){			
				//if more than one roles are assigned then use loop to assign them
				//converting the object to array and assigning it to Element Roles
				//check for all the elements passed to it and see if they exist in the Roles of this graph or not
				//if they don't exist then add them to Roles of this graph
				var curRoles = [];
				if(typeof this.custom.roles.role ==='string'){
					curRoles.push(fixSlashes(this.custom.roles.role))
				}else if(typeof this.custom.roles.role ==='object'){
					for (var i = 0; i < this.custom.roles.role.length; i++) {
						curRoles.push(fixSlashes(this.custom.roles.role[i]))
					};
				}
				
				//foreach()this.custom.roles.role.toString().split(',')
				var elRoles = [];
				for (var i = 0; i < curRoles.length; i++) {
					var index = checkForMatch(this.graph.Roles, 'title', curRoles[i]);
					var index2 = checkForMatch(this.graph.ReferredRoles, 'title', curRoles[i]);
					//if item is in simple array then ok
					if(index>=0){
						elRoles.push(this.graph.Roles[index]);
					}else if(index2>=0){
						//if item is in referred array then ok
						elRoles.push(this.graph.ReferredRoles[index2]);
					}else if(checkForMatch(this.graph.ReferredRoles, 'title', curRoles[i])<0){
						//if item not found in any array then add it in the simple array
						var newRole = {'id': GUID(), 'title':curRoles[i], 'description': '', 'specification': ''};
						this.graph.Roles.push(newRole);
						elRoles.push(newRole);
					}
				};
				this.custom.roles = elRoles; elRoles = [];

			}else{
				this.custom.roles = [];
			}

			//getting the event Groups and setting em to event data
			if(this.custom.groups != undefined && this.custom.groups.group != undefined && this.custom.groups.group.length>0){
				var curGroups = [];
				if(typeof this.custom.groups.group ==='string'){
					curGroups.push(fixSlashes(this.custom.groups.group))
				}else if(typeof this.custom.groups.group ==='object'){
					for (var i = 0; i < this.custom.groups.group.length; i++) {
						curGroups.push(fixSlashes(this.custom.groups.group[i]))
					};
				}
				var elGroups = [];
				for (var i = 0; i < curGroups.length; i++) {
					var index = checkForMatch(this.graph.Groups, 'title', curGroups[i]);
					var index2 = checkForMatch(this.graph.ReferredGroups, 'title', curGroups[i]);
					//if item is in simple array then ok
					if(index>=0){
						elGroups.push(this.graph.Groups[index]);
					}else if(index2>=0){
						//if item is in referred array then ok
						elGroups.push(this.graph.ReferredGroups[index2]);
					}else if(checkForMatch(this.graph.ReferredGroups, 'title', curGroups[i])<0){
						//if item not found in any array then add it in the simple array
						var newGroup = {'id': GUID(), 'title':curGroups[i], 'sequence':0, 'description': ''};
						this.graph.Groups.push(newGroup);
						elGroups.push(newGroup);
					}
				};
				this.custom.groups = elGroups; elGroups = [];
			}else{
				this.custom.groups = [];
			}

			//getting the event Phases
			if(this.custom.phases != undefined && this.custom.phases.phase != undefined && this.custom.phases.phase.length>0){
				var curPhases = [];
				if(typeof this.custom.phases.phase ==='string'){
					curPhases.push(fixSlashes(this.custom.phases.phase))
				}else if(typeof this.custom.phases.phase ==='object'){
					for (var i = 0; i < this.custom.phases.phase.length; i++) {
						curPhases.push(fixSlashes(this.custom.phases.phase[i]))
					};
				}
				var elPhases = [];
				for (var i = 0; i < curPhases.length; i++) {
					var index = checkForMatch(this.graph.Phases, 'title', curPhases[i]);
					var index2 = checkForMatch(this.graph.ReferredPhases, 'title', curPhases[i]);
					//if item is in simple array then ok
					if(index>=0){
						elPhases.push(this.graph.Phases[index]);
					}else if(index2>=0){
						//if item is in referred array then ok
						elPhases.push(this.graph.ReferredPhases[index2]);
					}else if(checkForMatch(this.graph.ReferredPhases, 'title', curPhases[i])<0){
						//if item not found in any array then add it in the simple array
						//TODO: need to provide unique sequence for new phase
						var newPhase = {'id': GUID(), 'title':curPhases[i], 'sequence':0, 'description': ''};
						this.graph.Phases.push(newPhase);
						elPhases.push(newPhase);
					}
				};
				this.custom.phases = elPhases; elPhases = [];
			}else{
				this.custom.phases = [];
			}
			
			//getting the event Phases
			if(this.custom.interfaces != undefined && this.custom.interfaces.interface != undefined){
				var curInterfaces = [];
				if(this.custom.interfaces.interface instanceof Object && (this.custom.interfaces.interface instanceof Array)==false ){
					curInterfaces.push(this.custom.interfaces.interface)
				}else if(this.custom.interfaces.interface instanceof Array){
					for (var i = 0; i < this.custom.interfaces.interface.length; i++) {
						curInterfaces.push(this.custom.interfaces.interface[i])
					};
				}
				this.custom.interfaces = curInterfaces;
			}else{
				this.custom.interfaces = [];
			}			


			//setting the scope of the event based on the obj details
			var itemScope = '';
			if(this.scope!=undefined){
				itemScope = this.scope;
			}else if(this.custom.eventScope != undefined){
				itemScope = this.custom.eventScope;
			}
			if(itemScope != 'private' && itemScope != 'shared'){
				itemScope = 'private';
			}
			this.scope = itemScope;

			//setting the Event Type of Event
			if(this.custom.eventType != undefined && this.custom.eventType.length>0){
				var curEventTypes = [this.custom.eventType.toString()];
				for (var i = 0; i < curEventTypes.length; i++) {
					var index = checkForMatch(this.graph.EventTypes, 'title', curEventTypes[i]);
					var index2 = checkForMatch(this.graph.ReferredEventTypes, 'title', curEventTypes[i]);
					//if item is in simple array then ok
					if(index>=0){
						this.custom.eventType = this.graph.EventTypes[index];
						break;
					}else if(index2>=0){
						//if item is in referred array then ok
						this.custom.eventType = this.graph.ReferredEventTypes[index2];
					}else{
						this.custom.eventType = undefined;
					}
				};
			}else{
				//this.custom.eventType = {'id': GUID(), 'title':'none', 'description': ''};
				this.custom.eventType = undefined;
			}	
			if(this.custom.eventType!=undefined && this.custom.eventTypeData != undefined && this.custom.eventTypeData.parameter != undefined){	
				var elParams = this.custom.eventType.parameters;
				var newParameters = [], curParameters = [];
				//need to check if these are parameters of selected eventtype or not?
				for (var i = 0; i < elParams.length; i++) {
					var curParam = {}
					for (prop in elParams[i]) {
						curParam[prop] = elParams[i][prop]
					};
					newParameters.push(curParam)
				};
				if(this.custom.eventTypeData.parameter.constructor === Object){
					curParameters.push(this.custom.eventTypeData.parameter)
				}else if(this.custom.eventTypeData.parameter.constructor === Array){
					for (var i = 0; i < this.custom.eventTypeData.parameter.length; i++) {
						curParameters.push(this.custom.eventTypeData.parameter[i])
					};
				}
				for (var i = 0; i < curParameters.length; i++) {
					var index = checkForMatch(newParameters, 'title', curParameters[i].title);
			if(index>=0){
						newParameters[index].value = fixSlashes(curParameters[i].value);
						newParameters[index].required = curParameters[i].required;
					}
				};
				this.custom.eventTypeData = newParameters, newParameters = [], curParameters = [];
			}else{
				this.custom.eventTypeData = [];
			}

			//setting up some base values it not found in xml
			if(this.custom.visualization != undefined){
				if(this.custom.visualization.location != undefined){
					if(this.custom.visualization.location.xLoc != undefined){
						this.custom.visualization.location.xLoc = parseInt(this.custom.visualization.location.xLoc);
					}else{
						this.custom.visualization.location.xLoc = defaultLocation.xLoc;
					}

					if(this.custom.visualization.location.yLoc != undefined){
						this.custom.visualization.location.yLoc = parseInt(this.custom.visualization.location.yLoc);
					}else{
						this.custom.visualization.location.yLoc = defaultLocation.yLoc;
					}
	
				}else{
					this.custom.visualization.location = defaultLocation;
				}

				if(this.custom.visualization.dimension != undefined  ){
					if(this.custom.visualization.dimension.width != undefined){
						this.custom.visualization.dimension.width = parseInt(this.custom.visualization.dimension.width);
					}else{
						this.custom.visualization.dimension.width = defaultDimension.width;
					}

					if(this.custom.visualization.dimension.height != undefined){
						this.custom.visualization.dimension.height = parseInt(this.custom.visualization.dimension.height);
					}else{
						this.custom.visualization.dimension.height = defaultDimension.height;
					}
				}else{
					this.custom.visualization.dimension = defaultDimension
				}

				if(this.custom.visualization.colors != undefined  ){
					if(this.custom.visualization.colors.bg == undefined){
						this.custom.visualization.colors.bg = defaultColors.bg;
					}

					if(this.custom.visualization.colors.textStroke == undefined){
						this.custom.visualization.colors.textStroke = defaultColors.textStroke;
					}

					if(this.custom.visualization.colors.stroke == undefined){
						this.custom.visualization.colors.stroke = defaultColors.stroke;
					}
				}else{
					this.custom.visualization.colors = defaultColors
				}
			}else{
				this.custom.visualization = {
						location : defaultLocation,
						colors : defaultColors,
						dimension : defaultDimension
					}
			}

        };

	    Element.prototype = elproto;
	    elproto.constructor = Element;

	    //attr('description','test')
	    /*elproto.attr = function (attr, value) {
	    	//check the arguments
	    	if(arguments.length==0){
	    		return this;
	    	}else if(arguments.length==1){
	    		//get the value of that attribute and show it to user //String.prototype.toLowerCase.call("function")
	    		for(var k in attr){
	    			console.log(attr[k]);
	    		}

	    	}

	    	return this;
	    }*/

	    /*//function to calculate the Nesting level of an Event/Process
	    function calculateNLevel (childEvent, conEvent) {
	    	var conLevel = conEvent.nLevel;
	    	var addition = conLevel;

	    	if(addition==0){
	    		addition = 1;
	    	}
	    	childEvent.nLevel = addition + childEvent.nLevel;

	    }*/


	    /** Function to create a connection from one object to another object or vice versa
	    *
	    * @memberof Element 
	    * @method createConnection 
	    *
	    * @param {object}  secObj               - An Element object is passed as source/target element.
		* @param {string}  type         - Connection type is passed as string so a connection can be identified, possible values are 'condition', 'response', 'include', 'exclude', 'milestone', 'spawn', 'update'.
		* @param {boolean}  isFrom         - This value determines either to create connectoin to second object passed or from it, default connection will be to the second object.
		* @param {string}  guard         - Guard for the connection as string.
		* @param {number}  level         - filter level of the connection greater than or equal to Zero.
		* @param {string}  desc         - Description of the connection as string.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'});
		* myApp.createEvent({'id':'Enter'}).createConnection(myApp.createEvent({'id':'Exit'}), 'response', true);
		* //this will create an Event Element Enter and Exit, then we can use the function to create a response connection between two setting source as Exit and target as Enter.
		* @returns {object} Returns an object of Connection Class.
	    */
	    elproto.createConnection = function (secObj, type, isFrom, guard, level, desc, time, groups, strong, businessRule, valueExpression){
	    	//if to Element is not in the graph then return null
	    	if($.inArray(secObj, this.graph.Events)===-1){
	    		return null;
	    	}

	    	//if to Element is in the graph then
	    	if(isFrom == true){
	    		this.connectFrom(secObj, type, guard, level, desc, time, groups, strong, businessRule, valueExpression);
	    	}else{
	    		this.connectTo(secObj, type, guard, level, desc, time, groups, strong, businessRule, valueExpression);
	    	}

	    }

	    /** Function to create a connection from one object to another object
	    *
	    * @memberof Element 
	    * @method connectTo 
	    *
		* @param {object}  to       - An Element object is passed as target element to where connection will end up.
		* @param {string}  type         - Connection type is passed as string so a connection can be identified, possible values are 'condition', 'response', 'include', 'exclude', 'milestone', 'spawn', 'update'.
		* @param {string}  guard         - Guard for the connection as string.
		* @param {number}  level         - filter level of the connection greater than or equal to Zero.
		* @param {string}  desc         - Description of the connection as string.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'}).connectTo(myApp.createEvent({'id':'Exit'}), 'response');
		* //this will create an Event Element Enter and Exit, then we can use the function to create a response connection between two.
		* @returns {object} Returns an object of Connection Class.
	    */
	    elproto.connectTo = function (to, color, type, guard, level, desc, time, groups, strong, businessRule, valueExpression){
	        return this.graph.createConnection(this, to, color, type, guard, level, desc, time, groups, strong, businessRule, valueExpression);
	    }

	    /** Function to create a connection from one object to another object, similar to connectTo but this is inverse of it as this selects the calling object as target and the object passed as source.
	    *
	    * @memberof Element 
	    * @method connectFrom 
	    *
		* @param {object}  from       - An Element object is passed as target element to where connection will end up.
		* @param {string}  type         - Connection type is passed as string so a connection can be identified, possible values are 'condition', 'response', 'include', 'exclude', 'milestone', 'spawn', 'update'.
		* @param {string}  guard         - Guard for the connection as string.
		* @param {number}  level         - filter level of the connection greater than or equal to Zero.
		* @param {string}  desc         - Description of the connection as string.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Exit'}).connectFrom(myApp.createEvent({'id':'Enter'}), 'condition');
		* //this will create an Event Element Enter and Exit, then we can use the function to create a condition connection between two.
		* @returns {object} Returns an object of Connection Class.
	    */
	    elproto.connectFrom = function (from, color, type, guard, level, desc, time, groups, strong, businessRule, valueExpression){
	        return this.graph.createConnection(from, this, color, type, guard, level, desc, time, groups, strong, businessRule, valueExpression);
	    }


	   /* elproto.getConnections = function () {
			var curObj = this;

			var eventCons = $.grep(this.graph.Connections, function (el) {
					return el.to == curObj ||  el.from == curObj;
				});

			return eventCons;
		}

		//getting to/from connections
		//default will get connections to, but if passed true the connections from will be get
		
		elproto.getConnections = function (getFrom) {
			var curObj = this;
			var res = [];

			if(getFrom==true){
				var eventCons = $.grep(this.graph.Connections, function (el) {
					return el.to == curObj;
				});
				for (var i = 0; i < eventCons.length; i++) {
					res.push(eventCons[i].from);
				};
			}else{
				var eventCons = $.grep(this.graph.Connections, function (el) {
					return el.from == curObj;
				});
				for (var i = 0; i < eventCons.length; i++) {
					res.push(eventCons[i].to);
				};
			}

			return res;
		}*/

		/** Function to get all to/from Connections of an Element object.
	    *
	    * @memberof Element 
	    * @method getConnections 
	    *
		* @param {boolean}  fromOrTo       - Getting to or from connections according to type provided, if passed true from connections will be returned, if false is passed then to will be returned if nothing is passed then all will be returned.
		* @param {string}  type         - Connection type is passed as string so a connection can be identified, possible values are 'condition', 'response', 'include', 'exclude', 'milestone', 'spawn'.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Exit'}).connectFrom(myApp.createEvent({'id':'Enter'}), 'condition');
		* myApp.getById('Exit').getConnections();
		* //this will get all the connections to/from the Exit Element
		*
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Exit'}).connectFrom(myApp.createEvent({'id':'Enter'}), 'condition');
		* myApp.getById('Exit').getConnections(true);
		* //this will get all the connections to the Exit Element
		*
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Exit'}).connectTo(myApp.createEvent({'id':'Enter'}), 'condition');
		* myApp.getById('Exit').getConnections(false);
		* //this will get all the connections from the Exit Element
		*
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Exit'}).connectTo(myApp.createEvent({'id':'Enter'}), 'condition');
		* myApp.getById('Exit').connectTo(myApp.createEvent({'id':'New'}), 'response');
		* myApp.getById('Exit').getConnections(false);
		* //this will get all the connections from the Exit Element
		* @returns {array} Returns an array of Element object to/from which connections are associated
	    */
	    elproto.getConnections = function (fromOrTo, type, getItems) {
			var curObj = this;
			var res = [], eventCons = [];
			//get all connections from
			if(fromOrTo===true){
				if(type){
					eventCons = $.grep(this.graph.Connections, function (el) {
						return el.to == curObj && type==el.type;
					});
				}else{
					eventCons = $.grep(this.graph.Connections, function (el) {
						return el.to == curObj;
					});
				}
				
				//if getItems is true then send Elements
				if(getItems===true){
					for (var i = 0; i < eventCons.length; i++) {
						res.push(eventCons[i].from);
					};
				}if(getItems===false){
					for (var i = 0; i < eventCons.length; i++) {
						res.push([eventCons, eventCons[i].from]);
					};
				}else{
					//else send connection objects
					res = res.concat(eventCons);
				}
				
			}else if(fromOrTo===false){ //get all connections to
				if(type){
					eventCons = $.grep(this.graph.Connections, function (el) {
						return el.from == curObj && type==el.type;
					});
				}else{
					eventCons = $.grep(this.graph.Connections, function (el) {
						return el.from == curObj;
					});	
				}
				//if getItems is true then send Elements
				if(getItems===true){
					for (var i = 0; i < eventCons.length; i++) {
						res.push(eventCons[i].to);
					};
				}if(getItems===false){
					for (var i = 0; i < eventCons.length; i++) {
						res.push([eventCons, eventCons[i].to]);
					};
				}else{
					//else send connection objects
					res = res.concat(eventCons);
				}
			}else{ //get all connections
				if(type){
					eventCons = $.grep(this.graph.Connections, function (el) {
						return ((el.to == curObj ||  el.from == curObj) && type==el.type);
					});
				}else{
					eventCons = $.grep(this.graph.Connections, function (el) {
						return el.to == curObj ||  el.from == curObj;
					});	
				}
				//if getItems is true then send Elements
				if(getItems===true){
					for (var i = 0; i < eventCons.length; i++) {
						//if to is in res then ignore it else add it
						if($.inArray(eventCons[i].to, res)===-1 && eventCons[i].to !=curObj){
							res.push(eventCons[i].to)
						}
						//if from is in res then ignore it else add it
						if($.inArray(eventCons[i].from, res)===-1 && eventCons[i].from !=curObj){
							res.push(eventCons[i].from)
						}
						//if connection is with it self and is not in res then add it
						if($.inArray(eventCons[i].from, res)===-1 && eventCons[i].from == eventCons[i].to && eventCons[i].from == curObj){
							res.push(eventCons[i].from)
						}
					};
				}if(getItems===false){
					for (var i = 0; i < eventCons.length; i++) {
						//if to is in res then ignore it else add it
						if($.inArray(eventCons[i].to, res)===-1 && eventCons[i].to !=curObj){
							res.push([eventCons[i], eventCons[i].to])
						}
						//if from is in res then ignore it else add it
						if($.inArray(eventCons[i].from, res)===-1 && eventCons[i].from !=curObj){
							res.push([eventCons[i], eventCons[i].from])
						}
						//if connection is with it self and is not in res then add it
						if($.inArray(eventCons[i].from, res)===-1 && eventCons[i].from == eventCons[i].to && eventCons[i].from == curObj){
							res.push([eventCons[i], eventCons[i].from])
						}
					};
				}else{
					//else send connection objects
					res = res.concat(eventCons);
				}
			}
			
			return res;
		}

		
		//get connections for only the child items in an Element
		elproto.getChildConnections = function () {
			var curObjChilds = this.getChilds(), formCons = [];
			//get all children for form and their connections only
			formCons = curObjChilds.map(function (el) {
				return el.getConnections().filter(function (con) {
					return (curObjChilds.indexOf(con.from) >-1 && curObjChilds.indexOf(con.to) >-1)
				})
			})

			// flat array:[].concat.apply([], formCons);
			formCons = [].concat.apply([], formCons);

			//remove duplicates
			return formCons.filter(function (el, i) {
				return formCons.indexOf(el) == i
			})
		}

		/** checks if event already has connection base on connection Type
		 * for stong condition (for strong condition to allow/disallow strong condition, also handle weak condition accordingly):
		 * 1. if we have weak condition, we can't create strong condition // done'
		 * 2. if we have milestone we can't create strong condition //
		 * 3. if we have strong condition, we can't create weak condition // done '
		 * 4. if we have strong condition, we can't create milestone // done'
		 * 
		 * @param {Element} sourceObj 
		 * @param {string} connectionType 
		 */
		elproto.checkIfAvailableConnection = function(sourceObj, connectionType, strong){
				if(sourceObj==null || sourceObj==undefined){
					return false;
				}

				var thisObj = this;
				if((connectionType == "scondition" || connectionType == "condition" || connectionType == "milestone") && strong && (!thisObj.checkIfAvailableConnection(sourceObj, 'milestone') || !thisObj.checkIfAvailableConnection(sourceObj, 'condition'))){ // if strong check if there is milestone already
					return false;
				}else if((connectionType == "logicalInclude" || connectionType == "include" || connectionType == "exclude") && strong && (!thisObj.checkIfAvailableConnection(sourceObj, 'exclude') || !thisObj.checkIfAvailableConnection(sourceObj, 'include'))){
					return false
				}else if(connectionType == "update" && thisObj == sourceObj){ // The source and target events for a value-arrow cannot be the same. (Because that is the same as shorthand for data event and computational event)
					return false
				}

				// find if connections already has this connection b/w objects or not
				return this.graph.Connections.filter(function(el){
					return el.to == thisObj && el.type == connectionType && ( thisObj == sourceObj ? el.from == thisObj:  el.from == sourceObj );
				}).length>0? false : true;
		}

		function getCommonParentPro (sourceObj, targetObj) {
			var commonParent = undefined;
			var sourceObjParentPros = sourceObj.getParents(true);
			var targetObjParentPros = targetObj.getParents(true);
			for (var i = 0; i < sourceObjParentPros.length; i++) {
				var curSourceParent = sourceObjParentPros[i];
				for (var j = 0; j < targetObjParentPros.length; j++) {
					var curTargetParent = targetObjParentPros[j];
					if(curSourceParent==curTargetParent){
						return curTargetParent;
					}
				};
			};
			return undefined;
		}
		
		/** Set Default value for an Activity having marking as Executed
		 * 
		 * @param {object} value e-g: {id: "Activity1", value: "1", isNull: "false", type: "int", nodeType: "variable"}
		 * 
		 * @returns {Element} Returns an Element object.
		 */
		elproto.setDefaultValue = function(value) {
			this.defaultValue = value;
			return this;
		}

		elproto.canHaveDefaultValue = function() {
			return this.getDataType().type && this.runtimes.executed? true: false;
		}

		//return insight of item
		elproto.getActivityType = function() {
			return typeof this.custom.eventType != 'undefined' && this.custom.eventType != undefined? this.custom.eventType: null;
		}
		
		elproto.getActivityTypeTitle = function(trimmed) {
			var activityType = this.getActivityType()
			var activityTypeTitle = activityType? activityType.title : ''
			return trimmed? activityTypeTitle.trim().length>20? activityTypeTitle.substr(0,20) + '...': activityTypeTitle: activityTypeTitle
		}

		//return insight of item
		elproto.getInsight = function() {
			return this.custom.insight;
		}
		
		//set insight of item
		elproto.setInsight = function(value) {
			return this.custom.insight = value;
		}

		//return dmn Xml definitions only or empty string 
		elproto.prepareDMNXML = function(xml) {
			var definitions = stringToXML(xml).getElementsByTagName('definitions')
			if(definitions && definitions.length>0){
				return XMLtoString(definitions[0])
			}
			return ''
		}
		
		//return resource user id expression of item
		elproto.getResourceExpression = function(key) {
			return typeof this.precondition != 'undefined' && typeof this.precondition[key] != 'undefined'? this.precondition[key] : null;
		}
		
		//set resource user id expression of item
		elproto.setResourceExpression = function(key, value) {
			if(typeof this.precondition == 'undefined' || typeof this.precondition[key] == 'undefined'){
				throw new Error('el>precondition || key['+key+'] not found');
			}

			// "user" will be __USER__ in expression
			// If no user is on the left of = or !=, then add "user" - replace "user" with "__USER__" in expression.
			// TODO: enable following when userid expression validation is implemented
			/* if(key == 'value' && value.match('=')!=null){
				var expression = '__USER__'
				// if has user, just replace it with __USER__, else add __USER__
				value = value.match('user')==null? expression + value : value.replace('user', expression)
			}*/
			return this.precondition[key] = value;
		}
		
		
		//return the full path to item
		elproto.getPath = function(skipSelf) {
			var path = this.getParents().reverse().map(function (el){
				return el.id;
			})
			if(skipSelf!=true){
				path.push(this.id);		
			}	
			return path.join(".");
		}

		//check if this element has more than one parent processes then restrict the connections with it
		elproto.checkIfChildConAvailable = function(sourceObj) {
			if(sourceObj==null || sourceObj==undefined){
				return false;
			}
	
			var targetObj = this;	
			var sourceParentPro = sourceObj.getParentProcess(),
				targetParentPro = targetObj.getParentProcess();

			//check the source and target parent Pro, if parent pro is same then allow connections
			if(sourceParentPro==targetParentPro){
				return true;
			}else{
				//if parent pro is not same for both source/target
				// check the nested level of source parent pro and target parent pro
					// if they are on same level don't allow connection
					// if not same
						// check if either of the target or source parent lie +1 or -1 N level of any of them if they lie then allow connection else don't
				//if source is in root
				if(sourceParentPro==undefined){
					//then check for target if it is in pro or not
					if((targetObj.isProcess()==true && targetObj.getParentProcess()==sourceParentPro) || targetObj.isProcess()==false){
						return true // if target is process and is on 0 level then create spawn relation
					}else{
						return false;
					}
				}else if(targetParentPro==undefined){
					//then check for target if it is in pro or not
					//source can't be a process
					if(targetObj.isProcess()==true && targetObj.getParentProcess()!=sourceParentPro){
						return false;
					}else if(sourceObj.isProcess()==false){
						//allow connection
						return true;
					}else{
						return false;
					}
				}else{
					//this has to be much more optimized : this means that source and target are inside the processes
					if(sourceObj.isProcess()==true){
						//if source is process then no connection is allowed
						return false;
					}else if(targetObj.isProcess()==true){
						//if target is a process then check its nLevel with source
						//now check if the source parent is nested in the target parent or not
						//or target parent pro is nested in the source processes
						if(sourceParentPro==targetParentPro){
							//allow connection
							return true;
						}else{
							return false;
						}
						
					}else if(sourceObj.isProcess()==false && targetObj.isProcess()==false){
						//now check if the exist in same branch or not
						//Get all Parents and find the Common Parent of each items
						//check which one is direct child of topParent
						//if anyone is direct child of topParent then allow connection;
						var commonParent = getCommonParentPro (sourceObj, targetObj)
						var allowCon = false
						if(commonParent!=undefined){
							commonParent.getDirectChilds().forEach(function(el){
									if(sourceObj==el || targetObj==el){
										allowCon = true
										console.log(el)
									}
								})
							return allowCon
						}
					}else{
						return false;
					}

				}

				return false;
			}
		 

			return true;
		}

		// get master activity id with the event
		elproto.isCommonActivity = function() {
			return this.commonId
		}
		
		elproto.setCommonId = function(curID) {
			var idExists = this.graph.checkIfIDExists(curID);
			if (!idExists || curID == this.id) {
				this.id = curID;
				this.commonId = true
				return true;
			}
			return false;
		}
		
		elproto.resetCommonId = function(callback) {
			/* TODO: need to clear requirements with MMQ 
			var curID = this.id
			this.id = this.graph.checkIfIDExists(curID)? this.graph.uniqueEventID(curID, 1): curID;
			*/
			this.commonId = false;
			if(typeof(callback)=='function'){
				callback(this)
			}
		}

		
		// return true if the event is a refer event else returns false
		elproto.isReferEvent = function() {
			if(this.isRefer!=undefined && this.isRefer==true){
				return true;
			}
			return false;
		}
		
		// return true if the event is allowed to be interface Event else returns false
		elproto.canBeInterfaceEvent = function() {
			if(this.isRefer!=undefined && this.isRefer==true){
				return false;
			}

			if(this.baseType!=undefined && this.baseType=='event' && this.type!=undefined && this.type=="default" && this.isParent()!=true){
				return true;
			}
			return false;
		}
		

		elproto.canBeFragment = function() {
			if(this.isRefer!=undefined && this.isRefer==true){
				return false;
			}

			if((this.type =="subprocess" || this.type =="form") && this.isRefer==false && (this.fragmentId==null || this.fragmentId==undefined)){
				return true;
			}
			return false;
		}
		
		elproto.updateFragmentId = function(fragmentId, callback) {
			if((this.type =="subprocess" || this.type =="form") && this.isRefer==false && (fragmentId!=null && fragmentId!=undefined && typeof fragmentId !='undefined')){
				this.fragmentId = fragmentId;
				return true
			}
			return false;
		}
		
		elproto.removeFragmentId = function() {
			this.fragmentId = null;
		}

		elproto.resetInterfaces = function(force) {
			if(this.canBeFragment() || this.isFragment() || force){
				this.custom.interfaces = []
				return true
			}
			return false;
		}



		// return true if the event is a process else returns false
		elproto.isProcess = function() {
			if(this.baseType!=undefined && this.baseType=='process'){
				return true;
			}
			return false;
		}
		
		// return true if the event is a process else returns false
		elproto.isFragment = function() {
			if(( this.isSubProcess() == true || this.isForm() == true ) && this.fragmentId!=undefined && this.fragmentId == parseInt(this.fragmentId)){
				return true;
			}
			return false;
		}
		// return true if the event is a form else returns false
		elproto.isForm = function() {
			if(this.baseType!=undefined && this.baseType=='event' && this.type!=undefined && this.type=="form"){
				return true;
			}
			return false;
		}
		
		// return true if the event is a form else returns false
		elproto.isNesting = function() {
			if(this.baseType!=undefined && this.baseType=='event' && this.type!=undefined && this.type=="nesting"){
				return true;
			}
			return false;
		}
		
		// return true if the event is a form else returns false
		elproto.isSubProcess = function() {
			if(this.baseType!=undefined && this.baseType=='event' && this.type!=undefined && this.type=="subprocess"){
				return true;
			}
			return false;
		}
		
		// return true if the event is a form else returns false
		elproto.isReferForm = function() {
			if(this.isForm()==true && this.isRefer==true){
				return true;
			}
			return false;
		}
		
		//return true if the event has some datatype assigned to it
		elproto.isDataTypeEvent = function() {
			var hasDataType = this.getDataType();

			if(hasDataType!=undefined && hasDataType.type!=undefined){
				return true;
			}
			return false;
		}

		// return true if the event is a refer event else returns false
		elproto.isEvent = function() {
			if(this.baseType!=undefined && this.baseType=='event'){
				return true;
			}
			return false;
		}


		// check if element is present in the arrParents or not
		elproto.isParent = function() {
			var curEl = this;
			var elIsParent = $.grep(this.graph.Parents, function(el){
							//console.log('this->'+curEl.id+' el->'+el.id);
							return curEl.guid == el.guid;				
			});
			if(elIsParent && elIsParent.length >0){
				return true;
			}else{
				return false;
			}
		}

		// check if element is present in the arrChilds or not
		elproto.isChild = function() {
			var curEl = this;
			var elIsChild = $.grep(this.graph.Childs, function(el){
							return curEl.guid == el.guid;				
			});
			if(elIsChild && elIsChild.length >0){
				return true;
			}else{
				return false;
			}
		}

		// returns the sequence of an element for DCR Forms
		elproto.getSequence = function() {
			var curEl = this,
			seq = 0;
			if(curEl.custom.sequence !=undefined && curEl.custom.sequence == parseInt(curEl.custom.sequence)){
				seq = parseInt(curEl.custom.sequence)
			}else if(curEl.custom.eventData!=undefined && curEl.custom.eventData.dataType!=undefined && curEl.custom.eventData.dataType.sequence == parseInt(curEl.custom.eventData.dataType.sequence)){
				seq = parseInt(curEl.custom.eventData.dataType.sequence)
			}
			
			return seq;
		}

		// returns the datatype object of element
		elproto.getDataType = function() {
			var curEl = this,
			curDataType = undefined;
			//custom.eventData != undefined && curEl.custom.eventData === '[object Array]' && curEl.custom.eventData.length > 0
			if(curEl.custom.eventData!=undefined && curEl.custom.eventData.dataType!=undefined){
				curDataType = curEl.custom.eventData.dataType
			}
			
			return curDataType;
		}

		//return event data object which contains the dataType and other properties of event data
		elproto.getEventData = function() {
			var curEl = this,
			curDataType = undefined;
			//custom.eventData != undefined && curEl.custom.eventData === '[object Array]' && curEl.custom.eventData.length > 0
			if(curEl.custom.eventData!=undefined && curEl.custom.eventData.dataType!=undefined){
				curDataType = curEl.custom.eventData
			}
			
			return curDataType;
		}
		
		//return event data object which contains the dataType and other properties of event data,  remove datatype of the Element by making its type = undefined
		elproto.resetEventData = function() {
			if(this.isDataTypeEvent()){
				this.custom.eventData.dataType.type = undefined
				return true;
			}
			return false;
		}

		// TODO: get form for an event or an inline form
		elproto.getForm = function () {
			
		}
		
		//return event data object which contains the dataType and other properties of event data
		elproto.getGraph = function(isFragment, callback) {
			if(isFragment==true){
				var graph = new DCR();
				getGraph (graph, this.fragmentId, undefined, configs, callback, function (graph, restResponse, referPro, callback) {
					if(typeof(callback)=='function'){
						callback(graph, restResponse)
					}
				})
			}else if(this.isForm()==true || this.isProcess()==true){
				var graph = new DCR();
				graph.loadXML(this.dcrgraph);
				return graph;
			}else{
				return this.graph;
			}
		}
		// return interfaces for a fragment
		// TODO: WIP need to refine this in future
		elproto.getInterfaces = function() {
			return this.custom.interfaces.map(function (el) {
				return el
			});
		}

		//update element interfaces
		elproto.updateInterfaces = function (interfaces, items) {
			if(!interfaces){return;}
			var curInterfaces = JSON.parse(JSON.stringify( interfaces ));
			//validate interfaces from subItems in a fragment graph
			// TODO: conform if we need to filter and check if items exist in fragment or not.
			
			this.custom.interfaces = curInterfaces.filter(function (el) {
				return items.some(function (elm) {
					return elm.id===el.from
				})
			}).filter(function (el) {
				return el.to.trim().length>0
			});
	        return this;
	    };
		
		//update element interface type
		elproto.updateInterfaceType = function (type) {
			this.interfaceType = (type == "inner" || type == "outer" )? type : null;
	        return this;
	    };

		//get element interface type
		elproto.getInterfaceType = function () {
			return this.interfaceType && (this.interfaceType == "inner" || this.interfaceType == "outer" )? this.interfaceType : null;
	    };

		/** Function to return the direct parent of a child Element
	    *
	    * @memberof Element 
	    * @method getParent 
	    *
		* @returns {object|null} Returns an Element object.
	    */
	    elproto.getParent = function (){
	    	var curObj = this;
	    	var curItem = $.grep(this.graph.Parents, function (el) {
	    		if(curObj.parentObj!=null){
	    			return  el.guid == curObj.parentObj.guid;
	    		}
	    	});

	    	if(curItem.length>0){
	    		return curItem[0];
	    	}

	    	return undefined;
	    }

	    /** Function to get all parents of current element.
	    *
	    * @memberof Element 
	    * @method getParents 
	    *
		* @returns {array} Returns an array of Element objects.
	    */
		elproto.getParents = function (onlyPros){
			if(this.getParent()!=undefined){
				var allParents = [],
					curParent = this.getParent();
				while(curParent!=undefined){
					if(onlyPros==true){
						if(curParent.isProcess()==true){
					allParents.push(curParent);
						}
					}else{
						allParents.push(curParent);
					}
					curParent = curParent.getParent();
				}

				if(allParents.length>0){
					return allParents
				}
			}

			return [];
		}


		/** Recursive Function to get all childs of current element.
	    *
	    * @memberof Element 
	    * @method getChilds 
	    *
		* @param {boolean}  skipProChilds       - If this value is passed true then all the events with in the processes will be skipped and only those processes will be considered childs including their sibling events.
	    *
		* @returns {array} Returns an array of Element objects.
	    */
		elproto.getChilds = function (skipProChilds, skipReferFormChilds){
			var curObj = this;
			//first get all direct childs 
			var allChilds = [];

			var curChilds = $.grep(this.graph.Childs, function (el) {
				return el.parentGUID == curObj.guid //&& el[0].parentObj.guid = el.parentGUID;
			});

			for (var i = 0; i < curChilds.length; i++) {
				allChilds.push(curChilds[i]);
				allChilds = allChilds.concat(curChilds[i].getChilds(false));
			};

			if(skipProChilds==true){ //this will filter all the events of the process on N level but will not go inside the child Processes
				allChilds.forEach(function(el, i){
					if(el.baseType=='process'){
						el.getChilds(false).forEach(function (elm, indx) {
							allChilds = $.grep(allChilds, function (pEl) {
								return pEl!=elm;
							})
						});
					}
				});
			}

			if(skipReferFormChilds==true){ //this will filter all the events of the process on N level but will not go inside the child Processes
				allChilds.forEach(function(el, i){
					if(el.type=='form' && el.isReferForm()==true){
						el.getChilds(false).forEach(function (elm, indx) {
							allChilds = $.grep(allChilds, function (pEl) {
								return pEl!=elm;
							})
						});
					}
				});
			}

			allChilds.sort(function (a, b) {
						return a.id.toLowerCase().localeCompare(b.id.toLowerCase());
					});

			return allChilds;
		}


		/** Function to get only direct child of current element.
	    *
	    * @memberof Element 
	    * @method getDirectChilds 
	    *
		* @returns {array} Returns an array of Element objects.
	    */
    	elproto.getDirectChilds = function () {
    		var curObj = this;
    		//if traversing to N levels then get all childs of this element
    		//if(nLevel==true){
    			//console.log('hello there!');
    		//}
			var curChilds = $.grep(this.graph.Childs, function(el){
				return el.parentGUID == curObj.guid;
			});

			var curElChild = [];

			for (var i = 0; i < curChilds.length; i++) {
					curElChild.push(curChilds[i]);
			};

			return curElChild;
    	}

    	/** Function to get the parent process of current Element.
	    *
	    * @memberof Element 
	    * @method getParentProcess 
	    *
		* @returns {object|null} Returns an object of Element objects or null.
	    */
	    elproto.getParentProcess = function (topParent, isSubProcess){
			var obj = this;
	    	var curPar = obj.getParents().filter(function (el) {
				return isSubProcess==true? el.baseType == "event" && el.type == "subprocess" :  el.baseType == 'process';
			})
	    	if(curPar.length>0){
	    		if(topParent==true){
	    			var topPar = curPar[0];
	    			for (var i = 0; i < curPar.length; i++) {
	    				if(curPar[i].nLevel<topPar.nLevel){
	    					topPar = curPar[i]
	    				}
	    				
	    			};
	    			return topPar;
	    		}else{
	    			return curPar[0];
	    		}
	    	}

	    	return undefined;		
	    }
		
		/** Function to get the parent form of current Element.
	    *
	    * @memberof Element 
	    * @method getParentForm 
	    *
		* @returns {object|null} Returns an object of Element objects or null.
	    */
	    elproto.getParentForm = function (topParent){
	    	var obj = this;
	    	var curPar = $.grep(obj.getParents(), function (el) {
	    		return el.isForm()==true;
	    	})
	    	if(curPar.length>0){
	    		if(topParent==true){
	    			var topPar = curPar[0];
	    			for (var i = 0; i < curPar.length; i++) {
	    				if(curPar[i].nLevel<topPar.nLevel){
	    					topPar = curPar[i]
	    				}
	    				
	    			};
	    			return topPar;
	    		}else{
	    			return curPar[0];
	    		}
	    	}

	    	return undefined;		
	    }

	    /** Function to get the the default runtimes of current Element.
	    *
	    * @memberof Element 
	    * @method getRuntime
	    *
	    * @param {string}  eRuntime       - The runtime for which the value to get against of current element. possible values are:  'included', 'pending', 'executed'.
	    *
		* @returns {boolean|null} Returns a value of requested property or null.
	    */
	    elproto.getRuntime = function (eRuntime){
	    	if(eRuntime.length<1){
	    		return null;
	    	}

	    	switch(eRuntime){
	    		case 'included':
	    			return this.runtimes.included;
	    		case 'pending':
	    			return this.runtimes.pending;
	    		case 'executed':
	    			return this.runtimes.executed;
	    		default:
	    			return null;
	    	}
	    }

	    /** Function to get current Nested level of current Element.
	    *
	    * @memberof Element 
	    * @method currentLevel
	    *
		* @returns {integer} Returns the nesting level of current level.
	    */
		elproto.currentLevel = function (){
			//current event is determined based on the event's node classes
			// the number of classes on the events will determine its level
			/*var totalClassCount = this.node.className.baseVal.split(" ");
			totalClassCount = $.grep(totalClassCount, function(el){
				return el != '' && el != ' ' && el != 'moving';
			});
			return totalClassCount.length;*/
			

			/*var curObj = this;
			var currentLevel = this.nLevel;

			//check the object in childs array, if it is not in childs array return nLevel 0
			var isChild = $.grep(this.graph.Childs, function(el){
				return el[0] == curObj;
			});

			if(isChild.length==0){
				this.nLevel = 0;
				return this.nLevel;
			}



			//if the obj is in childs array then search for its parent and calculate the nesting
			//get the parent of this Event
			var curCParentID = isChild[0][1];
			var curCParent = $.grep(this.graph.Parents, function(el){
				return el.id == curCParentID;
			});

			calculateNLevel (curObj, curCParent[0])


			return curObj.nLevel;*/
			return this.nLevel;
		}

		 // return raphael object based on the node element provided
	    elproto.dashedId = function (){
	        return this.id.replace(new RegExp(" ", 'g'), "-");
		}
		
		//sets colors for the element e-g {bg: "#b1ea98"}
		elproto.colors = function(props){
			if(props){
				for(var k in props) this.custom.visualization.colors[k]=props[k];
			}else{
				this.custom.visualization.colors
			}
		}

		 // transfroms an element to defined types, only works for baseTypeEvents
	    elproto.transformTo = function (type){
			if(this.baseType!="event"){
				return undefined
			}
			var types = ["default", "nesting", "subprocess", "form", "transactional_subprocess"]
			if(types.indexOf(type)!= -1){
				this.type = type;

				if(type!=="default"){
					//check if this has any datatype, if any then remove it
					this.resetEventData();
				}

				if(type == "subprocess"){
					this.custom.roles = [];
				}

				var formOptions = {'cancelText': '' , 'sendText': '', 'hideCancel': false, 'formShowInitialPhase': 1};
				if(type=="form"){
					/* TODO: disabled form colors, remove in future
					this.colors({
						bg : '#b1ea98',
						textStroke : '#000000',
						stroke : '#6aa84f'
					})	*/
					// if form doesn't already have these properties then add these
					for (var key in formOptions) {
						if(!this.hasOwnProperty(key)){
							this[key] = formOptions[key];
						}
					}
				}else{
					// reset the values
					for (var key in formOptions) {
						if(this.hasOwnProperty(key)){
							this[key] = formOptions[key];
						}
					}
				}
			}	

	    }

	     //this function is used to remove the activity or process form Graph
	    elproto.remove = function (forceDelete) {

	    	var curEl = this,
	    	graph = this.graph;

	        //see if the item is a refer item child then don't allow delte on this.
			if(curEl.isReferEvent()==true && curEl.isProcess()==false && forceDelete!=true && curEl.getParentProcess()!=undefined || (curEl.getParentProcess()!=undefined && curEl.getParentProcess().isRefer==true)){
				alert('This operation is not allowed for referred element')
				return false;
			}

			//check if the unnest is allowed on this element or not?
			if(graph.checkIfNestingOpAllowed(curEl, false)==false && forceDelete!=true){
				//show message nesting operation can't be performed
				alert('Some Connections are Restricting the Operations you want to Perfrom, remove connections and try again')
				return false;
			}
						
			//if current node is parent then remove its class from all of its children
			if(curEl.isParent()==true){

				if((curEl.isProcess() && curEl.isRefer==true) || (curEl.isForm() && curEl.isRefer==true)){
					//then delete all of its childs
					console.log('is Refer process');
					curEl.getChilds().forEach(function(el, index){
						el.removed = true;
						//if this parent has childs then remove them form childs array as well
						if(graph.Childs.indexOf(el)!= -1){
							graph.Childs.splice(graph.Childs.indexOf(el), 1);
						}
						//if any child is in the parents array remove it from there too
						if(graph.Parents.indexOf(el)!= -1){
							graph.Parents.splice(graph.Parents.indexOf(el), 1);
						}
						//if any child is in the parents array remove it from there too
						if(graph.Events.indexOf(el)!= -1){
							graph.Events.splice(graph.Events.indexOf(el), 1);
						}
						//if any child is in the parents array remove it from there too
						if(graph.Processes.indexOf(el)!= -1){
							graph.Processes.splice(graph.Processes.indexOf(el), 1);
						}
						//if any child is in the parents array remove it from there too
						if(graph.ReferredPros.indexOf(el)!= -1){
							graph.ReferredPros.splice(graph.ReferredPros.indexOf(el), 1);
						}

						if(graph.ReferredForms.indexOf(el)!= -1){
							graph.ReferredForms.splice(graph.ReferredForms.indexOf(el), 1);
						}

						for(var i =0 ; i<graph.Connections.length; i++){
							//console.log(connections.length);
							if(graph.Connections[i].from == el || graph.Connections[i].to ==el){
								graph.Connections[i].graph = null 
							}
						}

					})
					//remove it from referred Pros array
					for(var i =0 ; i<graph.ReferredPros.length; i++){
						if(graph.ReferredPros[i] == curEl ){
							 graph.ReferredPros.splice(i,1); 
						}
					}

					for(var i =0 ; i<graph.ReferredForms.length; i++){
						if(graph.ReferredForms[i] == curEl ){
							 graph.ReferredForms.splice(i,1); 
						}
					}
				}else{
					curEl.getDirectChilds().forEach(function(el, index){
						//if this parent has childs then remove them form childs array as well
						if(graph.Childs.indexOf(el)!= -1){
							graph.Childs.splice(graph.Childs.indexOf(el), 1);
						}

						//if any child is in the parents array remove it from there too
						// if(graph.Parents.indexOf(el)!= -1){
						// 	graph.Parents.splice(graph.Parents.indexOf(el), 1);
						// }

						//can not do this as unnest will not work for referred elements
						//el.unNest(); //simple un nest the direct child 

						el.parentGUID = undefined;
						el.parentId = null;
						el.parentObj =  null;
						el.parentPro = 'root';

						var curElLevel = el.nLevel - curEl.nLevel;
						el.nLevel = 0;

						el.getChilds().forEach(function (elx, index) {
							// setting the Nested Level of childs of current Event
							if (elx.baseType == 'event') {
								elx.nLevel = elx.nLevel - curElLevel;
							}
						})

					});
				}

				

				//remove it from parents array
				for(var i =0 ; i<graph.Parents.length; i++){
					if(graph.Parents[i] == curEl ){
						 graph.Parents.splice(i,1); 
					}
				}

			}

			//if current event is child then remove it from child array
			//remove it from children array
			if(graph.Childs.indexOf(curEl)!= -1){
				graph.Childs.splice(graph.Childs.indexOf(curEl), 1);
			}
			
				
			graph.Connections.filter(function (el) {
				if(el.from == curEl || el.to ==curEl){
					//checks if the current object has any relation with any other object
					return el;
				}
			}).forEach(function (el) {
				//then remove all the to and from connections related to current object	
				el.remove()
			})

			//finally remove it from arrAllEvents
			if(checkForMatch(graph.Events, 'guid', curEl.guid)!= -1){
				graph.Events.splice(checkForMatch(graph.Events, 'guid', curEl.guid), 1);
			}else if(curEl.isProcess()==true && checkForMatch(graph.Processes, 'guid', curEl.guid)!= -1){
				graph.Processes.splice(checkForMatch(graph.Processes, 'guid', curEl.guid), 1);
			}	

			removeHighlights(graph, curEl)

			graph.eCount = graph.Events.length;
			graph.pCount = graph.getProcessCount();

			return true;
	    }

    	/** Function to get the bounding box of current Element.
	    *
	    * @memberof Element 
	    * @method getBBox
	    *
		* @returns {object} Returns an object containing x, y cordinates of current element along with height and width of it.
	    */
    	elproto.getBBox = function () {
			var x = this.custom.visualization.location.xLoc,
				y = this.custom.visualization.location.yLoc,
				width = this.custom.visualization.dimension.width,
				height = this.custom.visualization.dimension.height;

			return {
				x: x,
				y: y,
				x2: x+ width,
				y2: y+ height,
				cx: x+ (width/2),
				cy: y+ (height/2),
				width: width,
				height: height
			}
		}

    	elproto.printDetails = function () {
	        //if (Graph.CurrentEl) {
				console.log(this.id);
				//console.log(this);
			//}
			return this;
	    };

	    elproto.setID = function (id) {
	        if (/*Graph.CurrentEl && */arguments.length>0) {
				console.log('setting ID');
				this.id = id;
			}
			return this;
	    };

	    // function to nest an element in to other element
		elproto.nestUnder = function (nestTo) {

			// see if the item is a refer item child then don't allow delte on this.
			if ((nestTo.isRefer == true) || nestTo.isProcess() == true && nestTo.isRefer == true) {
				alert('This operation is not allowed for referred element');
				return false;
			}

			// if the this is already a child then return
			if (this.isChild() == true) {
				alert(this.custom.label + ' is already nested under, first unnest it and then try again.');
				return false;
			}

			// check if a nesting element is to be nested to one of its own childs then restrict it
			if (checkForMatch(this.getChilds(), 'guid', nestTo.guid) >= 0) {
				alert(this.custom.label + ' can not be nested in its own childs.');
				return false;
			}

			// check if the unnest is allowed on this element or not?
			if (this.graph.checkIfNestingOpAllowed(nestTo, true, this) == false) {
			// show message nesting operation can't be performed
				alert('Some Connections are Restricting the Operations you want to Perfrom, remove connections and try again')
				return false;
			}

			// if source is Process then don't nest it under an event
			if (this.isProcess() == true && nestTo.isProcess() == false) {
				alert("A process can't be nested in an activity")
				return false;
			}

			// same element can't be nested in itself
			if (this == nestTo) {
				alert("same element can't be nested in itself")
				return false;
			}

			// if nestTo has a datatype then remove it: Important! If the activity had a data type it should be removed once something is nested inside.
			if(nestTo.isDataTypeEvent()){
				nestTo.resetEventData()
			}

			// add parent and child info to arrParents and arrChilds
			// check if parent already exists in arrParents then don't add it more than once
			if(checkForMatch(this.graph.Parents, 'guid', nestTo.guid)<0){
				this.graph.Parents.push(nestTo);
			}

			// add source as child in arrChilds
			this.graph.Childs.push(this);
			this.parentGUID = nestTo.guid;
			this.parentId = nestTo.id;
			this.parentObj = nestTo;

			//TODO: need to handle parentPro for subprocess nesting, it will also have impact on import

			//update the type for the items
			if(((nestTo.type=="default" && nestTo.getChilds().length<2) || nestTo.type==undefined) && nestTo.isProcess()==false){
				nestTo.transformTo("subprocess");
			}


			// setting the Nested Level of selected Event
			this.nLevel = parseInt(nestTo.nLevel) + 1
			// check if source has any child already
			var nestEl = this;
			nestEl.getChilds().forEach(function (el, index) {
			    // setting the Nested Level of childs of current Event
			    el.nLevel = el.nLevel + nestEl.nLevel;
			})

			return true;
		}

		//function to apply runtimes for the event
		elproto.applyMarking = function (markingCase, markValue) {
			if (markingCase == 'included') {
				// for included runtime
				if (markValue == true) {
					this.runtimes.included = true;
				} else {
					this.runtimes.included = false;
				}
			}else if (markingCase == 'pending') {
				// for pending runtime
				if (markValue == true) {
					this.runtimes.pending = true;
				} else {
					this.runtimes.pending = false;
				}
			}else if (markingCase == 'executed') {
				// for executed runtime
				if (markValue == true) {
					this.runtimes.executed = true;
				} else {
					this.runtimes.executed = false;
				}
			}
		}

		elproto.unNest = function () {
			// see if the item is a refer item child then don't allow delte on this.
			if ((this.getParentProcess() != undefined && this.getParentProcess().isRefer != undefined && this.getParentProcess().isRefer == true) || this.isProcess() == true && this.isRefer == true) {
				alert('This operation is not allowed for referred element')
				return false;
			}

			// check if the unnest is allowed on this element or not? 
			if (this.graph.checkIfNestingOpAllowed(this, false) == false) {
				// show message nesting operation can't be performed
				alert('Some Connections are Restricting the Operations you want to Perfrom, remove connections and try again')
				return false;
			}

			// if the this is already a child then return
			if (this.isChild() != true) {
				return false;
			}


			// remove it from children array
			for (var i = 0; i < this.graph.Childs.length; i++) {
				if (this.graph.Childs[i].guid == this.guid) {
					this.graph.Childs.splice(i, 1)
				}
			}

			// remove parent from arrParents
			// check if parent has no more child then remove it from arrParents
			var sParent = this.getParent()
			if (sParent.getChilds().length == 0 ) {
				for (var i = 0; i < this.graph.Parents.length; i++) {
					if (this.graph.Parents[i].guid == sParent.guid) {
						this.graph.Parents.splice(i, 1)
					}
				}
				//update its type as default if it is nesting type
				if(sParent.type== "nesting"){
					sParent.transformTo("default");
				}
			}

			//this.nLevel = parseInt(nestTo.nLevel) + 1
			var delta = this.nLevel - sParent.nLevel;
			this.nLevel = 0;

			this.getChilds().forEach(function (el, index) {
				// setting the Nested Level of childs of current Event
				//if (el.baseType == 'event') {
					el.nLevel = el.nLevel - delta;
				//}
			})

			this.parentGUID = null;
			this.parentId = null;
			this.parentObj = null;

			return true;
		}

		elproto.hasRole = function (role) {
			return this.custom.roles.find(function(el){return el==role})
		}

		elproto.isComputeable = function () {
			return this.computation!=undefined && this.computation.trim().length>0? true: false
		}
		
		//get computation
		elproto.getComputedValue = function () {
			var self = this;
			if(this.isComputeable()){
				var item = this.graph.GlobalStore.find(function (el) {
					return el.id == self.id
				})
				return item!=undefined?item.value: null;
			}
		}

	    //to extend the library for plugins usage
	    D.fn = graphproto = Graph.prototype = D.prototype;

	    /** Function to reset the graph and its properties 
	    *
	    * @memberof Graph 
	    * @method reset 
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent(); //An Event will be added to the graph.
		* myApp.reset(); // will reset the graph.
		* @returns {object} Returns an object of Graph Class.
	    */
	    graphproto.reset = function () {
	    	//creating a new graph object
	    	var newGraph = new Graph();
	    	//transfering all the new properties to the current object
	    	for(var k in newGraph) this[k]=newGraph[k];
	        return this;
	    };

	    //function to get all child events of DCR Root (supports N level nesting) the Main Paper Variable is DCR
		graphproto.getAllRootEvents = function (){

			//filtering only Events from curEventChild
			var curElEventChilds = [];

			this.Events.forEach(function(el){
				curElEventChilds.push(el);
			});

			this.Processes.forEach(function(el){
				el.getChilds(false).forEach(function (elm, indx) {
					curElEventChilds = $.grep(curElEventChilds, function (pEl) {
						return pEl!=elm;
					})
				})
			});
			
			return curElEventChilds;
		}

		graphproto.getFragmentsList = function (){
			return this.Events.filter(function (el) {
				return el.isFragment()
			}).map(function (el) {
				return {Id: el.fragmentId,
					Path: el.getPath(),
					Interfaces: el.getInterfaces()}	
			})
		}

		//function to check if the nesting or the undesting is allowed because of the connections of the obj
		graphproto.checkIfNestingOpAllowed = function (targetObj, isNestUnder, sourceObj) {
			var graph = this;
			var curObjs = [], 
				curProChilds = [], 
				curObjsExtCons = [], 
				curObjsIntCons = [];
			//if nest under is active then
			if(isNestUnder==true){
				//check for csource obj and this obj

				if(targetObj.baseType=='process' || targetObj.getParentProcess()!=undefined){
					//if nesting inside a process or an event which is inside a process
						//then check if the source has any connections
							//if has any connections out of its elements then which is not spawn then return true
							//else if it has no connections with others than his siblings then allow it
					
								
					if(sourceObj.baseType=='process'){
						//if source is process, then check if it has spawn relation or not
						//if it has spawn relation then restrict nesting
						var curProDirectChilds = sourceObj.getDirectChilds();
						for (var i = 0; i < graph.Connections.length; i++) {
							if(graph.Connections[i].to == sourceObj && checkForMatch(curProDirectChilds, "guid", graph.Connections[i].from.guid)<0){
								return false;
							}
						};
						//else continue testing on its childs
						curObjs = sourceObj.getChilds();
						curProChilds = sourceObj.getChilds();
					}else{
						if(sourceObj.getChilds(false).length>0){
							curObjs = sourceObj.getChilds(false);
						}
						curObjs.push(sourceObj);
						
						//if source is already inside a processes
						if(sourceObj.getParentProcess()!=undefined){
							return false;
						}else{
							curProChilds = graph.getAllRootEvents();
						}
					}			

					if(targetObj.baseType=='process'){
						var curProDirectChilds = targetObj.getDirectChilds();
						targProChilds = targetObj.getChilds(true);
					}else{
						if(targetObj.getParentProcess()!=undefined){
							targProChilds = targetObj.getParentProcess().getChilds(true);
						}else{
							targProChilds = [];
						}
					}

					//check the children of the processes if any of them has a connections with the outer event then it is not allowed to perform the operation					

					//if the source object doesn't have any connecitons then check its childs for connections 
					// if they have connections with other processes then restrict the source to nestunder
					for (var j = 0; j < curObjs.length; j++) {
						for (var i = 0; i < graph.Connections.length; i++) {
							if(graph.Connections[i].from == curObjs[j]){
								//if this from then check the to of this con
									//if the con exists in cur ProChilds then contine else return false and break
									if(checkForMatch(curProChilds, "guid", graph.Connections[i].to.guid)<0){
										curObjsExtCons.push(graph.Connections[i]);
									}else{
										curObjsIntCons.push(graph.Connections[i]);
									}
							}else if(graph.Connections[i].to == curObjs[j]){
								//if this to then check the from of this con
									//if the con exists in cur ProChilds then contine else return false and break
									if(checkForMatch(curProChilds, "guid", graph.Connections[i].from.guid)<0){
										curObjsExtCons.push(graph.Connections[i]);
									}else{
										curObjsIntCons.push(graph.Connections[i]);
									}
							}
						}

					}
					//also check the levels of source and targets
					for (var i = 0; i < curObjsExtCons.length; i++) {

						//check if source and target can have connections then allow nesting else reject
						if(curObjsExtCons[i].to.baseType=='process' && (curObjsExtCons[i].to == targetObj && checkForMatch(curProDirectChilds, "guid", curObjsExtCons[i].from.guid)<0)){
										return false;
										}
									}

							}

				return true;

			}else{
				//if it for unnesting then 


				if(targetObj.baseType=='process'){
					//if source is process, then check if it has spawn relation or not
					//if it has spawn relation then restrict nesting
					var curProDirectChilds = targetObj.getDirectChilds();
					for (var i = 0; i < graph.Connections.length; i++) {
						if(graph.Connections[i].to == targetObj && checkForMatch(curProDirectChilds, "guid", graph.Connections[i].from.guid)<0){
							return false;
						}
					};
					curObjs = targetObj.getChilds();
					curProChilds = targetObj.getChilds();
				}else{
					return true;
					// if(targetObj.getChilds(false).length>0){
					// 	curObjs = targetObj.getChilds(false);
					// }
					// curObjs.push(targetObj);
					// if(targetObj.getParentProcess()!=undefined){
					// 	curProChilds = targetObj.getParentProcess().getChilds(true);
					// }else{
					// 	curProChilds = graph.getAllRootEvents();
					// }
				}

				// if(targetObj.getParentProcess()==undefined){
				// 	return true;
				// }

				//check the children of the processes if any of them has a connections with the outer event then it is not allowed to perform the operation
				//if the source object doesn't have any connecitons then check its childs for connections 
				// if they have connections with other processes then restrict the source to nestunder
				for (var j = 0; j < curObjs.length; j++) {
					for (var i = 0; i < graph.Connections.length; i++) {
						if(graph.Connections[i].from == curObjs[j]){
							//if this from then check the to of this con
								//if the con exists in cur ProChilds then contine else return false and break
								if(checkForMatch(curProChilds, "guid", graph.Connections[i].to.guid)<0){
									curObjsExtCons.push(graph.Connections[i]);
								}else{
									curObjsIntCons.push(graph.Connections[i]);
								}
						}else if(graph.Connections[i].to == curObjs[j]){
							//if this to then check the from of this con
								//if the con exists in cur ProChilds then contine else return false and break
								if(checkForMatch(curProChilds, "guid", graph.Connections[i].from.guid)<0){
									curObjsExtCons.push(graph.Connections[i]);
								}else{
									curObjsIntCons.push(graph.Connections[i]);
								}
						}
					}
				}
				//if this is a subprocess and any of its child has external connection then return false as process to process connections are not allowed
				//unless the item to which connection is made has no parent process i-e it exists in root process
				for (var i = 0; i < curObjsExtCons.length; i++) {
					//check if source and target can have connections then allow nesting else reject
					if(curObjsExtCons[i].from.getParentProcess()!=undefined && curObjsExtCons[i].to.getParentProcess()!=undefined && curObjsExtCons[i].to != targetObj){
						return false;
					}
				}

				return true;

			}
		}

	    //checks if the id of an event already exists or not
		graphproto.checkIfIDExists = function(itemID){
			var idStatus = false;

			var items = this.Events.concat(this.Processes)

			for (var i = 0; i < items.length; i++) {
				if(items[i].id === itemID){
					idStatus = true;
				}
				
			};

			return idStatus;
		}

		// gets unique ID for the Events
		graphproto.uniqueEventID = function(eventID, p){
			if (this.checkIfIDExists(eventID + "_" + p))
		        return this.uniqueEventID(eventID, p + 1);
		    else
		        return eventID + "_" + p;
		}

		graphproto.getProcessCount = function () {
			var count = 0;
			for (var i = this.Processes.length - 1; i >= 0; i--) {
				if(this.Processes[i].isRefer==false){
					count++;
				}
			};
			return count;
		}
		graphproto.getFormCount = function () {
			return this.ReferredForms.length
		}
	    //if item is passed then it will create copy of the itemID
	    graphproto.getNewID = function (isProcess, itemID, itemLabel) {

	    	var curCount = this.eCount;
	    	var curID = 'Activity' + curCount;
	    	
	    	if(isProcess == true){
	    		curCount = this.getProcessCount();
		    	curID = 'Process' + curCount;
		    }else if(isProcess == false){
		    	//this means it is a form
	    		curCount = this.getFormCount();
		    	curID = 'Form' + curCount;

		    }

		    // this is for copy paste function
		    if (itemID != undefined) {
		      curID = itemID + 'Copy'
		      var idExists = this.checkIfIDExists(curID);
		      if (idExists) {
		        curID = this.uniqueEventID(curID, 1);
		      }
		      if (itemLabel != undefined) {
		        if (curID.split('_').length > 1) {
		          itemLabel = itemLabel + 'Copy' + curID.split('_')[curID.split('_').length - 1]
		        } else {
		          itemLabel = itemLabel + 'Copy'
		        }
		      }else{
		      	itemLabel = curID;
		      }
		    } else {
		    	itemLabel = curID;
				var idExists = this.checkIfIDExists(curID);
				if (idExists) {
					curID = this.uniqueEventID(curID, 1);
				}
		    }

		    return {id: curID, label:itemLabel}
	    };

	    //helper functions to add resources to graph
	    //TODO: add validations and class for resources
	    graphproto.addEventType = function (el) {
	    	if(!el){return;}
	        this.EventTypes.push(el);
	        return el;
	    };
		
		
		//TODO: need to create new connections as these will have same object
		graphproto.updateConnections = function (graph) {
			if(!graph || !graph instanceof D){return;}
			graph.Connections = graph.Connections;
	        return el;
	    };

	    //helper functions to create events/processes 
	    /** Function to to create an Events in graph 
	    *
	    * @memberof Graph 
	    * @method createEvent 
	    *
	    * @param {object} el -An object can be passed with properties assign to it, see example
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent(); //this will create a simple event
		* myApp.createEvent({'custom' : {'label':'An Event', 'eventDescription':'This is a test Event'}});
		* //we can also provide attributes for the event object like above
		* @returns {object} Returns an object of Element Class.
	    */
	    graphproto.createEvent = function (el) {
	    	if(!el){el = {}}
	        var res = new Element(this, el, false);
	        this.Events.push(res);
	        this.eCount++; //console.log(res);
	        return res;
	    };

	    graphproto.removeEvent = function (el) {
	    	if(!el){return false}

	    };

	    /** Function to to create Process in graph
	    *
	    * @memberof Graph
	    * @method createProcess 
	    *
	    * @param {object} el -An object can be passed with properties assign to it, see example
	    *
		* @example var myApp = new DCR();
		* myApp.createProcess(); //this will create a simple process
		* myApp.createProcess({'custom' : {'label':'A Process', 'eventDescription':'This is a test Process'}});
		* //we can also provide attributes for the process object like above, most of the properties of events and processes are same so we can use the same properties here
		* @returns {object} Returns an object of Element Class.
	    */
	    graphproto.createProcess = function (el, isRefer) {
	    	if(this.ProsDisabled==true) return
	    	if(!el){el = {}}
    		if(isRefer==true){
    			var res = new Element(this, el, true, false, true);
    			this.Parents.push(res);
				this.ReferredPros.push(res);
    		}else{
    			var res = new Element(this, el, true);
    		}
	        
	        this.Processes.push(res);
	        return res;
	    };
	    /** Function to to create Form in graph
	    *
	    * @memberof Graph
	    * @method createForm 
	    *
	    * @param {object} el -An object can be passed with properties assign to it, see example
	    *
		* @example var myApp = new DCR();
		* myApp.createForm(); //this will create a simple process
		* myApp.createForm({'custom' : {'label':'A Form', 'eventDescription':'This is a test Form'}});
		* //we can also provide attributes for the process object like above, most of the properties of events and processes are same so we can use the same properties here
		* @returns {object} Returns an object of Element Class.
	    */
	    graphproto.createForm = function (el) {
	    	if(this.ProsDisabled==true) return
	    	if(!el){el = {}}
	        var res = new Element(this, el, false, true);
	        this.Events.push(res);
		    this.Parents.push(res);
			this.ReferredForms.push(res);
	        return res;
	    };
		/** Function to to create Fragment in graph
	    *
	    * @memberof Graph
	    * @method createFragment 
	    *
	    * @param {object} el -An object can be passed with properties assign to it, see example
	    *
		* @example var myApp = new DCR();
		* myApp.createFragment(); //this will create a simple process
		* myApp.createFragment({'custom' : {'label':'A Form', 'eventDescription':'This is a test Form'}});
		* //we can also provide attributes for the process object like above, most of the properties of events and processes are same so we can use the same properties here
		* @returns {object} Returns an object of Element Class.
	    */
	    graphproto.createFragment = function (el, isForm) {
	    	if(this.ProsDisabled==true) return
	    	if(!el){el = {}}
	        var res = new Element(this, el, false, isForm, false, true);
	        this.Events.push(res);
	        return res;
	    };

	    /** Function to to create a Connection in graph, if connection is strong condition, create a condition and a milestone with link
	    *
	    * @memberof Graph 
	    * @method createConnection
	    *
	    * @param {object}  from               - An element object is passed as source element from where connection will originate.
		* @param {object}  to       - An element object is passed as target element to where connection will end up.
		* @param {string}  type         - Connection type is passed as string so a connection can be identified, possible values are 'condition', 'response', 'include', 'exclude', 'milestone', 'spawn', 'update'.
		* @param {string}  guard         - Guard for the connection as string.
		* @param {number}  level         - filter level of the connection greater than or equal to Zero.
		* @param {string}  desc         - Description of the connection as string.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'Enter'});
		* myApp.createEvent({'id':'Exit'});
		* myApp.createConnection(myApp.getById('Enter'), myApp.getById('Exit'), 'response');
		* //this will create an Event Element Enter and Exit, then we can use the app to create a response connection between two by finding them by their Ids.
		* @returns {object} Returns an object of Connection Class.
	    */
	    graphproto.createConnection = function (from, to, color, type, guard, level, desc, time, groups, strong, businessRule, valueExpression) {
			// if connection already exists then don't create new relation
			if(to.checkIfAvailableConnection(from, type, strong)){
				var res = new Connection(this, from, to, color, type, guard, level, desc, time, groups, strong, null, businessRule, valueExpression);
				this.Connections.push(res);
				if(type == 'condition' && strong){
					// create a new milestone connection as well, as condition will be primary connection so we will only return that
					this.Connections.push((new Connection(this, from, to, color, 'milestone', guard, level, desc, time, groups, false, res.link, businessRule, valueExpression)));
				}else if(type == 'include' && strong){
					// create a new milestone connection as well, as condition will be primary connection so we will only return that
					this.Connections.push((new Connection(this, from, to, color, 'exclude', guard, level, desc, time, groups, false, res.link, businessRule, valueExpression)));
				}
				return res;
			}	
			return null
	    };

	    /** Function to get the number of Nesting levels currently available, this number is generated on the basis of nesting in the graph to find out to which extant nesting is occuring. Base starts from 0 to N level of nesting
	    *
	    * @memberof Graph 
	    * @method getMaxNLevel
	    *
		* @returns {Number} Returns the maximum number of the nesting level.
	    */
		graphproto.getMaxNLevel = function(){
			var currentMaxLevel = 0;
			for(var i = 0; i<this.Events.length; i++){
				//console.log('level is '+ arrAllEvents[i].data('NLevel'));
				if(this.Events[i].nLevel>currentMaxLevel){
					currentMaxLevel = this.Events[i].nLevel;
				}
			}
			return currentMaxLevel;
		}
		/** Function to get the number of Sequence number currently available. Base starts from 0 
	    *
	    * @memberof Graph 
	    * @method getMaxSequence
	    *
		* @returns {Number} Returns the maximum number of the sequence number.
	    */
		graphproto.getMaxSequence = function(){
			var currentMaxSequence = 0;
			for(var i = 0; i<this.Events.length; i++){
				if(this.Events[i].custom.sequence>currentMaxSequence){
					currentMaxSequence = this.Events[i].custom.sequence;
				}
			}
			return currentMaxSequence;
		}

		/** Function to get all the Filter levels currently available.
	    *
	    * @memberof Graph
	    * @method getAllLevels 
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'custom' : {'label':'An Event', 'level':2}});
		* myApp.createEvent({'custom' : {'label':'Another Event', 'level':5}});
		* myApp.getAllLevels();
		* //returns [2, 5]
		* @returns {array} Returns an array of numbers containing the filter levels available in graph.
	    */
		graphproto.getAllLevels = function(){
			var allLevels = [];
			for (var i = 0; i < this.Events.length; i++) {
				if($.inArray(this.Events[i].custom.level, allLevels)===-1){
					allLevels.push(this.Events[i].custom.level);
				}
			};
			return allLevels;
		}

		/** Function to get all the events by a specific role.
	    *
	    * @memberof Graph 
	    * @method getEventsByRole
	    *
	    * @param {string}  sRole         - Name of the role for which to search Events against.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'custom' : {'label':'An Event', 'roles':['test']}});
		* myApp.createEvent({'custom' : {'label':'Another Event','roles':['test']}});
		* myApp.getEventsByRole('test');
		* //returns [Element, Element]
		* @returns {array} Returns an array of Element Class object which have the specified role assigned to them in graph.
	    */
		graphproto.getEventsByRole = function (sRole) {
			var res = $.grep(this.Events, function (el) {
				if($.inArray(sRole, el.custom.roles)>=0){
		    		return el;
		    	}
			})	
			return res;
		}

		/** Function to get all the events by a specific level
	    *
	    * @memberof Graph 
	    * @method getEventsByLevel
	    *
	    * @param {number}  sLevel         - Value of the level of which events are to be find.
	    * @param {boolean}  proToo         - Requires True to find Processes too.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'custom' : {'label':'An Event', 'level':2}});
		* myApp.createEvent({'custom' : {'label':'Another Event','level':5}});
		* myApp.getEventsByLevel(5);
		* //returns [Element]
		* @returns {array} Returns an array of Element Class object which have the specified level assigned to them in graph.
	    */
		graphproto.getEventsByLevel = function (sLevel, proToo) {
			var res = $.grep(this.Events, function (el) {
					return el.custom.level == parseInt(sLevel);
				});
			var resP = [];
			if(proToo==true){
				resP = $.grep(this.Processes, function (el) {
					return el.custom.level == parseInt(sLevel);
				});
			}
			return res.concat(resP);
		}
		
		/** Function to get all interface Events
	    *
	    * @memberof Graph 
	    * @method getInterfaceEvents
	    *
		* @example var myApp = new DCR();
		* myApp.getInterfaceEvents({'interfaceEvent': true, 'custom' : {'label':'An Event', 'level':2}});
		* myApp.createEvent({'custom' : {'label':'Another Event','level':5}});
		* myApp.getInterfaceEvents();
		* //returns [Element]
		* @returns {array} Returns an array of Element Class object which are interface Events in graph.
	    */
		graphproto.getInterfaceEvents = function (parentEl, type) {
			if(!type) {type = "outer"}; //interfaceFromOuter
			return this.Events.filter(function (el) {
				if(parentEl){
					var curParent = parentEl.isForm()? el.getParentForm(): el.getParentProcess(false, true);
					return el.interfaceType == type && curParent? curParent.id == parentEl.id: false;
				}else{
					return el.interfaceType == type;
				}	
			});
		}

		/** Function to search events in a graph
	    *
	    * @memberof Graph 
	    * @method findActivity
	    *
	    * @param {string}  id         - Id of the object to be found, value is case sensitive.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'An Event', 'custom' : {'label': 'test item'}});
		* myApp.findActivity('An Event');
		* //returns Element
		* @returns {object} Returns the first item found as an object of Element class or returns null.
	    */
	    graphproto.findActivity = function (id) {

			if(id==undefined || id == null){
				return [];
			}

			//get the event from this.Events and match its ID
			var res = this.Events.filter(function (item) {
				return id.split('_').every(function (el) {
					return item.id.indexOf(el) > -1;
				});
			});
			return res.length>0? res[0]: null;
	    };

	    /** Function to search events/processes in a graph
	    *
	    * @memberof Graph 
	    * @method getById
	    *
	    * @param {string}  id         - Id of the object to be found, value is case sensitive.
	    *
		* @example var myApp = new DCR();
		* myApp.createEvent({'id':'An Event', 'custom' : {'label': 'test item'}});
		* myApp.getById('An Event');
		* //returns Element
		* @returns {object} Returns the first item found as an object of Element class.
	    */
	    graphproto.getById = function (id) {

			if(id==undefined || id == null){
				return undefined;
			}

			var path = id.split('.'), res = [], items = this.Events.concat(this.Processes, this.ReferredForms, this.Childs), self = this;

			//! as same activity id can be in fragments or referred graphs so need to find the exact event
			return findItem(path, items);
		};

		// https://tc39.github.io/ecma262/#sec-array.prototype.find
		if (!Array.prototype.find) {
			Object.defineProperty(Array.prototype, 'find', {
			value: function(predicate) {
				if (this == null) {
				throw new TypeError('"this" is null or not defined');
				}
		
				var o = Object(this);
				var len = o.length >>> 0;
				if (typeof predicate !== 'function') {
				throw new TypeError('predicate must be a function');
				}
				var thisArg = arguments[1];
				var k = 0;
				while (k < len) {
				var kValue = o[k];
				if (predicate.call(thisArg, kValue, k, o)) {
					return kValue;
				}
				k++;
				}
				return undefined;
			},
			configurable: true,
			writable: true
			});
		}

		function findItem(path, items) {
			var curId = path.shift()
			var res = items.find(function (el, i) {
				return el.id == curId;
			})

			if(res && path.length>0){
				//get child of the item and search for the item under it.
				var childItems = res.getChilds();

				if(childItems.length>0){
					return findItem(path, childItems)
				}else if(path.length>0){ //if path is still continuing and no more branch to traverse then item is not found
					return undefined;
				}
			}
			return res;
		}

	    graphproto.getByUId = function (uId) {


			if(uId==undefined || uId == null){
				return undefined;
			}

			var itemsToSearch = [];

			itemsToSearch = this.Events.concat(this.Processes)
	        //get the event from this.Events and match its ID
	        var res = $.grep(itemsToSearch, function (el) {
	        	return el.guid == uId;
	        });
	        if(res.length>0){
	        	return res[0];
	        }else{
	        	//search for Resources
	        	itemsToSearch = []
	        	itemsToSearch = this.Roles.concat(this.Groups).concat(this.EventTypes).concat(this.Parameters).concat(this.Phases).concat(this.Connections);
	        	var prop;
	        	res = $.grep(itemsToSearch, function (el) {
                    if (el.hasOwnProperty('id')) {
                        prop = el.id;
                    } else if (el.hasOwnProperty('guid')) {
                        prop = el.guid;
                    }
                  return prop === uId;
			    });
                    

		        if(res.length>0){
	        		return res[0];
	        	}
	        }
			return undefined;
	    };

	    graphproto.getEventsByGroup = function (group) {
            var items = []
            for (var i = 0; i < this.Events.length; i++) {
                if(checkForMatch(this.Events[i].custom.groups, 'title', group.title)>=0){
                    items.push(this.Events[i])
                }
            };
            return items;
	    }

	    //set the unique ids for all the events of current graph
	    function setupEventGUIDs (events) {
	    	for (var i = 0; i < events.length; i++) {
	    		events[i].setAttribute('guid', GUID());
	    		if($(events[i]).find('event').length>0){
	    			setupEventGUIDs ($(events[i]).find('event'))
	    		}
	    	};

	    	return events;
	    }

	    /*graph loading related global functions*/

	    //function to get all events from xml for graph except the ones which are referred
	    function getEventLocalGraph(events, curEl) {
	    	//console.log(events);
	    	for (var i = 0; i < events.length; i++) {
	    		if(events[i].getAttribute("type")=="form" && events[i].getAttribute("referId")!=undefined){
	    			if(events[i].getAttribute("id")!=undefined && events[i].id==curEl.id && events[i].getAttribute("referId")==curEl.referId){
	    				return events[i].getElementsByTagName("dcrgraph")[0]
	    			}
	    		}else if((events[i].getAttribute("type")=="form" || events[i].getAttribute("type")=="subprocess") && events[i].getAttribute("fragmentId")!=undefined){
					if(events[i].getAttribute("id")!=undefined && events[i].id==curEl.id && events[i].getAttribute("fragmentId")==curEl.fragmentId){
	    				return events[i].getElementsByTagName("dcrgraph")[0]
	    		}
				}
	    		
	    	}

	    	return null
	    }

		// get the DMN XML from the main graph XML based on index provided from expressions list
		function getExpressionDecisionXMLString($ServiceData, mainResourcesLoc, index) {
			var curExpression = $ServiceData.find('expressions')[mainResourcesLoc].getElementsByTagName("expression")[index]
			if(curExpression){
				var curDecision = curExpression.getElementsByTagName('definitions');
				if(curDecision.length>0){
					return '<?xml version="1.0" encoding="UTF-8"?>' + XMLtoString(curDecision[0])
				}
			}
			return ''
		}

		// TODO: add default layer for graph if none
		// function to load the xml file provided it
		function populateGraph (graph, serviceData, isRoot, curPro, options){



			if(serviceData.getElementsByTagName("specification")[0]==undefined){
				noty({ text: translations.error_graphxml, layout: 'top', timeout: 3500, type: 'warning' });
				return;
			}
			var $ServiceData = $(serviceData);

			var mainResourcesLoc = parseInt($ServiceData.find('specification').length -1);


			var arrLabelMapping = [], arrExpressions = [], arrConditions = [], arrResponse = [], arrCoResponse = [], arrInclude = [], arrExclude = [], arrMilestone = [], arrUpdate = [], arrSpawns = [], arrParameters = [], arrRoles = [], arrGroups = [],arrPhases = [], arrEventTypes = [], arrParameters = [], arrGlobalStore = [], arrEventParameters = [];

			if($ServiceData.find('labelMappings')[mainResourcesLoc] != undefined){
				arrLabelMapping = xmlToJsonArray($ServiceData.find('labelMappings')[mainResourcesLoc].getElementsByTagName("labelMapping"));
			}

			if($ServiceData.find('expressions')[mainResourcesLoc] != undefined){
				arrExpressions = xmlToJsonArray($ServiceData.find('expressions')[mainResourcesLoc].getElementsByTagName("expression"));
			}

			if($ServiceData.find('conditions')[mainResourcesLoc] != undefined){
				arrConditions = xmlToJsonArray($ServiceData.find('conditions')[mainResourcesLoc].getElementsByTagName("condition"));
			}

			if($ServiceData.find('responses')[mainResourcesLoc] != undefined){
					arrResponse = xmlToJsonArray($ServiceData.find('responses')[mainResourcesLoc].getElementsByTagName("response"));
			}
			
			if($ServiceData.find('coresponses')[mainResourcesLoc] != undefined){
					arrCoResponse = xmlToJsonArray($ServiceData.find('coresponses')[mainResourcesLoc].getElementsByTagName("coresponse"));
			}

			if($ServiceData.find('includes')[mainResourcesLoc] != undefined){
					arrInclude = xmlToJsonArray($ServiceData.find('includes')[mainResourcesLoc].getElementsByTagName("include"));
			}

			if($ServiceData.find('excludes')[mainResourcesLoc] != undefined){
					arrExclude = xmlToJsonArray($ServiceData.find('excludes')[mainResourcesLoc].getElementsByTagName("exclude"));
			}

			if($ServiceData.find('milestones')[mainResourcesLoc] != undefined){
					arrMilestone = xmlToJsonArray($ServiceData.find('milestones')[mainResourcesLoc].getElementsByTagName("milestone"));
			}
			
			if($ServiceData.find('updates')[mainResourcesLoc] != undefined){
					arrUpdate = xmlToJsonArray($ServiceData.find('updates')[mainResourcesLoc].getElementsByTagName("update"));
			}

			if($ServiceData.find('spawns').length>0 && $ServiceData.find('spawns')[mainResourcesLoc] != undefined){
				arrSpawns = xmlToJsonArray($ServiceData.find('spawns')[mainResourcesLoc].getElementsByTagName("spawn"));
			}

			//var globalMarkings = $ServiceData.find('globalMarking')[0];
			var graphMarkings = $ServiceData.find('runtime')[mainResourcesLoc].getElementsByTagName('marking')[0];

			// if(globalMarkings){
			// 	var arrIncludedEvents = xmlToJsonArray(globalMarkings.getElementsByTagName("included")[0].getElementsByTagName("event")),
			// 		arrPendingEvents = xmlToJsonArray(globalMarkings.getElementsByTagName("pending")[0].getElementsByTagName("event")),
			// 		arrExecutedEvents = xmlToJsonArray(globalMarkings.getElementsByTagName("executed")[0].getElementsByTagName("event"));


			// }else{
				var arrIncludedEvents = xmlToJsonArray(graphMarkings.getElementsByTagName("included")[0].getElementsByTagName("event")),
					arrPendingEvents = xmlToJsonArray(graphMarkings.getElementsByTagName("pendingResponses")[0].getElementsByTagName("event")),
					arrExecutedEvents = xmlToJsonArray(graphMarkings.getElementsByTagName("executed")[0].getElementsByTagName("event"));
			//}
			
			if($ServiceData.find('variables')[mainResourcesLoc] != undefined){
				arrParameters = $ServiceData.find('variables')[mainResourcesLoc].getElementsByTagName("variable");
			}
			if(graphMarkings != undefined){
				var globalStoreItems = graphMarkings.getElementsByTagName("globalStore")[0].getElementsByTagName("variable");
				//[].forEach.call(globalStoreItems, el=> {console.log(el, el.type)})
				arrGlobalStore = xmlToJsonArray(globalStoreItems)
			}

			
			//check if the import roles is checked on importing the file or not
			// if importing roles is checked or if file is loaded normally then load roles too
			if(options.importRoles==true || options.isImported==false ){
				//$('#pageOverlay').html('Reading Roles');

				if($ServiceData.find('roles').length>0){
					arrRoles = $ServiceData.find('roles')[$ServiceData.find('roles').length - 1].getElementsByTagName("role");
				}

				var arrRolesFiltered = [];
				$.each(arrRoles, function(i, el){
					if($(el).text().trim().length > 0 ){
						$(el).text($(el).text());
						arrRolesFiltered.push(el);
					}
				});

				arrRoles = xmlToJsonArray(arrRolesFiltered)
				// filtering the arrRoles to remove duplicate values
				$.each(arrRoles, function(i, el){
					if(el.text != undefined){
						if(el.description==undefined){
				    		el.description = '';
				    	}
						if(el.specification==undefined){
				    		el.specification = '';
				    	}

				    	el.text = fixSlashes(el.text)
						if($ServiceData.attr('isRefer') == 'true'){
							if(checkForMatch(graph.ReferredRoles, "title", el.text) === -1) graph.ReferredRoles.push({'id': GUID(),'title':el.text, 'description' : fixSlashes(el.description), 'specification': fixSlashes(el.specification)});
						}else{
							if(checkForMatch(graph.Roles, "title", el.text) === -1) graph.Roles.push({'id': GUID(),'title':el.text, 'description' : fixSlashes(el.description), 'specification': fixSlashes(el.specification)});
						}
					}
				});

				graph.Roles = graph.Roles.sort(function (a, b) {
														return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
													});

				//$('#pageOverlay').html('Initializing Roles List');
			}

			if(options.importGroups==true || options.isImported==false ){
				//$('#pageOverlay').html('Reading Groups');

				if($ServiceData.find('groups').length>0){
					arrGroups = $ServiceData.find('groups')[$ServiceData.find('groups').length - 1].getElementsByTagName("group");
				}			   
				
				var arrGroupsFiltered = [];
				$.each(arrGroups, function(i, el){
					if($(el).text().trim().length > 0 ){
						$(el).text($(el).text());
						arrGroupsFiltered.push(el);
					}
				});

			    
				arrGroups = xmlToJsonArray(arrGroupsFiltered)

			    try {
			        arrGroups = sortArray("sequence", arrGroups, true);
			    } catch (ex) {
			        console.log("Exception while sorting groups : " + ex);
			    }

				// filtering the arrRoles to remove duplicate values
				$.each(arrGroups, function(i, el){
					if(el.text != undefined){
						if(el.sequence == undefined){
				    		el.sequence = 0;
				    	}
				    	if(el.description==undefined){
				    		el.description = '';
				    	}
				    	el.text = fixSlashes(el.text)
				    	//pushing the items to array
				    	if($ServiceData.attr('isRefer') == 'true'){
							if(checkForMatch(graph.ReferredGroups, "title", el.text) === -1) graph.ReferredGroups.push({'id': GUID(),'title':el.text, 'sequence': el.sequence, 'description' : fixSlashes(el.description)});
						}else{
							if(checkForMatch(graph.Groups, "title", el.text) === -1) graph.Groups.push({'id': GUID(), 'title':el.text, 'sequence': el.sequence, 'description' : fixSlashes(el.description)});
						}

					}
				});

				graph.Groups = graph.Groups.sort(function (a, b) {
									return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
								});

			}

			if(options.importPhases==true || options.isImported==false ){
				//$('#pageOverlay').html('Reading Groups');

				if($ServiceData.find('phases').length>0){
					arrPhases = $ServiceData.find('phases')[$ServiceData.find('phases').length - 1].getElementsByTagName("phase");
				}			   
				
				var arrPhasesFiltered = [];
				$.each(arrPhases, function(i, el){
					if($(el).text().trim().length > 0 ){
						$(el).text($(el).text());
						arrPhasesFiltered.push(el);
					}
				});

			    
				arrPhases = xmlToJsonArray(arrPhasesFiltered)

			    try {
			        arrPhases = sortArray("sequence", arrPhases, true);
			    } catch (ex) {
			        console.log("Exception while sorting phases : " + ex);
			    }

				// filtering the arrRoles to remove duplicate values
				$.each(arrPhases, function(i, el){
					if(el.text != undefined){
						if(el.sequence == undefined){
				    		el.sequence = 0;
				    	}
				    	if(el.description==undefined){
				    		el.description = '';
				    	}
				    	el.text = fixSlashes(el.text)
				    	//pushing the items to array
				    	if($ServiceData.attr('isRefer') == 'true'){
							if(checkForMatch(graph.ReferredPhases, "title", el.text) === -1) graph.ReferredPhases.push({'id': GUID(),'title':el.text, 'sequence': el.sequence, 'description' : fixSlashes(el.description)});
						}else{
							if(checkForMatch(graph.Phases, "title", el.text) === -1) graph.Phases.push({'id': GUID(), 'title':el.text, 'sequence': el.sequence, 'description' : fixSlashes(el.description)});
						}

					}
				});

				graph.Phases = graph.Phases.sort(function (a, b) {
									return a.sequence - b.sequence
								});

			}
			
			if((options.importTypes==true && options.isReferred==false) || options.isImported==false ){
				//$('#pageOverlay').html('Reading Event Types');

				if($ServiceData.find('eventTypes')[mainResourcesLoc] != undefined){
					arrEventTypes = $ServiceData.find('eventTypes')[mainResourcesLoc].getElementsByTagName("eventType");
				}

				if($ServiceData.find('eventParameters')[mainResourcesLoc] != undefined){
					arrEventParameters = $ServiceData.find('eventParameters')[mainResourcesLoc].getElementsByTagName("parameter");
				}
				var arrEventTypesFiltered = [];
				$.each(arrEventTypes, function(i, el){
					if($(el).text().trim().length > 0 ){
						$(el).text($(el).text());
						arrEventTypesFiltered.push(el);
					}
				});

				arrEventTypes = xmlToJsonArray(arrEventTypesFiltered)
				// filtering the arrRoles to remove duplicate values
				$.each(arrEventTypes, function(i, el){
					if(el.text != undefined){
						el.text = fixSlashes(el.text)
						//pushing the items to array
				    	if($ServiceData.attr('isRefer') == 'true'){
							if(checkForMatch(graph.ReferredEventTypes, "title", el.text) === -1) graph.ReferredEventTypes.push({'id': GUID(),'title':el.text, 'description' : fixSlashes(el.description), parameters : []});
						}else{
							if(checkForMatch(graph.EventTypes, "title", el.text) === -1) graph.EventTypes.push({'id': GUID(), 'title':el.text, 'description' : fixSlashes(el.description), parameters : []});
						}
						
					}
				});


				graph.EventTypes = graph.EventTypes.sort(function (a, b) {
														return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
													});
				//get event type parameters and set them to their types
				arrEventParameters = xmlToJsonArray(arrEventParameters);
				for (var i = 0; i < arrEventParameters.length; i++) {
					var curParam = arrEventParameters[i];
					var index = checkForMatch(graph.EventTypes, "title", fixSlashes(curParam.eventtypeid))
					if(index>=0 && checkForMatch(graph.EventTypes[index].parameters, "title", fixSlashes(curParam.title)) === -1){
						graph.EventTypes[index].parameters.push({title: fixSlashes(curParam.title), value: fixSlashes(curParam.value), required: curParam.required})
					}
				};
			}
			
			if((options.importParams==true && options.isReferred==false) || options.isImported==false ){
				//$('#pageOverlay').html('Reading Parameters');
				//filtering the variables in DCR file
				var arrParametersFiltered = [];
				$.each(arrParameters, function(i, el){
					if($(el).attr('id') != '' && $(el).attr('id').trim().length >0 ){
						$(el).attr('value', $(el).attr('value'));
						arrParametersFiltered.push(el);
					}
				});

				arrParameters = xmlToJsonArray(arrParametersFiltered);
				//svalue is for sim value
				for (var i = 0; i < arrParameters.length; i++) {
					if(checkForMatch(graph.Parameters, "title", fixSlashes(arrParameters[i].id)) === -1) {
						graph.Parameters.push({'id': GUID(), 'title':fixSlashes(arrParameters[i].id), 'value' : fixSlashes(arrParameters[i].value), 'type' : arrParameters[i].type, 'svalue' : fixSlashes(arrParameters[i].value)});				
					}
				};

			}
			
			if(isRoot){
				graph.GlobalStore = arrGlobalStore;
			}
			
			//$('#pageOverlay').html('Initializing Events');
			// rendering the events from dataservice (events, roles , labels, runtime and initial locations)
			var events = serviceData.getElementsByTagName("specification")[0].getElementsByTagName("events")[0].getElementsByTagName("event");

			events = setupEventGUIDs(events);


			var arrDCREvents = parseXML(events);

			//getting all the external events and removing them from the arr events, so they are not drawn on canvas
			if($ServiceData.find('externalEvents').length>0){
				var externalEvents = $ServiceData.find('externalEvents')[mainResourcesLoc].getElementsByTagName("externalEvent");
			}else{
				var externalEvents = [];
			}
			
			var arrCurExternalEvents = [];

			$.each(externalEvents, function(i, el){
				arrCurExternalEvents.push(el.attributes.localId.value);
				graph.ExternalEvents.push(el);
			});

			var arrEvents = [];
			$.each(arrDCREvents, function(i, el){
				if(el != undefined){
					if($.inArray(el.id, arrCurExternalEvents) === -1) arrEvents.push(el);
				}
			});


			//$('#pageOverlay').html('Drawing Events');
			for(i=0;i<arrEvents.length;i++){

					//for refer graphs, ignore events which are private
					if(options.isReferred == true &&  arrEvents[i].scope=="private" || (arrEvents[i].custom==undefined)){
						continue;
					}
					
					var label = $.grep(arrLabelMapping, function(obj){
						return obj.eventId == arrEvents[i].id;
					});
					var eventLabel = '';
					if(label.length>0){
						eventLabel = fixSlashes(label[0].labelId);
					}	

					//setting up event label found in the xml
					arrEvents[i].custom.label = eventLabel;					

					//setting up the runtimes of the event		
					arrEvents[i].runtimes = {};

					var curEventId = arrEvents[i].id;
					if(options.isSimulation==true && options.simPaused!=true && curPro!=undefined && options.isReferred==true){
						//in simulation we have may have more than one event with same id for the referred graphs so we need this for now
						curEventId = arrEvents[i].oriId;
					}

					if(arrIncludedEvents != undefined){
						var dataIncEvnt =  $.grep(arrIncludedEvents, function(obj){
							return obj.id == curEventId;
						});
						if(dataIncEvnt.length>0){
							arrEvents[i].runtimes.included = true;
						}else{
							arrEvents[i].runtimes.included = false;
						}
					}
					if(arrPendingEvents != undefined){
						var dataPenEvnt =  $.grep(arrPendingEvents, function(obj){
							return obj.id == curEventId;
						});
						//pending events will have deadline attribute too add it too
						if(dataPenEvnt.length>0){
							arrEvents[i].runtimes.pending = true;
							if(dataPenEvnt[0].deadline!=undefined){
								var curTime = fixSlashes(dataPenEvnt[0].deadline);
								var curTimeAsDate = new Date(curTime);
								arrEvents[i].deadline = isDate(curTimeAsDate)? curTimeAsDate.toISOString(): curTime;
							}
						}else{
							arrEvents[i].runtimes.pending = false;
						}
					}
					if(arrExecutedEvents != undefined){
						var dataExeEvnt =  $.grep(arrExecutedEvents, function(obj){
							return obj.id == curEventId;
						});
						//executed events will have time attribute add it too

						if(dataExeEvnt.length>0){
							arrEvents[i].runtimes.executed = true;
							if(dataExeEvnt[0].time!=undefined){
								var curTime = fixSlashes(dataExeEvnt[0].time);
								var curTimeAsDate = new Date(curTime);
								arrEvents[i].time = isDate(curTimeAsDate)? curTimeAsDate.toISOString(): curTime;
							}
						}else{
							arrEvents[i].runtimes.executed = false;
						}
					}
					

										
					//console.log(arrEvents[i]);
					arrEvents[i].parentPro = curPro;

					if(arrEvents[i].computation!=undefined){
						var expressionIndex = checkForMatch(arrExpressions, 'id', arrEvents[i].computation)
						if(expressionIndex>=0){
							var expression = arrExpressions[expressionIndex]
							if(expression.type && expression.type=='DMN'){
								arrEvents[i].dmnXML = getExpressionDecisionXMLString($ServiceData, mainResourcesLoc, expressionIndex)
							}
							arrEvents[i].computation = expression.value || '';
						}
					}

					// TODO: need to check if we are setting null true for any value, if so we need to update this check accordingly
					var eventDefaultValue = arrGlobalStore.find(function (item) {
						return item.id === arrEvents[i].id && item.isNull == "false"
					});
					if(eventDefaultValue){
						arrEvents[i].defaultValue = eventDefaultValue;
					}

					// set precondition value, get it from expressions if any found
					if(arrEvents[i].precondition!=undefined && typeof arrEvents[i].precondition.id !='undefined' && arrEvents[i].precondition.id!= null){
						var expressionIndex = checkForMatch(arrExpressions, 'id', arrEvents[i].precondition.id)
						if(expressionIndex>=0){
							arrEvents[i].precondition.value = arrExpressions[expressionIndex].value
						}
					}
					
					if(arrEvents[i].type == "form" && arrEvents[i].referId!=undefined && isInteger(parseInt(arrEvents[i].referId))==true){
						console.log("DCRForm");
						arrEvents[i].graphID = arrEvents[i].referId
						arrEvents[i].graphXML = getEventLocalGraph(events, arrEvents[i])
						var curEl = graph.createForm(arrEvents[i]);
					}else if(arrEvents[i].fragmentId!=undefined && isInteger(parseInt(arrEvents[i].fragmentId)) && (arrEvents[i].dcrgraph!=undefined)){
						//! if fragment has dcgraph then load it in main graph
						console.log("DCR Fragment");
						arrEvents[i].dcrgraph = getEventLocalGraph(events, arrEvents[i])
						var curEl = graph.createFragment(arrEvents[i]);
					}else{
						var curEl = graph.createEvent(arrEvents[i]);
					}
					

					if(curPro!=undefined && curPro.isInstance==true){
							curEl.isInstance = true;
						}
			}
			/*events drawing loop ends here*/

			//getting all the parents of childs
			var allParentIDs = [], uniqueParentIDs = [];
			for(var i=0; i<graph.Childs.length; i++){
				if(graph.Childs[i].parentGUID!=undefined && graph.Childs[i].parentGUID!=null){
					allParentIDs.push(graph.Childs[i].parentGUID);
				}
				
			}
			// filtering the Parent IDS to remove duplicate values
			$.each(allParentIDs, function(i, el){
				if($.inArray(el, uniqueParentIDs) === -1) {uniqueParentIDs.push(el);}
			});

			//adding the Parents to arrParents
			$.each(uniqueParentIDs, function(i, el){
				//pEl = graph.getEventById(el).e; 
				var pEl = graph.getByUId(el); 
				if(pEl!= undefined && $.inArray(pEl, graph.Parents) === -1){
					graph.Parents.push(pEl);
				}
			});

			//get the classes for childs based on their parents (N level)
			for(var j=0; j<graph.Childs.length; j++){
				graph.Childs[j].nLevel = parseInt(graph.Childs[j].parentObj.nLevel + 1);				
			}

			//pushing the connections to all connections for initializing later when the graph is fully loaded and 

			//TODO::
			/*
			lets setup the connections arrays here and update the from and to with the elements found here if possible
			*/


			//all events are created
			if(arrConditions.length>0){
				for (var i = 0; i < arrConditions.length; i++) {
					arrConditions[i].curPro = curPro;
				};
				graph.AllConnections.push([arrConditions, "#FFA500", arrExpressions]);
			}
			if(arrResponse.length>0){
				for (var i = 0; i < arrResponse.length; i++) {
						arrResponse[i].curPro = curPro;
					};
				graph.AllConnections.push([arrResponse, "#1E90FF", arrExpressions]);
			}
			if(arrCoResponse.length>0){
				for (var i = 0; i < arrCoResponse.length; i++) {
						arrCoResponse[i].curPro = curPro;
					};
				graph.AllConnections.push([arrCoResponse, "#795548", arrExpressions]);
			}
			if(arrInclude.length>0){
				for (var i = 0; i < arrInclude.length; i++) {
						arrInclude[i].curPro = curPro;
					};
				graph.AllConnections.push([arrInclude, "#29A81A", arrExpressions]);
			}
			if(arrExclude.length>0){
				for (var i = 0; i < arrExclude.length; i++) {
						arrExclude[i].curPro = curPro;
					};
				graph.AllConnections.push([arrExclude, "red", arrExpressions]);
			}
			if(arrMilestone.length>0){
				for (var i = 0; i < arrMilestone.length; i++) {
						arrMilestone[i].curPro = curPro;
					};
				graph.AllConnections.push([arrMilestone, "#BC1AF2", arrExpressions]);
			}
			if(arrUpdate.length>0){
				for (var i = 0; i < arrUpdate.length; i++) {
						arrUpdate[i].curPro = curPro;
					};
				graph.AllConnections.push([arrUpdate, "#b0bfc3", arrExpressions]);
			}
			if(arrSpawns.length>0){
				for (var i = 0; i < arrSpawns.length; i++) {
						arrSpawns[i].curPro = curPro;
					};
				graph.AllConnections.push([arrSpawns, "#334960", arrExpressions]);
			}
			
			
			//$('#pageOverlay').html('Reading Graph Details');
			//var graphDetails = $ServiceData.find('resources')[mainResourcesLoc].getElementsByTagName("graphDetails");
			var graphDetails = $ServiceData.find('graphDetails')[mainResourcesLoc]

			if(graphDetails!=undefined){
				if((options.isImported == true && options.importDocDesc==true && options.isReferred==false) || options.isImported==false){
					graph.Description  = fixSlashes($(graphDetails).text());
				}
			}
			
			var graphDocumentation = $ServiceData.find('graphDocumentation')[mainResourcesLoc]

			if(graphDocumentation!=undefined && ((options.isImported == true && options.isReferred==false) || options.isImported==false)){
				graph.Documentation  = fixSlashes($(graphDocumentation).text());
			}
			var graphLanguage = $ServiceData.find('graphLanguage')[mainResourcesLoc]

			if(graphLanguage!=undefined){
				if((options.isImported == true && options.importDocLanguage==true && options.isReferred==false) || options.isImported==false){
					graph.Language  = fixSlashes($(graphLanguage).text());
				}
			}
			var graphDomain = $ServiceData.find('graphDomain')[mainResourcesLoc]

			if(graphDomain!=undefined){
				if((options.isImported == true && options.importDocDomain==true && options.isReferred==false) || options.isImported==false){
					graph.Domain  = fixSlashes($(graphDomain).text());
				}
			}

			//load the root graph resources and assign them to the graph properties
			if(isRoot && $ServiceData.attr('isRefer') != 'true'){

				var graphType = $ServiceData.attr('graphType');
				if(graphType!=undefined && graphType!=null && !isNaN(graphType)){
					graph.Type = parseInt(graphType);
				}else{
					graph.Type = 0;
				}


				var docdataTypesStatus = $ServiceData.attr('dataTypesStatus');
				if(docdataTypesStatus!=undefined && docdataTypesStatus=='show' && $ServiceData.find('subProcess').length<1){
					graph.DataTypesStatus = 'show';
				}else{
					graph.DataTypesStatus = 'hide';
				}

				//$('#pageOverlay').html('Reading Graph Title');
				// setting up the window title based on the values in graph XML
				var docTitle = $ServiceData.attr('title');
				if((options.isImported == true && options.importDocTitle==true) || options.isImported==false ){
					if(docTitle!=undefined){
						if(docTitle.length<1 || docTitle.replace(/ /g,'').length<1){
							graph.Title = 'DCR';
						}else{
							graph.Title = docTitle;
						}
					}else{
						graph.Title = 'DCR';
					}
					//console.log(docTitle);
				}

				var docTime = $ServiceData.find('runtime')[mainResourcesLoc].getElementsByTagName("time");

				if(docTime[0]!=undefined){
					var docCurrentTime = docTime[0].attributes.current.value
					if(isDate(docCurrentTime)==true){
						graph.Time = new Date(docCurrentTime).toISOString();
					}else{
						graph.Time = null;
					}

					var docDeadLine = docTime[0].attributes.deadline.value
					if(isDate(docDeadLine)==true){
						graph.DeadLine = new Date(docDeadLine).toISOString();
					}else{
						graph.DeadLine = null;
					}

					var docDelay = docTime[0].attributes.delay.value
					if(isDate(docDelay)==true){
						graph.Delay = new Date(docDelay).toISOString();
					}else{
						graph.Delay = null;
					}
				}else{
					graph.Time = null;
					graph.DeadLine = null;
					graph.Delay = null;
				}

				var docKeywords = $ServiceData.find('keywords')[mainResourcesLoc];
				if((options.isImported == true && options.importKeywords==true) || options.isImported==false ){
					if(docKeywords!=undefined && $(docKeywords).text().trim().length>0){
					    graph.Keywords = $(docKeywords).text().split(',').map(function(e) {
                            return addSlashes(htmlEncode(e));
                        });
                        console.log($(docKeywords).text());
					}
				}

				var currentMarkup = null;
				if($ServiceData.find('hightlighterMarkup').length>0 && $ServiceData.find('hightlighterMarkup')[mainResourcesLoc] != undefined){
					currentMarkup = fixSlashes(htmlDecode($ServiceData.find('hightlighterMarkup')[mainResourcesLoc].innerHTML))
				}

				//on graph load check if this is old markup then transform it to new format
				if(currentMarkup!=null){
					// this means that it has some old markup, update it new format
					currentMarkup = upgradeHighlighterMarkup(graph, currentMarkup)
				}

				//if it finds new markup then it will update the markup
				if($ServiceData.find('highlighterMarkup').length>0 && $ServiceData.find('highlighterMarkup')[mainResourcesLoc] != undefined){
					currentMarkup = $.xml2json($ServiceData.find('highlighterMarkup')[mainResourcesLoc])
				}

				graph.highlighterMarkup = loadHighlighterMarkup(graph, currentMarkup);
				

				//$('#pageOverlay').html('Setting Up Graph Filter Level');

				//if graph is being imported then check if resources are being imported or not

				if($ServiceData.find('graphFilters').length>0){
					//check if roles are being imported or not?
					if((options.isImported == true && options.importRoles==true) || options.isImported==false ){
						var arrFilteredGroups = $ServiceData.find('graphFilters')[mainResourcesLoc].getElementsByTagName("filteredGroups");
					}
					//check if groups are being imported or not?
					if((options.isImported == true && options.importGroups==true) || options.isImported==false ){
						var arrFilteredRoles = $ServiceData.find('graphFilters')[mainResourcesLoc].getElementsByTagName("filteredRoles");
					}
					//check if groups are being imported or not?
					if((options.isImported == true && options.importPhases==true) || options.isImported==false ){
						var arrFilteredPhases = $ServiceData.find('graphFilters')[mainResourcesLoc].getElementsByTagName("filteredPhases");
					}
					
				}else{
					var arrFilteredGroups = "";
					var arrFilteredRoles = "";
					var arrFilteredPhases = "";
				}
				

				if($(arrFilteredGroups).text()!=""){
					if((options.isImported == true && options.importDocFilters==true) || options.isImported==false ){
						graph.FilterGroups = $(arrFilteredGroups).text().split(',');
					}
					
				}
				if($(arrFilteredRoles).text()!=""){
					if((options.isImported == true && options.importDocFilters==true) || options.isImported==false ){
						graph.FilterRoles = $(arrFilteredRoles).text().split(',');
					}
					
				}

				if($(arrFilteredPhases).text()!=""){
					if((options.isImported == true && options.importDocFilters==true) || options.isImported==false ){
						graph.FilterPhases = $(arrFilteredPhases).text().split(',');
					}
					
				}

				// setting up the graph filter on loading the xml
				var docFilterLevel = $ServiceData.attr('filterLevel');
				var docInsightFilter = $ServiceData.attr('insightFilter');

				if((options.isImported == true && options.importDocFilters==true) || options.isImported==false ){
					if(docFilterLevel!=undefined && docFilterLevel.trim().length>=0 && parseInt(docFilterLevel)!=NaN){
							graph.FilterLevel = parseInt(docFilterLevel);
					}else{
						graph.FilterLevel = -1;
					}
					graph.InsightFilter = (docInsightFilter!=undefined && docInsightFilter=="true")
				}
				

				//$('#pageOverlay').html('Setting Up Graph Zoom Level');
				// setting up the graph zoom on loading the xml
				var docZoomLevel = $ServiceData.attr('zoomLevel');
				if((options.isImported == true && options.importDocZoom==true) || options.isImported==false ){
					if(docZoomLevel!=undefined /*&& options.isSimulation==false*/){
						if(docZoomLevel.trim().length<1 || docZoomLevel==0){
							graph.ZoomLevel = 0;
						}else{
							graph.ZoomLevel = parseInt(docZoomLevel);				    	
						}
					}else{
						graph.ZoomLevel = 0;
					}
				}

				//graph background
				if((options.isImported == true && options.importDocBG==true) || options.isImported==false){
					var graphBG = $ServiceData.attr('graphBG');
					if(graphBG!=undefined && graphBG!=null){
						graph.BG = graphBG;
					}else{
						graph.BG = '#EBEBEB';
					}
				}
				
				// graph Exercise: this.Exercise = false
				var isExercise = $ServiceData.attr('exercise');
				graph.Exercise = isExercise!=undefined && isExercise!=null && isExercise=='true' ? true: false;			
				
				var sendText = $ServiceData.attr('sendText');
				graph.SendText = sendText!=undefined && sendText!=null ? fixSlashes(sendText) : '';	

				var cancelText = $ServiceData.attr('cancelText');
				graph.CancelText = cancelText!=undefined && cancelText!=null ? fixSlashes(cancelText) : '';			
				
				var hideCancel = $ServiceData.attr('hideCancel');
				graph.HideCancel = hideCancel!=undefined && hideCancel!=null && hideCancel=='true' ? true: false;			
				
				var formShowInitialPhase = $ServiceData.attr('formShowInitialPhase');
				graph.FormShowInitialPhase = formShowInitialPhase!=undefined && formShowInitialPhase!=null && formShowInitialPhase=='2' ? 2: 1;			

				// setting up the graph group style on loading the xml
				var docFormGroupStyle = $ServiceData.attr('formGroupStyle');
				if(docFormGroupStyle!=undefined){
					graph.FormGroupStyle = docFormGroupStyle;
				}else{
					graph.FormGroupStyle = "Normal";
                }
	                // setting up the form layout style on loading the xml
	                var docFormLayoutStyle = $ServiceData.attr('formLayoutStyle');
	                if (docFormLayoutStyle != undefined) {
	                    graph.FormLayoutStyle = docFormLayoutStyle;
	                } else {
	                    graph.FormLayoutStyle = "Horizontal";
				}


			}
			
			
		}

		graphproto.graphFrom = function (item, includeEl){
			var self = this, path = item!=undefined && item!=null? item.id: null;
			var graph = new DCR();
			//self.importTo(graph, undefined, {isFormImport}) //this fails as it has the same instances for graph items, which affect main graph
			//create a new graph based on current graph and delete the rest of items
			graph.loadXMLString(self.writeXML(true));
			//find the item in graph and let it be and remove all other items from graph
			if(item!=null){
				var curItem = graph.getById(path);
				var childItems = curItem.getChilds();
				var itemsToRemove = graph.Events.filter(function (el) {
					return childItems.indexOf(el) < 0
				})

				//if we want to include the main item
				if(includeEl==true){
					itemsToRemove =	itemsToRemove.filter(function (el) {
						return el!=curItem
					})
				}
				console.log(itemsToRemove)
				//remove the items now
				itemsToRemove.map(function (el) {
					el.remove();
				})
			}
			return graph;
		}


		//TODO: function to import a graph in current Graph using merge sementics
		function importFrom (path, includePath){ 
		}

		//function to get GUID //http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript/21963136#21963136
		/*GUID = function  () {
			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
			    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
			    return v.toString(16);
			});
		}*/

		//function to get UUID //http://jcward.com/UUID.js
		GUID = function() {
		  var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
		  var d0 = Math.random()*0xffffffff|0;
		    var d1 = Math.random()*0xffffffff|0;
		    var d2 = Math.random()*0xffffffff|0;
		    var d3 = Math.random()*0xffffffff|0;
		    return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
		      lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
		      lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
		      lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
		}

		//this is the recursive function to load the main graph and all of its sub processes
		function getGraphResouces (graph, graphXML, isRoot, options) {
			//console.log(graphXML)
			var mainResourcesLoc = parseInt($(graphXML).find('specification').length -1);
			var graphSubProcesses = $(graphXML).find("resources:first-child subProcess");

			if(isRoot){
				populateGraph(graph, graphXML, true, 'root', options);
			}

			//adding this check so that if any dynamic graph loaded has any sub process we ignore them
			if(graph.dataTypesStatus=="show"){
					return;
			}
			
			//this means this graph has subprocessess
			if(graphSubProcesses.length>0){
				graphSubProcesses.each(function (index, el) {

					var curID = el.attributes.id.value;
					var curGUID = GUID();
					el.setAttribute('guid', curGUID);

					if($.inArray(curGUID, graph.ProcessedPs) === -1 ){

						

						graph.ProcessedPs.push(curGUID);
						//console.log(el);
						var parentProcessNode = el.parentNode.parentNode.parentNode.parentNode.parentNode;
						var parentProcess = parentProcessNode.nodeName;
						var parentProcessId = '';
						var parentProcessGUID = '';
						if(parentProcess=='subProcess'){
							parentProcessId = parentProcessNode.attributes.id.value;
							parentProcessGUID = parentProcessNode.attributes.guid.value;
						}
						if(parentProcessId!=''){
							el.setAttribute('parentId', parentProcessId);
						}
						if(parentProcessGUID!=''){
							el.setAttribute('parentGUID', parentProcessGUID);
							var curParent = graph.getByUId(parentProcessGUID)
						}

						 
						var processesObj = $.xml2json(el);
						if(options.isSimulation==true){
							processesObj.dcrgraph = $(stringToXML($(el).find('dcrgraph').outerHTML())).find('dcrgraph')[0]
						}else{
							processesObj.dcrgraph = $(el).find('dcrgraph')[0];
						}
						
						if(processesObj.custom==undefined){
							processesObj.custom = {}
						}
						processesObj.custom.label = el.attributes.name.value;

						var curPro = graph.createProcess(processesObj);
						curPro.parentObj = curParent;

						//if no template or instance id is found then draw the process, if found then it means it is an instance we don't need to draw it
						if(((el.attributes.instanceId != undefined && el.attributes.instanceId.value != "") && (el.attributes.template != undefined && el.attributes.template.value != "")) || (el.attributes.isInstance != undefined && el.attributes.isInstance.value != "")){
							// if an instance then do something
							//return true; // skip next things and move to next subprocess
							curPro.isInstance = true;
							//find all subProcesses and mark them as instance as they are not original now
							$(el).find('subProcess').each(function (i, eel) { 
								eel.setAttribute('isInstance', true); 
							});
						}

						var mainResourcesLoc = parseInt($(el).find('specification').length -1);

						//while reading the xml from DB on load, check if the process added was a reference then continue and add this to arrReferredPros
						if($(el).attr('isRefer')=="true" && options.isSimulation==false){
							graph.ReferredPros.push(curPro);
							graph.Parents.push(curPro)
							return; //returning here for lazy loading on the graphs later on
						}

						//updating the subprocess xml before populating it to nest them in this process
						//$(el).find('events event').each(function (i, eel) { 
						$($(el).find('events:first-child')[0]).children().each(function (i, eel) { 
							eel.setAttribute('parentId', curID); 
							eel.setAttribute('parentGUID', curGUID);
							eel.setAttribute('isRefer', curPro.isRefer);
							if((curPro.instanceId != undefined && curPro.instanceId != "") && (curPro.template != undefined && curPro.template != "")){
								//eel.setAttribute('isInstance', true);
								eel.setAttribute('instanceId', curPro.instanceId);
								eel.setAttribute('template', curPro.template);
							}
						});

						populateGraph(graph, el, false, curPro, options);

						
						var subGraph = $(el).find('dcrgraph')[0];
						getGraphResouces(graph, subGraph, false, options);
					}else{
						console.log('already pro p')
					}
				});

			}
			var graphResources = '';
		}

		function getLocalEvent (graph, sharedEventId) {
			var localEvent = undefined;
			for (var i = 0; i < graph.ExternalEvents.length; i++) {
				if(graph.ExternalEvents[i].attributes.localId.value == sharedEventId){
					// find the item in the process location defined
					var curPro = graph.getById(graph.ExternalEvents[i].attributes.externalLocation.value);
					var localID = graph.ExternalEvents[i].attributes.externalId.value
					localEvent = findElement (curPro, localID)
				}
			};
			return localEvent;
		}
		function findElement (curPro, itemID) {
			var item = undefined
			if(curPro==undefined) return
						curPro.getChilds(true).forEach(function (el, indx) {
				if (el.oriId == itemID) {
				  item = el
				            }
				        })
			var parentPro = curPro.getParentProcess()
			if (item == undefined && parentPro!=undefined) {
				item = findElement(parentPro, itemID)
			}else if(item == undefined && parentPro==undefined){
				curPro.graph.getAllRootEvents().forEach(function (el, indx) {
					if (el.oriId == itemID) {
					  item = el
					}
				})
				}
				


			return item;
		}

		function getExpressionValue(expressionId, arrExpress) {
			let guardVal = '';
			if(expressionId!=undefined){
				guardVal = arrExpress.find(function (el) {
					return expressionId==el.id;
				})
				if(guardVal){
					guardVal = fixSlashes(guardVal.value)
				}
			}
			return guardVal
		}


		function setupConnections(graph, arr, color, arrExpress){

			for(var i = 0; i<arr.length; i++){

				var curPro = arr[i].curPro;
				// if connections are inside the refer processes
				if ((curPro != undefined && curPro.isRefer == true) || (curPro != undefined && curPro.instanceId != undefined && curPro.instanceId.length > 0) || (curPro != undefined && curPro.isInstance != undefined && curPro.isInstance == true)) {
			          // find the source and target
			          // if both source and target are found then make connections else return

			          source = findElement (curPro, arr[i].sourceId);


			          target = findElement (curPro, arr[i].targetId);

			          if (source == undefined || target == undefined) {


			            continue
			          }
			      } else {
			        source = graph.getById(arr[i].sourceId);
					target = graph.getById(arr[i].targetId);
			      }

				//search for the source or the target in the shared events and if the event is found then use its id to create the connection
				if(source==undefined){
					source =  getLocalEvent(graph, arr[i].sourceId);
				}

				if(target==undefined){
					target =  getLocalEvent(graph, arr[i].targetId);
				}

				//still incase if the connections are between the distributed events
				if(source==undefined || target==undefined){
					graph.ReferredCons.push([[arr[i]], color, arrExpress]);
				}else{
					// if this is milestone for strong connections then ignore that as that will be created automatically when we create, as properties are shared we don't have to worry about that
					if(arr[i].type=='milestone' && typeof arr[i].link !== 'undefined' && arr[i].link.trim().length>0){
						continue;
					}
					
					if(arr[i].type=='exclude' && typeof arr[i].link !== 'undefined' && arr[i].link.trim().length>0){
						continue;
					}
					// if condition and has link then treat as strong relation
					const guard = getExpressionValue(arr[i].expressionId, arrExpress);
					
					const valueExpression = getExpressionValue(arr[i].valueExpressionId, arrExpress);
 
					graph.createConnection(source, target, color, arr[i].type, guard , arr[i].filterLevel, arr[i].description, arr[i].time, arr[i].groups, (typeof arr[i].link !== 'undefined'? true: false), (arr[i].businessRule == 'true'? true: false), valueExpression)
					//checking if the relation has a guard or not

					

				}

			}
		}

		/** Main funtion to get a DCR graph based on the id of the graph. The function will make an ajax request to dcrgraphs.net api to get the graph details and if successful it will load the xml of graph
	    *
	    * @memberof Graph
	    * @method loadGraph 
	    *
	    * @param {number} graphId -Requires DCR Graph id from dcrgraphs.net to load the graph XML
	    * @param {function} callback -This function will be executed when the Graph will be successfully loaded after ajax request
	    *
		* @example var myApp = new DCR();
		* myApp.loadGraph(2275);
		* //if the request is made successful then this will load the graph ready to be used
		* @returns {object} Returns an object of Graph Class.
	    */
		graphproto.loadGraph = function (graphId, callback, initialize) {
		    var graph = this;
		    var serviceUrl = "/api/dl_dcrgraph/"+parseInt(graphId);
		    if (initialize==true) {
		        serviceUrl = "/api/dl_dcrgraph/" + parseInt(graphId) + "?initialize=true";
		    }

		 	if(graphId==getQueryVariable('id') || graphId == parseInt(graphId)){
		 		$.ajax({
			        type: "GET",
			        contentType: "application/json; charset=utf-8",
			        url: serviceUrl,
			        dataType: "json",
			        beforeSend: function () {
			           console.log("sending graph loading request");
			        }
			    }).done(function (restResponse) {
			    	if((restResponse!=null || restResponse != undefined) && restResponse.Id === parseInt(restResponse.Id)){
			    		graph.loadXMLString(restResponse.GraphXml);
			    		if(typeof(callback) === "function"){
			    			callback(graph, restResponse);
			    		} 
			    		return graph;
			    	}
			    }).fail(function (err) {
					console.log("some error occured on getting graph details.");
					if(typeof(callback) === "function"){
						callback(undefined, err);
					}
			    }).always(function () {
			        console.log("completed getting graph details");
			    });
	    	}
	    	//return graph;
		}

	    /** The function will make an ajax request to dcrgraphs.net api to initialize the graph and if successful it will callback the function provided
	    *
	    * @memberof Graph
	    * @method intializeGraphXml 
	    *
	    * @param {string} graphXml -Requires DCR Graph id from dcrgraphs.net to load the graph XML
	    * @param {function} callback -This function will be executed when the Graph will be successfully loaded after ajax request
	    *
	    * @example var myApp = new DCR();
	    * myApp.intializeGraphXml(xml);
	    * //if the request is made successful then this will load the graph ready to be used
	    * @returns {object} Returns an object of Graph Class.
	    */
	    graphproto.intializeGraphXml = function (graphXml, callback) {
	        var graph = this;
	        var serviceUrl = "/api/dl_dcrgraph/initialize";


	        $.ajax({
	            type: "POST",
	            contentType: "application/json; charset=utf-8",
	            url: serviceUrl,
	            dataType: "json",
	            data: JSON.stringify({GraphXml: graphXml }),
	            beforeSend: function () {
	                console.log("sending graph loading request");
	            }
	        }).done(function (restResponse) {
	            if ((restResponse != null || restResponse != undefined)) {
	                graph.loadXMLString(restResponse);
	                if (typeof (callback) === "function") {
	                    callback(restResponse);
	                }
	                return graph;
	            }
	        }).fail(function () {
				console.log("some error occured while initializing graph.");
				events.fire("error", {
					message: "some error occured while initializing graph.", 
					module: "DCR", 
					functionName: "intializeGraphXml", 		
					parameters: JSON.stringify({graphXml: graphXml})
				})
	        }).always(function () {
	            console.log("completed getting graph details");
	        });

	    }

	    /** Main funtion to load the DCR XML and populate the graph with XML data. The standard DCR Graph XML structure will be needed to properly load the Graph
	    *
	    * @memberof Graph
	    * @method loadXML
	    *
	    * @param {string} graphXML -Requires DCR Graph XML in XML format to load the graph
	    *
	    * @returns {object} Returns an object of Graph Class.
	    */
	    graphproto.loadXML = function (graphXML) {
	    	this.loadXMLString(XMLtoString(graphXML));
	    	return this;
	    }

	    function updateItemsResource (arrItems, rType, resource) {
	    	for (var i = 0; i < arrItems.length; i++) {
	    		var resources = arrItems[i].custom[rType];
	    		if(resources!=undefined && resources.length>0){
	    			for (var j = 0; j < resources.length; j++) {
	    				if(resources[j].title.toLowerCase() === resource.title.toLowerCase()){
	    					arrItems[i].custom[rType][j] = resource
	    				}
	    			};
	    		}
	    	};
	    }

	    graphproto.importTo = function (graph, parentPro, options) {

	    	//check for the resources of the elements if they exist in the graph then don't push them there
	    		//also check if any of the imported graph items is using resources and they already exist in the graph then update the items with those resources

	    	for (var i = 0; i < this.Groups.length; i++) {
	    		//if this is simple import or import as simple process then add/update the items of the parent graph
	    		//else if the import is as referred graph then add the items to referred resources
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
	    			var index = checkForMatch(graph.Groups, 'title', this.Groups[i].title);
    				if(index>=0){
	    				console.log(this.Groups[i].title + ' Group exists in graph');
	    				updateItemsResource (this.Events, 'groups', graph.Groups[index]);
	    			}else{
	    				graph.Groups.push(this.Groups[i]);
	    			}
	    		}else if(parentPro!=undefined && parentPro.isRefer==true){
	    			graph.ReferredGroups.push(this.Groups[i]);
	    		}

	    	};

	    	for (var i = 0; i < this.Phases.length; i++) {
	    		//if this is simple import or import as simple process then add/update the items of the parent graph
	    		//else if the import is as referred graph then add the items to referred resources
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
	    			var index = checkForMatch(graph.Phases, 'title', this.Phases[i].title);
    				if(index>=0){
	    				console.log(this.Phases[i].title + ' Phase exists in graph');
	    				updateItemsResource (this.Events, 'phases', graph.Phases[index]);
	    			}else{
	    				graph.Phases.push(this.Phases[i]);
	    			}
	    		}else if(parentPro!=undefined && parentPro.isRefer==true){
	    			graph.ReferredPhases.push(this.Phases[i]);
	    		}

	    	};

	    	for (var i = 0; i < this.Roles.length; i++) {
	    		//if this is simple import or import as simple process then add/update the items of the parent graph
	    		//else if the import is as referred graph then add the items to referred resources
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
	    			var index = checkForMatch(graph.Roles, 'title', this.Roles[i].title);
    				if(index>=0){
	    				console.log(this.Roles[i].title + ' Role exists in graph');
    				updateItemsResource (this.Events, 'roles', graph.Roles[index]);
	    			}else{
	    				graph.Roles.push(this.Roles[i]);
	    			}
	    		}else if(parentPro!=undefined && parentPro.isRefer==true){
	    			graph.ReferredRoles.push(this.Roles[i]);
	    		}

	    	};

	    	for (var i = 0; i < this.Keywords.length; i++) {
	    		//if this is simple import or import as simple process then add/update the items of the parent graph
	    		//else if the import is as referred graph then add the items to referred resources
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
    				if($.inArray(this.Keywords[i], graph.Keywords) === -1){
	    				graph.Keywords.push(this.Keywords[i]);
	    			}
	    		}
	    	};

	    	if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
		    	for (var i = 0; i < this.EventTypes.length; i++) {
		    		var index = checkForMatch(graph.EventTypes, 'title', this.EventTypes[i].title);
	    			if(index>=0){
	    				console.log(this.EventTypes[i].title + ' EventType exists in graph');
	    				updateItemsResource (this.Events, 'eventType', graph.EventTypes[index]);
	    			}else{
	    				graph.EventTypes.push(this.EventTypes[i]);
	    			}
		    	};


		    	for (var i = 0; i < this.Parameters.length; i++) {
		    		var index = checkForMatch(graph.Parameters, 'title', this.Parameters[i].title);
	    			if(index>=0){
	    				console.log(this.Parameters[i].title + ' Parameter exists in graph');
	    				//updateItemsResource (this.Events, 'groups', graph.Parameters[index]);
	    			}else{
	    				graph.Parameters.push(this.Parameters[i]);
	    			}
		    	};
			}

	    	//push all the events/connections process in the graph	
	    	for (var i = 0; i < this.Events.length; i++) {
	    		var curItem = this.Events[i];
	    		// console.log(curItem);
	    		// console.log(checkForMatch(graph.Events, 'id', curItem.id));
	    		//check if the Event with same name exists in the graph to be imported then update its id so no confusion occurs
	    		//if the parentPro is undefined this means it is import as subprocess
	    		//if parentPro is defined this means that it is to be nested under referred pro
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
	    			if(graph.checkIfIDExists(curItem.id)==true){
		    			var newID = graph.uniqueEventID(curItem.id, 1);
		    			curItem.getChilds().forEach(function (el) {
		    				if(el.parentId===curItem.id){
		    					el.parentId = newID;
		    				}
		    			})
		    			curItem.id = newID;
		    		}
	    		}
	    		if(checkForMatch(graph.Events, 'guid', curItem.guid)<0){
	    			this.Events[i].graph = graph;
	    			if(options.isProcessImport==true || options.isFormImport==true){
		    			this.Events[i].nLevel = this.Events[i].nLevel + 1;
		    			if(parentPro!=undefined){
		    				this.Events[i].isRefer = parentPro.isRefer;
		    			}
		    			
		    		}
    				graph.Events.push(this.Events[i]);
    			}
	    	};

	    	//push all the events/connections process in the graph	
	    	for (var i = 0; i < this.Processes.length; i++) {
	    		var curItem = this.Processes[i];
	    		console.log(curItem);
	    		console.log(checkForMatch(graph.Processes, 'id', curItem.id));
	    		//check if the Event with same name exists in the graph to be imported then update its id so no confusion occurs
	    		//if the parentPro is undefined this means it is import as subprocess
	    		//if parentPro is defined this means that it is to be nested under referred pro
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
		    		if(graph.checkIfIDExists(curItem.id)==true){
		    			var newID = graph.uniqueEventID(curItem.id, 1);
		    			curItem.getChilds().forEach(function (el) {
		    				if(el.parentId===curItem.id){
		    					el.parentId = newID;
		    				}
		    			})
		    			curItem.id = newID;
		    		}
		    	}
	    		if(checkForMatch(graph.Processes, 'guid', curItem.guid)<0){
	    			this.Processes[i].graph = graph;
	    			if(options.isProcessImport==true || options.isFormImport==true){
	    				this.Processes[i].nLevel = this.Processes[i].nLevel + 1;
	    				if(parentPro!=undefined && this.Processes[i].parentPro==="root"){
		    				this.Processes[i].parentGUID = parentPro.guid;
			    			this.Processes[i].parentObj = parentPro;
			    			this.Processes[i].parentId = parentPro.id;
			    			this.Processes[i].parentPro = parentPro;
			    			graph.Childs.push(this.Processes[i]);	
		    			}
	    			}
    				graph.Processes.push(this.Processes[i]);
    			}
	    		
	    	};

	    	

	    	//push all the events/connections process in the graph	
	    	for (var i = 0; i < this.Connections.length; i++) {
	    		console.log(this.Connections[i]);
	    		this.Connections[i].graph = graph;
	    		graph.Connections.push(this.Connections[i]);
	    	};	 

	    	if(options.importDocTitle==true){
				graph.Title = this.Title;
			}

			if(options.importKeywords==true){
				graph.Keywords = this.Keywords;
			}

			if(options.importDocDesc==true){
				graph.Description = this.Description;
			}
			
			graph.Documentation = this.Documentation

			if(options.importDocLanguage==true){
				graph.Language = this.Language;
			}
			if(options.importDocDomain==true){
				graph.Domain = this.Domain;
			}

			if(options.importDocZoom==true){
				graph.ZoomLevel = this.ZoomLevel
				events.fire('zoomLevelUpdated', graph);
			}

			if(options.importDocBG==true){
				graph.BG = this.BG;
				events.fire('graphBGUpdated', graph);
			}  

			graph.Type = this.Type;
 	

	    	//push all the events/connections process in the graph	
	    	/*for (var i = 0; i < this.ExternalEvents.length; i++) {
	    		console.log(this.ExternalEvents[i]);
	    		graph.ExternalEvents.push(this.ExternalEvents[i]);
	    	};

	    	//push all the events/connections process in the graph	
	    	for (var i = 0; i < this.AllSharedEvents.length; i++) {
	    		console.log(this.AllSharedEvents[i]);
	    		graph.AllSharedEvents.push(this.AllSharedEvents[i]);
	    	};*/

	    	//push all the events/connections process in the graph	
	    	if(options.isProcessImport==true || options.isFormImport==true){
	    		//create a process first and then add these items in it
	    		if(parentPro==undefined){
	    			parentPro = graph.createProcess();
	    			graph.Parents.push(parentPro);
	    		}
	    		for (var i = 0; i < this.Parents.length; i++) {
	    			//if any parent has parentObj as null and parentPro as root 
	    			//then set this new Pro as a parent for that
	    			if((this.Parents[i].parentObj==null || this.Parents[i].parentObj==undefined) && this.Parents[i].parentPro=='root'){
	    				if(checkForMatch(graph.Parents, 'guid', this.Parents[i].guid)<0){
		    				this.Parents[i].parentGUID = parentPro.guid;
			    			this.Parents[i].parentObj = parentPro;
			    			this.Parents[i].parentId = parentPro.id;
			    			this.Parents[i].parentPro = parentPro;
		    				graph.Parents.push(this.Parents[i]);
		    			}
		    			
		    			//now as this parent is child of parentPro so add this in the childs array
		    			if(checkForMatch(graph.Childs, 'guid', this.Parents[i].guid)<0){
		    				graph.Childs.push(this.Parents[i]);
		    			}
	    			}else{
	    				//push this item to graph parents
	    				if(checkForMatch(graph.Parents, 'guid', this.Parents[i].guid)<0){
	    					graph.Parents.push(this.Parents[i]);
	    				}
	    			}
	    		};
	    		//get all the root events and set them as childs for this new pro
	    		this.getAllRootEvents().forEach(function (el) {
	    			//if any parent has parentObj as null and parentPro as root 
	    			//or the item is not already there then push it to childs
	    			if((el.parentObj==null || el.parentObj==undefined) && el.parentPro=='root' && checkForMatch(graph.Childs, 'guid', el.guid)<0){
	    				el.parentGUID = parentPro.guid;
		    			el.parentObj = parentPro;
		    			el.parentId = parentPro.id;
		    			el.parentPro = parentPro;
	    				graph.Childs.push(el);
	    			}
	    		});

	    		//now move all the childs of this to graph
	    		for (var i = 0; i < this.Childs.length; i++) {
	    			if(checkForMatch(graph.Childs, 'guid', this.Childs[i].guid)<0){
	    				if(parentPro!=undefined && this.Childs[i].parentPro == "root"){
	    					this.Childs[i].parentPro = parentPro;
	    				}
	    				graph.Childs.push(this.Childs[i]);
	    			}
		    		console.log(this.Childs[i]);
		    	};

	    		//parentPro.dcrgraph = stringToXML(this.writeXML(true).XML);
	    	}else{
	    		for (var i = 0; i < this.Parents.length; i++) {
		    		console.log(this.Parents[i]);
		    		graph.Parents.push(this.Parents[i]);
		    	};
		    	//push all the events/connections process in the graph	
		    	for (var i = 0; i < this.Childs.length; i++) {
		    		console.log(this.Childs[i]);
		    		graph.Childs.push(this.Childs[i]);
		    	};
	    	}  

	    	if(options.isFormImport==true){
	    		//- we will use eventType=DCRForm to identify forms in "open" - if "new group /subprocess is enabled - then show "Open"
	    		var item = graph.EventTypes.filter(function(el){ return el.title =="DCRForm"})
	    		var curEventType = null;
 				if(item.length>0){
 					curEventType = item[0];
 					//check if id parameter exists or not
 					var idParam = curEventType.parameters.filter(function(el){ return el.title =="id"})
 					if(idParam.length>0){
 						idParam[0].required = "true";
 					}else{
 						curEventType.parameters.push({title: "id", value: "0", required: "true"})
 					}
 				}else{
 					curEventType = graph.addEventType({id: GUID(), title: "DCRForm", description: "", parameters: [{title: "id", value: "0", required: "true"}]})
 				}
 				if(parentPro!=undefined){
 					parentPro.custom.eventType = curEventType
 					parentPro.custom.eventTypeData = [{title: "id", value: parentPro.graphID, required: "true"}]
 				}
 				
			}
			
			//for now just adding importing layers and highlights as it is
			//TODO: need to optimize the import for layers as there can be many now with default being true
			for (var i = 0; i < this.HighlightLayers.length; i++) {
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
	    			graph.HighlightLayers.push(this.HighlightLayers[i]);
	    		}

			};
			
			for (var i = 0; i < this.Highlights.length; i++) {
	    		if((options.isFormImport!=true && options.isProcessImport!=true) || (options.isProcessImport==true && parentPro==undefined) || (parentPro!=undefined && parentPro.isRefer==false)){
	    			graph.Highlights.push(this.Highlights[i]);
	    		}

	    	};

	    	
	    }

	    /** Main function to import DCR XML and populate the graph with XML data.
	    *
	    * @memberof Graph
	    * @method import
	    *
	    * @param {string} graphXML   -XML of graph to be imported
	    * @param {number} graphID    -Used for creating forms/processes
	    * @param {object} configs    -Main configs
	    * @param {object} options    -Import options
	    * @param {function} callback -Function to be called after import is done
	    *
	    * @returns {object} Returns an object of Graph Class.
	    */
	    graphproto.import = function (graphXML, graphID, configs, options, callback) {
	    	var graph = this;
	    	var importedGraph = new DCR();

	    	if(typeof(graphXML)=='object'){
	    		graphXML = XMLtoString(graphXML)	
	    	}else if(typeof(graphXML)=='string'){

	    	}

	    	//if graph is imported as refer graph then use its id to store in the graph

	    	//Always Enable try catch for the production
	    	try{
    			importedGraph.loadXMLString(graphXML, configs, options);

    			if(options.isReferred==true && options.isFormImport == true){
    				console.log('referred form loading');
		    		var parentPro = this.createForm({graphID: graphID, graphXML: stringToXML(graphXML).getElementsByTagName('dcrgraph')[0]});

		    	}else if(options.isReferred==true && options.isProcessImport==true){
		    		console.log('referred graph loading');
		    		var parentPro = this.createProcess({graphID: graphID, graphXML: stringToXML(graphXML).getElementsByTagName('dcrgraph')[0]}, true);
		    	}else if(options.isReferred==false && options.isProcessImport==true){
		    		//just importing in to a sub process
		    		var parentPro = this.createProcess();
	    			this.Parents.push(parentPro);
		    	}
    			importedGraph.importTo(graph, parentPro, options);

    			if(typeof(callback) === "function"){
	    			callback(importedGraph, graph, parentPro, options);
	    		} 
    			return this;
    		}catch(ex){
				console.error('error occured during file import '+ex)
				events.fire("exception", {message: "graph import failed", details: ex, module: "DCR", functionName: "import"})
	    	}

	    	return this;
	    }

	    /** Main funtion to export DCR XML.
	    *
	    * @memberof Graph
	    * @method export
	    *
	    * @returns {object} Returns XML as string of Graph.
	    */
	    graphproto.export = function () {
	    	return this.writeXML(true);
	    }

	    graphproto.exportGlobalStore = function () {
	    	return '<globalStore>'+
					variablesToXML (this, true)+
					'</globalStore>';
	    }

	    graphproto.isEmpty = function () {
	    	if(this.Events.length>0){
				return false
			}else if(this.EventTypes.length>0){
				return false;
			}else if(this.Roles.length>0){
				return false;
			}else if(this.Groups.length>0){
				return false;
			}else if(this.Phases.length>0){
				return false;
			}else if(this.Parameters.length>0){
				return false;
			}else if(this.Processes.length>0){
				return false;
			}
			return true;
	    }


	    /** Main funtion to load the DCR XML and populate the graph with XML data. The standard DCR Graph XML structure will be needed to properly load the Graph
	    *
	    * @memberof Graph
	    * @method loadXMLString 
	    *
	    * @param {string} graphXML -Requires DCR Graph XML in string format to load the graph
	    *
	    * @example 
	    *	<!doctype html>
	    *	<html>
	    *	<head>
	    *	    <meta charset="utf-8">
	    *	    <title>Demo App</title>
	    *	</head>
	    *	<body>
	    *	    <script src="jquery.js"></script>
	    *	    <script src="xml2json.js"></script>
	    *	    <script src="DCR.js"></script>	
	    *	    <script>
	    *		$(document).ready(function () {
	    *	 		var myApp = new DCR();
	    * 			
	    *			$('#loadGraph').on('click', function () {
	    *				var fileXML = $('#xmlInput').val();
	    *				if(fileXML==" " || fileXML == ""){
	    *					alert('Invalid Input');
	    *					return;
	    *				}
	    *				myApp.loadXMLString(fileXML);
	    *				//graph will reset first by default by this function just in case user clicks several time
	    *				//so each time new graph is to be laoded properly
	    *			});
	    *	    })
	    *	 
	    *	    </script>
	    *		<textarea id="xmlInput"></textarea>
	    *		<input type="submit" id="loadGraph" value="Load DCR Graph" />
	    *	</body>
	    *	</html>
	    * @returns {object} Returns an object of Graph Class.
	    *///loadDCRXML
	    graphproto.loadXMLString = function (graphXML, configs, options, reloadRefers) {
	        //this.reset();
	        //console.profile('loading graph XML');
	        console.time('loading graph XML')
	        //console.dirxml('loading XML' + graphXML);
	        if(graphXML==null || graphXML == undefined || graphXML.length==0){
	        	return;
	        }
	        //Always Enable try catch for the production
	        try{
	        this.XML = graphXML;
	        var parsedGraphXML = stringToXML(graphXML);
	        this.ProcessedPs = [];
	        //using this as this scope changes inside the functions
	        var graph = this;
	        var dOptions = {
	        		isImported : false,
	        		isReferred : false,
					importRoles : true,
        			importGroups : true,
        			importTypes : true,
        			importParams : true,
        			importPhases : true,
        			importDataTypes : true,
        			importDocDesc : true,
        			importDocLanguage : true,
        			importDocDomain : true,
        			importDocTitle : true,
        			importKeywords : true,
        			importDocFilters : true,
        			importDocZoom : true,
        			importDocBG : true,
        			isSimulation : false
	        	}
	        if(options!=undefined){
	        	for(var k in options) dOptions[k]=options[k];
	        }

	        /*if(referProId==null || referProId=="" || referProId==" " ){
				referProId = undefined;
			}

			if(referID==null || referID=="" || referID==" " ){
				referID = undefined;
			}*/

	        //getting the graph and its subgraphs
	        getGraphResouces(this, $(parsedGraphXML).find('dcrgraph')[0], true, dOptions);
			
			// creating connections
			for (var i = 0; i < this.AllConnections.length; i++) {
				setupConnections(this, this.AllConnections[i][0], this.AllConnections[i][1], this.AllConnections[i][2]);
			};

			this.AllConnections = [];

			this.Highlights = this.Highlights.map(function(el){
				el.items = el.items.map(function (item) {
					//find the item in graph and add it to highlight
					return findHighlightItem(graph, el.type, item)
				})

				return el;
			})

			//add global marking of the xml if any exists
			var globalMarkings = $(parsedGraphXML).find('globalMarking');
			this.GlobalMarking = $.xml2json(globalMarkings[globalMarkings.length-1] || null);
	        }catch(ex){
				 console.error('Exception' + ex);
				 events.fire("exception", 
				 {
					message: "graph xml loading failed",
					module: "DCR",
					fileName: "DCR.js",
					functionName: "loadXMLString",
					logLevel: "Error",
					severity: "High",
					parameters: JSON.stringify({graphXML:graphXML, configs:configs, options:options, reloadRefers:reloadRefers}),
					details: ex
				  })
	        }
	        // this.loadFragments() // ! not needed now, may be required if we need to load fragments on graph load
	        this.loadReferGraphs(reloadRefers, configs) 
	       	
	        console.timeEnd('loading graph XML')
	        //console.profileEnd('loading graph XML');
	        return this;
	    };

	    //function to get the graphs of the user, have to pass referProId to get it later for usage
		function getGraph (graph, graphId, referPro, configs, callback, callbackGet) {
			$.ajax({
				type: configs.api.graph.get.type,
		        contentType: "application/json; charset=utf-8",
		        url: configs.api.graph.get.url +parseInt(graphId),
		        dataType: "json",
		        beforeSend : function(){
		        	console.log('fetching graph')
		        }
			}).done(function(restResponse){
				if(restResponse!=null || restResponse!= undefined){			
					if(typeof(callbackGet) === "function"){
						//if process id is passed then it can be used for storing the graph to
		    			callbackGet(graph, restResponse, referPro, callback);
		    		} 
		    		return restResponse;
				}
			}).fail(function(){
				console.log("some error occured in getting graph.");
				events.fire('loader', 'hide');
				events.fire('showMessage', { msg: (translations? translations.something_went_wrong: "some error occured in getting graph."), type: 'error', timeout: 2000 })
				events.fire("getGraphFailed", {graph: graph, id: graphId, referPro: referPro})
				events.fire("error", {message: "some error occured in getting graph.", module: "DCR", functionName: "getGraph", 		parameters: JSON.stringify({graphId: graphId})
				})
			}).always(function(){
				console.log("completed getting graph");
				events.fire('loader', 'hide');
			});
		}

		//function to check if a process is dynmaic form or not?
		function isDynamicForm (curPro) {
			if(curPro!=null && curPro!=undefined && curPro.dcrgraph !=undefined && curPro.dcrgraph !=null){
				if(curPro.dcrgraph.attributes.dataTypesStatus!=undefined && curPro.dcrgraph.attributes.dataTypesStatus.value == "show"){
					return true;
				}
			}
			return false;
		}

		function populateReferGraph(graph, restResponse, referPro, reloadRefers, callback, isFormImport) {

			if(reloadRefers==true){
				referPro.dcrgraph = stringToXML(restResponse.GraphXml).getElementsByTagName('dcrgraph')[0];  
			}else{
				//get the refer pro xml from the current xml
			}

			if(isFormImport==true){
				var options = {isFormImport:true}
			}else{
				var options = {isProcessImport:true}
			}

			// if any refer graph with dcrgraph then load it and import into graph
			var curGraph = new DCR();
			if( referPro.dcrgraph){
				curGraph.loadXML(referPro.dcrgraph);
				curGraph.importTo(graph, referPro, options);
				console.log('referred graph loading');
			}
			

			referPro.isDynamicForm = isDynamicForm(referPro);
			if(graph.ReferredCons.length>0){
            	for (var i = 0; i < graph.ReferredCons.length; i++) {
            		setupConnections(graph, graph.ReferredCons[i][0], graph.ReferredCons[i][1], graph.ReferredCons[i][2]);
            	};
            }
            events.fire('referredProcessLoaded', {graph : graph, referGraph: curGraph, referPro: referPro});
            if(typeof(callback)=='function'){
		      callback(curGraph, referPro)
		    }
		}

		function loadReferGraphs(graph, items, reloadRefers, configs, callback, isFormImport) {
			for (var i = 0; i < items.length; i++) {
		        var curGraphId = parseInt(items[i].referId);
		        //var referProId = items[i].id;
		        if ($.inArray(items[i], graph.ProcessedReferGraphs) === -1) {
		            graph.ProcessedReferGraphs.push(items[i]);

		            if (reloadRefers == true) {
		            	//let create a new graph for the curProcess and have this graph xml updated with the XML from refer graph DB XML
		            	getGraph(graph, curGraphId, items[i], configs, callback, function (graph, restResponse, referPro, callback) {
		            		populateReferGraph(graph, restResponse, referPro, reloadRefers, callback, isFormImport)
		                })
		                
		            } else {
		                populateReferGraph(graph, null, items[i], reloadRefers, callback, isFormImport)
		            }

		        }

		    }
		}

		//main function to be used for loading referGraphs in the DCR
	    graphproto.loadReferGraphs = function (reloadRefers, configs, callback){
	    	if(this.ReferredPros.length<1 && this.ReferredForms.length<1){
	    		return this;
	    	}

	    	this.ProcessedReferGraphs = [];
	    	var graph = this;
	    	//get the graph info for all the sub processes and populate it on the graph so that it can be shown to user
	    	loadReferGraphs(graph, this.ReferredPros, reloadRefers, configs, callback)
	    	loadReferGraphs(graph, this.ReferredForms, reloadRefers, configs, callback, true)
		}
		function loadFragment(graph, container) {
			if(container.dcrgraph===null){
				return; //if no graph xml
			}
			var options = {isProcessImport:true}
		            		var curGraph = new DCR();
			curGraph.loadXML(container.dcrgraph);
			curGraph.importTo(graph, container, options);

			//import any referred connections from fragment to main
			//TODO: need to verify this with different graphs as it may have issues if ids for items are same from main/fragment graph
			for (var i = 0; i < curGraph.ReferredCons.length; i++) {
				setupConnections(graph, curGraph.ReferredCons[i][0], curGraph.ReferredCons[i][1], curGraph.ReferredCons[i][2]);
		                    	};
		                    }
		
		//main function to be used for loading fragments in the DCR
	    graphproto.loadFragments = function (callback){
	    	if(this.Fragments.length<1){
	    		return this;
						    }
			var graph = this;
	    	//populate fragments in the graph
	    	graph.Fragments.map(function (el) {
				return loadFragment(graph, el)
		                })
		                
	                    


	                    if(typeof(callback)=='function'){
				callback(graph)
					    }



	    }

	    //creating runtimes xml markup
		function runtimesToXML (eRuntime, xEvents){
			var runtimeTag =eRuntime;
			if (eRuntime == 'pending') {
				runtimeTag = 'pendingResponses';
			}

			var runtimeOutput = '<'+runtimeTag+'>';
			xEvents.forEach(function(el){
				if(el.getRuntime(eRuntime)!=undefined && el.getRuntime(eRuntime)==true){
					var extraAttr = '';
					if (eRuntime == 'pending' && el.deadline!=undefined) {
						extraAttr = 'deadline="'+replaceSlashes(htmlEncode(el.deadline))+'"';
					}else if(eRuntime == 'executed' && el.time!=undefined){
						extraAttr = 'time="'+replaceSlashes(htmlEncode(el.time))+'"';
					}
					runtimeOutput += '<event id="'+el.id+'" '+extraAttr+'/>'
				}
			});

			runtimeOutput += '</'+runtimeTag+'>';
			return runtimeOutput;
		}

		function storeConnection (el, curProcess, gEvents, subProcesses, gMultiInsProcesses) {




						

			var makeXML = false //, useFromExtID = false, useToExtID = false;
						var fromParPro = el.from.getParentProcess();
						var toParPro = el.to.getParentProcess();
						//compare the parents of the from and to elements
			if(fromParPro==toParPro && toParPro ==curProcess){
							//if both lie in the same parent then use local ids and xml
				//useLocal = true;
							makeXML = true;						
						}else {
							// if it is from and it exists in this processes then check the to
							if($.inArray(el.from, gEvents)>=0){



					if(fromParPro==undefined && toParPro!=undefined){


						//if from is in parent and to is not in parent but another process then it is already stored in that process
											makeXML = false;
					}else if(el.from.nLevel>=el.to.nLevel){
										makeXML = true;
									}


							}else if($.inArray(el.to, gEvents)>=0 || $.inArray(el.to, subProcesses)>=0 || $.inArray(el.to, gMultiInsProcesses)>=0){

					if(toParPro==undefined && fromParPro!=undefined){
						//if to is in parent and from is not in parent but another process then it is already stored in that process
											makeXML = false;
					}else if(el.to.nLevel>=el.from.nLevel){
											makeXML = true;
										}



									}
									}

			return makeXML;
							}
		//creating constraints xml markup
		function constraintsToXML (graph, curProcess, eConstraint, gEvents, gSubProcesses, gMultiInsProcesses){
			var constraintTag = eConstraint+'s';

			var constraintOutput = '<'+constraintTag+'>';

			graph.Connections.forEach(function(el){
				if(el.type==eConstraint){

					//get source parent pro and target parent pro
					//if which ever has higher nLevel store XML in that
					if($.inArray(el.from, gEvents)>=0 || $.inArray(el.to, gEvents)>=0 || ($.inArray(el.from, gEvents)>=0 && gSubProcesses!=undefined && $.inArray(el.to, gSubProcesses)>=0) || ($.inArray(el.from, gEvents)>=0 && $.inArray(el.to, gMultiInsProcesses)>=0)){	

						//check if the source or the target is an event inside a process and is shared or not and use its credentials to make the connections
						var fromID = el.from.id;
						var toID = el.to.id;

						if(storeConnection(el, curProcess, gEvents, gSubProcesses, gMultiInsProcesses) == true){

							constraintOutput += '<'+eConstraint+' sourceId="'+fromID+'" targetId="'+toID+'"';
						
							constraintOutput += ' filterLevel="'+htmlEncode(parseInt(el.level))+'" ';
							constraintOutput += ' description="'+htmlEncode(el.description)+'" ';
							constraintOutput += ' time="'+htmlEncode(el.time)+'" ';
							constraintOutput += ' groups="'+htmlEncode(el.groups.map(function (x) { return x.title; }).join(','))+'" ';

							if(el.guard.length>0){
								constraintOutput += ' expressionId="'+el.from.id + "-path-"+el.to.id+'--'+el.type+'" ';
							}
							
							if(el.valueExpression.length>0){
								constraintOutput += ' valueExpressionId="'+el.from.id + "-path-"+el.to.id+'--'+el.type+'--value" ';
							}
							
							if(el.link.length>0){
								constraintOutput += ' link="'+el.link+'" ';
							}
							
							if(el.businessRule){
								constraintOutput += ' businessRule="'+el.businessRule+'" ';
							}
							constraintOutput += ' />';
						}
						
					}else{
						//there are no connections for gevents so check for shared events if there any connections is between them
					}
					 
				}
			});

			constraintOutput += '</'+constraintTag+'>';
			return constraintOutput;
		}
		//creating label mapping xml markup
		function labelMappingToXML (elabelMap, xEvents){
			var mappingTag = elabelMap+'s';

			var mappingOutput = '<'+mappingTag+'>';

			xEvents.forEach(function(el){
				if(el.custom.label.length>0 && el.custom.label !=' '){
					var objId = el.id;
					mappingOutput += '<'+elabelMap+' eventId="'+objId+'" labelId="'+replaceSlashes(htmlEncode(el.custom.label))+'"/>';
				}
			});

			mappingOutput += '</'+mappingTag+'>';
			return mappingOutput;
		}



		//creating events xml markup on base of object and its properties
		function eventsToXml (graph, xEvents, generateChilds, isProcess, isShared, includeRefer){
			xEvents.forEach(function(el){

				if($.inArray(el, graph.ProcessedEvents) === -1 ){

					if(el.baseType=='process' && isProcess==false){
						return;
					}


					var objId = el.id,
						eventScope = el.scope,
						objBox = el.getBBox(),
						xLoc = parseInt(objBox.x),
						yLoc = parseInt(objBox.y),
						objId = objId, 
						eventSequence = 0;


					if(isProcess==true){
						if(el.instanceId==undefined){
							el.instanceId = ''
						}
						if(el.template==undefined){
							el.template = ''
						}
						eventXMLStr += '<subProcess id="'+objId+'" isRefer="'+el.isRefer+'" multiInstance="'+el.multiInstance+'" name="'+htmlEncode(el.custom.label)+'" instanceId="'+el.instanceId+'"  template="'+el.template+'" >';
					}else{

						var attrs = {id: objId}

						//<computation id="B-computation-expression"></computation>
						if(el.computation.length>0 || el.dmnXML.length>0){
						 	attrs.computation = el.id+'-computation'
						}
						
						if(el.interfaceType && (el.interfaceType=="inner" || el.interfaceType=="outer")){
						 	attrs.interfaceType = el.interfaceType;
						}
						
						if(el.commonId && el.commonId==true){
						 	attrs.commonId = el.commonId;
						}

						if(el.type == 'form'){
							attrs.cancelText = replaceSlashes(htmlEncode(el.cancelText));
							attrs.sendText = replaceSlashes(htmlEncode(el.sendText));
							attrs.hideCancel = el.hideCancel;
							attrs.formShowInitialPhase =  parseInt(el.formShowInitialPhase);
						}
						
						// if any datatype other than default, add it to xml as type=<type>, i-e: (el.type =="subprocess" || el.type=="nesting" || el.type=="form" )
						if(typeof el.type != 'undefined' && el.type!=undefined && el.type !="default"){
							attrs.type = el.type;
							if(el.isFragment() == true){
								attrs.fragmentId = el.fragmentId;
								attrs.serialise = "inline";
							}
						}

						eventXMLStr += '<event '

						for(attr in attrs){
							eventXMLStr += attr+'="'+attrs[attr]+'" ';
						}

						eventXMLStr += '>';
						
					}
					var elExpressionMsg = el.getResourceExpression('message');
					var elExpressionAttrs = {
						message: (elExpressionMsg != null? replaceSlashes(htmlEncode(elExpressionMsg)):'')
					}
					var rExpression = el.getResourceExpression('value');
					if(rExpression!=null && rExpression.trim().length>0){
						elExpressionAttrs.id = el.id+'-resource'
					}

					eventXMLStr +=		'<precondition ';
					for(attr in elExpressionAttrs){
						eventXMLStr += attr+'="'+elExpressionAttrs[attr]+'" ';
					}
					eventXMLStr += ' />';
				    eventXMLStr +=      '<custom>'+
				                        	'<visualization>'+
				                                '<location xLoc="'+xLoc+'" yLoc="'+yLoc+'" />'+
				                                '<colors bg="'+el.custom.visualization.colors.bg+'" textStroke="'+el.custom.visualization.colors.textStroke+'" stroke="'+el.custom.visualization.colors.stroke+'" />'+
				                            '</visualization>'+
				    						 '<roles>';

							                    //prepare roles of event
								                if(el.custom.roles.length>0){
								                	el.custom.roles.forEach(function(eRole){
									                	eventXMLStr += '<role>'+replaceSlashes(htmlEncode(eRole.title))+'</role>'
									                })
								                }else{
								                	eventXMLStr += '<role />';
								                }


			    	eventXMLStr +=	    	 '</roles>'+
											 '<groups>';
								                //prepare groups of event
								                if(el.custom.groups.length>0){
								                	el.custom.groups.forEach(function(eGroup){
									                	eventXMLStr += '<group>'+replaceSlashes(htmlEncode(eGroup.title))+'</group>'
									                })
								                }else{
								                	eventXMLStr += '<group />';
								                }
							                    

					eventXMLStr +=	 		 '</groups>'+
											 '<phases>';
								                //prepare groups of event
								                if(el.custom.phases.length>0){
								                	el.custom.phases.forEach(function(ePhase){
									                	eventXMLStr += '<phase>'+replaceSlashes(htmlEncode(ePhase.title))+'</phase>'
									                })
								                }else{
								                	eventXMLStr += '<phase />';
								                }

					eventXMLStr +=          '</phases>'+
								          	'<eventType>';
					                    	 //setting Event Type
					                    	 if(el.custom.eventType!= undefined && el.custom.eventType.title!= 'none'){
					                    	 	eventXMLStr += replaceSlashes(htmlEncode(el.custom.eventType.title));
					                    	 }

					eventXMLStr +=      	 '</eventType>'+
											'<eventScope>'+ eventScope + '</eventScope>';   	 

											if(el.custom.eventTypeData!=undefined){
					                    	 	eventXMLStr += '<eventTypeData>';
					                    	 	for (var i = 0; i < el.custom.eventTypeData.length; i++) {
					                    	 		var curParam = el.custom.eventTypeData[i];
					                    	 		var attrs = 'title="'+replaceSlashes(htmlEncode(curParam.title))+'" value="'+replaceSlashes(htmlEncode(curParam.value))+'" required="'+curParam.required+'"';
					                    	 		eventXMLStr += '<parameter '+attrs+' />';
					                    	 		//<parameter title="untitled" required="true" value="asd"></parameter>
					                    	 	};
					                    	 	eventXMLStr += '</eventTypeData>';
					                    	 }
					eventXMLStr +=      	 '<eventDescription>';
												if(el.custom.eventDescription!=undefined && htmlEncode(el.custom.eventDescription).length>0){
													eventXMLStr += replaceSlashes(htmlEncode(el.custom.eventDescription));
												}

					eventXMLStr +=      	 '</eventDescription>';

					eventXMLStr +=      	 '<purpose>';
												if(el.custom.purpose!=undefined && htmlEncode(el.custom.purpose).length>0){
													eventXMLStr += replaceSlashes(htmlEncode(el.custom.purpose));
												}

					eventXMLStr +=      	 '</purpose>';

					eventXMLStr +=      	 '<guide>';
												if(el.custom.guide!=undefined && htmlEncode(el.custom.guide).length>0){
													eventXMLStr += replaceSlashes(htmlEncode(el.custom.guide));
												}

					eventXMLStr +=      	 '</guide>';

					eventXMLStr +=		  '<insight use="'+ (el.custom.insight!=undefined && el.custom.insight.use!=undefined? el.custom.insight.use: false )+'">';  
												  if(el.custom.insight!=undefined && el.custom.insight.deadlineExpression!=undefined && el.custom.insight.deadlineExpression.trim().length>0){
													eventXMLStr += '<deadlineExpression>';
													eventXMLStr += replaceSlashes(htmlEncode(el.custom.insight.deadlineExpression));
													eventXMLStr += '</deadlineExpression>';
												} 
												
					eventXMLStr +=      	'</insight>';

					                    	 //level of the event
					eventXMLStr +=      	'<level>'+htmlEncode(el.custom.level)+'</level>';
											if(el.custom.sequence!=undefined && parseInt(el.custom.sequence) != NaN){
												eventSequence = parseInt(el.custom.sequence);
					eventXMLStr +=      	'<sequence>'+eventSequence+'</sequence>'; 
											}
					eventXMLStr +=      	'<costs>'+replaceSlashes(htmlEncode(toNumber(el.custom.costs)))+'</costs>';

					 // //<computation id="B-computation-expression"></computation>
					 // if(el.custom.computation.length>0){
					 // 	eventXMLStr +=      	'<computation id="'+el.id+'-computation"></computation>'; 
					 // }
					

					if(isProcess==true){
						eventXMLStr +=      '<label>'+replaceSlashes(htmlEncode(el.custom.label))+'</label>'+  
										 '</custom>';
					}else{
						                //event data

					eventXMLStr +=        '<eventData>';
					//typeof(el.custom.eventData)==="object" && el.custom.eventData.dataType.type != undefined
											if(el.getDataType()!=undefined && el.custom.eventData.dataType.type != undefined){
												var dataType = el.custom.eventData.dataType;
												dataType.type = dataType.type.toLowerCase()
												var eventSequence = 0;
												if(dataType.sequence!=undefined && parseInt(dataType.sequence) != NaN){
													eventSequence = parseInt(dataType.sequence);
												}
												var displayWidth ="medium";
												if(dataType.width !=undefined){
													displayWidth = dataType.width
												}
												switch(dataType.type){
													case 'int':
													case 'money':
													case 'float':
													case 'text':
													case 'date': 
													case 'datetime':
												    case 'password':
												        if (dataType.type != 'date' && dataType.type != 'datetime') {
												            if (dataType.type == 'float') {
												                dataType.min = parseFloat(dataType.min)
												                dataType.max = parseFloat(dataType.max)
												            }
												            else {
												                dataType.min = parseInt(dataType.min)
												                dataType.max = parseInt(dataType.max)
												            }
                                                        }
														eventXMLStr += '<dataType sequence="'+eventSequence+'" width="'+displayWidth+'" min="'+dataType.min+'" max="'+dataType.max+'" placeholder="'+htmlEncode(dataType.placeholder)+'" hinttext="'+htmlEncode(dataType.hinttext)+'">'+dataType.type+'</dataType>';
														break;
                                                    case 'bool':
                                                    case 'label':
														eventXMLStr += '<dataType sequence="'+eventSequence+'" width="'+displayWidth+'" default="'+dataType.default+'" placeholder="'+htmlEncode(dataType.placeholder)+'" hinttext="'+htmlEncode(dataType.hinttext)+'">'+dataType.type+'</dataType>';
														break;
													case 'table':
														eventXMLStr += '<dataType sequence="'+eventSequence+'" width="'+displayWidth+'" placeholder="'+htmlEncode(dataType.placeholder)+'" hinttext="'+htmlEncode(dataType.hinttext)+'">'+dataType.type+'</dataType>';
														var curChoices = el.custom.eventData.dictionary.item;

														if(curChoices.length>0){
															eventXMLStr += '<dictionary>';
															for (var i = 0; i < curChoices.length; i++) {
																eventXMLStr += '<item key="'+htmlEncode(curChoices[i].key)+'" value="'+htmlEncode(curChoices[i].value)+'"></item>'
																
															};
								                            eventXMLStr += '</dictionary>';
														}
                                                        break;	
                                                    case 'slider':
                                                        eventXMLStr += '<dataType sequence="' + eventSequence + '" width="' + displayWidth + '" placeholder="' + htmlEncode(dataType.placeholder) + '" hinttext="' + htmlEncode(dataType.hinttext) + '">' + dataType.type + '</dataType>';
                                                        var curChoices = el.custom.eventData.dictionary.item;
                                                        if (curChoices.length > 0) {
                                                            eventXMLStr += '<dictionary>';
                                                            for (var i = 0; i < curChoices.length; i++) {
                                                                eventXMLStr += '<item key="' + htmlEncode(curChoices[i].key) + '" value="' + htmlEncode(curChoices[i].value) + '"></item>'
															};
								                            eventXMLStr += '</dictionary>';
														}
														break;	
													case 'choice':
													    eventXMLStr += '<dataType sequence="' + eventSequence + '" width="' + displayWidth + '" placeholder="' + htmlEncode(dataType.placeholder) + '" hinttext="' + htmlEncode(dataType.hinttext) + '" dataSetList="' + htmlEncode(dataType.dataSetList) + '" multiple="'+ (typeof dataType.multiple=="undefined" || dataType.multiple=="undefined"? false: dataType.multiple) +'" format="'+(typeof dataType.format=="undefined" || dataType.format=="undefined"? false: dataType.format)+'">' + dataType.type + '</dataType>';
														var curChoices =  [];
														if(el.custom.eventData.dictionary!=undefined && el.custom.eventData.dictionary.item!=undefined){
															curChoices = el.custom.eventData.dictionary.item;
														}	
															eventXMLStr += '<dictionary>';
															for (var i = 0; i < curChoices.length; i++) {
																eventXMLStr += '<item label="'+htmlEncode(curChoices[i].key || curChoices[i].label)+'" value="'+htmlEncode(curChoices[i].value)+'"></item>'
																
															};
								                            eventXMLStr += '</dictionary>';
														
														break;
													default:
														eventXMLStr += '<dataType sequence="'+eventSequence+'" width="'+displayWidth+'" min="" max="" placeholder="'+htmlEncode(dataType.placeholder)+'" hinttext="'+htmlEncode(dataType.hinttext)+'">'+dataType.type+'</dataType>';
														break;
												}

												eventXMLStr +=	'<validationRules>'
												if(dataType.rules!=undefined){	
													for (var i = 0; i < dataType.rules.length; i++) {
														var curRule = dataType.rules[i];
														// if rule has details, which are when we assign rule, then use it's title
														var curRuleDetails = curRule['details'];
														// if details are not there which are when we load the xml, as we don't put the updated rules in xml
														var curRuleTitle = typeof curRuleDetails !=='undefined'? curRuleDetails.Title: 
														curRule['title']? curRule['title']: ''
														eventXMLStr += '<rule id="'+replaceSlashes(htmlEncode(curRule.id))+'" title="'+replaceSlashes(htmlEncode(curRuleTitle))+'" >'+
																		'<customMessage>'+replaceSlashes(htmlEncode(curRule.customMessage))+'</customMessage>'+
																			'<parameters>';
																			for (var j = 0; j < curRule.parameters.length; j++) {
																				var currentParam = curRule.parameters[j]
																				eventXMLStr += '<parameter id="'+replaceSlashes(htmlEncode(currentParam.id))+'" required="'+currentParam.required+'" value="'+replaceSlashes(htmlEncode(currentParam.value))+'" title="'+replaceSlashes(htmlEncode(currentParam.title))+'" type="'+currentParam.type+'"></parameter>'
																			};

														eventXMLStr +=		 '</parameters>'+
																		'</rule>';
													};
												}
												eventXMLStr +=	'</validationRules>'
											}
					eventXMLStr +=      	'</eventData>'+
											'<interfaces>';

							if(el.custom.interfaces.length>0){
								el.custom.interfaces.map(function(curItem){
									eventXMLStr += '<interface from="' + curItem.from + '" to="' + curItem.to + '" />';
									return curItem;
								})
							}
					eventXMLStr +=      	'</interfaces>';

					eventXMLStr +=      '</custom>';
						graph.ProcessedEvents.push(el);

										if(generateChilds==true){
											//check if this event has any childs then add them here and remove them from 
					                        el.getDirectChilds().forEach(function (elx) {
					                        	//TODO: don't create child nodes for referred events as form
					                        	//if(elx.parentPro=="root" || (elx.parentPro!=undefined && elx.parentPro!=null && elx.parentPro.isForm()!=true)){
					                        		if(elx.parentPro!="root" && elx.parentPro!=undefined && elx.parentPro!=null && elx.parentPro.isReferForm()==true){
					                        			return;
					                        		}
					                        		eventsToXml(graph, [elx], true, false, false, includeRefer);
					                        	//}
					                        })
					                        	
										}
					                        
						if((el.isRefer == true && includeRefer== true && el.isReferForm()==true)){
            				//have to do this to load xml and then write it to make sure clean XML is passed
            				var curGraph = new DCR();
            				curGraph.loadXML(el.dcrgraph);
            				eventXMLStr += curGraph.writeXML(true);
            			}
					    eventXMLStr +=       '</event>';
					}					
				    
				}else{ /*console.log(el.id+' is Already Processed');*/}
			})
			//return eventXMLStr;
			
		}

		function expressionsToXML (graph, curProcess, gEvents, subProcesses, gMultiInsProcesses) {
			var expressionsXML = '';
			for(var i = 0; i<graph.Connections.length; i++){
				if(storeConnection(graph.Connections[i], curProcess, gEvents, subProcesses, gMultiInsProcesses) == true){
					if(graph.Connections[i].guard!=undefined && graph.Connections[i].guard.length>0){
						expressionsXML += '<expression id="'+graph.Connections[i].from.id+'-path-'+graph.Connections[i].to.id+'--'+graph.Connections[i].type+'" value="'+replaceSlashes(htmlEncode(graph.Connections[i].guard))+'" />'
					}	
					if(graph.Connections[i].type=='update' && graph.Connections[i].valueExpression!=undefined && graph.Connections[i].valueExpression.length>0){
						expressionsXML += '<expression id="'+graph.Connections[i].from.id+'-path-'+graph.Connections[i].to.id+'--'+graph.Connections[i].type+'--value" value="'+replaceSlashes(htmlEncode(graph.Connections[i].valueExpression))+'" />'
					}
				}
			}

			for (var i = 0; i < graph.Events.length; i++) {
				if(graph.Events[i].dmnXML!=undefined && graph.Events[i].dmnXML.trim().length>0){
					expressionsXML += '<expression id="'+graph.Events[i].id+'-computation" value="'+replaceSlashes(htmlEncode(graph.Events[i].computation))+'" type="DMN">';
					expressionsXML += graph.Events[i].prepareDMNXML(graph.Events[i].dmnXML)
					expressionsXML += '</expression>';
				}else if(graph.Events[i].computation!=undefined && graph.Events[i].computation.trim().length>0){
					expressionsXML += '<expression id="'+graph.Events[i].id+'-computation" value="'+replaceSlashes(htmlEncode(graph.Events[i].computation))+'" />'
				}

				var rExpression = graph.Events[i].getResourceExpression('value');
				if(rExpression !=null && rExpression.trim().length>0){
					expressionsXML += '<expression id="'+graph.Events[i].id+'-resource" value="'+replaceSlashes(htmlEncode(rExpression))+'" />'
				}
			}

			return expressionsXML;
		}

		function variablesToXML (graph, isSimVars) {
			var variablesXML = '';
			var itemsToWrite = [];

			for(var i = 0; i<graph.Parameters.length; i++){
				itemsToWrite.push(JSON.parse(JSON.stringify(graph.Parameters[i])))
			}
			if(isSimVars==true){
				for (var i = 0; i < graph.GlobalStore.length; i++) {
					var index = checkForMatch(itemsToWrite, 'title', graph.GlobalStore[i].id);
					// check/update only parameters value
					if(index>=0 && itemsToWrite[index].type == graph.GlobalStore[i].type){
						itemsToWrite[index].value = replaceSlashes(htmlEncode(graph.GlobalStore[i].value))
					}
				};

				/*  add event Default Values to GlobalStore
					add the type of item as type of activity datatype sent by globalstore
					only have dafault value for datatype events */
				var eventsWithDefaults = graph.Events.filter(function (activity) {
					return typeof activity.defaultValue == 'object' && activity.defaultValue !=null && activity.defaultValue.value.trim().length> 0 && activity.canHaveDefaultValue()
				}).map(function (activity) {
					return { title: activity.id, value: replaceSlashes(htmlEncode(activity.defaultValue.value)), type: activity.defaultValue.type, isNull: activity.defaultValue.isNull }
				})

				itemsToWrite = itemsToWrite.concat(eventsWithDefaults)
			}
				
			for (var i = 0; i < itemsToWrite.length; i++) {
				var id = itemsToWrite[i].title, value = itemsToWrite[i].value, isNull = '';
				if(itemsToWrite[i].isNull==undefined){ //they are parameters
					id = replaceSlashes(htmlEncode(itemsToWrite[i].title));
					if(isSimVars==true){
						value = replaceSlashes(htmlEncode(itemsToWrite[i].svalue))
					}else{
						value = replaceSlashes(htmlEncode(itemsToWrite[i].value))
					}
				}else{
					isNull = 'isNull="'+itemsToWrite[i].isNull+'" type="'+itemsToWrite[i].type+'"';
				}
				variablesXML += '<variable id="'+id+'" value="'+value+'" '+isNull+'/>'
			};
			return variablesXML;
		}

		function getMakringItemXML(runtime, events) {

			var xml = '<'+runtime+'>';

			for (var i = 0; i < events.length; i++) {
				var attrs = ''
				for(attr in events[i]){
                //attrs += attr + '="' + events[i][attr] + '" '
                attrs += attr + '="' + replaceSlashes(htmlEncode(events[i][attr])) + '" '
				}
				xml += '<event '+attrs+' />'
			}
			return xml += '</'+runtime+'>';
		}

		function generateGlobalMarkings(graph) {

			var xml = '<globalMarking>',
				markings = graph.GlobalMarking;

			var items = ['enabled', 'enabledSubprocesses', 'executed', 'pending', 'included']

			for (var i = 0; i < items.length; i++) {
				if(markings[items[i]] && markings[items[i]].event){
					if(markings[items[i]].event.constructor === Object){
						xml += getMakringItemXML(items[i], [markings[items[i]].event])
					}else{
						xml += getMakringItemXML(items[i], markings[items[i]].event)
					}
				}
				
			}

			return xml += '</globalMarking>';
		}

	    //function to write the appropriate xml markup of the objects available on canvas
		function generateXML (graph, gEvents, curProcess, subProcesses, multiInsProcesses, includeRefer){
			console.info('generating XML')

			var graphAttrs = '';
			var attrs = {
				title : htmlEncode(graph.Title),
				dataTypesStatus : graph.DataTypesStatus,
				filterLevel : graph.FilterLevel,
				insightFilter : graph.InsightFilter,
				zoomLevel : graph.ZoomLevel,
				formGroupStyle : graph.FormGroupStyle,
				formLayoutStyle : graph.FormLayoutStyle,
				graphBG : graph.BG,
				graphType : graph.Type,
				exercise : graph.Exercise
			}

			if(graph.Type == '1'){
				// if it is a form only then add these properties
				attrs.sendText = replaceSlashes(htmlEncode(graph.SendText)),
				attrs.cancelText = replaceSlashes(htmlEncode(graph.CancelText)),
				attrs.hideCancel = graph.HideCancel
				attrs.formShowInitialPhase = parseInt(graph.FormShowInitialPhase)
			}

			for(attr in attrs){
				graphAttrs += attr+'="'+attrs[attr]+'" ';
			}

			//xml main container start //DCRTitle
            var outputXML = '<dcrgraph '+ graphAttrs +'>'+
							    '<specification>'+
							        '<resources>'+
							        	'<events>';



			//prepare events
			//resetting the event xml string and proccessed event array;
			eventXMLStr ='', graph.ProcessedEvents = [];
			var rootEvents = [];

			if(curProcess==undefined){
				gEvents.forEach(function(el){
					if(el.currentLevel()==0){
						rootEvents.push(el)
					}
				});
				eventsToXml (graph, rootEvents, true, false, false, includeRefer);
			}else{
				gEvents.forEach(function(el){
					var elParentLevel = -5;
					//if parent element exists then
					if(el.getParentProcess()!=undefined){
						elParentLevel = el.getParentProcess().currentLevel()
					}
					//if this event is in subprocess and the its parents nLevel + 1 is = to this nLevel this means this is root element to subProcess
					if(el.currentLevel()==parseInt(elParentLevel+1)){
						rootEvents.push(el)
					}
				});
				eventsToXml (graph, rootEvents, true, false, false, includeRefer);
			}
			


			outputXML += eventXMLStr;







			

			outputXML += '</events>'+
						  '<subProcesses>';

						  //check if this graph has any sub process then add them here and remove them from 

		                    if(subProcesses.length>0){
		                    	for(var i=0; i<subProcesses.length; i++){
		                    		if($.inArray(subProcesses[i], graph.ProcessedProcesses) === -1){

		                    			//get all the events of the graph neglecting sub process and events inside that process


		                    			//getting all the child of the this process
		                    			var arrCurProChilds = [];
		                    			var arrCurProSubPros = [];

										subProcesses[i].getChilds(true, true).forEach(function (el) {
		                    				if(el.baseType=='process'){
		                    					arrCurProSubPros.push(el);
		                    				}else{
		                    					arrCurProChilds.push(el);
		                    				}
											
										});

		                    			graph.ProcessedProcesses.push(subProcesses[i]);

		                    			//outputXML += '<subProcess id="'+subProcesses[i].data('eventid')+'">';
		                    			eventXMLStr ='';
		                    			eventsToXml(graph, [subProcesses[i]],false, true, false, includeRefer);
		                    			outputXML += eventXMLStr;


		                    			//if we want to export referred graph xml then need its childs
		                    			//or if if is not referred and referred XML is not required then just make XML
		                    			if((subProcesses[i].isRefer == true && includeRefer== true)){
		                    				//have to do this to load xml and then write it to make sure clean XML is passed
		                    				var curGraph = new DCR();
		                    				curGraph.loadXML(subProcesses[i].dcrgraph);
		                    				outputXML += curGraph.writeXML(true);
		                    			}else if(subProcesses[i].isRefer != true){
		                    				outputXML += generateXML(graph, arrCurProChilds, subProcesses[i], arrCurProSubPros, multiInsProcesses, includeRefer);
		                    			}else{
		                    				//if process is refer but we don't want its XML then we just send empty
		                    				outputXML += '';
		                    			}

										outputXML += '</subProcess>';
		                    		}
		                    		
								}

		                    }



			outputXML += '</subProcesses>';


			//creating the distribution xml
			outputXML += '<distribution></distribution>';

									





			outputXML += '<labels>';			  
			//prepare labels
			gEvents.forEach(function(el){
				var labelId = el.custom.label;
				if(labelId.trim().length>0){
					outputXML += '<label id="'+replaceSlashes(htmlEncode(labelId))+'" />';
				}	
			});

			outputXML +=  '</labels>';

			//setting up label mappings
			outputXML += labelMappingToXML('labelMapping', gEvents);

			// prepare strong constraints to be processed				  
			graph.Connections.forEach(function(el){
				// for each strong condition create a linked milestone
				// remove any relations which are siblings and don't have leader ( strong relation )
				if(el.isOrphanSibling()) el.remove();
				if(el.isSibling()){ // if is sibling, get the values from strong and apply those here
					var strong = el.hasSibling(true);
					if(strong){ // if has strong
						var props = ['guard', 'time', 'level', 'description', 'groups'];
						props.forEach(function(prop){
							el[prop] = strong[prop]
							if(el.type=='exclude'){
								el['guard'] = strong['guard'].length>0 ? 'not('+ strong['guard'] +')' : 'not(true)';
							}
						})
					}
				}
			})


		    outputXML +=  '<expressions>'+
		    				//expressions in the DCR
		    				expressionsToXML (graph, curProcess, gEvents, subProcesses, multiInsProcesses);

			outputXML +=  '</expressions>'+
							'<variables>'+
								variablesToXML (graph, false);
			
			outputXML +=  '</variables>'+	
						  '<variableAccesses>'+
			                '<writeAccesses />'+
			              '</variableAccesses>'+
			              '<custom>';
			outputXML +=  '<keywords>'+              
							graph.Keywords.join(',')
			outputXML +=  '</keywords>'+
			                '<roles>';

			                //prepare roles in the DCR
			                graph.Roles.forEach(function(el){
			                	outputXML += '<role description="'+replaceSlashes(htmlEncode(el.description))+'" specification="'+replaceSlashes(htmlEncode(el.specification))+'">'+replaceSlashes(htmlEncode(el.title))+'</role>';
			                });

			outputXML +=     '</roles>'+
							'<groups>';
							//prepare Groups in the DCR
			                graph.Groups.forEach(function(el){
			                	outputXML += '<group sequence="'+el.sequence+'"  description="'+replaceSlashes(htmlEncode(el.description))+'">'+replaceSlashes(htmlEncode(el.title))+'</group>';
			                });

			outputXML +=	'</groups>'+
							'<phases>';
							//prepare Groups in the DCR
			                graph.Phases.forEach(function(el){
			                	outputXML += '<phase sequence="'+el.sequence+'"  description="'+replaceSlashes(htmlEncode(el.description))+'">'+replaceSlashes(htmlEncode(el.title))+'</phase>';
			                });

			outputXML +=	'</phases>'+
							'<eventTypes>';
							var eventTypesData = []
							//prepare Groups in the DCR
							graph.EventTypes.forEach(function(el){
		                    	 outputXML += '<eventType description="'+replaceSlashes(htmlEncode(el.description))+'">'+replaceSlashes(htmlEncode(el.title))+'</eventType>';
		                    	 if(el.parameters!=undefined){
								 	eventTypesData.push({id: el.title, parameters: el.parameters})
		                    	 }	
				            });

			outputXML += 	'</eventTypes>'+
							'<eventParameters>';
							for (var j = 0; j < eventTypesData.length; j++) {
								var el = eventTypesData[j]
								for (var i = 0; i < el.parameters.length; i++) {
							 		var curParam = el.parameters[i];
							 		var attrs = 'eventtypeid="'+replaceSlashes(htmlEncode(el.id))+'" title="'+replaceSlashes(htmlEncode(curParam.title))+'" value="'+replaceSlashes(htmlEncode(curParam.value))+'" required="'+curParam.required+'"';
							 		outputXML += '<parameter '+attrs+' />';
							 		//<parameter title="untitled" required="true" value="asd"></parameter>
							 	};
							};
			outputXML += '</eventParameters>'+
							'<graphDetails>';

								var docDescription = replaceSlashes(htmlEncode(graph.Description));
								if(docDescription.length>0){
									outputXML += docDescription;	
								}
			outputXML += 	'</graphDetails>'+
							'<graphDocumentation>';	
							var docDocumentation = replaceSlashes(htmlEncode(graph.Documentation));
							if(docDocumentation.length>0){
								outputXML += docDocumentation;	
							}
			outputXML +=	'</graphDocumentation>'+	
							'<graphLanguage>';
								outputXML += replaceSlashes(htmlEncode(graph.Language));
			outputXML += 	'</graphLanguage>'+
							'<graphDomain>';
								outputXML += replaceSlashes(htmlEncode(graph.Domain));
			outputXML += 	'</graphDomain>'+
							'<graphFilters>'+
							'<filteredGroups>';
							if(graph.FilterGroups.length>0){
								outputXML += graph.FilterGroups.join(',');
							}

			outputXML += 	'</filteredGroups>'+
							'<filteredRoles>';
							if(graph.FilterRoles.length>0){
								outputXML += graph.FilterRoles.join(',');
							}
			outputXML += 	'</filteredRoles>'+
							'<filteredPhases>';
							if(graph.FilterPhases.length>0){
								outputXML += graph.FilterPhases.join(',');
							}
			outputXML += 	'</filteredPhases>'+
						   '</graphFilters>';
			outputXML += 	'<hightlighterMarkup id="HLM">';
						  if(graph.highlighterMarkup){
							outputXML += replaceSlashes(htmlEncode(graph.highlighterMarkup)); //add your code in this section i-e your highligter html/css whatever for now
						  }
			outputXML += 	'</hightlighterMarkup>';
			outputXML += 	'<highlighterMarkup>';
								outputXML += graph.generateHighlightXML() //proper highlighter markup with items to be parsed/generated by DCR library
			outputXML += 	'</highlighterMarkup>'+
						  '</custom>'+
			            '</resources>'+
							  '<constraints>';
			

			//prepare events executed runtime
			outputXML += constraintsToXML(graph, curProcess, 'condition', gEvents);

			//prepare events executed runtime
			outputXML += constraintsToXML(graph, curProcess, 'response', gEvents);
			outputXML += constraintsToXML(graph, curProcess, 'coresponse', gEvents);

			//prepare events executed runtime
			outputXML += constraintsToXML(graph, curProcess, 'exclude', gEvents);

			//prepare events executed runtime
			outputXML += constraintsToXML(graph, curProcess, 'include', gEvents);

			//prepare events executed runtime
			outputXML += constraintsToXML(graph, curProcess, 'milestone', gEvents);	
			
			outputXML += constraintsToXML(graph, curProcess, 'update', gEvents);	

			//writing the multi instance connections on XML
			outputXML += constraintsToXML(graph, curProcess, 'spawn', gEvents, subProcesses, multiInsProcesses);		            

			outputXML +=       '</constraints>'+
						    '</specification>'+
						    '<runtime>'+
						    '<custom>'+
								generateGlobalMarkings(graph);
			if(graph.Time!=null){
				outputXML += '<time current="'+graph.Time+'" deadline="'+graph.DeadLine+'" delay="'+graph.Delay+'" />';
			}					
			outputXML +=      '</custom>'+
						        '<marking>'+
							        '<globalStore>'+
		        						variablesToXML (graph, true)+
		      						'</globalStore>';

			//prepare events executed runtime
			outputXML += runtimesToXML('executed', gEvents);
			//prepare events included runtime
			outputXML += runtimesToXML('included', gEvents);
			//prepare events included runtime
			outputXML += runtimesToXML('pending', gEvents);		

			outputXML += '</marking>'+
						    '</runtime>'+
						'</dcrgraph>';
			//console.log(outputXML);
			//console.log('data converted');
			return outputXML;

		}


	    /** Main function to generate the graph XML based on the data in the graph properties, as this function is called the XML of graph is also updated to latest changes in the graph data
	    *
	    * @memberof Graph
	    * @method writeXML 
	    *
		* @example var myApp = new DCR();
		* myApp.loadGraph(2275);
		* myApp.createEvent({'custom' : {'label':'An Event'}});
		* myApp.writeXML();
		* //we can get the latest XML of the graph through the above command
		* @returns {object} Returns an object of Graph Class.
	    */
	    graphproto.writeXML = function (includeRefer) {
	        //console.log(this.XML);

	        this.AllSharedEvents = [];
			this.ProcessedProcesses = [];
			var subProcesses = [];

	        this.Processes.forEach(function (el) {
				if(el.currentLevel()==0){
					subProcesses.push(el);
				};
			});

			//all sub process childs array
			var arrAllProcessesChilds = [];
			this.Processes.forEach(function (el) {
				if($.inArray(el, arrAllProcessesChilds) === -1){
					el.getChilds(false).forEach(function (elm, indx) {
							arrAllProcessesChilds.push(elm);
					});
					 
				}	
			});

			var arrAllFormEvents = [];
			this.Events.forEach(function (el) {
				if($.inArray(el, arrAllFormEvents) === -1 && el.isRefer==true && el.referId==undefined){
					arrAllFormEvents.push(el); 
				}	
			});



			//getting all the events of the main graph but not the subProcesses and forms
			var mainGraphEvents = [];
			this.Events.forEach(function(el){
				if($.inArray(el, mainGraphEvents) === -1 && $.inArray(el, arrAllProcessesChilds) === -1 && $.inArray(el, arrAllFormEvents) === -1 ){
						 mainGraphEvents.push(el);
					}
			});

			var multiInsProcesses = [];

			for (var i = 0; i < this.Processes.length; i++) {
				if(this.Processes[i].multiInstance == true){
					multiInsProcesses.push(this.Processes[i]);
				}
			};

			var DCRGraphXML = 	generateXML(this, mainGraphEvents, undefined, subProcesses, multiInsProcesses, includeRefer);
			
			//setting up the computed xml as this graphs final xml
			// this.XML = DCRGraphXML;
	  //       return this;
	  		return DCRGraphXML;
	    };

		// TODO: update events to support updateMultiLocated if we need it on write XML

		graphproto.updateMultiLocatedEvents = function (prime) {
			var self = this;
			if(!prime) return

			var propsToCopy = ['baseType', 'commonId', 'computation', 'defaultValue', 'precondition', 'runtimes', 'scope', 'type'];

			self.Events.filter(function (elx) {
				return prime.id === elx.id;
			}).map(function (elx) {

				var currentvisualization = JSON.parse(JSON.stringify(elx.custom.visualization))
				console.log('888888888', elx , currentvisualization)

				// copy custom as it is
				Object.assign(elx.custom, prime.custom)
				
				// copy visualizations
				elx.custom.visualization = currentvisualization
				
				// copy other required properties
				propsToCopy.map(function (prop) {
					elx[prop] = prime[prop]
				})
			})
			
		}
	    
	    /** Fucntion to print current XML of graph on the console
	    *
	    * @memberof Graph
	    * @method printXML 
	    *
		* @example var myApp = new DCR();
		* myApp.loadGraph(2275);
		* myApp.printXML();
		* //we can get the latest XML of the graph through the above command
		* @returns {object} Returns an object of Graph Class.
	    */
	    graphproto.printXML = function () {
	        console.log(this.XML);
	        return this;
		};
		

		/* Highlighter related Functions here */
		//add highlight for a layer in the graph
		function addHighlight(graph, el){
			var res = new Highlight(graph, el);
	        graph.Highlights.push(res);
	        return res;
		}

		/** Add Highlight to graph.
		 * 
		 * @memberof Graph 
	     * @method addHighlight 
		 * 
		 * @returns {Highlight} - An object of `Highlight` class.
		 * 
		 */
	    graphproto.addHighlight = function (el, item) {
			if(!el){el = {}}
			if(item!=undefined) el.items = [item]
			return addHighlight(this, el)
		}

		/** Add Highlight to an Element of graph, e-g: activity, process, form.
		 * 
		 * @memberof Element 
	     * @method addHighlight 
		 * 
		 * @returns {Highlight} - An object of `Highlight` class.
		 * 
		 */
	    elproto.addHighlight = function (el) {
			if(!el){el = {}}
			if(!el.items) el.items = [this]
			return addHighlight(this.graph, el)
		}
		
		/** Add Highlight to Connection of graph.
		 * 
		 * @memberof Connection 
	     * @method addHighlight 
		 * 
		 * @returns {Highlight} - An object of `Highlight` class.
		 * 
		 */
		conproto.addHighlight = function (el) {
			if(!el){el = {}}
			if(!el.items) el.items = [this]
			return addHighlight(this.graph, el)
		}
		
		/** Add Highlight layer to graph.
		 * 
		 * @memberof Graph 
	     * @method addHighlightLayer 
		 * 
		 * @returns {HighlightLayer} - An object of `HighlightLayer` class.
		 * 
		 */
		graphproto.addHighlightLayer = function (el) {
			if(!el){el = {}}
	        var res = new HighlightLayer(this, el);
	        this.HighlightLayers.push(res);
	        return res;
		}
		
		/** Get default Highlight layer of graph, it will add a new layer if graph doesn't have any layer.
		 * 
		 * @memberof Graph 
	     * @method getDefaultHighlightLayer 
		 * 
		 * @returns {HighlightLayer} - An object of `HighlightLayer` class or return undefined.
		 * 
		 */
		graphproto.getDefaultHighlightLayer = function () {
			var res = undefined 
			if(this.HighlightLayers.length<1){
				res = this.addHighlightLayer({default: true, text: this.Description});
			}else{
				res = this.HighlightLayers.find(function (el) {
					return el.default== true;
				})
			}
	        return res;
		}
		
		
		/** Get Highlights related to a Element of graph, e-g: activity, process, form.
		 * 
		 * @memberof Element 
	     * @method getHighlights 
		 * 
		 * @returns {array} - An array of graph Highlights.
		 * 
		 */
		elproto.getHighlights = function(){
			var self = this;
			return this.graph.Highlights.filter(function (el) {
				var hasItem = [];
				if(el.type == "activity"){
					hasItem = el.items.filter(function (elx) {
						return elx!=undefined && elx.getPath() == self.getPath();
					})
				}
				return hasItem.length>0
			})
		}
		
		/** Get Highlights related to a connection of graph.
		 * 
		 * @memberof Connection 
	     * @method getHighlights 
		 * 
		 * @returns {array} - An array of graph Highlights.
		 * 
		 */
		conproto.getHighlights = function(){
			var self = this;
			return this.graph.Highlights.filter(function (el) {
				var hasItem = [];
				if(el.type == "relation"){
					hasItem = el.items.filter(function (elx) {
						return elx!=undefined && elx.getId() == self.getId();
					})
				}
				return hasItem.length>0
			})
		}

		/** Generates Highlight XML.
		 * 
		 * @param {Highlight} highlight - An object of `Highlight` class.
		 * 
		 * @returns {string} -
			<highlight type="activity">
				<layers>
					<layer name="description">
						<ranges>
							<range start="119" end="130">understand</range>
						</ranges>
					</layer>
				</layers>
				<items>
					<item id="Activity1" />
				</items>
			</highlight>
		 */
		function prepareHighlightXML(highlight) {
			return '<highlight type="'+highlight.type+'">'
			+'<layers>'
			+ (highlight.layers.map(function (item) {
				return '<layer name="'+ replaceSlashes(htmlEncode(item.layer.name)) +'">'
							+'<ranges>'
							 + (item.ranges.map(function (range) {
								return '<range start="'+range.start+'" end="'+range.end+'">'+ replaceSlashes(htmlEncode(range.text)) +'</range>'
							}).join(''))	
							+'</ranges>'
				 		+'</layer>'
			}).join(''))
			+'</layers>'
			+'<items>'
			+ (highlight.items.map(function (item) {
				return '<item id="'+highlight.getItemId(item)+'" />'
			}).join(''))
				
			+'</items>'
			+'</highlight>';
		}
		
		
		function prepareHighlightLayerXML(layer) {
			return '<highlightLayer default="'+layer.default+'" name="'+replaceSlashes(htmlEncode(layer.name))+'">'+ (layer.text!=null?replaceSlashes(htmlEncode(layer.text)): '') +'</highlightLayer>';
		}

		/** Generates Highlights XML markup for highlights
		 * 
		 * @memberof Graph 
	     * @method generateHighlightXML 
		 * 
		 * @returns {string} - Highlight markup for DCR containing layers and highlights within it.
		 * 
		 * @example <highlighterMarkup>
						<highlightLayers>
							<highlightLayer default="true" name="description">... highlight text here ...</highlightLayer>
						</highlightLayers>
						<highlights>
							... highlight xml here ...
						</highlights>
					</highlighterMarkup>
		 */
		graphproto.generateHighlightXML = function () {
			var markup = '<highlightLayers>';

			//get all layers and then add highlights based on layers
			markup += this.HighlightLayers.map(function (el) {
				return prepareHighlightLayerXML(el)
			}).join('');

			markup += '</highlightLayers>'
						+'<highlights>';

			markup += this.Highlights.map(function (el) {
				return prepareHighlightXML(el)
			}).join('');

			markup += '</highlights>';

			return markup;
		}

		/** Removes the item from Highlights, if there are no more Items in Highlight then Highlight will also be removed
		 * 
		 * @memberof Graph 
	     * @method removeHighlightsOf 
		 * 
		 * @param {object} item - An object either of Class `Element`, `Connection` or Roles of graph is to be passed.
		 * 
		 */
		graphproto.removeHighlightsOf = function(item){
			removeHighlights(this, item)
		}
		
		/** Get a Highlight in graph by using its GUID.
		 * 
		 * @memberof Graph 
	     * @method getHighlightByGUID 
		 * 
		 * @param {string} id 	- GUID of the highlight to get.
		 * 
		 * @returns {object} 	- Returns Highlight Object, or undefined if no item found.
		 */
		graphproto.getHighlightByGUID = function(id){
			return this.Highlights.find(function (el) {
				return el.guid == id;
			})
		}
		
		//TODO: if any layer is passed then return the text of that layer
		/** Get text of Highlight layer, for now it will return the text of ist default layer found, or graph description if none found.
		 * 
		 * @memberof Graph 
	     * @method getHighlighterText 
		 * 
		 * @param {object} layer 	- HighlightLayer object to get text of, //optional for now as it is to be implemented later with layer full support
		 * 
		 * @returns {string} 		- Returns text of default HighlightLayer or Graph Description
		 */
		graphproto.getHighlighterText = function (layer) {
			var res = this.HighlightLayers.find(function (el) {
				return el.default == true;
			})
			return res!=undefined && res.text!=undefined? res.text: this.Description;
		}
		
		/** Get escaped text of Highlight layer to be used as base text to be embeded in DOM
		 * 
		 * @memberof Graph 
	     * @method getEscapedHighlighterText 
		 * 
		 * 
		 * @returns {string} 		- Returns text of default HighlightLayer or Graph Description
		 */
		graphproto.getEscapedHighlighterText = function() {
			var highlighterText = this.getHighlighterText()
			return typeof highlighterText != 'undefined'? highlighterText.replace(/(?:\r\n|\r|\n)/g, "<br />"): "";
		}
		
		/** Default markup function, createe Highlither HTML Node
		 * 
		 * @param {Highlight} highlight 
		 * @param {Object} item 			// An object either of Class `Element`, `Connection` or Roles of graph is to be passed.
		 * @param {HighlightRange} range 
		 * @param {DOMElement} textContainer 
		 * @param {Window} curWindow 
		 * @param {Document} curDocument 
		 */
		function createHighlighterItem(highlight, item, range, textContainer, curWindow, curDocument) {
			console.log(textContainer); 
			if(!textContainer) return
			if(curWindow==undefined){ curWindow = window}	
			if(curDocument==undefined){ curDocument = document}	
			restoreSelection(textContainer, {start: range.start, end: range.end}, curWindow, curDocument);
			console.log(curWindow)
			try {
				var sel = curWindow.getSelection()
				var r = sel.getRangeAt(0)
				var sc = r.extractContents()
				var span = curDocument.createElement("span");
				span.className = "selected-text-"+ highlight.type;
				span.appendChild(sc);
				r.insertNode(span);
				if(item){
					span.setAttribute("data-item-id", highlight.getItemId(item));
				}
				span.setAttribute("id", range.guid);
				span.setAttribute("data-highlight-id", highlight.guid);

				highlight.attrs.map(function (attr) {
					span.setAttribute(attr.name, attr.value);
				})
				range.hElement = span;
				clearSelection(curWindow, curDocument);
			} catch (error) {
				events.fire("error", {
					message: "Something went wrong with creating Highlighter Item", 
					module: "DCR", 
					fileName: "DCR.js",
					functionName: "createHighlighterItem", 	
					details: error,
					parameters: JSON.stringify({highlight: highlight, item: highlight.getItemId(item), range: {start: range.start, end: range.end}})
				})
			}
			
		}
		
		// gets ranges from layer of highlight and creats html nodes
		function createHighlighterRangeItems(layer, el, elx, textContainer, curWindow, curDocument) {
			if(el.layers && el.layers.length>0){
				// check if item range belongs to current layer
				var curLayer = getLayerInHighlight(el, layer)
				if(curLayer!=undefined){
					// find the layer in el layers and select its ranges only, else skip creating item
					curLayer.ranges.map(function (range) {
						createHighlighterItem(el, elx, range, textContainer, curWindow, curDocument)
					})
				}
			}else{
				throw new Error('no highlight layer found')
			}	
		}

		// TODO: need to handle layers here so only default/selected layer items are marked/created
		/** Prepares the Html required for Highlighter, this HTML can be used anywhere
		 * 
		 * @param {Graph} graph  
		 * @param {DOMElement} textContainer 
		 * @param {Window} curWindow 
		 * @param {Document} curDocument 
		 */

		function prepareMarkupHtml(graph, textContainer, curWindow, curDocument) {
			var layer = graph.getDefaultHighlightLayer();
			if(layer!=undefined){
				graph.Highlights.map(function (el) {
					//TODO: update function to support both items and ranges
					// el.items.length>0?
					// el.items.map(function (elx) {
					// 	createHighlighterRangeItems(layer, el, elx, textContainer, curWindow, curDocument)
					// }) : 
					createHighlighterRangeItems(layer, el, null, textContainer, curWindow, curDocument);
				})
			}else{
				throw new Error('no default highlight layer found')
			}
		}

		function getNode(id, document) {
			return document.getElementById(id)
		}

		/** update markup position as well as the layer text
		 * 
		 * @param {Graph} graph 
		 * @param {DOMElement} textContainer 
		 */
		function updateMarkup(graph, textContainer) {
			var defaultLayer = graph.getDefaultHighlightLayer();
			if(defaultLayer!=undefined){
				var oldMarkup = textContainer.innerHTML;
				var a = prepareMarkup(oldMarkup); 
				var b = generateLayerTextFromMarkup(oldMarkup);
				$(document.body).append([a,b])

				defaultLayer.text = htmlEncode(b[0].textContent)

				/* only update highlights of current default layer, don't update any other highlights as those nodes will not be available.
					1. get highlights of current layer
					2. get ranges from those highlights for current layer
					3. flat the array and update positions for only those ranges in current layer
				*/
				defaultLayer.getHighlights()
					.map(function (item) {
						return item.layers.find(function (layerItem) {
							return layerItem.layer == defaultLayer
						}).ranges;
					})
					.flat()
					.map(function (range) {
						console.log(range)
						range.updatePosition(getUpdatedPosition(getNode(range.guid, document), a[0], window, document))
						clearSelection(window, document);
					})

				a.remove();
				b.remove();
			}else{
				console.error("no highlight layer found")
			}	
		}

		/** Creates the markup required for current app to work with in HTML format, so that app still works as it is
		 * @memberof Graph
		 * @method setupHighlighterMarkup
		 * 
		 * @param {string} textContainerId - Id of the element in which HTML markup is to be generated.
		 */
		graphproto.setupHighlighterMarkup = function (textContainerNode, curWindow, curDocument) {
			prepareMarkupHtml(this, textContainerNode, curWindow, curDocument)
		}

		/** Updates the range postions if the HTML is edited in Highlighter app.
		 * @memberof Graph
		 * @method updateMarkup
		 * 
		 * @param {string} textContainerId - Id of the element in which HTML markup is to be generated.
		 */
		graphproto.updateMarkup = function(textContainerNode) {
			try{
				updateMarkup(this, textContainerNode)
			}catch(ex){
				console.error('Exception' + ex);
				events.fire("exception", 
				{
					message: "update Markup for Highlighter failed",
					module: "DCR",
					fileName: "DCR.js",
					functionName: "updateMarkup",
					logLevel: "Error",
					parameters: '',
					details: ex,
					severity: "High",
				})
			}
			
		}


		/** Default function load Highlights of Graph From Markup
		 * 
		 * @param {Graph} graph 
		 * @param {Object} data 
		 */
		function loadHighlighterMarkup(graph, data) {
			if(data==null) data = ""
			var layers = data.highlightLayers;
			var highlights = data.highlights;
			//setup layers in graph
			if(layers!=undefined && layers.highlightLayer!=undefined){

				if(!Array.isArray(layers.highlightLayer)){
					//if it is not an array then make it an array
					layers.highlightLayer = [layers.highlightLayer];
				}
				//add layers in graph
				layers.highlightLayer.map(function (el) {
					graph.addHighlightLayer({
						name: el.name,
						default: el.default && el.default === "true"? true: false,
						text: el.text
					})
				})	
			}else{
				// if no layers, then add a default layer for graph
				graph.getDefaultHighlightLayer()
			}

			//setup highlights
			if(highlights!=undefined && highlights.highlight!=undefined){

				if(!Array.isArray(highlights.highlight)){
					//if it is not an array then make it an array
					highlights.highlight = [highlights.highlight];
				}
				//add highlights in graph
				highlights.highlight.map(function (el) {
					graph.addHighlight(el)
				})	
			}

		}

		function findHighlightItem(graph, type, id) {
			var item = undefined;
			switch (type) {
				case 'activity':
					item = graph.getById(id);
					break;
				case 'role':
					item = graph.Roles.find(function (el) {
						return el.title === fixSlashes(htmlDecode(id));
					})
					break;
				case 'relation':
					item = graph.Connections.find(function (el) {
						return el.getId() === id;
					})
					break;
				default:
					break;
			}
			if(item==undefined){
				console.warn(id, type + "_-_ITEM_NOT_FOUND")
			}
			return item;
		}

		//https://stackoverflow.com/questions/13949059/persisting-the-changes-of-range-objects-after-selection-in-html/13950376#13950376
		//http://jsfiddle.net/WeWy7/3/
		// var saveSelection, restoreSelection, clearSelection;

		if (window.getSelection && document.createRange) {
			/** Getting start and end position of a selection from a node with in which selection is being made
			 * @function saveSelection
			 * 
			 * @param {object} containerEl - HTML node of the element with in which selection is being made
			 * 
			 * @returns {object} - Returns object with start and end postion of selection
			 */
			saveSelection = function(containerEl, curWindow) {
				if(curWindow==undefined){ curWindow = window}	
				console.log('SAVE SELECTION')
				var start = '', range = '';
				try {
					range = curWindow.getSelection().getRangeAt(0);
					var preSelectionRange = range.cloneRange();
					preSelectionRange.selectNodeContents(containerEl);
					preSelectionRange.setEnd(range.startContainer, range.startOffset);
					start = preSelectionRange.toString().length;
				} catch (error) {
					events.fire("error", {
						message: "Something went wrong with saveSelection", 
						module: "DCR", 
						fileName: "DCR.js",
						functionName: "saveSelection", 	
						details: error
					})
				}
				

				return {
					start: start,
					end: start + range.toString().length
				}
			};

			/** Creates a selection based on start, end postions provided with in a text container
			 * @function restoreSelection
			 * 
			 * @param {object} containerEl - HTML node of the element with in which selection is being made
			 * @param {object} savedSel - An object having start, end postions, e-g:{start: null ,end: null}. `HighlightRange` object can also be used.
			 * 
			 */
			restoreSelection = function(containerEl, savedSel, curWindow, curDocument) {
				console.log('RESTORE SELECTION')
				if(curWindow==undefined){ curWindow = window}	
				if(curDocument==undefined){ curDocument = document}	
				try {
					var charIndex = 0, range = curDocument.createRange();
					range.setStart(containerEl, 0);
					range.collapse(true);
					var nodeStack = [containerEl], node, foundStart = false, stop = false;
					
					while (!stop && (node = nodeStack.pop())) {
						if (node.nodeType == 3) {
							var nextCharIndex = charIndex + node.length;
							if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
								range.setStart(node, savedSel.start - charIndex);
								foundStart = true;
							}
							if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
								range.setEnd(node, savedSel.end - charIndex);
								stop = true;
							}
							charIndex = nextCharIndex;
						} else {
							var i = node.childNodes.length;
							while (i--) {
								nodeStack.push(node.childNodes[i]);
							}
						}
					}

					var sel = curWindow.getSelection();
					sel.removeAllRanges();
					sel.addRange(range);
				} catch (error) {
					events.fire("error", {
						message: "Something went wrong while restoring selections", 
						module: "DCR", 
						functionName: "restoreSelection", 		
						parameters: JSON.stringify({savedSel: savedSel}),
						details: error
					})
				}
				
			}

			/** Clears any selection made in the document.
			 * @function clearSelection
			 */
			clearSelection = function(curWindow, curDocument) {
				if(curWindow==undefined){ curWindow = window}		
				if(curDocument==undefined){ curDocument = document}
				console.log('CLEAR SELECTION')
				try {
					if (curWindow.getSelection) {
						if (curWindow.getSelection().empty) {  // Chrome
							curWindow.getSelection().empty();
						} else if (curWindow.getSelection().removeAllRanges) {  // Firefox
							curWindow.getSelection().removeAllRanges();
						}
					} else if (curDocument.selection) {  // IE?
						curDocument.selection.empty();
					}
				} catch (error) {
					events.fire("error", {
						message: "Something went wrong while clearing selections", 
						module: "DCR", 
						functionName: "clearSelection",
						details: error
					})
				}
			}
		} else if (document.selection && document.body.createTextRange) {
			saveSelection = function(containerEl, curWindow, curDocument) {
				if(curWindow==undefined){ curWindow = window}
				if(curDocument==undefined){ curDocument = document}		
				var selectedTextRange = curDocument.selection.createRange();
				var preSelectionTextRange = curDocument.body.createTextRange();
				preSelectionTextRange.moveToElementText(containerEl);
				preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
				var start = preSelectionTextRange.text.length;

				return {
					start: start,
					end: start + selectedTextRange.text.length
				}
			};

			restoreSelection = function(containerEl, savedSel, curWindow, curDocument) {
				if(curWindow==undefined){ curWindow = window}		
				if(curDocument==undefined){ curDocument = document}
				var textRange = curDocument.body.createTextRange();
				textRange.moveToElementText(containerEl);
				textRange.collapse(true);
				textRange.moveEnd("character", savedSel.end);
				textRange.moveStart("character", savedSel.start);
				textRange.select();
			};
		}
		
		/** Provides the position of Highlight Node in container
		 * @function getUpdatedPosition
		 * 
		 * @param {DOMElement} anode - HTML node of the element with in which selection is being made
		 * @param {DOMElement} textContainer
		 * @param {Window} curWindow 
		 * @param {Document} curDocument
		 */
		getUpdatedPosition = function(anode, textContainer, curWindow, curDocument) {				
			if(curDocument==undefined){ curDocument = document}
			try {
				if(anode){
					var range = new Range();
					range.selectNodeContents(anode); // or selectNode(p) to select the <p> tag too
		
					curDocument.getSelection().removeAllRanges(); // clear existing selection if any
					curDocument.getSelection().addRange(range);
				}else{
					console.error('Node not found to get range', anode);
					events.fire("error", {message: "Node not found to get range", module: "DCR", functionName: "getUpdatedPosition", 		parameters: JSON.stringify({anode: anode, textContainer:textContainer})
					})
				}
			} catch (error) {
				events.fire("error", {
					message: "Something went wrong with getUpdatedPosition", 
					module: "DCR", 
					functionName: "getUpdatedPosition", 		
					parameters: JSON.stringify({anode: anode, textContainer:textContainer}),
					details: error
				})
			}
			return saveSelection(textContainer, curWindow)
		}

		function getItemType(el) {
			// item type are: selected-text-[role, activity, relation] 
			// or later introduced for some duration were: marked-[role, relation, activity]
			// also data-item-type="[relation, role, activity]" was introduced at somepoint
			// it seems some of the graphs still have experimental attributes so need to handle according to that.
			/**
			 * get class list of el, find item type from class list, if still not found try data-item-type
			 * if still no sucess return undefined
			 * types: 'activity', 'role', 'relation', 'suggestion', 'alias', 'comment', 'note'
			 * prefixs = ['selected-text', 'marked']
			 */
			var types = ['activity', 'role', 'relation', 'alias', 'comment'];
			var itemTypeFromAttr = el.getAttribute('data-item-type');
			var itemType = el.classList.value.split(" ").map(function(cItem){
				var splitted = cItem.split("-")
				return splitted[splitted.length-1]
			}).filter(function (item) {
				// filter through all classes and find which has types in it and use that class to determine type by comparing list with types list
				return types.find(function(cItem){
					return cItem == item
				 })
			});
			itemType = itemType.length>0? itemType[0]: null;
			if(itemType==undefined || itemType=="undefined" || typeof itemType == "undefined"){
				console.log("itemType", itemType, " FOR ", el)
			}
			// if still no item type based on class, then try attribute
			if(el.getAttribute('data-item-type')!==null && itemType==null){
				itemType = types.find(function(cItem){
					return cItem == itemTypeFromAttr
				 })
			}
			//if all fails try to analyze the id and if id is base on relation pattern then setType as relation, try to split it
			var elId = el.getAttribute('data-item-id');
			if(elId!=null && (itemType==null || typeof itemType == "undefined") && elId.split("--").length>2){
				itemType = "relation"
				console.log("settingType", itemType, " FOR ", elId)
			}
			return typeof itemType == "undefined"? null: itemType;
		}
		/** Converts Old HTML Element for Highlights to New Highlighter Item
		 * 
		 * @param {DOMElement} el 
		 * @param {DOMElement} textContainer 
		 */
		function getOldHighlightDetails(el, textContainer){
			var positions = getUpdatedPosition(el, textContainer);
			if(el.classList.length>0){
				var itemType = getItemType(el);
			return {
						type: itemType!=null && itemType!=""? itemType: 'none',
				items: {
					item: [{id: el.getAttribute("data-item-id")}]
				},
				layers:{
					layer: [{
							name: "description",
							ranges: {
								range: [{
									start: positions.start,
									end: positions.end,
									text: el.textContent
								}]
							}
						}]
				}
			}
			}
			return null	
		}


		/** Main function to upgrade the Highlighter Old markup to new structure
		 * 
		 * innerText resolves the new lines but messes up the ranges so we do following:
		 * 
		 * we use textContent, ist we replace any line break still missing br and add br for it and store it in a div from where we shall get the ranges
		 * oldMarkup.replace(/(?:\r\n|\r|\n)/g, "<br />") //to replace any new lines in to <br /> as current markup is inconsistent and maynot have have <br /> on each line break;
		 * 
		 * in ist part if we replace the br with \n then we loose the linebreaks in textContent so we ist replace the br with \n and then add a new div with \n text to get the actual text with linebreaks,
		 * baseText.replace(/<br\s*[\/]?>/g, "\n")
		 * 
		 * we pass the textContent to layer and find ranges on baseText
		 * why we use textContent: https://stackoverflow.com/questions/35213147/difference-between-textcontent-vs-innertext
		 */
		function upgradeHighlighterMarkup(graph, oldMarkup) {
			var a = prepareMarkup(oldMarkup); 
			var b = generateLayerTextFromMarkup(oldMarkup);
			$(document.body).append([a,b])
			//lets create a new layer ist, 
			var data = {
				highlightLayers : {
					highlightLayer: [{name:"description", default: "true", text: b[0].textContent}]
				},
				highlights: {
					highlight: []
				}
			}

			//find the possible items and prepare their data
			$(a).find('span').each(function(i, el){
				var item = getOldHighlightDetails(el, a[0]);
				if(item!=null){
					data.highlights.highlight.push(item)
				}
				console.log("getOldHighlightDetails:", item)
			})
			//remove the extra div created
			a.remove();
			b.remove();
			return data;
		}

		function prepareMarkup(oldMarkup) {
			var baseText = oldMarkup.replace(/(?:\r\n|\r|\n)/g, "<br>");
			//we place the html with br to get the indexes
			return $('<div id="tempUpgradeHolder"/>').html(baseText).css({'opacity': 0})
		}

		function generateLayerTextFromMarkup(oldMarkup) {
			var baseText = oldMarkup.replace(/(?:\r\n|\r|\n)/g, "<br>");
			//we place the html in another div to get the textContent with linebreaks
			return $('<div id="tempUpgradeHolderTextOnly"/>').html(baseText.replace(/<br\s*[\/]?>/g, "\n")).css({'opacity': 0})
		}



	    if(typeof String.prototype.trim !== 'function') {
		  String.prototype.trim = function() {
		    return this.replace(/^\s+|\s+$/g, ''); 
		  }
		}



		$.fn.outerHTML = function(){
 
		    // IE, Chrome & Safari will comply with the non-standard outerHTML, all others (FF) will have a fall-back for cloning
		    return (!this.length) ? this : (this[0].outerHTML || (
		      function(el){
		          var div = document.createElement('div');
		          div.appendChild(el.cloneNode(true));
		          var contents = div.innerHTML;
		          div = null;
		          return contents;
		    })(this[0]));
		 
		}

	    //setting DCR as global to be used
        window.DCR = D;
        return D;
    }
));