// INTEL CONFIDENTIAL
// Copyright 2017-2019 Intel Corporation All Rights Reserved.
// The source code contained or described herein and all documents related to the
// source code ("Material") are owned by Intel Corporation or its suppliers or
// licensors. Title to the Material remains with Intel Corporation or its
// suppliers and licensors. The Material may contain trade secrets and proprietary
// and confidential information of Intel Corporation and its suppliers and
// licensors, and is protected by worldwide copyright and trade secret laws and
// treaty provisions. No part of the Material may be used, copied, reproduced,
// modified, published, uploaded, posted, transmitted, distributed, or disclosed
// in any way without Intel's prior express written permission.
// No license under any patent, copyright, trade secret or other intellectual
// property right is granted to or conferred upon you by disclosure or delivery of
// the Materials, either expressly, by implication, inducement, estoppel or
// otherwise. Any license under such intellectual property rights must be express
// and approved by Intel in writing.
STAGES_STATUS_MAP = [:]

def getDockerEnvList(String projectName, String dockerContainerNamePrefix, String projectRoot = projectName) {
    /**
    * This method generates configuration map list using dockerfiles available in dockerfiles directory
    *
    * @param projectName name of the project used in paths and configuration map.
    * @param dockerContainerNamePrefix docker container name prefix.
    * @param projectRoot path to project root containing directory with dockerfiles to run
    */

    def rawList = findFiles(glob: "${projectRoot}/dockerfiles/*.dockerfile")
    def envList = []
    for (int i = 0; i < rawList.size(); ++i) {
        def name = rawList[i].name - '.dockerfile'
        def dockerContainerName = "${dockerContainerNamePrefix}_${name}"
        envList.add([name:name, // name is the only obligatory vaiable
                     dockerfilePath:rawList[i].path,
                     projectName:projectName,
                     dockerContainerName:dockerContainerName])
    }
    return envList
}

def generateMap(Closure method, configurationMaps) {
    /**
    * Generates map for method using configurationMaps.
    *
    * @param method Method that will be executed in each map(configuration).
    * @param configurationMaps Map of configuration that will be parallelized.
    */

    def executionMap = [:]
    for (int i = 0; i < configurationMaps.size(); ++i) {
        configMap = configurationMaps[i]
        executionMap[configMap["name"]] = {
            method(configMap)
        }
    }
    return executionMap
}

def createStage(String stageName, Closure method, configurationMaps, force = false) {
    /**
    * Create pipeline stage.
    *
    * @param stageName Name of stage that will be create.
    * @param method Method that will be executed in each map(configuration).
    * @param configurationMaps Map of configuration that will be parallelized.
    */

    stage(stageName) {
        // Add current stage name to configurationMaps
        for (int i = 0; i < configurationMaps.size(); ++i) {
            configurationMaps[i]["stageName"] = stageName
        }

        // Fail current stage If earlier stage got aborted or failed
        // unless it's executed with force argument set to true
        Closure genericBodyMethod = {}
        if (!force && ["FAILURE", "ABORTED"].contains(currentBuild.result)) {
            genericBodyMethod = { configMap ->
                println("Skipping stage due to earlier stage ${currentBuild.result}")
                setConfigurationStatus(configMap["stageName"], configMap["name"], currentBuild.result)
                throw new Exception("Skipped due to ${currentBuild.result} in earlier stage")
            }
        }
        else
        {
            genericBodyMethod = { configMap ->
                def status = "SUCCESS"
                try {
                    method(configMap)
                } catch(Exception e) {
                    if (e.toString().contains("FlowInterruptedException")) {
                        status = "ABORTED"
                    } else {
                        status = "FAILURE"
                    }
                    currentBuild.result = status
                    throw e
                } finally {
                    setConfigurationStatus(configMap["stageName"], configMap["name"], status)
                }
            }
        }

        try {
            def prepareEnvMap = generateMap(genericBodyMethod, configurationMaps)
            parallel prepareEnvMap
        } catch(Exception e) {
            if (e.toString().contains("FlowInterruptedException")) {
                currentBuild.result = "ABORTED"
            } else {
                currentBuild.result = "FAILURE"
            }
        }
    }
}

def setConfigurationStatus(String stageName, String configurationName, String status) {
    /**
    * Set stage status.
    *
    * @param stageName The name of the stage in which the configuration is.
    * @param configurationName The name of the configuration whose status will be updated.
    * @param status Configuration status: SUCCESS or FAILURE.
    */
    if (!STAGES_STATUS_MAP.containsKey(stageName)) {
        STAGES_STATUS_MAP[stageName] = [:]
    }
    if (["FAILURE", "SUCCESS", "ABORTED"].contains(status.toUpperCase())) {
        STAGES_STATUS_MAP[stageName][configurationName] = status.toUpperCase()
    } else {
        throw new Exception("Not supported status name.")
    }
}

def propagateStatus(String parentStageName, String parentConfigurationName) {
    /**
    * Popagate status in parent configuration fails.
    * This method will throw exeption "Propagating status of $parentStageName"
    * if parent configuration name status is FAILURE
    *
    * @param parentStageName The name of the stage in which the configuration is.
    * @param parentConfigurationName The name of the configuration whose status will be propagated.
    */

    parentStageStatus = STAGES_STATUS_MAP[parentStageName][parentConfigurationName]
    if (parentStageStatus == "FAILURE") {
        throw new Exception("Propagating status of ${parentStageName}")
    }
}

def showStatusMap() {
    /**
    * Display status map for every defined stage.
    */

    echo "${STAGES_STATUS_MAP}"
}

return this