import java.io.File;
import java.util.List;
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 workingDirString = props['outputDir'].trim();

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

// the extracted directory
extractedDirString = workingDirString + "extracted" + File.separator

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

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

// copy the cell directory
oldCellDirString = extractedDirString + "Cell"
newCellDirString = templateDirString + "Cell"
newCellDir = new File(newCellDirString)
if (newCellDir.exists()) {
  newCellDir.deleteDir()
}
newCellDir.mkdirs()
new AntBuilder().copy( todir: newCellDirString ) {
  fileset( dir: oldCellDirString )
}

String nodeName = ""
String hostName = ""

// handle deployment manager, if there is one
dmgrJsonString = templateDirString + "Cell" + File.separator +"dmgr" + File.separator + "dmgr.json"
dmgrJson = new File(dmgrJsonString)
if (dmgrJson.exists()) {
  println "Tokenizing values for dmgr.json..."
  // get the dmgr node name
  String dmgrNodeName = getPropertyValueByRoleName(dmgrJson, "WebSphereServer", "path")
  startOfPath = "/" + cellName + "/Nodes/"
  startIndex = startOfPath.size()
  serversIndex = dmgrNodeName.lastIndexOf("/Servers/")
  dmgrNodeName = dmgrNodeName.substring(startIndex, serversIndex)
  println "dmgrNodeName to tokenize: " + dmgrNodeName

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

  // tokenize values
  dmgrJson = new File(dmgrJsonString)
  String dmgrFileContents = dmgrJson.getText('UTF-8')
  dmgrFileContents = dmgrFileContents.replace("/Nodes/" + dmgrNodeName + "/Servers/", "/Nodes/@websphere.node@/Servers/")
  dmgrFileContents = dmgrFileContents.replace("(node):" + dmgrNodeName, "(node):@websphere.node@")
  dmgrFileContents = dmgrFileContents.replace("/" + cellName + "/", "/@websphere.cell@/")
  dmgrFileContents = dmgrFileContents.replace("(cell):" + cellName, "(cell):@websphere.cell@")
  dmgrJson.delete()
  new File(dmgrJson.getParent()+File.separator+dmgrJson.getName()).write(dmgrFileContents, 'UTF-8')
  dmgrJson = new File(dmgrJsonString)
  tokenizeRolePropertyValues(dmgrJson, dmgrHostName, "@websphere.node.hostname@")

  // just to be safe, tokenize anything we may have missed
  dmgrJson = new File(dmgrJsonString)
  dmgrFileContents = dmgrJson.getText('UTF-8')
  dmgrFileContents = dmgrFileContents.replace(dmgrNodeName, "@websphere.node@")
  dmgrFileContents = dmgrFileContents.replace(cellName, "@websphere.cell@")
  dmgrJson.delete()
  new File(dmgrJson.getParent()+File.separator+dmgrJson.getName()).write(dmgrFileContents, 'UTF-8')

  // get dmgr name
  dmgrJson = new File(dmgrJsonString)
  String dmgrName = getRolePropertyValueFromFile(dmgrJson, "websphere.server")

  // add parent property to dmgr.json
  println "Adding parent property to dmgr.json..."
  dmgrJson = new File(dmgrJsonString)
  addPropertyToResource(dmgrJson, "/@websphere.cell@/Nodes/@websphere.node@/Servers/" + dmgrName, "parent", "{ \"name\": \"Servers\", \"path\": \"/@websphere.cell@/Nodes/@websphere.node@/Servers\", \"parent\": { \"name\": \"@websphere.node@\", \"path\": \"/@websphere.cell@/Nodes/@websphere.node@\", \"roleName\": \"WebSphereNode\", \"roleProperties\": { \"websphere.node\": \"@websphere.node@\" }, \"parent\": { \"name\": \"Nodes\", \"path\": \"/@websphere.cell@/Nodes\", \"parent\": { \"roleName\": \"WebSphereCell\", \"name\": \"@websphere.cell@\", \"path\": \"/@websphere.cell@\", \"roleProperties\": { \"websphere.cell\": \"@websphere.cell@\" } } } } }")

  // remove brackets
  dmgrJson = new File(dmgrJsonString)
  removeBracketsFromJson(dmgrJson)

  // fix double quotes
  dmgrJson = new File(dmgrJsonString)
  fixDoubleQuotes(dmgrJson)

  // set the nodeName and hostName for use later
  nodeName = dmgrNodeName
  hostName = dmgrHostName
} else {
  // no dmgr.json file exists, so delete the dmgr directory
  dmgrDirString = newCellDirString + File.separator + "dmgr"
  dmgrDir = new File(dmgrDirString)
  dmgrDir.deleteDir()

  // if there is no dmgr, this must be WAS Base.
  // if this is WAS Base, there must be only one application server.
  // that application server is on a node.
  // we need to get that node's name and host name (see WI 146549).
  println "No deployment manager detected, so this must be WAS Base..."
  println "Finding node the application server belongs to..."
  isNodeWeWant = false
  // get all directories and find ones that start with Node-
  extractedDir = new File(extractedDirString)
  dirs = getAllFoldersInDir(extractedDir)
  dirs.each {
    if (it.getName().startsWith("Node-") && isNodeWeWant == false){
      nodeFolder = new File(it.getParent()+File.separator+it.getName())
      // get all files for this node and find Server.json
      nodeFiles = getAllFilesInDir(nodeFolder)
      nodeFiles.each {
        if (it.getName() == "Server.json"){
          serverDirString = it.getParent()+File.separator+it.getName()
          serverJson = new File(serverDirString)
          String serverType = getRolePropertyValueFromFile(serverJson, "websphere.server.servertype")
          // see if this server is the application server. If it is, we are on the node we want
          if (serverType == "APPLICATION_SERVER"){
            println "Found the node the application server belongs to..."
            isNodeWeWant = true
          }
        }
      }
      if (isNodeWeWant == true){
        // get this node's Node.json file
        nodeDirString = it.getParent()+File.separator+it.getName()+ File.separator + "node" + File.separator + "Node.json"
        nodeJson = new File(nodeDirString)
        // get the node name
        nodeName = getRolePropertyValueFromFile(nodeJson, "websphere.node")
        println "The application server's node name is " + nodeName
        // get the node's host name
        hostName = getRolePropertyValueFromFile(nodeJson, "websphere.node.hostname")
      }
    }
  }
}


