//#######################################################################################################
//###   CREATED WITHIN THE DIPLOMA THESIS <Default Inheritance for OWL-S, 2007> by Simon Ferndriger   ###
//#######################################################################################################


/* *****************************************************************/
/* LOGIC ***********************************************************/


/*
	1. VIS [Visualize Service]
		1.1 [VIS] Produce ProcessTree
		
	2. CNS [Create New SubService]
		2.1 [CNS] Check New Service URI
		2.2 [CNS] Select SuperService
	
	3. VAS [Validate SubService]
		3.1 [VAS] Validate SubService
		
	4. DIS [Discover Service Subsitutes]
		4.1 [DIS] LIST Service Substitutes
		4.2 [DIS] Find Service Substitutes

	A. All TASKS
		A.0 Groundings
		A.1 Process type
		A.2 Service Model
		A.3 Interpret Inheritance Profile
			A.3.1 Get Inheritance Profile
				A.3.1.1 Get Inheritance Profile (Helper)
			A.3.2 Perform Inheritance Profile
			A.3.3 Lookup Inheritance Profile By Service URI
		A.4 Composite Process
			A.4.1 Recursive Lookup of Composite Process
			A.4.2 Recursive Lookup of Composite Process Sets
		A.5 DATA Types
			A.5.1 Check if arg1 is a sub datatype of arg2
*/

//////////////////////////////////////////////////////////////////////////////////////////
// 1. VIS [Visualize Service]
//////////////////////////////////////////////////////////////////////////////////////////


/* ######################################################################### */
// 1.1 [VIS] Produce ProcessTree
/* ######################################################################### */
function PRODUCE_ProcessTree(Service_URI) {
	
	CLEAR('VIS', 'ProcessTree');
	
	/* Error handling~~~~~~~~~~*/
	if(!Service_URI) {
		error_log('No Service URI provided.');
		return;
	}
	if(!getDOM(getURLfromURI(Service_URI))) {
		error_log('URI does not point to an online document.');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	log('Service identified: ' + Service_URI);


	// Interpret InheritanceProfile............................................
	InterpretIHP(Service_URI);
	

	// Lookup Service Model....................................................
	var ServiceModel_URI = ServiceModel(Service_URI);


	// Lookup process type.....................................................
	var type = ProcessType(ServiceModel_URI);

	/* Error handling~~~~~~~~~~*/
	if(!type)
		return;
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/


	// Lookup CompositeProcess composition.....................................
	if(type == 'CompositeProcess')
		lookup_CompositeProcess(CONSTRUCT_Component(ServiceModel_URI));


	// VISUAL ----------------------------------------------------------------/
	CREATE_VIS_ProcessTree(ServiceModel_URI);
}


//////////////////////////////////////////////////////////////////////////////////////////
// 2. CNS[Create New SubService]
//////////////////////////////////////////////////////////////////////////////////////////

/* ######################################################################### */
// 2.1 [CNS] Check New Service URI - Cannot exist already
/* ######################################################################### */
function CHECK_NewServiceURI(URI) {
	CLEAR('CNS', 'SuperService');

	/* Error handling~~~~~~~~~~*/
	if(!URI) {
		log('[WARNING] No URI given.');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	// Check whether a name has been given
	var id = getIDfromURI(URI);
	if(!id) {
		alert("Please provide a service name");
		return;
	}
	
	// Check whether an URL has been given
	var url = getURLfromURI(URI);
	if(!url) {
		alert("Please provide an ontology URL");
		return;
	}
	
	// Check whether ontology already exists or not
	log('Checking if URL already exists...');
	log('Looking up: ' + url);
	
	if(URL_exists(url)) {
		alert('Please choose a different name, ontology does already exist.');
		return;
	}

	log('[OK] Ontology does not yet exist.');
	INIT('CNS', 'SuperService');
	FINALIZE_CNS('ServiceName');
}

/* ######################################################################### */
// 2.2 [CNS] Select SuperService
/* ######################################################################### */
function select_SuperService(superserviceURI, mode) {
	
	/* Error handling~~~~~~~~~~*/
	if(!validURI(superserviceURI)) {
		error_log('SuperService ontology URI is not valid. Please try another URI.');
		return;
	}
	
	if(!getDOM(getURLfromURI(superserviceURI))) {
		error_log('SuperService cannot be found online.');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	log('SuperService selected: ' + superserviceURI);
	log('Modus: ' + mode);

	// Interpret InheritanceProfile............................................
	InterpretIHP(superserviceURI);
	
	// Prepare IR Modeling....................................................
	
	/* Lookup ServiceModel */
	var ServiceModel_URI = ServiceModel(superserviceURI);
	
	/* Lookup CompositeProcess composition */
	if(ProcessType(ServiceModel_URI) == 'CompositeProcess')
		lookup_CompositeProcess(CONSTRUCT_Component(ServiceModel_URI));
		
	// VISUAL ----------------------------------------------------------------/
	CREATE_CNS_MIR_Process_DropDown(CONSTRUCT_Component(ServiceModel_URI), 'adoptServiceModel', true);
	INIT('CNS', 'ModelingIR');
	FINALIZE_CNS('SuperService');
}


/* ######################################################################### */
// 2.3 [CNS] Save New Service
/* ######################################################################### */
function save_NewService(newIHP) {
	
	
	log('Saving Inheritance Profile..');
	rootDOM = getDOM(_FIX_storage_path + 'template');
	
	// Adjust namespace......................................................
	rootDOM.setAttribute('xmlns', getNSfromURI(newIHP['ServiceURI']));
	rootDOM.setAttribute('xml:base', getURLfromURI(newIHP['ServiceURI']));
	
	// Add imports...........................................................
	var existingOntologyNodes = rootDOM.getElementsByTagNameNS(_owl, 'Ontology');
	OWL_CreateProperty(existingOntologyNodes[0], _owl, 'imports', getURLfromURI(newIHP['SuperService']));
	
	// Create New Service.....................................................
	var newServiceNode = OWL_CreateElement(rootDOM, _service, 'Service', newIHP['ServiceURI']);
	OWL_CreateProperty(newServiceNode, _service, 'presents', '#InheritanceProfile');
	
	// Create New Inheritance Profile.........................................
	var newInheritanceProfileNode = OWL_CreateElement(rootDOM, _ihp, 'InheritanceProfile', '#InheritanceProfile');
	OWL_CreateProperty(newInheritanceProfileNode, _ihp, 'contains', '#SuperService');
	
	// Create New SuperService................................................
	var newInheritanceProfileNode = OWL_CreateElement(rootDOM, _ihp, 'SuperService', '#SuperService');
	OWL_CreateProperty(newInheritanceProfileNode, _ihp, 'hasSource', newIHP['SuperService']);
	OWL_CreateProperty(newInheritanceProfileNode, _ihp, 'fromType', _ihp + newIHP['Type']);
	OWL_CreateProperty(newInheritanceProfileNode, _ihp, 'specifiedBy', '#Specification');
	
	// Create New Specification................................................
	var newSpecificationNode = OWL_CreateElement(rootDOM, _ihp, 'Specification', '#Specification');
	OWL_CreateProperty(newSpecificationNode, _ihp, 'adoptServiceModel', newIHP['adoptServiceModel']);
	OWL_CreateDataTypeProperty(newSpecificationNode, _ihp, 'leaveOutGroundings', newIHP['leaveOutGroundings'], _xsd + 'boolean');

	/* Write the alterings */
	var newAlteringNodes = new Array();
	
	// Renamings...............................................................
	for(var i=0; newIHP['Renamings'][i]; i++) {
		
		var curAlteringProperty = OWL_CreateProperty(newSpecificationNode, _ihp, 'containsAltering');
		
		/* Create New Renaming */
		newAlteringNodes[i] = OWL_CreateElement(curAlteringProperty, _ihp, 'Renaming');
		OWL_CreateDataTypeProperty(newAlteringNodes[i], _ihp, 'oldID',  newIHP['Renamings'][i]['oldID'], _xsd + 'string');
		OWL_CreateDataTypeProperty(newAlteringNodes[i], _ihp, 'newID',  newIHP['Renamings'][i]['newID'], _xsd + 'string');
	}
	
	// All Alterings............................................................
	for(var i=0; newIHP['Alterings'][i]; i++) {
		
		var curAlteringProperty = OWL_CreateProperty(newSpecificationNode, _ihp, 'containsAltering');
		
		log('Creating ' + newIHP['Alterings'][i]['type']);
		switch(newIHP['Alterings'][i]['type']) {
			
			case 'ProcessReplacement':
			
				/* Create New ProcessReplacement */
				newAlteringNodes[i] = OWL_CreateElement(curAlteringProperty, _ihp, 'ProcessReplacement');
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'withProcess', newIHP['Alterings'][i]['withProcess']);
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'replaceProcess', newIHP['Alterings'][i]['replaceProcess']);
				
				/* No new process needs to be created */
				if(!newIHP['Alterings'][i]['createNewService'])
					break;
				
				log('Creating new process...');
				OWL_CreateElement(rootDOM, _process, 'AtomicProcess', newIHP['Alterings'][i]['replaceProcess']);
				
				/* Normal break */
				break;
			
			case 'ConditionReplacement':
			
				/* Create New ConditionReplacement */
				newAlteringNodes[i] = OWL_CreateElement(curAlteringProperty, _ihp, 'ConditionReplacement');
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'replaceCondition', newIHP['Alterings'][i]['replaceCondition']);
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'withCondition', newIHP['Alterings'][i]['withCondition']);
				
				/* Normal break */
				break;
			
			case 'ResultReplacement':
			
				/* Create New ResultReplacement */
				newAlteringNodes[i] = OWL_CreateElement(curAlteringProperty, _ihp, 'ResultReplacement');
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'replaceResult', newIHP['Alterings'][i]['replaceResult']);
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'withResult', newIHP['Alterings'][i]['withResult']);
				
				/* Normal break */
				break;
			
			case 'InputOrOutputDeletion':
			
				/* Create New InputOrOutputDeletion */
				newAlteringNodes[i] = OWL_CreateElement(curAlteringProperty, _ihp, 'InputOrOutputDeletion');
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'fromAtomicProcess', newIHP['Alterings'][i]['fromAtomicProcess']);
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'deleteIO', newIHP['Alterings'][i]['deleteIO']);
				
				/* Normal break */
				break;
			
			case 'InputOrOutputInsertion':
			
				/* Create New InputOrOutputDeletion */
				newAlteringNodes[i] = OWL_CreateElement(curAlteringProperty, _ihp, 'InputOrOutputInsertion');
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'forAtomicProcess', newIHP['Alterings'][i]['forAtomicProcess']);
				OWL_CreateProperty(newAlteringNodes[i], _ihp, 'addIO', newIHP['Alterings'][i]['addIO']);
				
				/* Normal break */
				break;
			
			default:
				error_log('Not implemented yet');
		}
	}
	
	
	// Save Service Model........................................................
	log('Saving Service Model...');
	var url = getURLfromURI(newIHP['ServiceURI']);
	var filename = getFileNameByURL(url);
	saveXML(getSerializedDOM(rootDOM), filename);
	log('...done.');
	
	// VISUAL ----------------------------------------------------------------/
	CLEAR('CNS', 'ModelingIR');
	INIT('CNS', 'SubserviceCreated', newIHP['leaveOutGroundings']);
}


