// This source file is part of the Swift.org open source project
//
// Copyright 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for Swift project authors

// This file contains Swift bindings for the llbuild C API.

import Foundation

enum DatabaseError: Error {
  case AttachFailure(message: String)
}

private func stringFromData(data: llb_data_t) -> String {
  // Convert as a UTF8 string, if possible.
  let tmp = NSData(bytes: unsafeBitCast(data.data, to: UnsafeRawPointer.self), length: Int(data.length))
  if let str = String(data: tmp as Data, encoding: String.Encoding.utf8) {
    return str
  }
    
  // Otherwise, return a string representation of the bytes.
  return String(describing: [UInt8](UnsafeBufferPointer(start: data.data, count: Int(data.length))))
}

private func stringFromUInt8Array(_ data: [UInt8]) -> String {
  // Convert as a UTF8 string, if possible.
  let tmp = NSData(bytes: data, length: data.count)
  if let str = String(data: tmp as Data, encoding: String.Encoding.utf8) {
    return str
  }
    
  // Otherwise, return a string representation of the bytes.
  return String(describing: data)
}

/// Key objects are used to identify rules that can be built.
public struct Key: CustomStringConvertible, Equatable, Hashable {
  public let data: [UInt8]

  // MARK: CustomStringConvertible Conformance

  public var description: String {
    return "<Key: '\(toString())'>"
  }

  // MARK: Hashable Conformance

  public var hashValue: Int {
    // FIXME: Use a real hash function.
    var result = data.count
    for c in data {
      result = result*31 + Int(c)
    }
    return result
  }

  // MARK: Implementation

  public init(_ data: [UInt8]) { self.data = data }
  public init(_ str: String) { self.init(Array(str.utf8)) }

  /// Convert to a string representation.
  public func toString() -> String {
    return stringFromUInt8Array(self.data)
  }

  /// Create a Key object from an llb_data_t.
  fileprivate static func fromInternalData(_ data: llb_data_t) -> Key {
    return Key([UInt8](UnsafeBufferPointer(start: data.data, count: Int(data.length))))
  }

  /// Provide a Key contents as an llb_data_t pointer.
  fileprivate func withInternalDataPtr<T>(closure: (UnsafePointer<llb_data_t>) -> T) -> T {
    return data.withUnsafeBufferPointer { (dataPtr: UnsafeBufferPointer<UInt8>) -> T in
        var value = llb_data_t(length: UInt64(self.data.count), data: dataPtr.baseAddress)
        return withUnsafePointer(to: &value, closure)
    }
  }
}

public func ==(lhs: Key, rhs: Key) -> Bool {
  return lhs.data == rhs.data
}

/// Value objects are the result of building rules.
public struct Value: CustomStringConvertible {
  public let data: [UInt8]

  public var description: String {
    return "<Value: '\(toString())'>"
  }
    
  public init(_ data: [UInt8]) { self.data = data }
  public init(_ str: String) { self.init(Array(str.utf8)) }

  /// Convert to a string representation.
  public func toString() -> String {
    return stringFromUInt8Array(self.data)
  }
    
  /// Create a Value object from an llb_data_t.
  fileprivate static func fromInternalData(_ data: llb_data_t) -> Value {
    return Value([UInt8](UnsafeBufferPointer(start: data.data, count: Int(data.length))))
  }

  /// Provide a Value contents as an llb_data_t pointer.
  fileprivate func withInternalDataPtr<T>(closure: (UnsafePointer<llb_data_t>) -> T) -> T {
    return data.withUnsafeBufferPointer { (dataPtr: UnsafeBufferPointer<UInt8>) -> T in
        var value = llb_data_t(length: UInt64(self.data.count), data: dataPtr.baseAddress)
      return withUnsafePointer(to: &value, closure)
    }
  }
    
  /// Create a Value object by providing an pointer to write the output into.
  ///
  /// \param closure The closure to execute with a pointer to a llb_data_t to
  /// use. The structure *must* be filled in by the closure.
  ///
  /// \return The output Value.
  fileprivate static func fromInternalDataOutputPtr(closure: (UnsafeMutablePointer<llb_data_t>) -> Void) -> Value {
    var data = llb_data_t()
    withUnsafeMutablePointer(to: &data, closure)
    return Value.fromInternalData(data)
  }
}

