#!/usr/bin/env groovy
/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Release
 * (c) Copyright IBM Corporation 2015, 2017. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */

import com.urbancode.air.AirPluginTool
import com.urbancode.air.plugin.tfs.MappingBoxMapper
import com.urbancode.air.plugin.tfs.TFSFactory

import com.urbancode.release.rest.framework.Clients
import com.urbancode.release.rest.models.Application
import com.urbancode.release.rest.models.Change
import com.urbancode.release.rest.models.Change.Status
import com.urbancode.release.rest.models.ChangeType
import com.urbancode.release.rest.models.Initiative
import com.urbancode.release.rest.models.internal.IntegrationProvider
import com.urbancode.release.rest.models.internal.Lifecycle
import com.urbancode.release.rest.models.internal.PluginIntegrationProvider
import com.urbancode.release.rest.models.Release
import com.urbancode.release.rest.models.Team

import com.microsoft.tfs.core.clients.workitem.fields.*
import com.microsoft.tfs.core.clients.workitem.project.Project
import com.microsoft.tfs.core.clients.workitem.query.WorkItemCollection
import com.microsoft.tfs.core.clients.workitem.WorkItem
import com.microsoft.tfs.core.clients.workitem.WorkItemClient
import com.microsoft.tfs.core.httpclient.UsernamePasswordCredentials
import com.microsoft.tfs.core.TFSTeamProjectCollection

def currentDirectory = new File(getClass().protectionDomain.codeSource.location.path).parent
System.setProperty('com.microsoft.tfs.jni.native.base-directory', currentDirectory + '/lib/native')

def apTool = new AirPluginTool(this.args[0], this.args[1])
def props = apTool.getStepProperties()

def integration = new Integration(props)
integration.runIntegration()

public class Integration {
    Integer changesAdded = 0
    Integer changesUpdated = 0
    MappingBoxMapper applicationMap
    MappingBoxMapper initiativeMap
    MappingBoxMapper releaseMap
    MappingBoxMapper statusMap
    MappingBoxMapper typeMap
    def pluginProviderId
    TFSTeamProjectCollection tfsCollection

    // Main constructor
    Integration (props) {
        def releaseToken = props['releaseToken']
        def serverUrl = props['releaseServerUrl']
        Clients.loginWithToken(serverUrl, releaseToken)

        String tfsUrl = props['tfsUrl'].trim()
        String tfsUserName = props['tfsUserName'].trim()
        String tfsPassword = props['tfsPassword']
        String tfsCollectionName = props['tfsCollectionName'].trim()

        pluginProviderId = props['releaseIntegrationProvider']

        this.tfsCollection = TFSFactory.createTFSCollection(tfsCollectionName, tfsPassword, tfsUrl, tfsUserName)

        this.releaseMap = new MappingBoxMapper(props['mappingRelease'],'releaseReleaseName','tfsIterationName')
        this.applicationMap = new MappingBoxMapper(props['mappingApplication'],'releaseApplicationName','tfsProjectName')
        this.typeMap = new MappingBoxMapper(props['mappingType'],'releaseTypeName','tfsTypeName')
        this.statusMap = new MappingBoxMapper(props['mappingStatus'],'releaseStatusName','tfsStatusName')
        this.initiativeMap = new MappingBoxMapper(props['mappingInitiative'],'releaseInitiativeName','tfsValueAreaName')
    }

    //--------------------------------------------------------------
    def runIntegration () {
        def provider = new PluginIntegrationProvider().id(pluginProviderId).get()
        provider.disabledFields('change', 'type', 'name', 'status', 'release', 'application', 'description', 'severity', 'initiative').save()

        def workItemClient = tfsCollection.getWorkItemClient()

        def integrationProvider = new IntegrationProvider().id(pluginProviderId)
        def existingChanges = new Change().getAllForIntegrationProvider(pluginProviderId)

        // Map of ucr changes from this IP by external ID.
        def changeMap = new HashMap<String, Change>()
        existingChanges.each {
            changeMap.put(it.getExternalId(), it)
        }

        def workItems = workItemClient.query('SELECT [System.Id],[System.WorkItemType],[System.Title],[System.AssignedTo],[System.State],[System.Tags], [Microsoft.VSTS.Common.ValueArea],[System.IterationPath],[System.TeamProject] FROM WorkItems')

        ChangeType changeType
        def application
        def applicationID
        def change
        def field
        def fieldsIterator
        def initiative
        def initiativeId
        def iterationID
        def release
        def releaseId
        def status
        def typeId
        def workItem
        int workItemsSize = workItems.size()
        Status changeStatus
        String workItemID

        for (int i = 0; i < workItemsSize; i++) {
            workItem = workItems.getWorkItem(i)
            workItemID = workItem.getID().toString()

            // if the change exists use the existing one
            change = changeMap.get(workItemID)
            if (change) {
                changesUpdated++
            }
            else {
                change = new Change().integrationProvider(integrationProvider).setExternalId(workItem.getID().toString())
                changesAdded++
            }
            change.name(workItem.getTitle())

            //update the change and save
            typeId = typeMap.getMapping(workItem.getType().getName().toString())
            changeType = new ChangeType().id(typeId)
            change = change.type(changeType)

            releaseId = releaseMap.getMapping(workItem.getFields().getField('Iteration ID').getValue().toString())
            release = new Release().id(releaseId)
            change.release(release)

            status = statusMap.getMapping(workItem.getFields().getField('State').getValue())
            if (!status.equals('NONE_VALUE')) {
                changeStatus = Status.valueOf(status.replaceAll(' ', '_').toUpperCase())
                change.status(changeStatus)
            }

            initiativeId = initiativeMap.getMapping(workItem.getFields().getField('Value Area').getValue())
            initiative = new Initiative().id(initiativeId)
            change.initiative(initiative)

            applicationID = applicationMap.getMapping(workItem.getFields().getField('Team Project').getValue().toString())
            application = new Application().id(applicationID)
            change.application(application)

            //Here we build a basic HTML representation of the change by iterating through available fields
            def description = "<ul>";

            for (Field fieldDefinition : workItem.getFields()) {
                def name = fieldDefinition.getName();
                def value = fieldDefinition.getValue().toString();

                if (value != null && value != "null") {
                    description+= "<li><span style='font-size: 13px;color: black;'><b>${name}</b></span>: ${value}</li>"
                }
            }

            description+= "</ul>"
            change.description(description)

            change.save()
        }
        println(changesAdded + ' changes added.')
        println(changesUpdated + ' changes updated.')
        tfsCollection.close()
    }
}