//////////////////////////////////////////////////////////////////////////////////////////
// 3. VAS [Validate SubService]
//////////////////////////////////////////////////////////////////////////////////////////

/* ######################################################################### */
// 3.1 [VAS] Validate SubService
/* ######################################################################### */
function VAS_validateSubService(SubService_URI) {

	CLEAR('VAS', 'Result');

	/* Error handling~~~~~~~~~~*/
	if(!validURI(SubService_URI)) {
		error_log('No valid URI provided.');
		return false;
	}
	if(!URL_exists(getURLfromURI(SubService_URI))) {
		error_log('URI is not online.');
		return false;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	log('Validating: ' + SubService_URI);


	// VISUAL --------------------------/
	INIT('VAS', 'Result');
	
	
	// ........................................................................
	// Check taxonomy
	
	/* Check */
	log('Checking taxonomy');
	var taxonomyCheck = AJAX_checkTaxonomy(SubService_URI);
	var hasClassifiedTaxonomy = false;
	
	switch(taxonomyCheck) {
		
		case 'OK':
			hasClassifiedTaxonomy = true;
			break;
			
		case 'NOK':
			break;

		default:
			log(taxonomyCheck);
	}
	
	// VISUAL ---------------------------/
	ADD_ResultLine('VAS', new Array('The Service ontology is consistent', '[WARNING] The Service ontology might be inconsistent'), hasClassifiedTaxonomy, true);// true = clear lines
	
	/* Do NOT Stop */
	if(!hasClassifiedTaxonomy);
		
	// ........................................................................
	// Check whether URI is a Service
	
	log('Checking Service');
	/* Construct Point */
	var Point = new Object();
	Point['type'] = 'URI';
	Point['URI'] = SubService_URI;
	
	/* Check type */
	var isService = OWL_checkElementTypeForPoint(Point, _service, 'Service');
	
	// VISUAL ---------------------------/
	ADD_ResultLine('VAS', new Array('Is an OWL-S Service', 'Is NOT an OWL-S Service'), isService);
	
	/* Stop */
	if(!isService)
		return false;


	// ........................................................................
	// Check whether Service has an Inhertiance Profile
	
	log('Checking Inheritance Profile');
	
	/* Create Service Point */
	var servicePoint = Point;
	servicePoint['matchTypes'] = new Array(_service + 'Service');
	servicePoint['inverseMatchTypes'] = new Array(_ihp + 'InheritanceProfile');

	/* Get Service Profiles */
	var profiles = OWL_getObjectsByProperty(servicePoint, _service, 'presents') ||
		OWL_getSubjectArrayByProperty(_service, 'presentedBy', servicePoint);

	var IHP = false;
	if(profiles)
		IHP = getInheritanceProfile(profiles, servicePoint['URI']);
	
	// VISUAL ---------------------------/
	ADD_ResultLine('VAS', new Array('Has an Inheritance Profile', 'DOES NOT HAVE an Inheritance Profile'), IHP);
	
	/* Stop */
	if(!IHP)
		return false;

	// ........................................................................
	// Check inherit options
	
	log('Checking Inheritance Profile options');
	
	var hasCorrectGroundingsReuse = true;
	
	if(!IHP['leaveOutGroundings']) {
		
		for(var i=0; IHP['Alterings'][i]; i++)
			if(_WebServiceManipulation.indexOf(IHP['Alterings'][i]['type']) != -1)
				hasCorrectGroundingsReuse = false;
		
		// VISUAL ---------------------------/
		ADD_ResultLine('VAS', new Array('Is allowed to reuse SuperService Groundings', 'IS NOT ALLOWED to reuse Groundings (Web Service Manipulation)'), hasCorrectGroundingsReuse);
	}
	
	/* Stop */
	if(!hasCorrectGroundingsReuse)
		return false;
		
	
	// ........................................................................
	// Check Relationship Type (only single inheritance implented yet)
	log('Checking Relationship type');
	
	ADD_ResultLine('VAS', new Array('Relationship type: ' + IHP['Type']), true);

	if(IHP['Type'] == 'strictOriginal' || IHP['Type'] == 'strictSubstitute') {
		
		/* ServiceModel must be the same if strict inheritance is used */
		if(!IHP['adoptedServiceModel']['URI'] || ServiceModel(IHP['SuperService']['URI']) != IHP['adoptedServiceModel']['URI']) {
	
			// VISUAL ---------------------------/
			ADD_ResultLine('VAS', new Array('', 'Adopted Service Model IS NOT the SuperService Model'), false);
			return false;
		}
		
		/* There are some alterings which are not allowed if strict inheritance is used*/
		for(var i=0; IHP['Alterings'][i]; i++) {
		
			// Not allowed alterings for strict inheritance
			var notAllowed = _WebServiceExtension;
			notAllowed.push('InputOrOutputDeletion');
			notAllowed.push('InputOrOutputInsertion');
			
			// Check
			if(notAllowed.indexOf(IHP['Alterings'][i]['type']) != -1) {
				
				// VISUAL ---------------------------/
				ADD_ResultLine('VAS', new Array('', 'HAS UNALLOWED Relationship Altering: ' + IHP['Alterings'][i]['type']), false);
				return false;
			}
		}

		// VISUAL ---------------------------/
		ADD_ResultLine('VAS', new Array('Adopted Service Model is the SuperService Model'), true);
	}
	
	
	// ........................................................................
	// Check Alterings[]
	log('Checking Alterings');
	var isValid = true;
	
	for(var i=0; IHP['Alterings'][i]; i++) {
		
		log('Checking ' + IHP['Alterings'][i]['type']);
		var isValid = true;
		
		// VISUAL ---------------------------/
		ADD_ResultDetailBlock('VAS', (i+1));
		
		switch(IHP['Alterings'][i]['type']) {
			
			case 'ProcessReplacement':
			
				/**********************************************************
					Check SuperService Type:
					
					Cannot be strictSubstitute, because the SubService
					would have the conflict of having a specialized
					service with (generalized) process replacements.
					
					Process replcaements mean always being a
					generalization: in order to be able to guarantee
					the process flow after the replacement.
					
				***********************************************************/
				if(IHP['Type'] == 'strictSubstitute') {
					
					// VISUAL ---------------------------/
					ADD_ResultLine('VAS', 'UNALLOWED Relationship Type. <StrictSubstitute> CANNOT have process replacements.' , false);
					
					// Invalid
					isValid = false;
					break;//Force break
				}
				
			
				/***********************************************************
				
					Check INPUTs and OUTPUTs
					
				************************************************************/
				log('Checking Process Replacement');
				
				// Original process..........................................
				var origProcPerfPoint = IHP['Alterings'][i]['withProcess'];
				origProcPerfPoint['matchTypes'] = new Array(_process + 'Perform');
				
				var origProcPoints = OWL_getObjectsByProperty(origProcPerfPoint, _process, 'process');
				origProcPoints[0]['matchTypes'] = new Array(_process + 'CompositeProcess', _process + 'AtomicProcess');

				var origInputPoints = OWL_getObjectsByProperty(origProcPoints[0], _process, 'hasInput');
					if(origInputPoints)
					for(var j=0; origInputPoints[j]; j++)
						origInputPoints[j]['matchTypes'] = new Array(_process + 'Input');
				
				var origOutputPoints = OWL_getObjectsByProperty(origProcPoints[0], _process, 'hasOutput');
				if(origOutputPoints)
					for(var j=0; origOutputPoints[j]; j++)
						origOutputPoints[j]['matchTypes'] = new Array(_process + 'Output');
				
				
				// Replacement process........................................
				var replProcPoint = IHP['Alterings'][i]['replaceProcess'];
				replProcPoint['matchTypes'] = new Array(_process + 'CompositeProcess', _process + 'AtomicProcess');

				var replInputPoints = OWL_getObjectsByProperty(replProcPoint, _process, 'hasInput');
				if(replInputPoints)
					for(var j=0; replInputPoints[j]; j++)
						replInputPoints[0]['matchTypes'] = new Array(_process + 'Input');
				
				var replOutputPoints = OWL_getObjectsByProperty(replProcPoint, _process, 'hasOutput');
				if(replOutputPoints)
					for(var j=0; replOutputPoints[j]; j++)
						replOutputPoints[0]['matchTypes'] = new Array(_process + 'Output');
				

				// Compare numbering.......................................................
				
				/* Inputs number */
				if(origInputPoints.length != replInputPoints.length)
					isValid = false;
				
				// VISUAL ---------------------------/
				ADD_ResultDetailLine('VAS', 'Same number of inputs: ' + (origInputPoints.length == replInputPoints.length), (i+1));
				
				/* Outputs number */
				if(origOutputPoints.length != replOutputPoints.length)
					isValid = false;
					
				// VISUAL ---------------------------/
				ADD_ResultDetailLine('VAS', 'Same number of outputs: ' + (origOutputPoints.length == replOutputPoints.length), (i+1));
				
				
				// Compare matching.........................................................

				/* Inputs compatibility ***********************************************/
				var replInputIDs = new Array();
				for(var j=0; replInputPoints[j]; j++)
					replInputIDs.push(getIDfromURI(getURIbyPoint(replInputPoints[j])));
				
				for(var j=0; origInputPoints[j]; j++) {

					var curOrigURI = getURIbyPoint(origInputPoints[j]);
					var curOrigID = getIDfromURI(curOrigURI);
					var curValid = false;
					
					var curIndex = replInputIDs.indexOf(curOrigID);
					
					/***********************************************************
						ID must be the same for replacement and original
						in order to identify inputs with equal types.
					************************************************************/
					if(curIndex != -1) {
						
						// Find out input types........................
						origInputPoints[j]['matchTypes'] = new Array(_process + 'Input');
						var origParamTypes = OWL_getDataTypeObjectByProperty(origInputPoints[j], _process, 'parameterType');
						
						replInputPoints[curIndex]['matchTypes'] = new Array(_process + 'Input');
						var replParamTypes = OWL_getDataTypeObjectByProperty(replInputPoints[curIndex], _process, 'parameterType');
						
						// Compare input types........................
						if(origParamTypes[0] && replParamTypes[0]) {
						
							var curOrigTypeURI = origParamTypes[0]['data'];
							var curReplTypeURI = replParamTypes[0]['data'];
							
							/* No valid type URI */
							if(!validURI(curOrigTypeURI) || !validURI(curReplTypeURI)) {
								isValid = false;
								break;
							}
							
							// VISUAL ---------------------------/
							ADD_ResultDetailLine('VAS', 'Replacement input type detected: ' + curReplTypeURI, (i+1));
						
							/*************************************
								Data Type
							**************************************/
							if(getNSfromURI(curOrigTypeURI) == _xsd) {
								
								// VISUAL ---------------------------/
								ADD_ResultDetailLine('VAS', 'Original input[' + curOrigID + '] DATA type detected: ' + curOrigTypeURI, (i+1));
								
								if(isSubDATAType(curReplTypeURI, curOrigTypeURI))
									curValid = true;
							}
							/*************************************
								Object Type
							**************************************/
							else {
							
								// VISUAL ---------------------------/
								ADD_ResultDetailLine('VAS', 'Original input[' + curOrigID + '] OBJECT type detected: ' + curOrigTypeURI, (i+1));
								
								var compatibilityCheck = AJAX_checkCompatibility('Inputs', curOrigTypeURI, curReplTypeURI);
								switch(compatibilityCheck) {
									
									case 'OK':
										curValid = true;
										break;
										
									case 'NOK':
										break;
							
									default:
									
										// VISUAL ---------------------------/
										ADD_ResultDetailLine('VAS', 'Response: ' + compatibilityCheck, (i+1));
										log(compatibilityCheck);
								}
							}
						}
					}
						
					// Current Input is NOT <compatible>
					if(!curValid)
						isValid = false;
						
					// VISUAL ---------------------------/
					ADD_ResultDetailLine('VAS', 'Original input[' + curOrigID + '] stays compatible: ' + curValid, (i+1));
				}
				
				
				/* Outputs compatibility ***********************************************/
				var replOutputIDs = new Array();
				for(var j=0; replOutputPoints[j]; j++)
					replOutputIDs.push(getIDfromURI(getURIbyPoint(replOutputPoints[j])));
				
				for(var j=0; origOutputPoints[j]; j++) {

					var curOrigURI = getURIbyPoint(origOutputPoints[j]);
					var curOrigID = getIDfromURI(curOrigURI);
					var curValid = false;
					
					var curIndex = replOutputIDs.indexOf(curOrigID);
					
					/***********************************************************
						ID must be the same for replacement and original
						in order to identify inputs with equal types.
					************************************************************/
					if(curIndex != -1) {

						// Find out output types........................
						origOutputPoints[j]['matchTypes'] = new Array(_process + 'Output');
						var origParamTypes = OWL_getDataTypeObjectByProperty(origOutputPoints[j], _process, 'parameterType');
						
						replOutputPoints[curIndex]['matchTypes'] = new Array(_process + 'Output');
						var replParamTypes = OWL_getDataTypeObjectByProperty(replOutputPoints[curIndex], _process, 'parameterType');
						
						// Compare output types........................
						if(origParamTypes[0] && replParamTypes[0]) {
					 
							var curOrigTypeURI = origParamTypes[0]['data'];
							var curReplTypeURI = replParamTypes[0]['data'];
							
							/* No valid type URI */
							if(!validURI(curOrigTypeURI) || !validURI(curReplTypeURI)) {
								isValid = false;
								break;
							}
							
							// VISUAL ---------------------------/
							ADD_ResultDetailLine('VAS', 'Replacement output type detected: ' + curReplTypeURI, (i+1));
							
							/*************************************
								Data Type
							**************************************/
							if(getNSfromURI(curOrigTypeURI) == _xsd) {
								
								// VISUAL ---------------------------/
								ADD_ResultDetailLine('VAS', 'Original output[' + curOrigID + '] DATA type detected: ' + curOrigTypeURI, (i+1));
								
								if(isSubDATAType(curOrigTypeURI, curReplTypeURI))
									curValid = true;
							}
							/*************************************
								Object Type
							**************************************/
							else {
							
								// VISUAL ---------------------------/
								ADD_ResultDetailLine('VAS', 'Original output[' + curOrigID + '] OBJECT type detected: ' + curOrigTypeURI, (i+1));
								
								compatibilityCheck = AJAX_checkCompatibility('Outputs', curReplTypeURI, curOrigTypeURI);
								switch(compatibilityCheck) {
									
									case 'OK':
										curValid = true;
										break;
										
									case 'NOK':
										break;
							
									default:
									
										// VISUAL ---------------------------/
										ADD_ResultDetailLine('VAS', 'Response: ' + compatibilityCheck, (i+1));
										log(compatibilityCheck);
								}
							}
						}
					}
						
					// Current Output is NOT <compatible>
					if(!curValid)
						isValid = false;
						
					// VISUAL ---------------------------/
					ADD_ResultDetailLine('VAS', 'Output[' + curOrigID + '] is compatible: ' + curValid, (i+1));
				}
				
				/*************************************************************
				
					Because there is no reasoning tool support yet to
					compare two (SWRL) rules among each other,
					the validation of the weekening of the preconditions
					and the strengthening of the results was not possible
					to implement yet.
				
				**************************************************************/
				
				// VISUAL ---------------------------/
				ADD_ResultDetailLine('VAS', 'Not testet: Preconditions[' + getIDfromURI(IHP['ServiceURI']) + '] must imply Preconditions[' + getIDfromURI(IHP['SuperService']['URI']) + ']', (i+1));
				ADD_ResultDetailLine('VAS', 'Not testet: Results[' + getIDfromURI(IHP['SuperService']['URI']) + '] must imply Results[' + getIDfromURI(IHP['ServiceURI']) + ']', (i+1));
				
				
				//...........................
				break;// Regular switch break
			
			
			case 'ProcessDeletion':
				// VISUAL ---------------------------/
				ADD_ResultLine('VAS', new Array('', '[' + (i+1) + '][WARNING] When ' + IHP['Alterings'][i]['type'] + ' is used the process flow cannot be guaranteed'), false);
				
				//...........................
				break;// Regular switch break
			
			
			case 'ProcessInsertion':
				// VISUAL ---------------------------/
				ADD_ResultLine('VAS', new Array('', '[' + (i+1) + '][WARNING] When ' + IHP['Alterings'][i]['type'] + ' is used the process flow cannot be guaranteed'), false);
				
				//...........................
				break;// Regular switch break
			
			
			case 'ConditionReplacement':
			
				// VISUAL ---------------------------/
				if(IHP['Type'] == 'strictOriginal')
					ADD_ResultDetailLine('VAS', 'Not testet: Condition[' + getIDfromURI(IHP['Alterings'][i]['withCondition']['URI']) + '] must imply Conditions[' + getIDfromURI(IHP['Alterings'][i]['replaceCondition']['URI']) + ']', (i+1));
				else if(IHP['Type'] == 'strictSubstitute')
					ADD_ResultDetailLine('VAS', 'Not testet: Condition[' + getIDfromURI(IHP['Alterings'][i]['replaceCondition']['URI']) + '] must imply Conditions[' + getIDfromURI(IHP['Alterings'][i]['withCondition']['URI']) + ']', (i+1));
				else					
					ADD_ResultDetailLine('VAS', 'Type detected: independent', (i+1));

				//...........................
				break;// Regular switch break
				
				
			case 'ResultReplacement':
			
				// VISUAL ---------------------------/
				if(IHP['Type'] == 'strictOriginal')
					ADD_ResultDetailLine('VAS', 'Not testet: Results[' + getIDfromURI(IHP['Alterings'][i]['replaceResult']['URI']) + '] must imply Results[' + getIDfromURI(IHP['Alterings'][i]['withResult']['URI']) + ']', (i+1));
				else if(IHP['Type'] == 'strictSubstitute')
					ADD_ResultDetailLine('VAS', 'Not testet: Results[' + getIDfromURI(IHP['Alterings'][i]['withResult']['URI']) + '] must imply Results[' + getIDfromURI(IHP['Alterings'][i]['replaceResult']['URI']) + ']', (i+1));
				else
					ADD_ResultDetailLine('VAS', 'Type detected: independent', (i+1));

				//...........................
				break;// Regular switch break
				
				
			case 'InputOrOutputDeletion':
			
				// Wrong type........................................
				if(IHP['Type'] != 'independent') {
					
					// VISUAL ---------------------------/
					ADD_ResultDetailLine('VAS', 'UNALLOWED Relationship Type. <' + IHP['Type'] + '>. Must be <independent> if InputOrOutputDeletion are made.' , (i+1));
					
					isValid = false;
					break; //Force break
				}

				// Not atomic........................................
				if(ProcessType(IHP['adoptedServiceModel']['URI']) != 'AtomicProcess') {
					
					// VISUAL ---------------------------/
					ADD_ResultDetailLine('VAS', 'UNALLOWED Service Model Process Type: <' + ProcessType(IHP['adoptedServiceModel']['URI']) + '>. Must be <AtomicProcess> if InputOrOutputDeletion are made.' , (i+1));
					
					isValid = false;
					break; //Force break
				}
				
				// Grounding check is already covered above..........
				
				// VISUAL ---------------------------/
				ADD_ResultDetailLine('VAS', 'Relationship Type <independent> OK. Service Model Process Type <AtomicProcess> OK.' , (i+1));

				//...........................
				break;// Regular switch break
				
				
			case 'InputOrOutputInsertion':
			
				// Wrong type........................................
				if(IHP['Type'] != 'independent') {
					
					// VISUAL ---------------------------/
					ADD_ResultDetailLine('VAS', 'UNALLOWED Relationship Type. <' + IHP['Type'] + '>. Must be <independent> if InputOrOutputInsertion are made.' , (i+1));
					
					isValid = false;
					break; //Force break
				}

				// Not atomic........................................
				if(ProcessType(IHP['adoptedServiceModel']['URI']) != 'AtomicProcess') {
					
					// VISUAL ---------------------------/
					ADD_ResultDetailLine('VAS', 'UNALLOWED Service Model Process Type: <' + ProcessType(IHP['adoptedServiceModel']['URI']) + '>. Must be <AtomicProcess> if InputOrOutputInsertion are made.' , (i+1));
					
					isValid = false;
					break; //Force break
				}
				
				// Grounding check is already covered above..........
				
				// VISUAL ---------------------------/
				ADD_ResultDetailLine('VAS', 'Relationship Type <independent> OK. Service Model Process Type <AtomicProcess> OK.' , (i+1));

				//...........................
				break;// Regular switch break
		}
		
		// VISUAL ---------------------------/
		ADD_ResultLine('VAS', new Array('[' + (i+1) + '] ' + IHP['Alterings'][i]['type'] + ' is valid', '[' + (i+1) + '] ' + IHP['Alterings'][i]['type'] + ' IS NOT valid'), isValid, false, (i+1));
		
	}


	// VISUAL ---------------------------/
	ADD_ResultLine('VAS', new Array('Final result: VALID', 'Final result: NOT VALID'), isValid);
	return isValid;
}


//////////////////////////////////////////////////////////////////////////////////////////
// 	4. DIS [Discover Service Subsitutes]
//////////////////////////////////////////////////////////////////////////////////////////

/* ######################################################################### */
// 4.1 [DIS] LIST Service Substitutes
/* ######################################################################### */
function LIST_ServiceSubstitutes(Service_URI) {
	
	CLEAR('DIS', 'Result');

	/* Error handling~~~~~~~~~~*/
	if(!validURI(Service_URI)) {
		error_log('No valid URI provided.');
		return false;
	}
	if(!URL_exists(getURLfromURI(Service_URI))) {
		error_log('URI is not online.');
		return false;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	log('Looking for Substitutes for: ' + Service_URI);


	// VISUAL --------------------------/
	var _start = true;
	var _positive = true;
	
	INIT('DIS', 'Result');
	ADD_ResultLine('DIS', new Array('Looking for service substitutes for: #' + getIDfromURI(Service_URI)), _positive, _start);// _start = clear lines
	
	
	var SubstitutePoints = find_ServiceRelationships(Service_URI, 'strictSubstitute');
	
	for(var i=0; SubstitutePoints[i]; i++) {
		
		// Set current IR type......................................................................
		if(SubstitutePoints[i]['SuperService'])
			var curIR = 'SuperService';
			
		else if(SubstitutePoints[i]['SubService'])
			var curIR = 'SubService';
			
		else
			break;
		
		// Check if the realtionship is bidirectional................................................
		var curOfficial = '';
		
		if(curIR == 'SuperService') var curIRopposite = 'SubService'; else var curIRopposite = 'SuperService';

		var OriginalPoints = find_ServiceRelationships(SubstitutePoints[i][curIR]['URI'], 'strictOriginal');

		for(var j=0; OriginalPoints[j]; j++) {
			if(OriginalPoints[j][curIRopposite]['URI'] == Service_URI)
				curOfficial = 'OFFICIAL ';
		}
		
		// VISUAL ---------------------------/
		ADD_ResultDetailBlock('DIS', (i+1));
		
		// Handle OFFICIAL vs. non official
		if(curOfficial.length != '')
			ADD_ResultDetailLine('DIS', SubstitutePoints[i]['ServiceURI'] + ' is a ' + curIRopposite + ' of ' + SubstitutePoints[i][curIR]['URI'], (i+1));
		
		// Add a 'Validate' link if the substitute is a subservice
		var _validate = false;
		if(curIR == 'SubService')
			_validate = SubstitutePoints[i][curIR]['URI'];
		
		ADD_ResultDetailLine('DIS', SubstitutePoints[i][curIR]['URI'] + ' is a ' + curIR + ' of ' + SubstitutePoints[i]['ServiceURI'], (i+1));
		ADD_ResultLine('DIS', new Array(curOfficial + 'Substitute found: #' + getIDfromURI(SubstitutePoints[i][curIR]['URI'])), _positive, false, (i+1), _validate);
	}
	
	ADD_ResultLine('DIS', new Array('FINISHED.'), _positive);
}

/* ######################################################################### */
// 4.2 [DIS] Find Service Substitutes
/* ######################################################################### */
function find_ServiceRelationships(Service_URI, what, results) {
	
	// Init Variables
	if(!results)
		results = new Array();

	var IHP = InheritanceProfile(Service_URI);

	var SubServiceIHPs = getSubServiceIHPs(Service_URI);
	
	// SuperService found
	if(IHP) {
		if(IHP['Type'] == what) {
			log('SuperService ' + what + ' found.');
			
			var isAlreadyMember = false;
			for(var i=0; results[i]; i++) {
			
					var curPoint = results[i]['SuperService'] || results[i]['SubService'];
					if(curPoint['URI'] == IHP['SuperService']['URI'])
					isAlreadyMember = true;
			}
					
			if(!isAlreadyMember) {
				results.push(IHP);
				results = find_ServiceRelationships(IHP['SuperService']['URI'], what, results);
			}
		}
	}

	// SubServices found
	if(SubServiceIHPs) {
		for(var i=0; SubServiceIHPs[i]; i++)
			if(SubServiceIHPs[i]['Type'] == what) {
				log('SubService ' + what + ' found.');
				
				var isAlreadyMember = false;
				for(var j=0; results[j]; j++) {
					
					var curPoint = results[j]['SuperService'] || results[j]['SubService'];
					if(curPoint['URI'] == SubServiceIHPs[i]['SubService']['URI'])
						isAlreadyMember = true;
				}
				
				if(!isAlreadyMember) {
					results.push(SubServiceIHPs[i]);
					results = find_ServiceRelationships(SubServiceIHPs[i]['SubService']['URI'], what, results);
				}
			}
	}

	
	// Finish return
	return results;
}

//////////////////////////////////////////////////////////////////////////////////////////
// A. All (CNS, VIS, VAS, DIS)
//////////////////////////////////////////////////////////////////////////////////////////

/* ######################################################################### */
// A.0 Lookup Service Groundings -> Returns Points[DOM/URI]
/* ######################################################################### */
function Groundings(Service_URI) {
	log('Looking for Service Groundings...');
	
	// Get DOM from where the service is located
	getDOM(getURLfromURI(Service_URI));
	
	/* Error handling~~~~~~~~~~*/
	if(!getDOM)
		return;
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	// Service Groundings are already known..........................................
	if(_Groundings[Service_URI]) {
		log('Found saved Service Groundings: ' + _Groundings[Service_URI]);
		return _Groundings[Service_URI];
	}
	
	// Create Service Point....................................................
	var service = new Object();
	service['type'] = 'URI';
	service['URI'] = Service_URI;
	service['matchTypes'] = new Array(_service + 'Service');

	// Lookup ServiceModel.....................................................
	service['inverseMatchTypes'] = new Array(_process + 'AtomicProcess', _process + 'CompositeProcess');
	
	var service_groundings = OWL_getObjectsByProperty(service, _service, 'supports') ||
		OWL_getSubjectArrayByProperty(_service, 'supportedBy', service);

	/* Error handling~~~~~~~~~~*/
	if(!service_groundings) {
		error_log('No Service Groundings found');
		return;
	}
	for(var i=0; service_groundings[i]; i++)
		if(service_groundings[i]['type'] != 'URI') {
			error_log('Service Grounding (' + (i+1) + ') does not have an URI.');
			return;
		}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/

	log(service_groundings.length + ' Service Grounding(s) found.');
	
	// Save Service Groundings....................................................
	_Groundings[Service_URI] = service_groundings;
	
	// Return Groundings..........................................................
	return service_groundings;
}


/* ######################################################################### */
// A.1 Process type Lookup > [returns process type]
/* ######################################################################### */
function ProcessType(process_URI) {
log('Looking for process type...');
	
	/* Possible process types******************************************/	
	var validTypes = new Array('AtomicProcess', 'CompositeProcess');
	/* ****************************************************************/
	
	var Point = new Object();
	Point['type'] = 'URI';
	Point['URI'] = OWL_$(process_URI);
	
	for(var t=0; t<validTypes.length; t++) {
	
		var cur_check = OWL_checkElementTypeForPoint(Point, _process, validTypes[t]);
		if(cur_check) {
			log(validTypes[t] + ' identified: ' + process_URI);
			return validTypes[t];
		}
	}
	
	/* Error handling~~~~~~~~~~*/
	error_log('No valid process type found for: ' + process_URI);
	return;
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/		
}

/* ######################################################################### */
// A.2 Lookup Service Model -> Returns URI
/* ######################################################################### */
function ServiceModel(Service_URI) {
	log('Looking for Service Model...');
	
	// Get DOM from where the service is located
	getDOM(getURLfromURI(Service_URI));
	
	/* Error handling~~~~~~~~~~*/
	if(!getDOM)
		return;
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	// Service Model is already known..........................................
	if(_ServiceModels[Service_URI]) {
		log('Found saved Service Model: ' + _ServiceModels[Service_URI]);
		return _ServiceModels[Service_URI];
	}
	
	// Create Service Point....................................................
	var service = new Object();
	service['type'] = 'URI';
	service['URI'] = Service_URI;
	service['matchTypes'] = new Array(_service + 'Service');

	// Lookup ServiceModel.....................................................
	service['inverseMatchTypes'] = new Array(_process + 'AtomicProcess', _process + 'CompositeProcess');
	
	var service_models = OWL_getObjectsByProperty(service, _service, 'describedBy') ||
		OWL_getSubjectArrayByProperty(_service, 'describes', service);

	/* Error handling~~~~~~~~~~*/
	if(!service_models) {
		error_log('No Service Model found');
		return;
	}
	if(service_models[0]['type'] != 'URI') {
		error_log('Service Model does not have an URI');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/

	var ServiceModel_URI = service_models[0]['URI'];
	log('Service Model found: ' + ServiceModel_URI);
	
	// Save Service Model.........................................................
	_ServiceModels[Service_URI] = ServiceModel_URI;
	
	// Return URI.................................................................
	return ServiceModel_URI;
}

/* ######################################################################### */
// A.3 Interpret Inheritance Profile -> Saves new Ontology on Server
/* ######################################################################### */
function InterpretIHP(Service_URI) {

	/* Create Service Point */
	var service = new Object();
	service['type'] = 'URI';
	service['URI'] = Service_URI;
	service['matchTypes'] = new Array(_service + 'Service');
	service['inverseMatchTypes'] = new Array(_ihp + 'InheritanceProfile');

	/* Get Service Profiles */
	var profiles = OWL_getObjectsByProperty(service, _service, 'presents') ||
		OWL_getSubjectArrayByProperty(_service, 'presentedBy', service);

	/******************************************************
		Parse the profiles and look for an inheritance
		profile.
		If there is one, IHP contains it as an array
		representation.
	*******************************************************/
	if(profiles)
		var IHP = getInheritanceProfile(profiles, Service_URI);
	
	/******************************************************
		If there is an inheritance profile, it gets now
		interpreted, such that the service file gets
		updated (if necessary).
	*******************************************************/
	if(IHP)
		doInheritanceProfile(IHP);
}

/* ######################################################################### */
// A.3.1 Get Inheritance Profile
/* ######################################################################### */
function getInheritanceProfile(profilePoints, serviceURI) {
	log('Looking for inheritance profile for... ' + serviceURI);

	var IHPs = getIHPs(profilePoints);
	var return_IHP = new Object();
	
	/* SAVE */ return_IHP['ServiceURI'] = serviceURI;
	
	// No inheritance profile found
	if(!IHPs)
		return;

	/* Error handling~~~~~~~~~~*/
	if(IHPs.length > 1) {
		error_log('More than 1 Inheritance Profile found!');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/


	// Get Relationship...............................................
	var ihpPoint = IHPs[0];
	log('Inheritance Profile found:' + logP(ihpPoint));
	
	ihpPoint['matchTypes'] = new Array(_ihp + 'InheritanceProfile');
	var IHP_Relationships = OWL_getObjectsByProperty(ihpPoint, _ihp, 'contains');

	// No Inheritance Relationship found
	if(IHP_Relationships.length == 0)
		return;
		
	
	// Discover Relationships ..........................................
	var countSuperService = 0;
	for(var i=0; IHP_Relationships[i]; i++) {
		
		log('Inheritance Relationship found: ' + logP(IHP_Relationships[i]));
		
		/* SuperService found */
		if(OWL_checkElementTypeForPoint(IHP_Relationships[i], _ihp, 'SuperService')) {
			
			countSuperService++;
			log('SuperService identified.');
			var SuperServicePoint = IHP_Relationships[i];
			break;
		}
	}

	/* Error handling~~~~~~~~~~*/
	if(countSuperService > 1) {
		error_log('Multiple Inheritance is not yet supported! Please declare at most 1 SuperService for each service.');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	// No SuperService found
	if(countSuperService == 0)
		return;
	
	SuperServicePoint['matchTypes'] = new Array(_ihp + 'SuperService');
	
	var SuperService_Sources = OWL_getObjectsByProperty(SuperServicePoint, _ihp, 'hasSource');
	var SuperService_Types = OWL_getObjectsByProperty(SuperServicePoint, _ihp, 'fromType');
	
	// No Source found
	if(SuperService_Sources.length == 0)
		return;

	// Checking for Relationship Type
	/* SAVE */ return_IHP['Type'] = 'independent';// default
	
	if(SuperService_Types) {
		if(OWL_checkElementTypeForPoint(SuperService_Types[0], _ihp, 'StrictOriginal'))
		/* SAVE */ return_IHP['Type'] = 'strictOriginal';
		
		else if(OWL_checkElementTypeForPoint(SuperService_Types[0], _ihp, 'StrictSubstitute'))
		/* SAVE */ return_IHP['Type'] = 'strictSubstitute';// default
	}
		
	
	
	// Discover Specification ..........................................
	var SourcePoint = SuperService_Sources[0];
	log('SuperService Source found: ' +  logP(SourcePoint));
	
	/* SAVE */ return_IHP['SuperService'] = SourcePoint;
	
	var SuperService_Specifications = OWL_getObjectsByProperty(SuperServicePoint, _ihp, 'specifiedBy');
	var SuperService_ExternalSpecifications = OWL_getObjectsByProperty(SuperServicePoint, _ihp, 'externallySpecifiedBy');
	
	/* Error handling~~~~~~~~~~*/
	if(SuperService_ExternalSpecifications.length > 0) {
		error_log('SWSL syntax is not supported for this prototype.');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	if(SuperService_Specifications.length == 0)
		return;

	// Interpreting Specification .........................................
	var SpecificationPoint = SuperService_Specifications[0];
	SpecificationPoint['matchTypes'] = new Array(_ihp + 'Specification');
	log('SuperService Specification found: ' + logP(SpecificationPoint)); 
	
	// Service Model
	var adoptedServiceModels = OWL_getObjectsByProperty(SpecificationPoint, _ihp, 'adoptServiceModel');
	if(adoptedServiceModels.length == 0)
		return;
		
	var ServiceModelPoint = adoptedServiceModels[0];
	log('Adopted ServiceModel found: ' + logP(ServiceModelPoint)); 
	
	/* SAVE */ return_IHP['adoptedServiceModel'] = ServiceModelPoint;
	
	// Groundings
	/* SAVE */ return_IHP['leaveOutGroundings'] = false; /* DEFAULT */
	var leaveOutGroundings = OWL_getDataTypeObjectByProperty(SpecificationPoint, _ihp, 'leaveOutGroundings');
	if(leaveOutGroundings.length > 0)
		if(leaveOutGroundings[0]['data'] == 'true')
		/* SAVE */ return_IHP['leaveOutGroundings'] = true;
		
	// Alterings
	var Alterings = OWL_getObjectsByProperty(SpecificationPoint, _ihp, 'containsAltering');
	
	if(Alterings)
		log(Alterings.length + ' Altering(s)/Renaming(s) found.');
		
	/* SAVE */ return_IHP['Alterings'] = new Array();
	/* SAVE */ return_IHP['Renamings'] = new Array();

	for(var i=0; Alterings[i]; i++) {
		
		var isRenaming = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'Renaming');
		var isProcessReplacement = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'ProcessReplacement');
		var isConditionReplacement = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'ConditionReplacement');
		var isResultReplacement = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'ResultReplacement');
		var isInputAndOutputDeletions = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'InputOrOutputDeletion');
		var isNewInputsAndOutputs = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'InputOrOutputInsertion');
		var isProcessDeletion = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'ProcessDeletion');
		var isProcessInsertion = OWL_checkElementTypeForPoint(Alterings[i], _ihp, 'ProcessInsertion');

		// Lookup Renamings.....................................................................
		if(isRenaming) {
			log('Renaming identified.');
			var RenamingPoint = Alterings[i];
			RenamingPoint['matchTypes'] = new Array(_ihp + 'Renaming');
			
			var oldIDs = OWL_getDataTypeObjectByProperty(RenamingPoint, _ihp, 'oldID');
			var newIDs = OWL_getDataTypeObjectByProperty(RenamingPoint, _ihp, 'newID');
			
			if(oldIDs && newIDs) {
				var cur_renaming = new Object();
				cur_renaming['oldID'] = oldIDs[0]['data']; 
				cur_renaming['newID'] = newIDs[0]['data']; 
			}
			/* Error handling~~~~~~~~~~*/
			else {
				error_log('Renaming IDs missing.');
				break;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			/* SAVE */ return_IHP['Renamings'].push(cur_renaming); 
		}
		
		// Lookup ProcessReplacements.....................................................................
		else if(isProcessReplacement) {
			log('ProcessReplacement identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'ProcessReplacement');
			
			var originals = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'withProcess');
			var replacements = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'replaceProcess');
			
			/* Error handling~~~~~~~~~~*/
			if(!originals) {
				error_log('No original process found');
				break;
			}
			if(!replacements) {
				error_log('No replacement process found');
				break;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			var cur_altering = new Object();
			cur_altering['type'] = 'ProcessReplacement'; 
			cur_altering['withProcess'] = originals[0]; 
			cur_altering['replaceProcess'] = replacements[0]; 
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		
		// Lookup ConditionReplacements.....................................................................
		else if(isConditionReplacement) {
			log('ConditionReplacement identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'ConditionReplacement');
			
			var replaceConditions = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'replaceCondition');
			var withConditions = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'withCondition');
			
			/* Error handling~~~~~~~~~~*/
			if(!replaceConditions) {
				error_log('No original condition found');
				break;
			}
			if(!withConditions) {
				error_log('No replacement condition found');
				break;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			var cur_altering = new Object();
			cur_altering['type'] = 'ConditionReplacement'; 
			cur_altering['replaceCondition'] = replaceConditions[0]; 
			cur_altering['withCondition'] = withConditions[0]; 
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		
		// Lookup ResultReplacements.....................................................................
		else if(isResultReplacement) {
			log('ResultReplacement identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'ResultReplacement');
			
			var replaceResults = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'replaceResult');
			var withResults = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'withResult');
			
			/* Error handling~~~~~~~~~~*/
			if(!replaceResults) {
				error_log('No original result found');
				break;
			}
			if(!withResults) {
				error_log('No replacement result found');
				break;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			var cur_altering = new Object();
			cur_altering['type'] = 'ResultReplacement'; 
			cur_altering['replaceResult'] = replaceResults[0]; 
			cur_altering['withResult'] = withResults[0]; 
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		
		// Lookup InputOrOutputDeletion.....................................................................
		else if(isInputAndOutputDeletions) {
			log('InputOrOutputDeletion identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'InputOrOutputDeletion');
			
			var deleteIOs = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'deleteIO');
			var fromAtomicProcesses = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'fromAtomicProcess');
			
			/* Error handling~~~~~~~~~~*/
			if(!deleteIOs) {
				error_log('No input/output found to delete');
				break;
			}
			if(!fromAtomicProcesses) {
				error_log('No corresponding process found for input/output deletion');
				break;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			var cur_altering = new Object();
			cur_altering['type'] = 'InputOrOutputDeletion'; 
			cur_altering['deleteIO'] = deleteIOs[0]; 
			cur_altering['fromAtomicProcess'] = fromAtomicProcesses[0]; 
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		
		// Lookup InputOrOutputInsertion.....................................................................
		else if(isNewInputsAndOutputs) {
			log('InputOrOutputInsertion identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'InputOrOutputInsertion');
			
			var addIOs = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'addIO');
			var forAtomicProcesses = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'forAtomicProcess');
			
			/* Error handling~~~~~~~~~~*/
			if(!addIOs) {
				error_log('No input/output found to add');
				break;
			}
			if(!forAtomicProcesses) {
				error_log('No corresponding process found for input/output adding');
				break;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			var cur_altering = new Object();
			cur_altering['type'] = 'InputOrOutputInsertion'; 
			cur_altering['addIO'] = addIOs[0]; 
			cur_altering['forAtomicProcess'] = forAtomicProcesses[0]; 
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		
		// Lookup ProcessDeletions.....................................................................
		else if(isProcessDeletion) {
			log('ProcessDeletion identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'ProcessDeletion');
			
			var deletes = OWL_getObjectsByProperty(ProRepPoint, _ihp, 'delete');
			
			/* Error handling~~~~~~~~~~*/
			if(!deletes) {
				error_log('No process found to delete');
				return;
			}
			/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
			
			var cur_altering = new Object();
			cur_altering['type'] = 'ProcessDeletion'; 
			cur_altering['delete'] = deletes[0]; 
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		
		// Lookup ProcessInsertions.....................................................................
		else if(isProcessInsertion) {
			log('ProcessInsertion identified.');
			var ProRepPoint = Alterings[i];
			ProRepPoint['matchTypes'] = new Array(_ihp + 'ProcessInsertion');
			

/* TO BE DONE ::: */
alert('Not implemented yet: ProcessInsertion');

			var cur_altering = new Object();
			cur_altering['type'] = 'ProcessInsertion';
			
			
			/* SAVE */ return_IHP['Alterings'].push(cur_altering);
		}
		else
			error_log('Unkown Altering Type found: ' + logP(Alterings[i]));
	}
	
	// Return gathered Inheritance Profile
	/*
		[ServiceURI]
		[SuperService]
		[adoptedServiceModel]
		[leaveOutGroundings]
		[Alterings][type]
		
	*/
	return return_IHP;
}

/* ######################################################################### */
// A.3.1.1 Get Inheritance Profile (Helper)
/* ######################################################################### */
function getIHPs(profilePoints) {
	
	// Checking if the profile is an inheritance profile......................................
	var InheritanceProfiles = new Array();
	var ihp_nodeType = _ihp + 'InheritanceProfile';
	
	for(var i=0; i<profilePoints.length; i++) {

		var nodeType = '';
		switch(profilePoints[i]['type']) {
			
			case 'URI':

				var DOMs = OWL_getDOMsByURI(_ihp, 'InheritanceProfile', profilePoints[i]['URI']);
				if(DOMs) {
					for(var j=0; j<DOMs.length; j++) {
						var nodeType = OWL_getElementTypeByDOM(DOMs[j]);
			
						// NodeType match positive :)
						if(nodeType == ihp_nodeType)
							InheritanceProfiles.push(profilePoints[i]);
					}
				}
				break;
			
			case 'blankNode_URI':
				/* Error handling~~~~~~~~~~*/
				error_log('Not supported (blankNode_URI) for inheritance profile');
				return;
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
				break;
			
			case 'DOM':
				var nodeType = OWL_getElementTypeByDOM(profilePoints[i]['DOM']);
				
				// NodeType match positive :)
				if(nodeType == ihp_nodeType)
					InheritanceProfiles.push(profilePoints[i]);
				break;
				
			default:
				/* Error handling~~~~~~~~~~*/
				error_log('No type given for inheritance profile');
				return;
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
		}
	}
	
	// No InheritanceProfiles found....................................
	if(InheritanceProfiles.length == 0) {
		log('No Inheritance Profile found');
		return false;
	}
	
	// InheritanceProfiles found :)....................................
	return InheritanceProfiles;
}

/* ######################################################################### */
// A.3.2 Perform Inheritance Profile
/* ######################################################################### */
function doInheritanceProfile(ihp) {
	
	/* Error handling~~~~~~~~~~*/
	if(!ihp) {
		error_log('No inheritance profile in doInheritanceProfile()');
		return;	
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	// No SuperService declared
	if(!ihp['SuperService'])
		return;
		
	/* Error handling~~~~~~~~~~*/
	if(ihp['adoptedServiceModel']['type'] != 'URI') {
		error_log('Adopted ServiceModel (atomic or composite process) must have an URI');
		return;	
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/

	// Identifying superservice model and service.................................................
	var oldBASE = getURLfromURI(ihp['adoptedServiceModel']['URI']);
	var newBASE = getURLfromURI(ihp['ServiceURI']);
	
	
	/*********************************************************
		This represents at the end the altered superservice,
		including all interpretations of the alterings.
	**********************************************************/
	superserviceDOM = getDOM(oldBASE);
	
	
	// Deleting connections from the service model to the old service.............................
	var describedByProperties = superserviceDOM.getElementsByTagNameNS(_service, 'describedBy');
	var describesProperties = superserviceDOM.getElementsByTagNameNS(_service, 'describes');
	
	/************************************************************
		Removing the service and service property.
		
		[process] *describes* [service]
	*************************************************************/
	for(var i=0; i<describesProperties.length; i++) {
		
		var cur_prop = describesProperties[i];
		var cur_process = cur_prop.parentNode;
		
		// Removing the <service:describes> property and every subchild (i.e. the service)
		cur_process.removeChild(cur_prop);
	}
	
	/*************************************************************
		Removing the service and <service:describedBy> property
	 	*WITHOUT* the subchildren.
		
	 	[service] *describedBy* [process]
	 *************************************************************/
	for(var i=0; i<describedByProperties.length; i++) {
		
		var cur_prop = describedByProperties[i];
		var cur_service = cur_prop.parentNode;
		var parent = cur_service.parentNode;
		
		// Keeping the subchildren of the property (i.e. the process)
		var keptChildren = cur_prop.childNodes;
		for(var j=0; j<keptChildren.length; j++)
			parent.appendChild(keptChildren[j]);
		
		// Removing the parent (i.e. service)
		parent.removeChild(cur_service);
	}
	
	/************************************************************
		Removing the old profile and grounding elements.
	*************************************************************/
	// Profiles
	var presentsProperties = superserviceDOM.getElementsByTagNameNS(_service, 'presents');
	var presentedByProperties = superserviceDOM.getElementsByTagNameNS(_service, 'presentedBy');
	var profileElements = merge_arrays(presentsProperties, presentedByProperties);
	
	// Groundings
	var supportsProperties = superserviceDOM.getElementsByTagNameNS(_service, 'supports');
	var supportedByProperties = superserviceDOM.getElementsByTagNameNS(_service, 'supportedBy');
	var groundingElements = merge_arrays(supportsProperties, supportedByProperties);
	
	// Total
	var totalElemens = merge_arrays(profileElements, groundingElements);
	
	// Remove
	for(var i=0; totalElemens[i]; i++) {
		
		cur_element = presentsProperties[i].parentNode;
		cur_element.parentNode.removeChild(cur_element);
	}
	
	/************************************************************
		Removing the old Inheritance Profile completly.
	*************************************************************/
	var removeAllTheseElements = new Array();
	removeAllTheseElements = merge_arrays(_WebServiceCustomization, _WebServiceExtension, _WebServiceManipulation);
	removeAllTheseElements.push('InheritanceProfile');
	removeAllTheseElements.push('SuperService');
	removeAllTheseElements.push('SubService');
	removeAllTheseElements.push('Specification');
	removeAllTheseElements.push('Type');
	
	for(var i=0; removeAllTheseElements[i]; i++) {
		var cur_elements = OWL_getElementsByNodeType(superserviceDOM, _ihp, removeAllTheseElements[i]);
		
		for(var j=0; cur_elements[j]; j++)
			cur_elements[j].parentNode.removeChild(cur_elements[j]);
	}


	// Performing alterings.......................................................................
	for(var i=0; i<ihp['Alterings'].length; i++) {
		
		log('Interpreting ' + ihp['Alterings'][i]['type'] + ' now.....');
		switch(ihp['Alterings'][i]['type']) {
			
			case 'ProcessReplacement':
			
				var replacementOK = false;
				
				var PerformPoint = ihp['Alterings'][i]['withProcess'];
				PerformPoint['matchTypes'] = new Array(_process + 'Perform');
				log('Original Process Perform identified: ' + logP(PerformPoint));

				var PerformDOMs = OWL_getDOMsByPoint(PerformPoint);
				
				/* Error handling~~~~~~~~~~*/
				if(!PerformDOMs) {
					error_log('No Perform DOMs found for Altering ' + (i+1));
					break;
				}
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/	
				
				for(var j=0; PerformDOMs[j]; j++) {
					
					/******************************************************************
						This is the right perform element. Now the property value
						gets replaced by the new process.
						In case the process is attached directly, it should not be
						deleted, because it could be needed by another process
						perform.
					*******************************************************************/
					
					// Check if it is the right property
					var cur_props = PerformDOMs[j].childNodes;
					var cur_foundProp = false;
					for(var k=0; cur_props[k]; k++) {
						
						var cur_propType = OWL_getElementTypeByDOM(cur_props[k]);
						if(cur_propType == _process + 'process') {
							var cur_foundProp = cur_props[k];
							break;
						}
					}
					
					// Has the property been found?
					if(cur_foundProp) {
						
						/***************************************************
							Save a potentially defined process as the
							source of the process performance.
						****************************************************/
						if(cur_foundProp.firstChild)
							superserviceDOM.appendChild(cur_foundProp.firstChild);
	
						// Remove property
						cur_foundProp.parentNode.removeChild(cur_foundProp);
						
						// Add new property
						var new_processPropNode = superserviceDOM.ownerDocument.createElementNS(_process, 'process');
						var appendedPropNode = PerformDOMs[j].appendChild(new_processPropNode);
						
						var ReplacementPoint = ihp['Alterings'][i]['replaceProcess'];
						switch(ReplacementPoint['type']) {
												
							case 'URI':
								var newProcessURI = ReplacementPoint['URI'];
								appendedPropNode.setAttributeNS(_rdf, 'resource', newProcessURI);
								break;
							
							case 'blankNode_URI':
								var newBlankNodeURI = ReplacementPoint['blankNode_URI'];
								appendedPropNode.setAttributeNS(_rdf, 'nodeID', getIDfromURI(newBlankNodeURI));
								break;
							
							case 'DOM':
								appendedPropNode.appendChild(ReplacementPoint['DOM']);
								break;
								
							default:
								/* Error handling~~~~~~~~~~*/
								error_log('No type given for doInheritanceProfile()');
								return;
								/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
							}
						
						// Set status OK
						replacementOK = true;
						
						// Update Superservice DOM
						superserviceDOM = PerformDOMs[j].ownerDocument.documentElement;
						
						// Leave loop
						break;
					}
				}
				
				/* Error handling~~~~~~~~~~*/
				if(!replacementOK) {
					error_log('No process resource found for replacement');
					break;	
				}
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/	
				
				/****************************************************
					The superserviceDOM needs to be updated, since
					the altering was interpreted on an other DOM
				*****************************************************/
				
				break;

			case 'ConditionReplacement':
			
				/* Original */
				var OriginalConditionPoint = ihp['Alterings'][i]['replaceCondition'];
				var OriginalCondition_URI = OWL_getIdentityByPoint(OriginalConditionPoint);
				log('Original SWRL-Condition identified: ' + logP(OriginalConditionPoint));
				
				/* Replacement */
				var ReplacementConditionPoint = ihp['Alterings'][i]['withCondition'];
				var ReplacementCondition_URI = OWL_getIdentityByPoint(ReplacementConditionPoint);
				log('Replacement SWRL-Condition identified: ' + logP(ReplacementConditionPoint));
				
				/* Error handling~~~~~~~~~~*/
				if(!OriginalCondition_URI) {
					error_log('No OriginalCondition URI found for Altering ' + (i+1));
					break;
				}
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/	
				
				// Get all properties
				var propertyTypes = new Array('hasEffect', 'whileCondition', 'inCondition', 'untilCondition', 'hasPrecondition');
				
				for(var p=0; propertyTypes[p]; p++) {
					
					var curProperties = superserviceDOM.getElementsByTagNameNS(_process, propertyTypes[p]);
					
					// Check if the properties are the right ones
					for(var j=0; j<curProperties.length; j++) {
						
						var direct_resourceURI = OWL_getResourceURI(curProperties[j]);
						var indirect_resourceURI = false;
						
						if(curProperties[j].hasChildNodes()) {
							var resourceDOMs = curProperties[j].childNodes;
							indirect_resourceURI = OWL_getNodeIdentityURI(resourceDOMs[0]);
						}
						
						var resourceURI = direct_resourceURI || indirect_resourceURI;

						if(resourceURI == OriginalCondition_URI) {
							
							/******************************************************************
								This is the right element.
								Now the node gets replaced by the new resource.
							*******************************************************************/
	
							// Creating a new elment which points to the new resource
							var new_property = superserviceDOM.ownerDocument.createElementNS(_process, propertyTypes[p]);
							new_property.setAttributeNS(_rdf, 'resource', ReplacementCondition_URI);
							
							// Replacing the properties
							var parent = curProperties[j].parentNode;
							parent.replaceChild(new_property, curProperties[j]);
						}
					}
				}

				/* Normal break */
				break;
			
			case 'ResultReplacement':
			
				/* Original */
				var OriginalResultPoint = ihp['Alterings'][i]['replaceResult'];
				var OriginalResult_URI = OWL_getIdentityByPoint(OriginalResultPoint);
				log('Original OWL-S Result identified: ' + OriginalResult_URI);
				
				/* Replacement */
				var ReplacementResultPoint = ihp['Alterings'][i]['withResult'];
				var ReplacementResult_URI = OWL_getIdentityByPoint(ReplacementResultPoint);
				log('Replacement OWL-S Result identified: ' + ReplacementResult_URI);
				
				/* Error handling~~~~~~~~~~*/
				if(!OriginalResult_URI) {
					error_log('No OriginalResult URI found for Altering ' + (i+1));
					break;
				}
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/	
				
				// Get all properties
				var propertyTypes = new Array('hasResult');
	
				for(var p=0; propertyTypes[p]; p++) {
					
					var curProperties = superserviceDOM.getElementsByTagNameNS(_process, propertyTypes[p]);

					// Check if the properties are the right ones
					for(var j=0; j<curProperties.length; j++) {
						
						var direct_resourceURI = OWL_getResourceURI(curProperties[j]);
						var indirect_resourceURI = false;
						
						if(curProperties[j].hasChildNodes()) {
							var resourceDOMs = curProperties[j].childNodes;
							for(var c=0; c<resourceDOMs.length; c++) {
								indirect_resourceURI = OWL_getNodeIdentityURI(resourceDOMs[c]);
								if(indirect_resourceURI)
									break;
							}
						}
						
						var resourceURI = direct_resourceURI || indirect_resourceURI;

						if(resourceURI == OriginalResult_URI) {
							
							/******************************************************************
								This is the right element.
								Now the node gets replaced by the new resource.
							*******************************************************************/
	
							// Creating a new elment which points to the new resource
							var new_property = superserviceDOM.ownerDocument.createElementNS(_process, propertyTypes[p]);
							new_property.setAttributeNS(_rdf, 'resource', ReplacementResult_URI);
							
							// Replacing the properties
							var parent = curProperties[j].parentNode;
							parent.replaceChild(new_property, curProperties[j]);
						}
					}
				}

				
				/* Normal break */
				break;
			
			case 'InputOrOutputDeletion':
			
				/* Process */
				var AtomicProcessPoint = ihp['Alterings'][i]['fromAtomicProcess'];
				var AtomicProcessPoint_URI = OWL_getIdentityByPoint(AtomicProcessPoint);
				log('Procss for input/output deletion identified: ' + logP(AtomicProcessPoint));
				
				/* Input/Output Deletion */
				var IODeletionPoint = ihp['Alterings'][i]['deleteIO'];
				var IODeletion_URI = OWL_getIdentityByPoint(IODeletionPoint);
				log('Input/Output to delete identified: ' + logP(IODeletionPoint));
				
				var isInput = OWL_checkElementTypeForPoint(IODeletionPoint, _process, 'Input');
				var isOutput = OWL_checkElementTypeForPoint(IODeletionPoint, _process, 'Output');
				
				/* Error handling~~~~~~~~~~*/
				if(ProcessType(AtomicProcessPoint_URI) != 'AtomicProcess') {
					error_log('Process is not atomic in Altering ' + (i+1));
					break;
				}
				if(!isInput && !isOutput) {
					error_log('Deletion is neither an Input nor an Output in Altering ' + (i+1));
					break;
				}
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/	
				
				// Set type of deletion
				var curType = 'Output';
				if(isInput) curType = 'Input';
				
				// Get all properties
				var propertyTypes = new Array('has' + curType);
	
				for(var p=0; propertyTypes[p]; p++) {
					
					var curProperties = superserviceDOM.getElementsByTagNameNS(_process, propertyTypes[p]);

					// Check if the properties are the right ones
					for(var j=0; j<curProperties.length; j++) {
						
						var direct_resourceURI = OWL_getResourceURI(curProperties[j]);
						var indirect_resourceURI = false;
						
						if(curProperties[j].hasChildNodes()) {
							
							var resourceDOMs = curProperties[j].childNodes;
							for(var c=0; c<resourceDOMs.length; c++) {
								indirect_resourceURI = OWL_getNodeIdentityURI(resourceDOMs[c]);
								if(indirect_resourceURI)
									break;
							}
						}
						
						var resourceURI = direct_resourceURI || indirect_resourceURI;

						if(resourceURI == IODeletion_URI) {
							
							/* It is the right process that holds the input */
							var parent = curProperties[j].parentNode;
							if(OWL_getNodeIdentityURI(parent) == AtomicProcessPoint_URI) {
								
								/******************************************************************
									This is the right element.
									Now the node gets deleted.
								*******************************************************************/
		
								// Deleting the input output
								parent.removeChild(curProperties[j]);
							}
						}
					}
				}

				/* Normal break */
				break;
			
			case 'InputOrOutputInsertion':

				/* Process */
				var AtomicProcessPoint = ihp['Alterings'][i]['forAtomicProcess'];
				var AtomicProcessPoint_URI = OWL_getIdentityByPoint(AtomicProcessPoint);
				log('Procss for input/output adding identified: ' + logP(AtomicProcessPoint));
				
				/* Input/Output Deletion */
				var IOAddingPoint = ihp['Alterings'][i]['addIO'];
				var IOAdding_URI = OWL_getIdentityByPoint(IOAddingPoint);
				log('Input/Output to add identified: ' + logP(IOAddingPoint));
				
				var isInput = OWL_checkElementTypeForPoint(IOAddingPoint, _process, 'Input');
				var isOutput = OWL_checkElementTypeForPoint(IOAddingPoint, _process, 'Output');
				
				/* Error handling~~~~~~~~~~*/
				if(ProcessType(AtomicProcessPoint_URI) != 'AtomicProcess') {
					error_log('Process is not atomic in Altering ' + (i+1));
					break;
				}
				if(!isInput && !isOutput) {
					error_log('Adding is neither an Input nor an Output in Altering ' + (i+1));
					break;
				}
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/	
				
				// Set type of deletion
				var curType = 'Output';
				if(isInput) curType = 'Input';
				
				/******************************************************************
					A new element that points to the input/output gets created
				*******************************************************************/

				// Creating a new element
				var new_atomicProcess = superserviceDOM.ownerDocument.createElementNS(_process, 'AtomicProcess');
				new_atomicProcess.setAttributeNS(_rdf, 'about', AtomicProcessPoint_URI);
				
				var new_hasIONode = superserviceDOM.ownerDocument.createElementNS(_process, 'has' + curType);
				new_hasIONode.setAttributeNS(_rdf, 'resource', IOAdding_URI);
				new_atomicProcess.appendChild(new_hasIONode);
				
				superserviceDOM.appendChild(new_atomicProcess);

				/* Normal break */
				break;

			case 'ProcessDeletion':
				alert('[INFO] ' + ihp['Alterings'][i]['type'] + ' (Web Service Extension) is not implemented yet.');
				/* Normal break */
				break;

			case 'ProcessInsertion':
				alert('[INFO] ' + ihp['Alterings'][i]['type'] + ' (Web Service Extension) is not implemented yet.');
				/* Normal break */
				break;

			default:
				/* Error handling~~~~~~~~~~*/
				error_log('No valid altering type found in doInheritanceProfile()');
				return;	
				/* ~~~~~~~~~~~~~~~~~~~~~~~~*/			
		}
	}


	// Asserting the inherited service model to the new service (via relative IDs)................
	var new_serviceNode = superserviceDOM.ownerDocument.createElementNS(_rdf, 'Description');
	new_serviceNode.setAttributeNS(_rdf, 'about', ihp['ServiceURI']);
	
	var new_describedByNode = superserviceDOM.ownerDocument.createElementNS(_service, 'describedBy');
	var adopted_SM_URI = '#' + getIDfromURI(ihp['adoptedServiceModel']['URI']);
	new_describedByNode.setAttributeNS(_rdf, 'resource', adopted_SM_URI);
	
	var appended_serviceNode = superserviceDOM.appendChild(new_serviceNode);
	appended_serviceNode.appendChild(new_describedByNode);

	
	/******************************************************************
		Old service DOM is potentially different now and needs to be
		downloaded again next time when this service is used.
	
		The new service needs to be downloaded again for sure, because
		now the interpretation of the Inheritance Profile is included.
	*******************************************************************/
	_loaded_URLs[oldBASE] = null;
	_loaded_URLs[newBASE] = null;
	
	
	// Asserting the inherited service groundings to the new service..............................
	if(!ihp['leaveOutGroundings']) {
		var groundings = Groundings(ihp['SuperService']['URI']);
		if(groundings)
			for(var g=0; groundings[g]; g++) {
				
				var newGrounding_URI = getNewGroundingsURI(groundings[g]['URI'], ihp['ServiceURI']);
				OWL_CreateProperty(new_serviceNode, _service, 'supports', newGrounding_URI);
			}
	}
	
	
	
	// Saving the new service as file on server...................................................
	saveNewService(superserviceDOM, ihp['Renamings'], oldBASE, newBASE);
	/******************************************************************
		All files will have a default URL and are stored in the same
		directory.
	*******************************************************************/	

	// Save the groundings as file on server......................................................
	if(!ihp['leaveOutGroundings']) {
		log('Saving Service Groundings...');
		var groundings = Groundings(ihp['SuperService']['URI']);
		saveNewGroundings(groundings, ihp['ServiceURI'], ihp['SuperService']['URI']);
		log('...done.');		
	}
	
}

/* ######################################################################### */
// A.3.3 Lookup Inheritance Profile By Service URI
/* ######################################################################### */
function InheritanceProfile(Service_URI) {
	
	/* Create Service Point */
	var service = new Object();
	service['type'] = 'URI';
	service['URI'] = Service_URI;
	service['matchTypes'] = new Array(_service + 'Service');
	service['inverseMatchTypes'] = new Array(_ihp + 'InheritanceProfile');

	/* Get Service Profiles */
	var profiles = OWL_getObjectsByProperty(service, _service, 'presents') ||
		OWL_getSubjectArrayByProperty(_service, 'presentedBy', service);

	/******************************************************
		Parse the profiles and look for an inheritance
		profile.
		If there is one, IHP contains it as an array
		representation.
	*******************************************************/
	if(profiles)
		var IHP = getInheritanceProfile(profiles, Service_URI);
	
	if(IHP)
		return IHP;
		
	return false;
}

function getSubServiceIHPs(serviceURI) {
	log('Looking for subservices for ' + serviceURI);

	var return_SubServices = new Array();
	
	
	/* Create Service Point */
	var service = new Object();
	service['type'] = 'URI';
	service['URI'] = serviceURI;
	service['matchTypes'] = new Array(_service + 'Service');
	service['inverseMatchTypes'] = new Array(_ihp + 'InheritanceProfile');

	/* Get Service Profiles */
	var profiles = OWL_getObjectsByProperty(service, _service, 'presents') ||
		OWL_getSubjectArrayByProperty(_service, 'presentedBy', service);

	var IHPs = getIHPs(profiles);
	
	// No inheritance profile found
	if(!IHPs)
		return;

	/* Error handling~~~~~~~~~~*/
	if(IHPs.length > 1) {
		error_log('More than 1 Inheritance Profile found!');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/


	// Get Relationship...............................................
	var ihpPoint = IHPs[0];
	log('Inheritance Profile found: ' + logP(ihpPoint)); 
	
	ihpPoint['matchTypes'] = new Array(_ihp + 'InheritanceProfile');
	var IHP_Relationships = OWL_getObjectsByProperty(ihpPoint, _ihp, 'contains');

	// Discover Relationships ..........................................
	for(var i=0; IHP_Relationships[i]; i++) {
		
		log('Inheritance Relationship found: ' + logP(IHP_Relationships[i]));
		
		/* Current SubService Object() */
		var return_IHP = new Object();
		
		/* SubService found */
		if(OWL_checkElementTypeForPoint(IHP_Relationships[i], _ihp, 'SubService')) {
			log('SubService identified.');
			
			IHP_Relationships[i]['matchTypes'] = new Array(_ihp + 'SubService');
			
			var Sources = OWL_getObjectsByProperty(IHP_Relationships[i], _ihp, 'hasSource');
			var Types = OWL_getObjectsByProperty(IHP_Relationships[i], _ihp, 'fromType');
			
			// No Source found
			if(Sources.length == 0)
				break;
		
			// Discover Type ..........................................
			/* SAVE */ return_IHP['Type'] = 'independent';// default
			
			if(Types) {
				if(OWL_checkElementTypeForPoint(Types[0], _ihp, 'StrictOriginal'))
				/* SAVE */ return_IHP['Type'] = 'strictOriginal';
				
				else if(OWL_checkElementTypeForPoint(Types[0], _ihp, 'StrictSubstitute'))
				/* SAVE */ return_IHP['Type'] = 'strictSubstitute';// default
			}
				
			
			// Save SubService ..........................................
			log('SubService Source found: ' + logP(Sources[0])); 
			/* SAVE */ return_IHP['SubService'] = Sources[0];
			/* SAVE */ return_IHP['ServiceURI'] = serviceURI;
		
			if(Sources[0]['type'] == 'URI')
				return_SubServices.push(return_IHP);
		}
	}
	
	return return_SubServices;
}

	

/* ######################################################################### */
// A.4 CompositeProcess Lookup
/* ######################################################################### */
function lookup_CompositeProcess(Component) {
	
	var URI = Component['Perform_URI'] || Component['Process_URI'];
	var Point = new Object();
	Point['type'] = 'URI';
	Point['URI'] = URI;
	Point['matchTypes'] = new Array(_process + 'CompositeProcess', _process + 'Perform');
	
	log('Looking up CompositeProcess: ' + URI);
	
	/************************************************
		In case Component is a process:Perform,
		the process needs to be found first.
	*************************************************/
	var ProcessPoints = new Array(Point);
	if(OWL_checkElementTypeForPoint(Point, _process, 'Perform'))
		var ProcessPoints = OWL_getObjectsByProperty(Point, _process, 'process');
	
	// Get the composition of the CompositeProcess
	ProcessPoints[0]['matchTypes'] = new Array(_process + 'CompositeProcess');
	var ControlConstructs = OWL_getObjectsByProperty(ProcessPoints[0], _process, 'composedOf');
	
	/* Error handling~~~~~~~~~~*/
	if(!ControlConstructs) {
		error_log('No composition found.');
		return;
	}
	/* ~~~~~~~~~~~~~~~~~~~~~~~~*/
		
	/* SAVE */ _ProcessTree[URI] = new Array();
	
	// Recursive Lookup
	RL_CompositeProcess(Component, ControlConstructs[0]);
}

/* ######################################################################### */
// A.4.1 Recursive Lookup of Composite Process
/* ######################################################################### */
function RL_CompositeProcess(SourceComponent, ControlConstructPoint, _CC_type, _Set_name) {
log('Looking up components of: ' + SourceComponent['Process_URI']);

	if(!validPoint(ControlConstructPoint))
		return;
		
	// Possible Types for a ControlConstruct
	var typeURIs = new Array(_process + 'Choice', _process + 'If-Then-Else', _process + 'Repeat-Until', _process + 'Repeat-While', _process + 'Perform', _process + 'Produce', _process + 'Sequence', _process + 'Split', _process + 'Split-Join');
	
	// Type of the current ControlConstruct
	SourceComponent['typeURI'] = OWL_getOneOfPointType(ControlConstructPoint, typeURIs);
	/********************************************************
		ControlConstruct is a Perform.
		SAVE Perform and Process.
	*********************************************************/
	if(SourceComponent['typeURI'] == _process + 'Perform') {
		
		var PerformPoint = ControlConstructPoint;
		PerformPoint['matchTypes'] = new Array(_process + 'Perform');
		var ProcessPoints = OWL_getObjectsByProperty(PerformPoint, _process, 'process');
		
		// Get Source URI (ServiceModel > Only Process URI)..............................................
		var Source_URI = SourceComponent['Perform_URI'] || SourceComponent['Process_URI'];
		
		// Get New Component.............................................................................
		var NewComponent = new Object();
		NewComponent['Perform_URI'] = OWL_getIdentityByPoint(PerformPoint);
		NewComponent['Process_URI'] = OWL_getIdentityByPoint(ProcessPoints[0]);
		log('Process component found: ' + NewComponent['Process_URI']);
		
		// Set Type (if available)
		if(_CC_type)
			NewComponent['type'] = _CC_type;
		if(_Set_name)
			NewComponent['name'] = _Set_name;
		
		/* SAVE */ _ProcessTree[Source_URI].push(NewComponent);

		// Lookup Composite Process if necessary.........................................................
		if(ProcessType(NewComponent['Process_URI']) == 'CompositeProcess')
			lookup_CompositeProcess(NewComponent);

		return;
	}
	
	/********************************************************
		ControlConstruct is NOT a Perform.
		Fint the included Performs now.
	*********************************************************/
	ControlConstructPoint['matchTypes'] = typeURIs;
	
	/* Choice, Sequence, Split, Split-Join */
	var Sets = OWL_getObjectsByProperty(ControlConstructPoint, _process, 'components');
	if(Sets)
		RL_CompositeProcess_Sets(SourceComponent, Sets[0], getIDfromURI(SourceComponent['typeURI']));
	/**********************************************************/
	
	/* If-Then-Else, Repeat-Until, Repeat-While */
	var thenCCs = OWL_getObjectsByProperty(ControlConstructPoint, _process, 'then');
	var elseCCs = OWL_getObjectsByProperty(ControlConstructPoint, _process, 'else');
	var untilCCs = OWL_getObjectsByProperty(ControlConstructPoint, _process, 'untilProcess');
	var whileCCs = OWL_getObjectsByProperty(ControlConstructPoint, _process, 'whileProcess');
	/**********************************************************/

	// Check ControlConstruct Type..................................................................
	var CC_type;
	if(thenCCs[0]) CC_type = '(if...) then';
	else if(untilCCs[0]) CC_type = 'do (until...)';
	else if(whileCCs[0]) CC_type = 'do (while...)';
		
	// Lookup the found ControlConstruct............................................................
	var NewControlConstruct = thenCCs[0] || untilCCs[0] || whileCCs[0];
	if(NewControlConstruct)
		RL_CompositeProcess(SourceComponent, NewControlConstruct, CC_type);
	
	/* Lookup ELSE */
	if(CC_type == 'If-Then' && elseCCs[0])
		RL_CompositeProcess(SourceComponent, NewControlConstruct, 'else');
}

/* ######################################################################### */
// A.4.2 Recursive Lookup of Composite Proces Sets
/* ######################################################################### */
function RL_CompositeProcess_Sets(SourceComponent, SetPoint, _Set_name) {
	
		// MatchTypes for Sets.............................................................
		var matchTypes = new Array(_process + 'ControlConstructList', _process + 'ControlConstructBag');
		

		// Get ControlConstructs...........................................................
		SetPoint['matchTypes'] = matchTypes;
		SetCCs = OWL_getObjectsByProperty(SetPoint, _object_list, 'first');
		
		/* Lookup ControlConstruct */
		RL_CompositeProcess(SourceComponent, SetCCs[0], false, _Set_name);


		// Crawl List......................................................................
		var RestSets = OWL_getObjectsByProperty(SetPoint, _object_list, 'rest');
		
		/* End of List reached **************/
		if(OWL_checkIdentityForPoint(RestSets[0], _object_list + 'nil'))
			return;
		/************************************/
		
		/* Lookup Set */
		RL_CompositeProcess_Sets(SourceComponent, RestSets[0], _Set_name);
}

/* ######################################################################### */
// A.5.1 Check if arg1 is a sub datatype of arg2 -> Return {true/false}
/* ######################################################################### */
function isSubDATAType(origDataTypeID, psubDataTypeID) {
	
		var curSubtypes = _dataTypes[origDataTypeID];
		
		if(curSubtypes)
			for(var i=0; curSubtypes[i]; i++) {
				if(curSubtypes[i] == psubDataTypeID)
					return true;
				else
					if(isSubDATAType(curSubtypes[i], psubDataTypeID))
						return true;
			}
		
		return false;
}