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 workingDirString = props['outputDir'].trim();
def configurationFile = props['configurationFile'].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
extractedDir = new File(extractedDirString)
if (!extractedDir.exists()) {
  extractedDir.mkdirs()
}

workingDir = new File(workingDirString)

// copy the configuration file to the working dir and give it a new name
tempConfigFile = new File(workingDirString + "ibm_ucd_wasconfigureplugin_config.txt")
if (tempConfigFile.exists()) {
  println "Deleting old copy of " + tempConfigFile
  tempConfigFile.delete()
}
new File(workingDirString + "ibm_ucd_wasconfigureplugin_config.txt") << new File(configurationFile).text
file = new File(workingDirString + "ibm_ucd_wasconfigureplugin_config.txt")

cellDirString = extractedDirString + "Cell" + File.separator + "cell"
dmgrDirString = extractedDirString + "Cell" + File.separator + "dmgr"
new File(cellDirString).mkdirs()

// Get the JSON from the config file
println "Getting the JSON from the config file..."
pullJsonFromFile(file)

// Get the Specified Configuration Types to Discover json entry, if it exists
discoveredConfigTypes = getDiscoveredConfigTypes(file)

// Replace all encrypted values with properties
println "Replacing encrypted values with properties..."
replaceEncryptedValues(file, workingDirString)

println "Extracting the Node config data."
extractresourceswithtypeandchildren(file, "WebSphereNode", "Node", true, discoveredConfigTypes)

println "Extracting the Cluster config data."
extractresourceswithtypeandchildren(file, "WebSphereCluster", "Cluster", true, discoveredConfigTypes)

println "Extracting the Dynamic Cluster Server Template config data."
extractresourceswithtypeandchildren(file, "WebSphereDynamicClusterServerTemplate", "DynamicClusterServerTemplate", true, discoveredConfigTypes)

println "Extracting the Dynamic Cluster config data."
extractresourceswithtypeandchildren(file, "WebSphereDynamicCluster", "DynamicCluster", true, discoveredConfigTypes)

files = getAllFilesInDir(workingDir)
files.each {
  if (it.getName().startsWith("Node-")){ 
	// get the Node name from the file
	String nodeName = getRolePropertyValueFromFile(it, "websphere.node")
	println "Parsing node " + nodeName 
	// create directories for Nodes
	nodeDirString = extractedDirString + "Node-" + nodeName + File.separator + "node"
	new File(nodeDirString).mkdirs()
	nodeDir = new File(nodeDirString)
	nodeAgentDirString = extractedDirString + "Node-" + nodeName + File.separator + "nodeagent"
	// move the Node-x.json file to the new node directory
	it.renameTo(new File(nodeDirString, "Node.json"))
	// extract the server config data
	nodeJsonFile = new File(nodeDirString + File.separator + "Node.json")
	extractresourceswithtypeandchildren(nodeJsonFile, "WebSphereServer", "Server", true, discoveredConfigTypes)
	// go through all the server files
	serverFiles = getAllFilesInDir(nodeDir)
	serverFiles.each {
	  if (it.getName().startsWith("Server-")) {
	    // get the server type
	    serverType = getRolePropertyValueFromFile(it, "websphere.server.servertype")
	    if (serverType == "DEPLOYMENT_MANAGER") {
	      // move to Cell/dmgr
		  println "Parsing the deployment manager"
		  new File(dmgrDirString).mkdirs()
		  it.renameTo(new File(dmgrDirString, "dmgr.json"))
	    } else if (serverType == "NODE_AGENT"){
	      // move to Node/nodeagent
		  println "Parsing a node agent"
		  nodeAgentDir = new File(nodeAgentDirString).mkdirs()
		  it.renameTo(new File(nodeAgentDirString, "nodeagent.json"))
	    } else {
	      // get the server name
		  serverName = getRolePropertyValueFromFile(it, "websphere.server")
		  println "Parsing server " + serverName
		  // create a directory for the server.json file
		  serverDirString = nodeDirString + File.separator + "Server-" + serverName
		  serverDir = new File(serverDirString).mkdirs()
		  // move the server.json file to the directory
		  it.renameTo(new File(serverDirString, "Server.json"))
	    }
	  }
	}
  } else if (it.getName().startsWith("Cluster-")) {
      // get the cluster name
	  clusterName = getRolePropertyValueFromFile(it, "websphere.cluster")
	  println "Parsing cluster " + clusterName
	  // create a directory
	  clusterDirString = extractedDirString + "Cluster-" + clusterName
	  new File(clusterDirString).mkdirs()
	  // move the cluster.json file to the directory
	  it.renameTo(new File(clusterDirString, "Cluster.json"))
  }
}