// tokenize Cell.json
println "Tokenizing values for Cell.json..."
cellJsonString = newCellDirString + File.separator + "cell" + File.separator + "Cell.json"

cellJson = new File(cellJsonString)
String cellFileContents = cellJson.getText('UTF-8')
cellFileContents = cellFileContents.replace("/" + cellName + "/", "/@websphere.cell@/")
cellFileContents = cellFileContents.replace("(cell):" + cellName, "(cell):@websphere.cell@")
cellJson.delete()
new File(cellJson.getParent()+File.separator+cellJson.getName()).write(cellFileContents, 'UTF-8')

// substitute any references to nodename and hostname
cellJson = new File(cellJsonString)
if (hostName?.trim()) {
  tokenizeRolePropertyValues(cellJson, hostName, "@websphere.node.hostname@")
}
if (nodeName?.trim()) {
  tokenizeRolePropertyValues(cellJson, nodeName, "@websphere.node@")
}

// just to be safe, tokenize anything we may have missed
cellJson = new File(cellJsonString)
cellFileContents = cellJson.getText('UTF-8')
cellFileContents = cellFileContents.replace(cellName, "@websphere.cell@")
cellJson.delete()
new File(cellJson.getParent()+File.separator+cellJson.getName()).write(cellFileContents, 'UTF-8')

// virtual host "default_host" has property websphere.virtualhost.aliases which
//  usually contains hardcoded hostnames. so, we will tokenize that value.
println "If applicable, tokenizing virtual host aliases for virtual host named 'default_host'..."
cellJson = new File(cellJsonString)
replaceRolePropertyValueFromFile(cellJson, "websphere.virtualhost.name", "default_host", "websphere.virtualhost.aliases", "@DEFAULTHOSTVIRTUALHOSTALIASES@")

// remove brackets
cellJson = new File(cellJsonString)
removeBracketsFromJson(cellJson)

// fix double quotes
cellJson = new File(cellJsonString)
fixDoubleQuotes(cellJson)



// method to get a property value from an object based on object's role name
String getPropertyValueByRoleName(File file, String roleName, String property) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  value = ""
  list.each {
    if (it.roleName == roleName){
      value = it.path
    }
  }
  return value
}

// 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 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 property to a resource
void addPropertyToResource(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 {
	parsedValue = new JsonSlurper().parseText(value)
    foundResource[0][propertyName] = parsedValue
  }

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

// method to get a 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 get all files in a directory
List getAllFilesInDir(File dir) {
  def list = []
  dir.eachFileRecurse (FileType.FILES) { file ->
    list << file
  }
  return list
}


// method to get all folders in a directory
List getAllFoldersInDir(File parentDir) {
  def list = []
  parentDir.eachDir() { dir ->
    list << dir
  }
  return list
}

// method to replace a role property value
//   rolePropertyNameKey = a role property to be used as an identifier so we know we have the correct entry (example: "websphere.virtualhost.name")
//   name = value of the rolePropertyNameKey we are looking for (example: "default_host")
//   rolePropertyKeyToUpdate = the role property to be updated
//   newValue = updated value of rolePropertyKeyToUpdate
// In other words: if JSON entry has role property named rolePropertyNameKey, and rolePropertyNameKey = name, and if JSON entry
//  also has a role property named rolePropertyKeyToUpdate, then update rolePropertyKeyToUpdate to newValue
String replaceRolePropertyValueFromFile(File file, String rolePropertyNameKey, String name, String rolePropertyKeyToUpdate, String newValue) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)
  list.each {
    if(it.keySet().contains( 'roleProperties' )) {
	  if (it.roleProperties.keySet().contains (rolePropertyNameKey)) {
		if (it.roleProperties[rolePropertyNameKey] == name) {
		  if (it.roleProperties.keySet().contains (rolePropertyKeyToUpdate))
		    it.roleProperties[rolePropertyKeyToUpdate] = newValue
		}
      }
    }
  }
  contents = new JsonBuilder(list).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(contents, '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')
  }
}
