String getJarsPath (Map properties) {
  return brltty.getJarsPath(properties.project)
}

String getLibrariesPath (Map properties) {
  return brltty.getLibrariesPath(properties.project)
}

String getABIPath (Map properties) {
  return brltty.getABIPath(properties.project, properties.ABI)
}

Map getABI (String abi) {
  if (!brltty.containsKey("ABI")) {
    brltty.ABI = [:]
  }

  def ABI = brltty.ABI
  if (!ABI.containsKey(abi)) ABI[abi] = [:]
  return ABI[abi]
}

Map getABI (Map properties) {
  return getABI(properties.ABI)
}

brltty.addConsumerTask = { Task producerTask, String consumerName ->
  gradle.projectsEvaluated {
    def consumerTask = producerTask.project.tasks.findByName(consumerName)

    if (consumerTask != null) {
      consumerTask.mustRunAfter producerTask
    }
  }
}

Task newTask (Project project, String name, Class<DefaultTask> type=DefaultTask, Closure closure) {
  def task = project.tasks.register(name, type, closure).get()

  task.configure {
    group "build"
  }

  return task
}

Task newTask (Map properties, String name, Class<DefaultTask> type=DefaultTask, Closure closure) {
  name += properties.taskNameSuffix
  return newTask(properties.project, name, type, closure)
}

Task newAssembleTask (Map properties) {
  return newTask(properties.project, "brlttyAssembleAllComponents") {
    description "Assemble all of the native jars, libraries, assets, etc."
  }
}

void addAssembleDependency (Map properties, Task task) {
  properties.assembleTask.dependsOn task
}

Task newCleanTask (Map properties) {
  return newTask(properties.project, "brlttyCleanAllComponents") {
    description "Clean all of the native jars, libraries, assets, etc."
  }
}

void addCleanDependency (Map properties, Task task) {
  properties.cleanTask.dependsOn task
}

Task newConfigureTask (Map properties) {
  return newTask(properties, "brlttyConfigureABI", Exec) {
    description "Configure the ${properties.componentName} for the ${properties.ABI} ABI."

    workingDir properties.abiDirectory
    ignoreExitValue false
    commandLine "${brltty.native.rootDirectory}/cfg-android-abi", properties.ABI
  }
}

Task getConfigureTask (Map properties) {
  def abi = getABI(properties)

  if (!abi.containsKey("configureTask")) {
    abi.configureTask = newConfigureTask(properties)
  }

  return abi.configureTask
}

Task newMakeComponentsTask (Map properties) {
  return newTask(properties, "brlttyMakeABI", Exec) {
    description "Make the ${properties.ABI} components of the ${properties.componentName}."
    dependsOn properties.configureTask

    workingDir properties.makeDirectory
    ignoreExitValue false

    commandLine "make"
    args properties.makeTargets
  }
}

Task newAddJarsTask (Map properties) {
  def task = newTask(properties, "brlttyAddJars", Copy) {
    description "Add the ${properties.componentName}'s ${properties.ABI} jars to the build."
    dependsOn properties.makeComponentsTask
    into getJarsPath(properties)

    properties.jarSubdirectories.each { subdirectory ->
      from properties.abiDirectory + File.separator + subdirectory
    }

    properties.jars.each { jar ->
      include "${jar}.jar"
    }
  }

  brltty.addConsumerTask(task, "mergeDebugJavaResource")
  brltty.addConsumerTask(task, "copyDebugJniLibsProjectAndLocalJars")

  return task
}

Task newAddLibrariesTask (Map properties) {
  def task = newTask(properties, "brlttyAddLibraries", Copy) {
    description "Add the ${properties.componentName}'s ${properties.ABI} libraries to the build."
    dependsOn properties.makeComponentsTask
    into getABIPath(properties)

    properties.librarySubdirectories.each { subdirectory ->
      from properties.abiDirectory + File.separator + subdirectory
    }

    properties.libraries.each { library ->
      include "lib${library}.so"
    }
  }

  brltty.addConsumerTask(task, "mergeDebugJniLibFolders")
  brltty.addConsumerTask(task, "mergeReleaseJniLibFolders")

  return task
}

Task newMakeCleanTask (Map properties) {
  return newTask(properties, "brlttyCleanABI", Exec) {
    description "Remove (make clean) the ${properties.ABI} components of the ${properties.componentName}."
    dependsOn properties.configureTask

    workingDir properties.makeDirectory
    ignoreExitValue true
    commandLine "make", "clean"
  }
}

Task newRemoveTask (Map properties) {
  return newTask(properties, "brlttyRemoveAllComponents", Delete) {
    description "Remove the ${properties.componentName}'s jars and libraries from the build."
    delete getJarsPath(properties)
    delete getLibrariesPath(properties)
  }
}

void addTasks (Map properties, String abi) {
  properties.ABI = abi
  def isPrimaryABI = abi.equals(brltty.native.abiList[0])

  properties.abiDirectory = brltty.native.abiDirectory + File.separator + properties.ABI
  properties.configureTask = getConfigureTask(properties)

  properties.makeDirectory = properties.abiDirectory + File.separator + properties.makeSubdirectory
  properties.makeComponentsTask = newMakeComponentsTask(properties)

  if (isPrimaryABI) {
    def jars = properties.jars

    if ((jars != null) && !jars.isEmpty()) {
      def addJarsTask = newAddJarsTask(properties)
      addAssembleDependency(properties, addJarsTask)
    }
  }

  def libraries = properties.libraries
  if ((libraries != null) && !libraries.isEmpty()) {
    def addLibrariesTask = newAddLibrariesTask(properties)
    addAssembleDependency(properties, addLibrariesTask)
  }

  def makeCleanTask = newMakeCleanTask(properties)
  addCleanDependency(properties, makeCleanTask)
}

void addTasks (Map properties) {
  def taskNameSuffix = ""
  properties.taskNameSuffix = taskNameSuffix

  properties.assembleTask = newAssembleTask(properties)
  properties.cleanTask = newCleanTask(properties)

  if (properties.makeTargets == null) properties.makeTargets = "all"
  if (properties.makeTargets instanceof String) properties.makeTargets = [properties.makeTargets]

  if (properties.jarSubdirectories == null) properties.jarSubdirectories = properties.makeSubdirectory
  if (properties.jarSubdirectories instanceof String) properties.jarSubdirectories = [properties.jarSubdirectories]

  if (properties.librarySubdirectories == null) properties.librarySubdirectories = properties.makeSubdirectory
  if (properties.librarySubdirectories instanceof String) properties.librarySubdirectories = [properties.librarySubdirectories]

  def removeTask = newRemoveTask(properties)
  addCleanDependency(properties, removeTask)

  brltty.native.abiList.each { abi ->
    properties.taskNameSuffix = "${taskNameSuffix}_${abi}"
    addTasks(properties, abi)
  }
}

brltty.addAssembleTask = { Project project, Task assembleTask ->
  project.afterEvaluate {
    project.tasks.withType(JavaCompile).each { compileTask ->
      compileTask.dependsOn assembleTask
    }
  }
}

brltty.buildComponent = { Map properties ->
  addTasks(properties)
  brltty.addAssembleTask(properties.project, properties.assembleTask)
  clean.dependsOn properties.cleanTask
}