/// Enumeration describing the possible status of a Rule, used by \see
/// Rule.updateStatus().
public enum RuleStatus {
  /// Indicates the rule is being scanned.
case IsScanning
  /// Indicates the rule is up-to-date, and doesn't need to run.
case IsUpToDate
  /// Indicates the rule was run, and is now complete.
case IsComplete
}

/// A rule represents an individual element of computation that can be performed
/// by the build engine.
///
/// Each rule is identified by a unique key and the value for that key can be
/// computed to produce a result, and supplies a set of callbacks that are used
/// to implement the rule's behavior.
///
/// The computation for a rule is done by invocation of its \see Action
/// callback, which is responsible for creating a Task object which will manage
/// the computation.
///
/// All callbacks for the Rule are always invoked synchronously on the primary
/// BuildEngine thread.
public protocol Rule {
  /// Called to create the task to build the rule, when necessary.
  func createTask() -> Task

  /// Called to check whether the previously computed value for this rule is
  /// still valid.
  ///
  /// This callback is designed for use in synchronizing values which represent
  /// state managed externally to the build engine. For example, a rule which
  /// computes something on the file system may use this to verify that the
  /// computed output has not changed since it was built.
  func isResultValid(_ priorValue: Value) -> Bool

  /// Called to indicate a change in the rule status.
  func updateStatus(_ status: RuleStatus)
}

/// Protocol extension for default Rule methods.
public extension Rule {
  final func isResultValid(_ priorValue: Value) -> Bool { return true }
  final func updateStatus(_ status: RuleStatus) { }
}

/// A task object represents an abstract in-progress computation in the build
/// engine.
///
/// The task represents not just the primary computation, but also the process
/// of starting the computation and necessary input dependencies. Tasks are
/// expected to be created in response to \see BuildEngine requests to initiate
/// the production of particular result value.
///
/// The creator may use \see TaskBuildEngine.taskNeedsInput() to specify input
/// dependencies on the Task. The Task itself may also specify additional input
/// dependencies dynamically during the execution of \see Task.start() or \see
/// Task.provideValue().
///
/// Once a task has been created and registered, the BuildEngine will invoke
/// \see Task::start() to initiate the computation. The BuildEngine will provide
/// the in progress task with its requested inputs via \see
/// Task.provideValue().
///
/// After all inputs requested by the Task have been delivered, the BuildEngine
/// will invoke \see Task.inputsAvailable() to instruct the Task it should
/// complete its computation and provide the output. The Task is responsible for
/// providing the engine with the computed value when ready using \see
/// TaskBuildEngine.taskIsComplete().
public protocol Task {
  /// Executed by the build engine when the task should be started.
  func start(_ engine: TaskBuildEngine)

  /// Invoked by the build engine to provide an input value as it becomes
  /// available.
  ///
  /// \param inputID The unique identifier provided to the build engine to
  /// represent this input when requested in \see
  /// TaskBuildEngine.taskNeedsInput().
  ///
  /// \param value The computed value for the given input.
  func provideValue(_ engine: TaskBuildEngine, inputID: Int, value: Value)

  /// Executed by the build engine to indicate that all inputs have been
  /// provided, and the task should begin its computation.
  ///
  /// The task is expected to call \see TaskBuildEngine.taskIsComplete() when it is
  /// done with its computation.
  ///
  /// It is an error for any client to request an additional input for a task
  /// after the last requested input has been provided by the build engine.
  func inputsAvailable(_ engine: TaskBuildEngine)
}

/// Delegate interface for use with the build engine.
public protocol BuildEngineDelegate {
  /// Get the rule to use for the given Key.
  ///
  /// The delegate *must* provide a rule for any possible key that can be
  /// requested (either by a client, through \see BuildEngine.build(), or via a
  /// Task through mechanisms such as \see TaskBuildEngine.taskNeedsInput(). If a
  /// requested Key cannot be supplied, the delegate should provide a dummy rule
  /// that the client can translate into an error.
  func lookupRule(_ key: Key) -> Rule
}