// now, we need to go through the files again and handle the dynamic cluster files
// (needed to make sure the Cluster dirs were created first)
files = getAllFilesInDir(workingDir)
files.each {
  if (it.getName().startsWith("DynamicCluster-")){
    // merge the dynamic cluster data into the Cluster.json file
    // first, get the dynamic cluster name (which is the same as the cluster name)
    dcName = getRolePropertyValueFromFile(it, "websphere.dynamiccluster.name")
    println "Parsing dynamic cluster config data for dynamic cluster " + dcName
    // get the cluster's directory
    clusterDirString = extractedDirString + "Cluster-" + dcName
    // get the Cluster.json contents
    clusterFile = new File(clusterDirString + file.separator + "Cluster.json")
    clusterFileContents = getFileContents(clusterFile)
    // get the dynamic cluster file's contents
    dcFileContents = getFileContents(it)
    // merge the contents
    mergedContents = "[\n" + clusterFileContents.trim() + ",\n" + dcFileContents.trim() + "\n]"
    // delete the old Cluster.json
    if (clusterFile.exists()) {
      clusterFile.delete()
    }
    // write the new, merged Cluster.json
    new File(clusterDirString + file.separator + "Cluster.json").write(mergedContents, 'UTF-8')
    // delete the dynamic cluster config file
    it.delete()
  }
  else if (it.getName().startsWith("DynamicClusterServerTemplate-")) {
    // move the dynamic cluster server template data to its cluster dir
    // first, get the dynamic cluster name (which is the same as the cluster name)
    dcName = getRolePropertyValueFromFile(it, "websphere.server.clustername")
    println "Parsing dynamic cluster server template config data for dynamic cluster " + dcName
    // get the cluster's directory
    clusterDirString = extractedDirString + "Cluster-" + dcName
    it.renameTo(new File(clusterDirString, "DynamicClusterServerTemplate.json"))
  }
}


// what's left over is the Cell level configuration data
// move the stdOut.txt file to the Cell/cell directory
println "Parsing cell configuration data"
file.renameTo(new File(cellDirString, "Cell.json"))

// need to clean up because values of "" are sometimes saved as "\"\""
extractedDir = new File(extractedDirString)
fixDoubleQuotes(extractedDir)

// method to get file contents
String getFileContents(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)
  }
  return fileContents
}

// method to fix "" saving as "\"\""
void fixDoubleQuotes(File dir) {
  dir.eachFileRecurse { curfile ->
    if (curfile.getName().endsWith(".json")) {  
	  String fileContents = curfile.getText('UTF-8')
      fileContents = fileContents.replaceAll("\"\\\\\"\\\\\"\"", "\"\"")
	  curfile.delete()
	  new File(curfile.getParent()+File.separator+curfile.getName()).write(fileContents, 'UTF-8')
	}
  }
}

// method to strip non-JSON from stdOut.txt
void pullJsonFromFile(File file) {
  String fileContents = file.getText('UTF-8')
  
  // no need to do this if the first char is [
  fileContents = fileContents.trim()
  firstChar = fileContents.charAt(0)
  if (firstChar != "[") {
	startIndex = fileContents.lastIndexOf("Configuration Discovery Complete.")+34
	endIndex = fileContents.length()
	fileContents = fileContents.substring(startIndex, endIndex)
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
  }
}

