import java.io.File;

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

import com.urbancode.air.AirPluginTool;


/*
  For a snippet to be applied individually (for example, adding a single JDBC Provider to WAS),
  two things are needed from the configuration data:

  1. The resource itself and all of its children.

  2. JSON entries for all items in the path above the resource we wish to extract.
     For example, if the resource we wish to extract has the path:

        /CloudBurstCell_1/Nodes/CloudBurstNode_3_1/Servers/Member2/JDBC Providers/myJDBCProvider

     We need to extract the JSON representing:

        JDBC Providers
        Member2
        Servers
        CloudBurstNode_3_1
        Nodes
        CloudBurstCell_1

     We don't need to extract all of the children for each item on this list.
*/

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

def configFile = props['configFile'].trim();
def outputFile = props['outputFile'].trim();
def newConfigFile = props['newConfigFile'].trim();
def pathToExtract = props['pathToExtract'].trim();

// fix the path to extract in case it has \ characters
pathToExtract = pathToExtract.replace("\\", "");

file =  new File(configFile)
String fileContents = file.getText('UTF-8')
// we expect the fileContents to be in brackets
fileContents = fileContents.trim();
if (fileContents.substring(0, 1) != "[") {
  fileContents = "[" + fileContents + "]"
}
def list = new JsonSlurper().parseText(fileContents)

def newArrayObj = []
def targetResource = []
def remainingJson = []
def targetResourceParent = ""
def intermediateObjects = []

// get all resources under and including the path
list.each {
  if (it.path == pathToExtract || it.path.indexOf(pathToExtract + "/", 0) == 0) {
    targetResource.push(it)
  }
  else {
    remainingJson.push(it)
  }
}

// determine and get the path of the resource that represents the snippet's resource type
// For example, if pathToExtract is: /MattExemplarCell01/Nodes/MattExemplarNode1/JDBC Providers/myJDBC,
// we want to get:                   /MattExemplarCell01/Nodes/MattExemplarNode1/JDBC Providers
lastSlash = pathToExtract.lastIndexOf("/")
parentPath = pathToExtract.substring(0, lastSlash)

list.find {
  if (it.path == parentPath) {
    println "Found the snippet type resource at path " + parentPath
    targetResourceParent = it;
    return true
  }
  else {
    return false
  }
}

// determine and get the parent resource (Cell, Node, Server, Cluster)
// can't rely on a scope being set because a scope is optional
parentScope = "Cell"
parentResourcePath = ""
if (pathToExtract.contains("/Servers/")){
  parentScope = "/Servers/"
} else if (pathToExtract.contains("/Nodes/")){
  parentScope = "/Nodes/"
} else if (pathToExtract.contains("/ServerClusters/")){
  parentScope = "/ServerClusters/"
}

if (parentScope != "Cell"){
  // if pathToExtract is: /MattExemplarCell01/Nodes/MattExemplarNode1/JDBC Providers/myJDBC,
  // we want to get:      /MattExemplarCell01/Nodes/MattExemplarNode1
  parentScopeIndex = pathToExtract.indexOf(parentScope)
  parentScopeLength = parentScope.length()
  nextSlash = pathToExtract.indexOf("/", parentScopeIndex + parentScopeLength)
  parentResourcePath = pathToExtract.substring(0, nextSlash)
} else {
  // for Cell, get the first piece of of the path
  nextSlash = pathToExtract.indexOf("/", 1)
  parentResourcePath = pathToExtract.substring(0, nextSlash)
}

// get the parent resource
if (parentResourcePath == ""){
  throw new RuntimeException("Error: Could not find a parent resource of path " + parentResourcePath)
}
else {
  list.find {
    if (it.path == parentResourcePath) {
      println "Found the parent resource at path " + parentResourcePath
      newArrayObj.push(it);
      return true
    }
    else {
      return false
    }
  }
}

// we've gotten the target resource, it's immediate parent, and its top level parent.
// next, we need to get everything in between.
// start by getting the path minus the found resource and the found resource's parent
// (because we already extracted them)
// for example, if our target resource's path is:
//    /@websphere.cell@/Securities/Security/JAAS Auth Data/JAASAuthData0
// we want to get the path:
//    /@websphere.cell@/Securities/Security
lastSlash = parentPath.lastIndexOf("/")
remainingPath = parentPath.substring(0, lastSlash)

// let's work up the remaining path until we get to the top level path,
// getting each resource as we go.
if (remainingPath) {
  while (remainingPath != parentResourcePath){
    list.find {
      if (it.path == remainingPath) {
        println "Extracting path " + remainingPath
        intermediateObjects.push(it);
        // trim the path before we loop again
        lastSlash = remainingPath.lastIndexOf("/")
        remainingPath = remainingPath.substring(0, lastSlash)
        return true
      }
      else {
        return false
      }
    }
  }
}

// merge everything into newArrayObj
// newArrayObj already has the top-level resource
// next, merge the intermediate objects in the reverse order that we found them
for (counter = intermediateObjects.size() - 1; counter >= 0; counter--) {
  newArrayObj.push(intermediateObjects[counter]);
}
// now add the target resource's parent
newArrayObj.push(targetResourceParent);

// finally, add the target resource and it's children
for (counter = 0; counter <= targetResource.size() -1; counter++) {
  newArrayObj.push(targetResource[counter]);
}

if (outputFile) {
  // create output file dir if needed
  outputFile = new File(outputFile)
  outputFileParent = outputFile.getParent()
  if (outputFileParent) {
    outputFileDir = new File(outputFileParent)
    if (!outputFileDir.exists()) {
      outputFileDir.mkdirs()
    }
  }
  else {
    outputFileParent = "."
  }
  // delete the output file if it already exists
  if (outputFile.exists()) {
    outputFile.delete()
  }

  // write the results to the outputFile
  println "Creating new snippet configuration file: " + outputFile
  contents = new JsonBuilder(newArrayObj).toPrettyString()
  // fix "" saving as "\"\""
  contents = contents.replace("\"\\\"\\\"\"", "\"\"")
  // remove brackets, if needed
  firstChar = contents.charAt(0)
  if (firstChar == "[") {
    startIndex = 1
    endIndex = contents.length()-1
    contents = contents.substring(startIndex, endIndex)
  }
  new File(outputFileParent+File.separator+outputFile.getName()).write(contents, 'UTF-8')
}
else {
  println "Not creating a snippet configuration file because the Extracted Snippet File field is blank."
}

if (newConfigFile) {
  // create newConfigFile dir if needed
  newConfigFile = new File(newConfigFile)
  newConfigFileParent = newConfigFile.getParent()
  if (newConfigFileParent) {
    newConfigFileDir = new File(newConfigFileParent)
    if (!newConfigFileDir.exists()) {
      newConfigFileDir.mkdirs()
    }
  }
  else {
    newConfigFileParent = "."
  }
  // delete the newConfig file if it already exists
  if (newConfigFile.exists()) {
    newConfigFile.delete()
  }

  // write the results to the outputFile
  println "Creating new new configuration file which does not contain the extracted resource: " + newConfigFile
  contents = new JsonBuilder(remainingJson).toPrettyString()
  // fix "" saving as "\"\""
  contents = contents.replace("\"\\\"\\\"\"", "\"\"")
  // remove brackets, if needed
  firstChar = contents.charAt(0)
  if (firstChar == "[") {
    startIndex = 1
    endIndex = contents.length()-1
    contents = contents.substring(startIndex, endIndex)
  }
  new File(newConfigFileParent+File.separator+newConfigFile.getName()).write(contents, 'UTF-8')
}
else {
  println "Not creating a new configuration file because the New Configuration File field is blank."
}