/// Wrapper to allow passing an opaque pointer to a protocol type.
//
// FIXME: Why do we need this, why can't we get a pointer to the protocol
// typed object?
private class Wrapper<T> {
  let item: T
  init(_ item: T) { self.item = item }
}

/// This protocol encapsulates the API that a task can use to communicate with
/// the build engine.
public protocol TaskBuildEngine {
  var engine: BuildEngine { get }

  /// Specify that the task depends upon the result of computing \arg key.
  ///
  /// The result, when available, will be provided to the task via \see
  /// Task.provideValue(), supplying the provided \arg inputID to allow the task
  /// to identify the particular input.
  ///
  /// NOTE: It is an unchecked error for a task to request the same input value
  /// multiple times.
  ///
  /// \param inputID An arbitrary value that may be provided by the client to
  /// use in efficiently associating this input.
  func taskNeedsInput(_ key: Key, inputID: Int)

  /// Specify that the task must be built subsequent to the computation of \arg
  /// key.
  ///
  /// The value of the computation of \arg key is not available to the task, and
  /// the only guarantee the engine provides is that if \arg key is computed
  /// during a build, then task will not be computed until after it.
  func taskMustFollow(_ key: Key)

  /// Inform the engine of an input dependency that was discovered by the task
  /// during its execution, a la compiler generated dependency files.
  ///
  /// This call may only be made after a task has received all of its inputs;
  /// inputs discovered prior to that point should simply be requested as normal
  /// input dependencies.
  ///
  /// Such a dependency is not used to provide additional input to the task,
  /// rather it is a way for the task to report an additional input which should
  /// be considered the next time the rule is evaluated. The expected use case
  /// for a discovered dependency is is when a processing task cannot predict
  /// all of its inputs prior to being run, but can presume that any unknown
  /// inputs already exist. In such cases, the task can go ahead and run and can
  /// report the all of the discovered inputs as it executes. Once the task is
  /// complete, these inputs will be recorded as being dependencies of the task
  /// so that it will be recomputed when any of the inputs change.
  ///
  /// It is legal to call this method from any thread, but the caller is
  /// responsible for ensuring that it is never called concurrently for the same
  /// task.
  func taskDiscoveredDependency(_ key: Key)

  /// Indicate that the task has completed and provide its resulting value.
  ///
  /// It is legal to call this method from any thread.
  ///
  /// \param value The new value for the task's rule.
  ///
  /// \param forceChange If true, treat the value as changed and trigger
  /// dependents to rebuild, even if the value itself is not different from the
  /// prior result.
  func taskIsComplete(_ result: Value, forceChange: Bool)
}

/// Single concrete implementation of the TaskBuildEngine protocol.
private class TaskWrapper: CustomStringConvertible, TaskBuildEngine {
  let engine: BuildEngine
  let task: Task
  var taskInternal: OpaquePointer?

  var description: String {
    return "<TaskWrapper engine:\(engine), task:\(task)>"
  }

  init(_ engine: BuildEngine, _ task: Task) {
    self.engine = engine
    self.task = task
  }

  func taskNeedsInput(_ key: Key, inputID: Int) {
    engine.taskNeedsInput(self, key: key, inputID: inputID)
  }

  func taskMustFollow(_ key: Key) {
    engine.taskMustFollow(self, key: key)
  }

  func taskDiscoveredDependency(_ key: Key) {
    engine.taskDiscoveredDependency(self, key: key)
  }

  func taskIsComplete(_ result: Value, forceChange: Bool = false) {
    engine.taskIsComplete(self, result: result, forceChange: forceChange)
  }
}

