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();

// 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)
String serverFileContents = serverFile.getText('UTF-8')

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

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

// changing the paths to be server clusters instead of nodes
serverFileContents = serverFileContents.replace("/Nodes/@websphere.node@/", "/ServerClusters/@websphere.cluster@/")
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)

// remove Server Entries
println "Removing Server Entry resources, if needed..."
serverFile = new File(serverFileString)
removeResourcesUnderPath(serverFile, "/@websphere.cell@/ServerClusters/@websphere.cluster@/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, "/@websphere.cell@/ServerClusters/@websphere.cluster@/Servers/ServerTemplate", "websphere.server.servercount", "@SERVER_COUNT@")

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

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

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

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

// 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 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 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.value in String) {
          if (e.value.contains("/profiles/")) {
            profileNameRegex = e.value =~ /\/profiles\/(.*?)(\n|\/)/;
            profileName = profileNameRegex[0][1];
            // replace the profile name with a token
            e.value = e.value.replace(profileName, "@websphere.node.profilename@")
            foundProfileName = true
          }
        }
      }
    }
  }

  if (foundProfileName) {
    println "Tokenizing profile name for " + file.getName()
    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')
  }
}
