import java.io.File;

import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
import groovy.io.FileType

import com.urbancode.air.AirPluginTool;

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

def outputDirString = props['outputDir'].trim();
def serverName = props['serverName'].trim();
def clusterName = props['clusterName'].trim();
def nodeName = props['nodeName'].trim();
def discoveryRunOnServer = props['discoveryRunOnServer'].trim();
def configFile = props['configFile'].trim();
def cellName = props['cellName'].trim();
def nodeHostName = props['nodeHostName'].trim();
def userDefinedTokenization = props['userDefinedTokenization'].trim();
def startTokenDelimiter = props['startTokenDelimiter'].trim();
def endTokenDelimiter = props['endTokenDelimiter'].trim();

// make sure the working directory ends with /
lastCarOfWorkingDir = outputDirString.substring(outputDirString.length() - 1)
if (lastCarOfWorkingDir != "/" && lastCarOfWorkingDir != "\\") {
  outputDirString = outputDirString + File.separator
}

if (discoveryRunOnServer == "false") {
  // the extracted directory
  extractedDirString = outputDirString + "extracted" + File.separator

  // the templates directory
  templateDirString = outputDirString + "templates" + File.separator
  templateDir = new File(templateDirString)
  if (!templateDir.exists()) {
    templateDir.mkdirs()
  }

  // verify cluster directory exists.  if it doesn't, the node probably wasn't templatized
  newClusterDirString = templateDirString + "Cluster-" + clusterName
  newClusterDir = new File(newClusterDirString)
  if (!newClusterDir.exists()) {
    throw new Exception("Trying to templatize a server for cluster " + clusterName  +
                        ", however " + clusterName + " does not exist in " + newClusterDirString +
                        ". Did you templatize " + clusterName + "?")
  }

  // get the cell name
  cellDirString = extractedDirString + "Cell" + File.separator + "cell" + File.separator + "Cell.json"
  cellJson = new File(cellDirString)
  cellName = getRolePropertyValueFromFile(cellJson, "websphere.cell")

  // copy the Server.json and directories to template directory
  sourceServerDirString = extractedDirString + "Node-" + nodeName + File.separator + "node" + File.separator + "Server-" + serverName
  sourceServerDir = new File(sourceServerDirString)
  if (!sourceServerDir.exists()) {
    throw new Exception("You chose to templatize a server named " + serverName + " of node " +
                        nodeName + ". I'm looking for it under " + sourceServerDirString +
                        " but can't find it.  Did you enter the correct server name and node name values?  Did you run the extract script?")
  }
  destServerDirString = templateDirString +  "Cluster-" + clusterName + File.separator + "ServerTemplate"
  destServerDir = new File(destServerDirString)
  if (destServerDir.exists()) {
    destServerDir.deleteDir()
  }
  new AntBuilder().copy( todir: destServerDirString ) {
    fileset( dir: sourceServerDirString )
  }

  // rename Server.json to servertemplate.json
  println "Renaming file servertemplate.json..."
  serverFileString = destServerDirString + File.separator + "servertemplate.json"
  serverFile = new File(destServerDirString + File.separator + "Server.json")
  serverFile.renameTo(new File(serverFileString))

  // get the host name
  nodeJson = new File(extractedDirString + "Node-" + nodeName + File.separator + "node" + File.separator + "Node.json")
  nodeHostName = getRolePropertyValueFromFile(nodeJson, "websphere.node.hostname")
  println "nodeHostName to tokenize: " + nodeHostName

} else {
  println "Discovery was run on a server only..."
  // discovery was run on the server only, so we need a config file, cell name, and node host name
  if (configFile == "") {
    throw new RuntimeException("Error: No config file was specifed. A config file is required when discovery was run on a server only.");
  }
  if (cellName == "") {
    throw new RuntimeException("Error: No cell name was specifed. A cell name is required when discovery was run on a server only.");
  }
  if (nodeHostName == "") {
    throw new RuntimeException("Error: No node host name was specifed. A node host name is required when discovery was run on a server only.");
  }
  // the output directory
  outputDir = new File(outputDirString + File.separator + "ServerTemplate")
  if (!outputDir.exists()) {
    outputDir.mkdirs()
  }
  // copy the Server.json and directories to template directory
  serverFileString = outputDirString + "ServerTemplate" + File.separator + "servertemplate.json"
  serverFile = new File(serverFileString)
  if (serverFile.exists()) {
    println "Deleting old copy of " + serverFileString
    serverFile.delete()
  }
  println "Copying the file from " + configFile + " to " + serverFileString
  new File(serverFileString) << new File(configFile).text
}