/// A build engine supports fast, incremental, persistent, and parallel
/// execution of computational graphs.
///
/// Computational elements in the graph are modeled by \see Rule objects, which
/// are assocated with a specific \see Key, and which can be executed to produce
/// an output \see Value for that key.
///
/// Rule objects are evaluated by first invoking their action to produce a \see
/// Task object which is responsible for the live execution of the
/// computation. The Task object can interact with the BuildEngine to request
/// inputs or to notify the engine of its completion, and receives various
/// callbacks from the engine as the computation progresses.
///
/// The engine itself executes using a deterministic, serial operation, but it
/// supports parallel computation by allowing the individual Task objects to
/// defer their own computation to signal the BuildEngine of its completion on
/// alternate threads.
///
/// To support persistence, the engine allows attaching a database (\see
/// attachDB()) which can be used to record the prior results of evaluating Rule
/// instances.
public class BuildEngine {
  /// The client delegate.
  private var delegate: BuildEngineDelegate

  /// The internal llbuild build engine.
  private var _engine: OpaquePointer?
    
  /// Our llbuild engine delegate object.
  private var _delegate = llb_buildengine_delegate_t()

  /// The number of rules which have been defined.
  public var numRules: Int = 0
    
  public init(delegate: BuildEngineDelegate) {
    self.delegate = delegate

    // Initialize the delegate.
    _delegate.context = unsafeBitCast(Unmanaged.passUnretained(self), to: UnsafeMutableRawPointer.self)

    _delegate.lookup_rule = { BuildEngine.toEngine($0!).lookupRule($1!, $2!) }
    // FIXME: Include cycleDetected callback.

    // Create the engine.
    _engine = llb_buildengine_create(_delegate)
  }

  deinit {
    if _engine != nil {
        close()
    }
  }

  public func close() {
    assert(_engine != nil)
    llb_buildengine_destroy(_engine)
    _engine = nil
  }
    
  /// Build the result for a particular key.
  public func build(key: Key) -> Value {
    return Value.fromInternalDataOutputPtr { resultPtr in
      key.withInternalDataPtr { llb_buildengine_build(self._engine, $0, resultPtr) }
    }
  }

  /// Attach a database for persisting build state.
  ///
  /// A database should only be attached immediately after creating the engine,
  /// it is an error to attach a database after adding rules or initiating any
  /// builds, or to attempt to attach multiple databases.
  public func attachDB(path: String, schemaVersion: Int = 0) throws {
    let errorPtr = UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>.allocate(capacity: 1)
    defer { errorPtr.deinitialize(count: 1) }

    // FIXME: Why do I have to name the closure signature here?
    var errorMsgOpt: String? = nil
    Key(path).withInternalDataPtr { (ptr) -> Void in
      if !llb_buildengine_attach_db(self._engine, ptr, UInt32(schemaVersion), errorPtr) {
        // If there was an error, report it.
        if let errorPointee = errorPtr.pointee {
            errorMsgOpt = String(cString: errorPointee)
        }
      }
    }
    // Throw the error, if found.
    if let errorMsg = errorMsgOpt {
      throw DatabaseError.AttachFailure(message: errorMsg)
    }
  }

  /// MARK: Internal Task-Only API

  fileprivate func taskNeedsInput(_ taskWrapper: TaskWrapper, key: Key, inputID: Int) {
    key.withInternalDataPtr { keyPtr in
      llb_buildengine_task_needs_input(self._engine, taskWrapper.taskInternal, keyPtr, UInt(inputID))
    }
  }

  fileprivate func taskMustFollow(_ taskWrapper: TaskWrapper, key: Key) {
    key.withInternalDataPtr { keyPtr in
      llb_buildengine_task_must_follow(self._engine, taskWrapper.taskInternal, keyPtr)
    }
  }

  fileprivate func taskDiscoveredDependency(_ taskWrapper: TaskWrapper, key: Key) {
    key.withInternalDataPtr { keyPtr in
      llb_buildengine_task_discovered_dependency(self._engine, taskWrapper.taskInternal, keyPtr)
    }
  }

  fileprivate func taskIsComplete(_ taskWrapper: TaskWrapper, result: Value, forceChange: Bool = false) {
    result.withInternalDataPtr { dataPtr in
      llb_buildengine_task_is_complete(self._engine, taskWrapper.taskInternal, dataPtr, forceChange)
    }
  }

  /// MARK: Internal Delegate Implementation

  /// Helper function for getting the engine from the delegate context.
  static fileprivate func toEngine(_ context: UnsafeMutableRawPointer) -> BuildEngine {
    return Unmanaged<BuildEngine>.fromOpaque(context).takeUnretainedValue()
  }

