/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* IBM UrbanCode Deploy
* IBM UrbanCode Release
* IBM AnthillPro
* (c) Copyright IBM Corporation 2002, 2013 - 2015. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*/
import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.json.JSONArray;
import com.urbancode.air.AirPluginTool;
import com.urbancode.air.plugin.websphere.WebSphereCmdLineHelper;

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

def weburl = System.getenv("AH_WEB_URL");
def user = apTool.getAuthTokenUsername();
def password = apTool.getAuthToken();
def rootResourcePath = props['resourcePath'];
def webSphereUser = props['wasuser'];
def webSpherePassword = props['waspassword'];
def profilePath = props['profilePath'];
def wsadminPath = props['commandPath'];
def wasPort = props['port'];
def wasHost = props['host'];
def wasConnType = props['connType'];
def resObjectString = props['fullResourceConfiguration'];
def resObjectInput = new JSONObject(resObjectString);
JSONObject roleProperties = resObjectInput.getJSONObject("roleProperties");
props["websphere.cell.configurationtypes"] = roleProperties.optString('websphere.cell.configurationtypes');
props["websphere.cell.enablebidi"] = roleProperties.optString('websphere.cell.enablebidi');
props["websphere.cell.cellregistered"] = roleProperties.optString('websphere.cell.cellregistered');
props["websphere.cell.shortname"] = roleProperties.optString('websphere.cell.shortname');
props["websphere.cell.biditextdirection"] = roleProperties.optString('websphere.cell.biditextdirection');
props["websphere.cell.celldiscoveryprotocol"] = roleProperties.optString('websphere.cell.celldiscoveryprotocol');
props["websphere.cell.celltype"] = roleProperties.optString('websphere.cell.celltype');
props["websphere.cell.discoveryaddressendpointname"] = roleProperties.optString('websphere.cell.discoveryaddressendpointname');
props["websphere.cell.multicastdiscoveryaddressendpointname"] = roleProperties.optString('websphere.cell.multicastdiscoveryaddressendpointname');


def WSDISC_HOME = System.getenv("PLUGIN_HOME");

