/*
* Licensed Materials - Property of IBM* and/or HCL**
* UrbanCode Deploy
* (c) Copyright IBM Corporation 2002-2017. All Rights Reserved.
* (c) Copyright HCL Technologies Ltd. 2018. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*
* * Trademark of International Business Machines
* ** Trademark of HCL Technologies Limited
*/

import java.util.Map;
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.json.JSONArray;

import com.urbancode.air.AirPluginTool;

import groovy.io.FileType
import groovy.util.XmlParser;
import com.urbancode.ud.client.UDRestClient;
import com.urbancode.ud.client.ResourceClient;

import com.urbancode.air.XTrustProvider;

import com.urbancode.air.plugin.websphere.WebSphereCmdLineHelper;

XTrustProvider.install();

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

def MAX_RETRIES         = 3;

def weburl              = System.getenv("AH_WEB_URL");
def user                = apTool.getAuthTokenUsername();
def password            = apTool.getAuthToken();
def finalURI            = new URI(weburl);
def udClient            = new ResourceClient(finalURI, user, password);

def rootResourcePath    = props['resourcePath'].trim();
def overridePath        = props['pathOverride'].trim();
def profilePathResource = props['profilePathResource'].trim();
def profilePathAgent    = props['profilePathAgent'].trim();
def roleName            = "WebSphereCell";

// Setup variables
def wsadminPath         = File.separator + "bin" + File.separator + WebSphereCmdLineHelper.getWSADMINValue();
def portdefsPath        = File.separator + "properties" + File.separator + "portdef.props";

def getOrCreateSubResource = { resourcePath, parentUUID, description ->
    def resourceName = resourcePath.substring(resourcePath.lastIndexOf("/") + 1);
    def resource = null;
    def tries = 0;
    def done = false;
    while (!done && tries < MAX_RETRIES) {
        try {
            try {
                resource = udClient.getResourceByPath(resourcePath);
            }
            catch (IOException e) {
                //resource does not exist(i hope)
                resource = null;
            }
            if (resource == null) {
                def nodeId = udClient.createSubResource(parentUUID, resourceName, description);
                resource = udClient.getResourceByPath(resourcePath);
            }
            done = true;
        }
        catch (IOException e) {
            tries++;
            done = false;
            println("Got IOException in getOrCreateSubResource for ${resourcePath}");
            if (tries < MAX_RETRIES) {
                println ("Retrying...")
            }
            else {
                throw e;
            }
        }
    }

    return UUID.fromString(resource.getString("id"));
}

def addRoleToResource = { resource, role, properties ->
    def tries = 0;
    def done = false;
    while (!done && tries < MAX_RETRIES) {
        try {
            udClient.setRoleOnResource(resource.toString(), role, properties);
            done = true;
        } catch (IOException e) {
            tries++;
            done = false;
            println("Got IOException in addRoleToResource for ${resource}");
            if (tries < MAX_RETRIES) {
                println ("Retrying...")
            } else {
                throw e;
            }
        }
    }
}


def createProfileResource = { path ->
    println "";
    println "Processing: " + path;
    // clean up string if necessary
    if (path.endsWith(wsadminPath)) {
        path = path.replace(wsadminPath, "");
    }

    File file = new File(path);
    path = file.getAbsolutePath();
    // Check that the path exists
    if (!file.exists()) {
        println "Path does not exist...";
        return;
    }
    // check that wsadmin script exists
    File wsadmin = new File(path + wsadminPath);
    if (!file.exists()) {
        println "wsadmin script does not exist in the path...";
        return;
    }

    // check that portdef.propertiesexists
    File portdef = new File(path + portdefsPath);
    if (!portdef.exists()) {
        println "Path does not contain a base or ND profile..."
        return;
    }

    // get the SOAP port
    Properties portDefProps = new Properties();
    portDefProps.load(portdef.newDataInputStream());
    def soapPort = portDefProps.getProperty("SOAP_CONNECTOR_ADDRESS");

    println("Found WebSphere profile");
    println("SOAP port: " + soapPort);

    def cellProps = new HashMap<String, String>();

    File profileBin = new File(path + File.separator + "bin");
    def commandPath = profileBin.getAbsolutePath();
    cellProps.put("websphere.commandPath", commandPath + File.separator);
    cellProps.put("websphere.profilePath", path);
    cellProps.put("websphere.port", soapPort);

    // Do the creation in the server
    def rootResource = udClient.getResourceByPath(rootResourcePath);
    def rootResourceIdString = rootResource.getString("id");
    def rootResourceId = UUID.fromString(rootResourceIdString);

    def profileName = path.substring(path.lastIndexOf(File.separator) + 1);
    def resourcePath = rootResource.path + "/WebSphereCell - " + profileName;
    def description = "WebSphere Application Server cell for profile " + profileName;

    def cellResource = getOrCreateSubResource(resourcePath, rootResourceId, description);
    addRoleToResource(cellResource, "WebSphereCell", cellProps);

    // Return the resource path of the resource created for the given path parameter.
    return resourcePath;
}

def addResourcePath = { JSONArray resourcePathJsonArr, String profilePath, String resourcePath ->
    // If a resource was created, add it to the array of resource paths
    if (resourcePath != null && !resourcePath.isEmpty()) {
        if (profilePath == null) {
            profilePath = "";
        }
        JSONObject resourcePair = new JSONObject();
        resourcePair.put("profilePath", profilePath);
        resourcePair.put("resourcePath", resourcePath);
        resourcePathJsonArr.put(resourcePair);
    }
}