// tokenize cell name, node name, and host name for Server.json
println "Tokenizing values for " + serverFile + "..."
serverFile = new File(serverFileString)

if (discoveryRunOnServer == "true") {
  fixPaths(serverFile, serverName, startTokenDelimiter, endTokenDelimiter)
  serverFile = new File(serverFileString)
}
String serverFileContents = serverFile.getText('UTF-8')
serverFileContents = serverFileContents.replace(clusterName + "/Servers/", "" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/")
serverFileContents = serverFileContents.replace("/Nodes/" + nodeName + "/Servers/", "/Nodes/" + startTokenDelimiter + "websphere.node" + endTokenDelimiter + "/Servers/")
serverFileContents = serverFileContents.replace("(node):" + nodeName, "(node):" + startTokenDelimiter + "websphere.node" + endTokenDelimiter + "")
serverFileContents = serverFileContents.replace("/" + cellName + "/", "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/")
serverFileContents = serverFileContents.replace("(cell):" + cellName, "(cell):" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "")
serverFileContents = serverFileContents.replace(serverName, "ServerTemplate")
serverFile.delete()
new File(serverFile.getParent()+"/"+serverFile.getName()).write(serverFileContents, 'UTF-8')
serverFile = new File(serverFileString)
tokenizeRolePropertyValues(serverFile, nodeHostName, startTokenDelimiter + "websphere.node.hostname" + endTokenDelimiter)

// just to be safe, tokenize anything we may have missed
serverFile = new File(serverFileString)
serverFileContents = serverFile.getText('UTF-8')
serverFileContents = serverFileContents.replace(clusterName, startTokenDelimiter + "websphere.cluster" + endTokenDelimiter)
serverFileContents = serverFileContents.replace(nodeName, startTokenDelimiter + "websphere.node" + endTokenDelimiter)
serverFileContents = serverFileContents.replace(cellName, startTokenDelimiter + "websphere.cell" + endTokenDelimiter)

// changing the paths to be server clusters instead of nodes
serverFileContents = serverFileContents.replace("/Nodes/" + startTokenDelimiter + "websphere.node" + endTokenDelimiter + "/", "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/")
serverFile.delete()
new File(serverFile.getParent()+"/"+serverFile.getName()).write(serverFileContents, 'UTF-8')

// find and tokenize the profile name, if there is one.
serverFile = new File(serverFileString)
tokenizeProfileName(serverFile, startTokenDelimiter, endTokenDelimiter)

// update SSLConfigGroup paths
println "Updating SSLConfigGroup paths, if needed..."
serverFile = new File(serverFileString)
updateSSLConfigGroupPaths(serverFile, startTokenDelimiter, endTokenDelimiter)

// remove Server Entries
println "Removing Server Entry resources, if needed..."
serverFile = new File(serverFileString)
removeResourcesUnderPath(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate/Server Entries")

// remove WebSphereEndPoints
println "Removing WebSphereEndPoint resources, if needed..."
serverFile = new File(serverFileString)
removeResourcesByType(serverFile, "WebSphereEndPoint")

// remove End Points
println "Removing resources named End Points, if needed..."
serverFile = new File(serverFileString)
removeResourcesByName(serverFile, "End Points")

// add server count roleProperty
println "Adding server count roleProperty..."
serverFile = new File(serverFileString)
addRolePropertyToResource(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate", "websphere.server.servercount", startTokenDelimiter + "SERVER_COUNT" + endTokenDelimiter)

// add node list roleProperty
println "Adding node list roleProperty..."
serverFile = new File(serverFileString)
addRolePropertyToResource(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate", "websphere.server.nodelist", startTokenDelimiter + "NODELIST" + endTokenDelimiter)

// add endpoint port mappings roleProperty
println "Adding endpoint port mappings roleProperty..."
serverFile = new File(serverFileString)
addRolePropertyToResource(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate", "websphere.server.endpointportmappings", startTokenDelimiter + "ENDPOINTPORTMAPPINGS" + endTokenDelimiter)

// add server name format roleProperty
println "Adding server name format roleProperty..."
serverFile = new File(serverFileString)
addRolePropertyToResource(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate", "websphere.server.servernameformats", startTokenDelimiter + "SERVERNAMEFORMATS" + endTokenDelimiter)

// add start token delimiter roleProperty
println "Adding start token delimiter roleProperty..."
serverFile = new File(serverFileString)
addRolePropertyToResource(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate", "websphere.server.starttokendelimiter", startTokenDelimiter)

// add end token delimiter roleProperty
println "Adding end token delimiter roleProperty..."
serverFile = new File(serverFileString)
addRolePropertyToResource(serverFile, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate", "websphere.server.endtokendelimiter", endTokenDelimiter)

// add simple resource
println "Adding a simple resource..."
serverFile = new File(serverFileString)
addSimpleResource(serverFile, "Servers", "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers")

// tokenize user defined values
serverFile = new File(serverFileString)
doUserDefinedTokenization(serverFile, userDefinedTokenization)

// remove brackets
serverFile = new File(serverFileString)
removeBracketsFromJson(serverFile)

// fix double quotes
serverFile = new File(serverFileString)
fixDoubleQuotes(serverFile)




// method to fix "" saving as "\"\""
void fixDoubleQuotes(File file) {
  String fileContents = file.getText('UTF-8')
  fileContents = fileContents.replace("\"\\\"\\\"\"", "\"\"")
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
}

// method to add a simple resource
void addSimpleResource(File file, String resourceName, String path) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  //def newArrayObj = []
  addSimpleResource = true
  list.each {
    if (it.path == path){
      println "*** Warning *** tried to add a simple resource but a resource already exists with path " + path
	  addSimpleResource = false
    }
  }

  if (addSimpleResource) {
	parsedValue = new JsonSlurper().parseText("{\"name\": \"" + resourceName + "\", \"path\": \"" + path + "\"}")
	list.push(parsedValue)
	contents = new JsonBuilder(list).toPrettyString()
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(contents, 'UTF-8')
  }
}

// method to remove resources by name
void removeResourcesByName(File file, String resourceName) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  def newArrayObj = []
  list.each {
    if (it.name != resourceName){
      newArrayObj.push(it)
    }
  }

  contents = new JsonBuilder(newArrayObj).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(contents, 'UTF-8')
}

// method to remove resources by type
void removeResourcesByType(File file, String resourceType) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  def newArrayObj = []
  list.each {
    if (it.roleName != resourceType){
      newArrayObj.push(it)
    }
  }

  contents = new JsonBuilder(newArrayObj).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(contents, 'UTF-8')
}

// method to remove brackets from JSON
void removeBracketsFromJson(File file) {
  String fileContents = file.getText('UTF-8')
  fileContents = fileContents.trim()
  firstChar = fileContents.charAt(0)
  if (firstChar == "[") {
	startIndex = 1
	endIndex = fileContents.length()-1
	fileContents = fileContents.substring(startIndex, endIndex)
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
  }
}

// method to remove resources under a path
void removeResourcesUnderPath(File file, String path) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  def newArrayObj = []
  list.each {
    if (it.path.lastIndexOf(path, 0) != 0){
    newArrayObj.push(it)
    }
  }

  contents = new JsonBuilder(newArrayObj).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(contents, 'UTF-8')
}

// method to change SSLConfigGroup paths
// we are removing the /Server Entries/ServerEntry/Named End Points/nepName/ part of the path
// so the SSLConfigGroup data will still be a valid part of the JSON
// (server entries and named end points will be removed from the JSON, making the original path invalid)
// special handling is needed in importobject.py for multiplicity cluster members with
// named end point SSL configuration (see WI 151250)
void updateSSLConfigGroupPaths(File file, String startTokenDelimiter, String endTokenDelimiter) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  def newArrayObj = []
  list.each {
    currentPath = it.path
    if (currentPath.contains("/SSL Config Groups")){
      start = currentPath.indexOf("/SSL Config Groups")
      sslPath = currentPath.substring(start, currentPath.length())
      newPath = "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate" + sslPath
      it.path = newPath
    }
    newArrayObj.push(it)
  }

  contents = new JsonBuilder(newArrayObj).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(contents, 'UTF-8')
}

// method to add a role property to a resource
void addRolePropertyToResource(File file, String path, String propertyName, String value) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  // find the desired path
  def foundResource = []
  list.each {
    if (it.path == path){
      foundResource.push(it)
    }
  }

  // make sure we found one and only one resource, then add the property to it
  if (foundResource.size() > 1) {
    throw new RuntimeException("Error: found more than one path of " + path + " found in file " + file);
  } else if (foundResource.size() == 0) {
    throw new RuntimeException("Error: no path of " + path + " found in file " + file);
  } else {
	foundResource[0].roleProperties[propertyName] = value
  }

  fileContents = new JsonBuilder(list).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
}

// method to get role property value
String getRolePropertyValueFromFile(File file, String rolePropertyKey) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  value = ""
  list.each {
    if(it.keySet().contains( 'roleProperties' )) {
	  for (e in it.roleProperties) {
		if (e.key == rolePropertyKey) {
		  value = e.value
		}
	  }
	}
  }
  return value
}

// method to tokenize profile name
void tokenizeProfileName(File file, String startTokenDelimiter, String endTokenDelimiter) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  foundProfileName = false

  // find the profile name, assuming it's under /profiles/
  list.each {
    if(it.keySet().contains( 'roleProperties' )) {
      for (e in it.roleProperties) {
        if (e.key == "websphere.variablemap.entries") {
          if (e.value in String) {
            if (e.value.contains("/profiles/")) {
              profileNameRegex = e.value =~ /\/profiles\/(.*?)(\n|\/)/;
              profileName = profileNameRegex[0][1];
              // replace the profile name with a token
              println "Tokenizing profile name " + profileName + " in " + file.getName()
              e.value = e.value.replace(profileName, startTokenDelimiter + "websphere.node.profilename" + endTokenDelimiter)
              foundProfileName = true
            }
          }
        }
      }
    }
  }

  if (foundProfileName) {
    fileContents = new JsonBuilder(list).toPrettyString()
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
  }
}