// 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 replace encrypted field values (*****) with a property
void replaceEncryptedValues(File file, String workingDirString) {
  String fileContents = file.getText('UTF-8')
  String propertiesToSetFileContents = ""
  def list = new JsonSlurper().parseText(fileContents)
  list.each {
    if(it.keySet().contains( 'roleProperties' )) {
      for (e in it.roleProperties) {
        if (e.value == "*****" || e.value == "****") {
          if (e.key == "websphere.keystore.password") {
            keystoreName = it.roleProperties["websphere.keystore.name"]
            e.value = ("@keystore." + keystoreName + ".password@")
            propertiesToSetFileContents = propertiesToSetFileContents + "keystore." + keystoreName + ".password\n"
          } else if (e.key == "websphere.keyset.password") {
            keysetName = it.roleProperties["websphere.keyset.name"]
            e.value = ("@keyset." + keysetName + ".password@")
            propertiesToSetFileContents = propertiesToSetFileContents + "keyset." + keysetName + ".password\n"
          } else {
            key = e.key
            e.value = "@" + key + "@"
            propertiesToSetFileContents = propertiesToSetFileContents + key + "\n"
          }
        }
      }
    }
  }
  fileContents = new JsonBuilder(list).toPrettyString()
  file.delete()
  new File(file.getParent()+File.separator+file.getName()).write(fileContents, 'UTF-8')
  // create a file that contains properties users must specify before running an apply
  if (propertiesToSetFileContents != "") {
    new File(workingDirString+File.separator+"properties_to_set.txt").write(propertiesToSetFileContents, 'UTF-8')
  }
}

// method to get a role property value from a file
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 the Specified Configuration Types to Discover json entry, if it exists
Object getDiscoveredConfigTypes(File file) {
  jsonObj = ""
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  // get the Specified Configuration Types to Discover
  list.find {
    if (it.name == "Specified Configuration Types to Discover") {
      println "Found Specified Configuration Types to Discover in the config file..."
      jsonObj = it
      return true
    }
    else {
      return false
    }
  }
  return jsonObj
}

// method to extract a resource and its children and place it into a separate file
void extractresourceswithtypeandchildren(File file, String typeToExtract, String fileNamePrefix, boolean createExtractedResourceFile = true, Object discoveredConfigTypes) {
  String fileContents = file.getText('UTF-8')
  def list = new JsonSlurper().parseText(fileContents)

  // get the path of the resources we want to extract
  def pathsToExtract = []
  list.each {
    if (it.roleName == typeToExtract){
      pathsToExtract.push(it.path)
    }
  }
  
  remainingResources = list

  // go through the resources and extract the ones which contain a path 
  // of the resources we wish to extract.
  def indexesToRemove = []
  fileCounter = 0;
  pathsToExtract.each {
    def extractedResources = []
    indexCounter = 0
	path = it
	list.each {
	  if (it.path == path || it.path.indexOf(path + "/", 0) == 0) {
        extractedResources.push(it);
		// save the index of the resources we will wish to remove from the original file
		indexesToRemove.push(indexCounter)	
      }
	  indexCounter = indexCounter + 1
	}

	if (extractedResources.size() > 0 && createExtractedResourceFile == true) {
      // add the Specified Configuration Types to Discover to all config files
      if (discoveredConfigTypes != "") {
        extractedResources.push(discoveredConfigTypes)
      }
      extractedFileContents = new JsonBuilder(extractedResources).toPrettyString()
      new File(file.getParent()+File.separator+fileNamePrefix+"-"+fileCounter+".json").write(extractedFileContents, 'UTF-8')
      fileCounter = fileCounter + 1
	}
	  
  }

  indexesToRemove.sort();

  // remove resources
  i = 0;
  for (index in indexesToRemove) {
    indexToRemove = index - i
    remainingResources.remove(indexToRemove)
    i = i + 1;
  }
	
  if (remainingResources.size() > 0) {
    remainingFileContents = new JsonBuilder(remainingResources).toPrettyString()
    file.delete()
    new File(file.getParent()+File.separator+file.getName()).write(remainingFileContents, 'UTF-8')
  }
}