//this code parses the json that represents a resource and creates the resources
def createOrUpdateResources = { data ->
    JSONObject cellObject = new JSONObject(data);
    String cellName = cellObject.getString("cell");
    String port = cellObject.getString("port");
    String connType = cellObject.getString("connType");
    String host = cellObject.getString("host");
    JSONArray nodeJSONs = cellObject.getJSONArray("nodes");
    JSONArray clusterJSONs = cellObject.getJSONArray("clusters");

    JSONArray portalJSONs = cellObject.getJSONArray("portalservers");

    nodes = [:];
    nodeHost = [:];
    nodeProfileName = [:];
    clusters = [:];

    portalservers = [:];

    for (int i = 0 ; i < nodeJSONs.length(); i++) {
        JSONObject node = nodeJSONs.getJSONObject(i);
        String nodeName = node.getString("node");
        nodes[nodeName] = [];
        nodeHost[nodeName] = node.getString("nodeHost");
        nodeProfileName[nodeName] = node.getString("nodeProfileName");
        JSONArray serverJSONs = node.getJSONArray("servers");

        for (int j = 0; j < serverJSONs.length(); j++) {
            JSONObject server = serverJSONs.get(j);
            if (server.has("was")) {
                nodes[nodeName] << ["type":"was", "name":server.getString("was")];
            }
            else if (server.has("portal")) {
                nodes[nodeName] << ["type":"portal", "name":server.getString("portal")];
            }
        }
    }

    for (int i =0 ; i < clusterJSONs.length(); i ++) {
        JSONObject cluster = clusterJSONs.getJSONObject(i);
        String clusterName = cluster.getString("cluster");
        clusters[clusterName] = [];

        JSONArray memberJSONs = cluster.getJSONArray("members");

        for (int j = 0 ; j < memberJSONs.length(); j++) {
            JSONObject member = memberJSONs.get(j);
            String nodeName =  member.getString("node");
            String memberName = member.getString("member");

            //nodes[nodeName].remove(memberName);

            clusters[clusterName] << ["node":nodeName, "member":memberName];
        }
    }

    for (int i =0 ; i < portalJSONs.length(); i ++) {
        JSONObject portal = portalJSONs.getJSONObject(i);
        String portalId = portal.getString("portalserver");
        portalservers[portalId] = [];

        JSONArray attrJSONs = portal.getJSONArray("attributes");

        for (int j = 0 ; j < attrJSONs.length(); j++) {
            JSONObject attr = attrJSONs.get(j);
            String serverName =  attr.getString("server_name");
            String portalHome = attr.getString("portal_home");
            String profileHome =  attr.getString("profile_home");
            String configPort = attr.getString("config_port");
            String serverHost = attr.getString("server_host");

            portalservers[portalId] << ["server_name":serverName, "portal_home":portalHome,
                                        "profile_home":profileHome, "config_port":configPort,
                                        "server_host":serverHost];
        }
    }


    def resArray = new JSONArray();
    def cellResource = new JSONObject();
    resArray.put(cellResource);

    def cellRoleProperties = new JSONObject();
    cellRoleProperties.put("websphere.cell", cellName);
    cellRoleProperties.put("websphere.port", port);
    cellRoleProperties.put("websphere.host", host);
    cellRoleProperties.put("websphere.profilePath", profilePath);
    cellRoleProperties.put("websphere.commandPath", wsadminPath);
    cellRoleProperties.put("websphere.user", webSphereUser);
    cellRoleProperties.put("websphere.password", webSpherePassword);
    cellRoleProperties.put("websphere.connType", connType);
    cellRoleProperties.put("websphere.cell.configurationtypes", props['websphere.cell.configurationtypes']);
    cellRoleProperties.put("websphere.cell.enablebidi", props['websphere.cell.enablebidi']);
    cellRoleProperties.put("websphere.cell.cellregistered", props['websphere.cell.cellregistered']);
    cellRoleProperties.put("websphere.cell.shortname", props['websphere.cell.shortname']);
    cellRoleProperties.put("websphere.cell.biditextdirection", props['websphere.cell.biditextdirection']);
    cellRoleProperties.put("websphere.cell.celldiscoveryprotocol", props['websphere.cell.celldiscoveryprotocol']);
    cellRoleProperties.put("websphere.cell.celltype", props['websphere.cell.celltype']);
    cellRoleProperties.put("websphere.cell.discoveryaddressendpointname", props['websphere.cell.discoveryaddressendpointname']);
    cellRoleProperties.put("websphere.cell.multicastdiscoveryaddressendpointname", props['websphere.cell.multicastdiscoveryaddressendpointname']);

    cellResource.put("path", "/${cellName}");
    cellResource.put("name", cellName);
    cellResource.put("roleName", "WebSphereCell");
    cellResource.put("roleProperties", cellRoleProperties);


    def nodesFolder = new JSONObject();
    nodesFolder.put("name", "Nodes");
    nodesFolder.put("path", "/${cellName}/Nodes");
    resArray.put(nodesFolder);

    def clustersFolder = new JSONObject();
    clustersFolder.put("name", "ServerClusters");
    clustersFolder.put("path", "/${cellName}/ServerClusters");
    resArray.put(clustersFolder);

    for (node in nodes) {
        println "Adding node: " + node.key.toString() + " with hostname: " + nodeHost[node.key] + " and profilename: " + nodeProfileName[node.key];

        def nodeResource =new JSONObject();
        nodeResource.put("name", node.key);
        nodeResource.put("path", "/${cellName}/Nodes/${node.key}");
        nodeResource.put("roleName", "WebSphereNode");

        def nodeRoleProperties = new JSONObject();
        nodeRoleProperties.put("websphere.node", node.key);
        nodeRoleProperties.put("websphere.node.hostname", nodeHost[node.key]);
        nodeRoleProperties.put("websphere.node.profilename", nodeProfileName[node.key]);
        nodeResource.put("roleProperties", nodeRoleProperties);

        resArray.put(nodeResource);

        def serversFolder = new JSONObject();
        serversFolder.put("name", "Servers");
        serversFolder.put("path", "/${cellName}/Nodes/${node.key}/Servers");

        def portalServersFolder = new JSONObject();
        portalServersFolder.put("name", "Portal Servers");
        portalServersFolder.put("path", "/${cellName}/Nodes/${node.key}/Portal Servers");

        resArray.put(serversFolder);
        resArray.put(portalServersFolder);

        for (server in node.value) {
            println "Adding server: " + server.get("name");
            def type = server.get("type");
            switch (type) {
                case "was":
                    def serverResource = new JSONObject();

                    def servername = server.get("name");
                    serverResource.put("name", servername);
                    serverResource.put("roleName", "WebSphereServer");
                    serverResource.put("path", "/${cellName}/Nodes/${node.key}/Servers/${servername}");

                    def serverRoleProperties = new JSONObject();
                    serverResource.put("roleProperties", serverRoleProperties);
                    serverRoleProperties.put("websphere.server", servername);

                    resArray.put(serverResource);
                    break;
                case "portal":
                    def portalIndex = server.get("name");
                    JSONObject portalAttrs = portalservers.get(portalIndex);
                    def servername = portalAttrs.get("server_name");
                    def portalHome = portalAttrs.get("portal_home");
                    def profileHome = portalAttrs.get("profile_home");
                    def configPort = portalAttrs.get("config_port");
                    def serverHost = portalAttrs.get("server_host");

                    def serverResource = new JSONObject();
                    def serverRoleProperties = new JSONObject();
                    serverResource.put("roleProperties", serverRoleProperties);

                    serverResource.put("name", servername);
                    serverResource.put("path", "/${cellName}/Nodes/${node.key}/Servers/${servername}");
                    serverResource.put("roleName", "WebSphereServer");

                    serverRoleProperties.put("websphere.server", servername);
                    resArray.put(serverResource);

                    def portalResource = new JSONObject();
                    def portalRoleProperties = new JSONObject();
                    portalResource.put("roleProperties", portalRoleProperties);

                    portalResource.put("name", "${servername}(Portal)");
                    portalResource.put("path", "/${cellName}/Nodes/${node.key}/Portal Servers/${servername}(Portal)");
                    portalResource.put("roleName", "PortalServer");

                    portalRoleProperties.put("websphere.server", servername);
                    portalRoleProperties.put("portal.host",serverHost);
                    portalRoleProperties.put("portal.home", portalHome);
                    portalRoleProperties.put("portal.profile.home", profileHome);
                    portalRoleProperties.put("portal.admin.user", "");
                    portalRoleProperties.put("portal.admin.password", "");
                    portalRoleProperties.put("portal.config.port", configPort);
                    portalRoleProperties.put("websphere.password", webSpherePassword);

                    resArray.put(portalResource);
                    break;
            }
        }
    }

    for (cluster in clusters) {
        def clusterResourceName = cluster.key.toString();
        println "Adding cluster: " + clusterResourceName;

        def clusterResource = new JSONObject();
        def clusterRoleProperties = new JSONObject();
        clusterResource.put("roleProperties", clusterRoleProperties);

        clusterResource.put("name", clusterResourceName);
        clusterResource.put("path", "/${cellName}/ServerClusters/${clusterResourceName}");
        clusterResource.put("roleName", "WebSphereCluster");

        clusterRoleProperties.put("websphere.cluster", clusterResourceName);

        resArray.put(clusterResource);
    }

    String reses = resArray.toString();
    println reses
    apTool.setOutputProperty("websphere.cell", cellName);
    apTool.setOutputProperty("resources", reses);
    apTool.setOutputProperties();

}


