/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Build
 * IBM UrbanCode Deploy
 * IBM UrbanCode Release
 * IBM AnthillPro
 * (c) Copyright IBM Corporation 2002, 2013 - 2016. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */

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 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'];
def overridePath = props['pathOverride'];
def profilePathResource = props['profilePathResource'];
def profilePathAgent = props['profilePathAgent'];
def agent = props['agent'];
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 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 = "";

        path = foundPath.substring(0, foundPath.lastIndexOf(File.separator)+1);
        apTool.setOutputProperty("roleName", roleName);
        apTool.setOutputProperty("websphere.commandPath", path);
        println "Found WebSphere install at " + path;
        tmpResourcePath = rootResourcePath + "/" + roleName;
        addResourcePath(resourcePathArr, path, tmpResourcePath); // add it to the array of resource paths
    }
    else {
        println "WebSphere installation not found. Ending discovery process.";
    }
}

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