
var ResultType = require('result-type')
var inherit = require('inherit')
var Result = require('./index')
var transfer = Result.transfer

/**
 * Deferred class
 */

function Deferred(fn){
  this.onNeed = fn
}

inherit(Deferred, Result) // inherit from Result

Deferred.prototype.state = 'awaiting'
Deferred.prototype.then = trigger(Result.prototype.then)
Deferred.prototype.read = trigger(Result.prototype.read)
Deferred.prototype.write = unawait(Result.prototype.write)
Deferred.prototype.error = unawait(Result.prototype.error)

/**
 * add a trigger aspect to `method`. This aspect
 * ensures `onNeed` is called on first read().
 *
 * @param {Function} method
 * @return {Function}
 * @api private
 */

function trigger(method){
  return function(onValue, onError){
    if (this.state === 'awaiting') {
      this.state = 'pending'
      try {
        transfer(this.onNeed(), this)
      } catch (e) {
        this.error(e)
      }
    }
    return method.call(this, onValue, onError)
  }
}

/**
 * add a state switching aspect to `method`.
 * Otherwise write/error would behave incorrectly
 *
 * @param {Function} method
 * @return {Function}
 * @api private
 */

function unawait(method){
  return function(value){
    if (this.state === 'awaiting') this.state = 'pending'
    return method.call(this, value)
  }
}

/**
 * create a Deferred which is associated with the
 * Function `onNeed`. `onNeed` will only be called
 * once someone actually reads from the Deferred.
 *
 *   defer(function(){
 *     this.write('hello')
 *   })
 *
 *   defer(function(cb){
 *     cb(null, 'hello')
 *   })
 *
 *   defer(function(write, error){
 *     write('hello')
 *   })
 *
 * @param {Function} onNeed(write, error)
 * @return {Deferred}
 */

function defer(onNeed){
  switch (onNeed.length) {
    case 2: return new Deferred(function(){
      var res = new Result
      onNeed.call(this,
        function(v){ res.write(v) },
        function(e){ res.error(e) })
      return res
    })
    case 1: return new Deferred(function(){
      var res = new Result
      onNeed.call(this, function(e, v){
        if (e != null) res.error(e)
        else res.write(v)
      })
      return res
    })
    default: return new Deferred(onNeed)
  }
}

module.exports = defer // expose defer
defer.prototype = Deferred.prototype // share prototypes
defer.Deferred = Deferred // expose class

@@ -207,56 +207,65 @@
 %0A%7D%0A%0A
-inherit(Deferred,
+/**%0A * inherit from
  Result
-) // 
+%0A */%0A%0A
 inherit
- from
+(Deferred,
  Result
+)
 %0A%0ADe
@@ -285,26 +285,22 @@
 ype.
-state = 'awaiting'
+called = false
 %0ADef
@@ -413,126 +413,8 @@
 ead)
-%0ADeferred.prototype.write = unawait(Result.prototype.write)%0ADeferred.prototype.error = unawait(Result.prototype.error)
 %0A%0A/*
@@ -673,52 +673,62 @@
 e ==
-=
  '
-awaiting') %7B%0A      this.state = 'pending'
+pending' && !this.called) %7B%0A      this.called = true
 %0A   
@@ -888,334 +888,8 @@
 %0A%7D%0A%0A
-/**%0A * add a state switching aspect to %60method%60.%0A * Otherwise write/error would behave incorrectly%0A *%0A * @param %7BFunction%7D method%0A * @return %7BFunction%7D%0A * @api private%0A */%0A%0Afunction unawait(method)%7B%0A  return function(value)%7B%0A    if (this.state === 'awaiting') this.state = 'pending'%0A    return method.call(this, value)%0A  %7D%0A%7D%0A%0A
 /**%0A

use "pending" for the initial state of a deferred