/*
 * Copyright (c) 2015-2019 ANSYS medini Technologies AG
 * All rights reserved.
 * 
 * The script is provided "as is" without warranty of any kind. 
 * ANSYS medini Technologies AG disclaims all warranties, either express or implied, 
 * including the warranties of merchantability and fitness for a particular purpose.
 * 
 * v2020-10-21 - added findOrCreateHazard
 * v2020-03-06 - initial support for traces
 * v2020-01-03 - initial support for variables
 * v2019-08-29 - initial support for Weaknesses and Triggers
 * v2019-06-26 - improved support for goals and functions
 * v2019-06-18 - added support for hazardous events 
 * v2019-04-11 - added support for general activities and actions 
 * v2017-03-01 - added support for project and system packages 
 * v2017-02-10 - added support for requirements
 * v2016-11-14 - added support for hazard
 * v2015-06-10 - added support for goal
 * v2015-06-08 - initial version
 */
if (!bind) {
	throw "This script requires extended API";
}

// extended finder methods
var AutoCounterSupport = bind("de.ikv.medini.metamodel.autocounter", "de.ikv.medini.metamodel.autocounter.AutoCounterSupport", false);
var TraceController = bind("de.ikv.medini.kernel.traceability", "de.ikv.medini.kernel.traceability.TraceController", false);

// helper
function findLimitation(scope, name) {
	if (!scope) {
		console.error("scope is undefined!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.Limitation, false).find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}
	
	return undefined;
}

// helper
function findOrCreateLimitation(scope, name) {
	var found = findLimitation(scope, name);
	if (found) {
		return found;
	}

	// create one
	var created = Factory.createElement(scope, Metamodel.safetyModel.Limitation);
	created.name = name;
	return created;
}

// helper
function findTriggeringCondition(scope, name) {
	if (!scope) {
		console.error("scope is undefined!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.TriggeringCondition, false).find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}
	
	return undefined;
}

// helper
function findOrCreateTriggeringCondition(scope, name) {
	var found = findTriggeringCondition(scope, name);
	if (found) {
		return found;
	}

	// create one
	var created = Factory.createElement(scope, Metamodel.safetyModel.TriggeringCondition);
	created.name = name;
	return created;
}

// helper
function findHazardousEvent(scope, id) {
	if (!scope) {
		console.error("scope is undefined!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.hazard.HazardousEvent, false).find("id", id);
	if (!found.isEmpty()) {
		return found.first();
	}
	
	return undefined;
}

// helper
function findOrCreateHazardousEvent(scope, id) {
	var found = findHazardousEvent(scope, id);
	if (found) {
		return found;
	}

	// create one
	var created = Factory.createElement(scope, Metamodel.hazard.HazardousEvent);
	created.id = id;
	return created;
}

// helper
function findAction(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in findAction!");
		return undefined;
	}
	
	var found = Global.getFinder(scope).findByType(Metamodel.sysml.SysMLAction, true)
		.find("name", name);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	
	return undefined;
}

// helper
function findOrCreateAction(scope, name) {
	var found = findAction(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.sysml.SysMLAction);
	created.name = name;
	return created;
}

// helper
function findActivity(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in findActivity!");
		return undefined;
	}
	
	var found = Global.getFinder(scope).findByType(Metamodel.sysml.SysMLActivity, true)
		.find("name", name);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	
	return undefined;
}

// helper
function findOrCreateActivity(scope, name) {
	var found = findActivity(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.sysml.SysMLActivity);
	created.name = name;
	return created;
}

// helper
function findFunction(scope, name, id) {
	if (!scope) {
		console.error("Scope is undefined in findFunction!");
		return undefined;
	}
	// id before name (!)
	if (id) {
		var found = Global.getFinder(scope).findByType(Metamodel.sysml.SysMLActivity, true)
			.and("typeCode", "function")
			.find("id", id);
		if (!found.isEmpty()) {
			// first() since 3.0.2
			return found.first();
		}
	}
	if (name) {
		found = Global.getFinder(scope).findByType(Metamodel.sysml.SysMLActivity, true)
			.and("typeCode", "function")
			.find("name", name);
		if (!found.isEmpty()) {
			// first() since 3.0.2
			return found.first();
		}
	}
	return undefined;
}

// helper
function findOrCreateFunction(scope, name, id) {
	var found = findFunction(scope, name, id);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.sysml.SysMLActivity);
	created.typeCode = "function";
	created.id = id ? id : AutoCounterSupport.createUniqueIDString(created, "id", "F-001");
	created.name = name;
	return created;
}

// helper
function findMalfunction(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in findMalfunction!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.Malfunction, true).find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}

	return undefined;
}

// helper
function findOrCreateMalfunction(scope, name) {
	var found = findMalfunction(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.safetyModel.Malfunction);
	created.name = name;
	return created;
}

// helper
function findHazard(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.Hazard, true).find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}

	return undefined;
}