// method to tokenize role properties only
void tokenizeRolePropertyValues(File file, String propertyToTokenize, String token) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  found = false

  // get all of the role properties and check their values
  list.each {
    if(it.keySet().contains( 'roleProperties' )) {
      for (e in it.roleProperties) {
        if (e.value in String) {
          if (e.value.contains(propertyToTokenize)) {
            e.value = e.value.replace(propertyToTokenize, token)
            found = true
          }
        }
      }
    }
  }

  if (found) {
    println "Tokenizing value " + propertyToTokenize + " to " + token + " for file " + file.getName()
    fileContents = new JsonBuilder(list).toPrettyString()
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
  }
}

// method to handle user defined tokenization
void doUserDefinedTokenization(File file, String userDefinedTokenization) {
  String fileContents = file.getText('UTF-8')
  lines = userDefinedTokenization.split('\n')
  for (line in lines) {
    if (line.indexOf("->") >= 0) {
      oldStart = 0
      oldEnd = line.indexOf("->")
      oldValue = line.substring(oldStart, oldEnd)
      newStart = line.indexOf("->") + 2
      newEnd = line.length();
      newValue = line.substring(newStart, newEnd)
      println "Replacing " + oldValue + " with " + newValue
      fileContents = fileContents.replace(oldValue, newValue)
    }
  }
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
}

// method to fix the paths if discovery was run on a server only
void fixPaths(File file, String serverName, String startTokenDelimiter, String endTokenDelimiter) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  found = false
  list.each {
    if(it.keySet().contains( 'path' )) {
      it.path = it.path.replace("/" + serverName + "/", "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate/")
      it.path = it.path.replace("/" + serverName, "/" + startTokenDelimiter + "websphere.cell" + endTokenDelimiter + "/ServerClusters/" + startTokenDelimiter + "websphere.cluster" + endTokenDelimiter + "/Servers/ServerTemplate")
      found = true
    }
  }

  if (found) {
    println "Fixing paths since discovery was run on a Server only..."
    fileContents = new JsonBuilder(list).toPrettyString()
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
  }
}