def loadProfileRegistry = { String inputPath ->
    def profilePaths = [];

    if (apTool.isWindows && inputPath.indexOf("bin\\wsadmin.bat")>0) {
        inputPath = inputPath.substring(0,inputPath.indexOf("bin\\wsadmin.bat")-1);
    }
    else if(inputPath.indexOf("bin/wsadmin.sh")>0){
        inputPath = inputPath.substring(0,inputPath.indexOf("bin/wsadmin.sh")-1);
    }

    def profileRegistryPath = inputPath +  File.separator +"properties" + File.separator + "profileRegistry.xml";

    println "Loading Profile Registry from path: "+profileRegistryPath;
    File profileRegistryFile = new File(profileRegistryPath);
    if (profileRegistryFile.exists() && profileRegistryFile.isFile()){
        def profiles = new XmlParser().parse(profileRegistryFile);
        profiles.'profile'.each {
            println "Profile Path: " + it.@'path';
            profilePaths.add(it.@'path');
        }
    }
    else {
        println "Profile registry not found at path: " + profileRegistryPath;
        println "Checking if this is a local profile directory: " + inputPath;
        def portDefsPath = inputPath +  File.separator +"properties" + File.separator + "portdef.props";
        File portDefsFile = new File(portDefsPath);
        if (portDefsFile.exists() && portDefsFile.isFile()){
            println "Profile Path: " + inputPath;
            profilePaths.add(inputPath);
        }
        else {
            println "No file found: " + portDefsFile;
        }
    }

    return profilePaths;
}

def paths = [];
def tmpResourcePath = "";
def tmpProfilePath = "";
JSONArray resourcePathArr = new JSONArray();

if (profilePathResource != null && profilePathResource != "" && profilePathResource != '${p:resource/websphere.profilePath}') {
    paths.addAll(profilePathResource.tokenize(','));
}
if (profilePathAgent != null && profilePathAgent != "" && profilePathAgent != '${p:agent/websphere.profilePath}') {
    paths.addAll(profilePathAgent.tokenize(','));
}
if (paths.size() > 0) {
    // First check the profile paths from the resource. This should come from the top-level resource group, or the agent, property websphere.profilePath
    // It can be in the form of:
    // Single path - <path1>
    // Comma separated list - <path1>,<path2>,<path3>,<pathN>
    // Root profile path - <pathRoot1> (containing multiple profiles)
    // Combination - <pathRoot1>,<path2>,...<pathRootN>

    for (path in paths) {
        if (path.contains(wsadminPath)) {
            // path including wsadmin script
            tmpResourcePath = createProfileResource(path);
            addResourcePath(resourcePathArr, path, tmpResourcePath); // add it to the array of resource paths
        } else if (!new File(path + wsadminPath).exists()) {
            // Root profile path, so grab all base/dmgr profiles
            def profileRoot = new File(path);
            if (profileRoot.exists() && profileRoot.isDirectory()) {
                profileRoot.eachFile(FileType.DIRECTORIES) { file ->
                    tmpProfilePath = file.getAbsolutePath();
                    tmpResourcePath = createProfileResource(tmpProfilePath);
                    addResourcePath(resourcePathArr, tmpProfilePath, tmpResourcePath); // add it to the array of resource paths
                }
            } else {
                println "";
                println "Path is not a valid profile root: " + path;
            }
        } else {
            // Fully qualified profile path
            tmpResourcePath = createProfileResource(path);
            addResourcePath(resourcePathArr, path, tmpResourcePath); // add it to the array of resource paths
        }
    }
} else {
    // If there is no profile path from the resource, check the agent override, so we can still pick up one path
    // If there is no agent override, use the default path as normal
    def standardInstallPath = [];
    if (overridePath != null && overridePath != "" && overridePath != '${p:agent/wsadmin.path}') {
        if (!overridePath.endsWith(wsadminPath)) {
            overridePath += wsadminPath;
        }
        standardInstallPath << overridePath;
    }
    else if (apTool.isWindows) {
        standardInstallPath << "C:" + File.separator + "Program Files" + File.separator + "IBM" + File.separator + "WebSphere" + File.separator + "AppServer" + File.separator + "bin" + File.separator + "wsadmin.bat";
        standardInstallPath << "C:" + File.separator + "IBM" + File.separator + "WebSphere" + File.separator + "AppServer" + File.separator + "bin" + File.separator + "wsadmin.bat";
    }
    else {
        standardInstallPath << "/opt/IBM/WebSphere/AppServer/bin/wsadmin.sh";
    }

    def foundPath = "";
    for (path in standardInstallPath) {
        File file = new File(path);
        println "Checking path for WebSphere install: " + path;
        if (file.exists()) {
            foundPath = file.getAbsolutePath();
            break;
        }
    }

    if (foundPath) {
        def path = "";

        println "No profiles in input; searching for Profile Registry based on installation path: "+foundPath;
        def discoveredprofilePaths = loadProfileRegistry(foundPath);
        discoveredprofilePaths.each {
            tmpResourcePath = createProfileResource(it);
            addResourcePath(resourcePathArr, it, tmpResourcePath);
        }
    }
    else {
        println "WebSphere installation not found. Ending discovery process.";
    }
}

apTool.setOutputProperty("createdResources", resourcePathArr.toString());
apTool.setOutputProperties();
