import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.link.RemoteIssueLinkManager
import com.atlassian.jira.issue.link.RemoteIssueLink
import org.apache.log4j.Logger
import org.apache.log4j.Level

// Simple script that finds the stored remote links and calcuates some metrics
// This is a read-only operation so no concerns on running on projects
// It does analyze many artifacts, so timelines and space could be a concern
// On large repositories you may be selective on the projects it reviews

// classes

class constants {
	// OSLC App contstants
	static String oslcConnectApp = "com.sodius.oslc.app.jira"
	static String oslcConnectName = "Collaboration Link"
}

class unitMetrics {
	String unitName
	Integer linkCount = 0;
	Integer issueCount = 0;
	Set<String> missingRelationships = new HashSet<String>()
	static List<String> relationshipTypes = ['affected by defect',
										'affects plan item',
										'affects requirement',
										'implements requirement',
										'elaborated by architecture element',
										'related change request',
										'tracks requirement',
										'tracks change set',
										'affects test case result',
										'blocks test execution',
										'tested by test case',
										'related test case',
										'related test plan',
										'related test script',
										'related test execution',
										'contributes to',
										'tracks',
										'affected by change request',
										'blocked by change request',
										'related test case change',
										'related test execution record change',
										'related test plan change',
										'related test script change',
										'validates requirement collection',
										'validates requirement',
										'validates architecture element',
										'tests change request',
										'affects test result',
										'blocks test execution record', 
										'related test execution record']
	ArrayList<Integer> linkTypeCounter = new ArrayList<Integer>()
	unitMetrics(String unitName) {
		this.unitName = unitName;
		// Initialize the listTypeCounter
		for (int i= 0; i < relationshipTypes.size(); i++ ) {
			linkTypeCounter.add(0)
		}
	}
	def incRelationshipCounter( String relationship ) {
		int linkTypeIndex = relationshipTypes.indexOf(relationship)
		if ( linkTypeIndex >= 0 ) {
			int count = linkTypeCounter.get(linkTypeIndex) + 1
			linkTypeCounter.set(linkTypeIndex, count)
		} else {
			missingRelationships.add(relationship)
		}
	}
	def incLinkCount() {
		linkCount++;
	}
	def incIssueCount() {
		issueCount++;
	}
	def String toString() {
		return missingRelationships
	}

	def String toHtmlRow() {
		StringBuffer line = new StringBuffer()
		line.append("<tr>")
		line.append("<td>" + unitName + "</td>")
		line.append("<td>" + issueCount + "</td>")
		line.append("<td>" + linkCount + "</td>")
		for (int i=0; i<linkTypeCounter.size(); i++ ) {
			line.append( "<td>" + linkTypeCounter.get(i) + "</td>")
		}
		if (missingRelationships.size()>0) {
			line.append("<td>Missing Relationships in Script -> " + missingRelationships.toString() + " </td>")
		}
		line.append("</tr>")
		return line.toString()
	}
}


// Functions
def runQuery( String query , unitMetrics unit ) {
	try {
		Issues.search( query ).findAll { issue ->
			
			log.debug("Reviewing issue " + issue.getKey() )
			unit.incIssueCount()

			// Need to manage Remote Links
			def remoteIssueLinkManager = ComponentAccessor.getComponent(RemoteIssueLinkManager.class)

			// We need to iterate over the existing links and capture any needed metrics
			for (RemoteIssueLink existingLink in remoteIssueLinkManager.getRemoteIssueLinksForIssue( issue ) ) {
				if ( existingLink.getApplicationType() == constants.oslcConnectApp ) {
					log.debug('Link Id: ' + existingLink.getId() + " Url from/to: " + existingLink.getUrl() )
					unit.incLinkCount();
					unit.incRelationshipCounter( existingLink.getRelationship() )
				}	
			}
		}
	} catch (Exception e) {
		log.info("Issue performing query on " + unit.unitName + " with exception " + e.message )
	}
}

// Set the log level.  Test mode disables the creation but runs all the checks
log = Logger.getLogger("com.onresolve.scriptrunner.runner.ScriptRunnerImpl")

log.info( "Reviewing Projects for OSLC Links" )

// Logging and test mode
log.setLevel(Level.INFO)


// Set the local username to be used to access jira
def userName = "Administrator"
def user = ComponentAccessor.getUserManager().getUserByName(userName)


def List<unitMetrics> allMetrics = new ArrayList<unitMetrics>()

// Set the search query (if true, custom query, otherwise iterate over all projects)
def String query = ""
boolean customquery = false
if ( customquery ) {
	query = 'Project=RAD600' 
	if (!query.isEmpty() ) {
		// limit the scope of the query only to OSLC Links
		query = query + ' AND issueFunction in linkedIssuesOfRemote("application type", "' + constants.oslcConnectApp + '")'
		log.info(query)
		def unit = new unitMetrics( "Custom Query (" + query + ")")
		runQuery(query, unit)
		allMetrics.add(unit)
	} else {
		log.error("JQL Query not defined to a scope")
	}
} else {
	// Get a list of all projects
	def projectManager = ComponentAccessor.getProjectManager()
	def projects = projectManager.getProjectObjects()
	log.info("Reviewing " + projects.size() + " projects for OSLC Links.")
	log.info("Performing standard project by project query restricted by linkedissuesofremote")

	projects.each { project ->
		// Always filter by linkedIssuesOfRemote to reduce the number of objects to review
		query =  'project="' + project.key + '" AND issueFunction in linkedIssuesOfRemote("application type", "' + constants.oslcConnectApp + '")'
		if ( !project.isArchived() ) {
			log.debug(query)
			def unit = new unitMetrics( project.getKey() )
			runQuery(query, unit)
			if (unit.issueCount > 0 ) {
				allMetrics.add(unit)
			}
		}
	}	
	log.info("Found " + allMetrics.size() + " projects with OSLC Links.")
}


// Create a table output (can be copied int excel)
def StringBuffer output = new StringBuffer()

output.append("<table border=1>")
output.append("<tr>")
output.append("<th>Scope (Project or Query)</th><th>Issues With OSLC Links</th><th>Total OSLC Links</th>")
	for(int rel = 0; rel < unitMetrics.relationshipTypes.size(); rel++) {
	output.append("<th>" + unitMetrics.relationshipTypes.get(rel) + "</th>")
}
output.append("<tr>")
for (int i=0; i < allMetrics.size(); i++ ) {
	output.append( allMetrics.get(i).toHtmlRow() )
}
output.append("</table>")


return output.toString()