  /// Helper function for getting the rule from a rule delegate context.
  static fileprivate func toRule(_ context: UnsafeMutableRawPointer) -> Rule {
    return Unmanaged<Wrapper<Rule>>.fromOpaque(context).takeUnretainedValue().item
  }

  /// Helper function for getting the task from a task delegate context.
  static fileprivate func toTaskWrapper(_ context: UnsafeMutableRawPointer) -> TaskWrapper {
    return Unmanaged<TaskWrapper>.fromOpaque(context).takeUnretainedValue()
  }
  
  fileprivate func lookupRule(_ key: UnsafePointer<llb_data_t>, _ ruleOut: UnsafeMutablePointer<llb_rule_t>) {
    numRules += 1
    
    // Get the rule from the client.
    let rule = delegate.lookupRule(Key.fromInternalData(key.pointee))

    // Fill in the output structure.
    //
    // FIXME: We need a deallocation callback in order to ensure this is released.
    ruleOut.pointee.context = unsafeBitCast(Unmanaged.passRetained(Wrapper(rule)), to: UnsafeMutableRawPointer.self)
    ruleOut.pointee.create_task = { (context, engineContext) -> OpaquePointer! in
      let rule = BuildEngine.toRule(context!)
      let engine = BuildEngine.toEngine(engineContext!)
      return engine.ruleCreateTask(rule)
    }
    ruleOut.pointee.is_result_valid = { (context, engineContext, internalRule, value) -> Bool in
      let rule = BuildEngine.toRule(context!)
      return rule.isResultValid(Value.fromInternalData(value!.pointee))
    }
    ruleOut.pointee.update_status =  { (context, engineContext, status) in
      let rule = BuildEngine.toRule(context!)
      let status = { (kind: llb_rule_status_kind_t) -> RuleStatus in
        switch kind.rawValue {
          case llb_rule_is_scanning.rawValue: return .IsScanning
          case llb_rule_is_up_to_date.rawValue: return .IsUpToDate
          case llb_rule_is_complete.rawValue: return .IsComplete
          default:
            fatalError("unknown status kind")
        } }(status)
      return rule.updateStatus(status)
    }
  }

  private func ruleCreateTask(_ rule: Rule) -> OpaquePointer {
    // Create the task.
    let task = rule.createTask()

    // Create the task wrapper.
    //
    // Note that the wrapper here is serving two purposes, it is providing a way
    // to communicate the internal task object to clients, and it is providing a
    // way to segregate the Task-only API from the rest of the BuildEngine API.
    let taskWrapper = TaskWrapper(self, task)

    // Create the task delegate.
    //
    // FIXME: Separate the delegate from the context pointer.
    var taskDelegate = llb_task_delegate_t()
    // FIXME: We need a deallocation callback in order to ensure this is released.
    taskDelegate.context = unsafeBitCast(Unmanaged.passRetained(taskWrapper), to: UnsafeMutableRawPointer.self)
    taskDelegate.start = { (context, engineContext, internalTask) in
      let taskWrapper = BuildEngine.toTaskWrapper(context!)
      taskWrapper.task.start(taskWrapper)
    }
    taskDelegate.provide_value = { (context, engineContext, internalTask, inputID, value) in
      let taskWrapper = BuildEngine.toTaskWrapper(context!)
      taskWrapper.task.provideValue(taskWrapper, inputID: Int(inputID), value: Value.fromInternalData(value!.pointee))
    }
    taskDelegate.inputs_available = { (context, engineContext, internalTask) in
      let taskWrapper = BuildEngine.toTaskWrapper(context!)
      taskWrapper.task.inputsAvailable(taskWrapper)
    }

    // Create the internal task.
    taskWrapper.taskInternal = llb_task_create(taskDelegate)

    // FIXME: Why do we have both of these, it is kind of annoying. It makes
    // some amount of sense in the C++ API, but the C API should probably just
    // collapse them.
    return llb_buildengine_register_task(self._engine, taskWrapper.taskInternal)
  }
}