// helper
function findOrCreateHazard(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in findOrCreate!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.Hazard, true).find("name", name);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.safetyModel.Hazard);
	created.name = name;
	return created;
}

// helper
function findOrCreateFailureMode(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in findOrCreate!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.FailureMode, true).find("name", name);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.safetyModel.FailureMode);
	created.name = name;
	return created;
}

// helper
function findOrCreateMeasure(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in findOrCreate!");
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetyModel.Measure, true).find("name", name);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.safetyModel.Measure);
	created.name = name;
	return created;
}

// helper
function findContainerPackage(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.sysml.SysMLContainerPackage, true).find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}
	
	return undefined;
}

// helper
function findOrCreateContainerPackage(scope, name) {
	var found = findContainerPackage(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.sysml.SysMLContainerPackage);
	created.name = name;
	return created;
}

// helper
function findPart(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.sysml.SysMLPart, true).find("name", name);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.asArray()[0];
	}
	
	return undefined;
}

// helper
function findOrCreatePart(scope, name) {
	var found = findPart(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.sysml.SysMLPart);
	created.name = name;
	return created;
}

// helper
function findGoal(scope, name, id) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
	}
	// id before name (!)
	if (id) {
		var found = Global.getFinder(scope).findByType(Metamodel.safetygoals.SafetyGoal, true).find("identifier", id);
		if (!found.isEmpty()) {
			// first() since 3.0.2
			return found.first();
		}
	}
	if (name) {
		found = Global.getFinder(scope).findByType(Metamodel.safetygoals.SafetyGoal, true).find("name", name);
		if (!found.isEmpty()) {
			// first() since 3.0.2
			return found.first();
		}
	}
	
	return undefined;
}

// helper
function findOrCreateGoal(scope, name, id) {
	var found = findGoal(scope, name, id);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.safetygoals.SafetyGoal);
	created.name = name;
	created.identifier = id;
	return created;
}

// helper
function findRequirement(scope, nameOrId) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
	}
	var found = Global.getFinder(scope).findByType(Metamodel.safetygoals.SafetyRequirement, true).find("name", nameOrId);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	// try again with ID
	found = Global.getFinder(scope).findByType(Metamodel.safetygoals.SafetyRequirement, true).find("identifier", nameOrId);
	if (!found.isEmpty()) {
		// first() since 3.0.2
		return found.first();
	}
	
	return undefined;
}

// helper
function findPackage(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
		return undefined;
	}
	var found = Global.getFinder(scope).findByType(Metamodel.projectmodel.PJPackage, true).find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}
	return undefined;
}

// helper
function findOrCreatePackage(scope, name) {
	var found = findPackage(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, Metamodel.projectmodel.PJPackage);
	created.name = name;
	return created;
}

// helper
function findVariable(scope, name) {
	if (!scope) {
		console.error("Scope is undefined in find method!");
		return undefined;
	}
	// only handle elements that may carry failure rate data
	if (!Metamodel.safetyModel.Failable.isInstance(scope)) {
		console.error("Scope is not a Failable but has to be!");
		return undefined;
	}
	// we can skip if elements has no failure rate data
	if (!scope.failureRateData) {
		return undefined;
	}
	
	// search for catalog variables first
	var found = Global.getFinder(scope.failureRateData.variables.toArray()).findByType("FRVariable").find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}

	// search for user variables next
	found = Global.getFinder(scope.failureRateData.userVariables.toArray()).findByType("FRVariable").find("name", name);
	if (!found.isEmpty()) {
		return found.first();
	}
	
	// give up
	return undefined;
}

// helper
function findOrCreateVariable(scope, name) {
	var found = findVariable(scope, name);
	if (found) {
		return found;
	}
	
	// create one
	var created = Factory.createElement(scope, "FRVariable");
	created.name = name;
//	created.description = description;
//	created.comment = comment;
//	created.value = value;
	return created;
}

function findTraces(project) {
	var traceSet = TraceController.INSTANCE.findTraceModel(project ? project : finder.project);
	return Global.getFinder(traceSet).findByType("Trace");
}