package sbt

import java.net.URI

object Resolve {
  def apply(index: BuildUtil[_], current: ScopeAxis[Reference], key: AttributeKey[_], mask: ScopeMask): Scope => Scope =
    {
      val rs =
        resolveProject(current, mask) _ ::
          resolveExtra(mask) _ ::
          resolveTask(mask) _ ::
          resolveConfig(index, key, mask) _ ::
          Nil
      scope => (scope /: rs) { (s, f) => f(s) }
    }
  def resolveTask(mask: ScopeMask)(scope: Scope): Scope =
    if (mask.task) scope else scope.copy(task = Global)

  def resolveProject(current: ScopeAxis[Reference], mask: ScopeMask)(scope: Scope): Scope =
    if (mask.project) scope else scope.copy(project = current)

  def resolveExtra(mask: ScopeMask)(scope: Scope): Scope =
    if (mask.extra) scope else scope.copy(extra = Global)

  def resolveConfig[P](index: BuildUtil[P], key: AttributeKey[_], mask: ScopeMask)(scope: Scope): Scope =
    if (mask.config)
      scope
    else {
      val (resolvedRef, proj) = scope.project match {
        case Select(ref) =>
          val r = index resolveRef ref
          (Some(r), index.projectFor(r))
        case Global | This =>
          (None, index.rootProject(index.root))
      }
      val task = scope.task.toOption
      val keyIndex = index.keyIndex
      val definesKey = (c: ScopeAxis[ConfigKey]) => keyIndex.keys(resolvedRef, c.toOption.map(_.name), task) contains key.label
      val projectConfigs = index.configurations(proj).map(ck => Select(ck))
      val config: ScopeAxis[ConfigKey] = (Global +: projectConfigs) find definesKey getOrElse Global
      scope.copy(config = config)
    }
}