def getDataFromWsadmin = {
    def wsadminExe = wsadminPath;

    while (wsadminExe.endsWith(File.separator)) {
        wsadminExe = wsadminExe.substring(0, wsadminExe.length()-1);
    }

    wsadminExe = wsadminExe + File.separator + WebSphereCmdLineHelper.getWSADMINValue();

    def cmdArgs = [wsadminExe];

    if (wasHost?.trim() && !wasHost.startsWith("p:")) {
        cmdArgs << "-host";
        cmdArgs << wasHost.trim();
    }

    if (wasPort?.trim() && !wasPort.startsWith("p:")) {
        cmdArgs << "-port";
        cmdArgs << wasPort.trim();
    }

    if (wasConnType?.trim() && !wasConnType.startsWith("p:")) {
        cmdArgs << "-conntype";
        cmdArgs << wasConnType.trim();
    }

    if ( webSphereUser?.trim() && !webSphereUser.trim().startsWith("p:")) {
        println "Using credentials";
        cmdArgs << "-user" << webSphereUser << "-password" << webSpherePassword;
    }

    cmdArgs << "-f" << "${WSDISC_HOME}/jythonScripts/discover.py";

    Process proc = cmdArgs.execute();
    proc.out.close();
    OutputStream oStream = new ByteArrayOutputStream();
    OutputStream eStream = new ByteArrayOutputStream();
    proc.waitForProcessOutput(oStream, eStream);
    String output = oStream.toString();
    String errorOutput = eStream.toString();
    
    println output;
    println errorOutput;

    //if output does not contain "{" then Topology JSON was not returned
    //and instead an error was returned
    if (output.contains("{")) {
        int start = output.indexOf("{");
        output = output.substring(start-1, output.length());
    } else {
        throw new RuntimeException("Did not receive WAS Topology JSON from server. Discovery stopped.");
    }

    return output;
}

def data = getDataFromWsadmin();

createOrUpdateResources(data);

