/* */ 
"use strict";
module.exports = function(Promise, INTERNAL) {
  var util = require('./util');
  var TimeoutError = Promise.TimeoutError;
  var afterTimeout = function(promise, message, parent) {
    if (!promise.isPending())
      return;
    var err;
    if (typeof message !== "string") {
      if (message instanceof Error) {
        err = message;
      } else {
        err = new TimeoutError("operation timed out");
      }
    } else {
      err = new TimeoutError(message);
    }
    util.markAsOriginatingFromRejection(err);
    promise._attachExtraTrace(err);
    promise._reject(err);
    parent.cancel();
  };
  var afterValue = function(value) {
    return delay(+this).thenReturn(value);
  };
  var delay = Promise.delay = function(ms, value) {
    var ret;
    if (value !== undefined) {
      ret = Promise.resolve(value)._then(afterValue, null, null, ms, undefined);
    } else {
      ret = new Promise(INTERNAL);
      setTimeout(function() {
        ret._fulfill();
      }, +ms);
    }
    ret._setAsyncGuaranteed();
    return ret;
  };
  Promise.prototype.delay = function(ms) {
    return delay(ms, this);
  };
  function successClear(value) {
    var handle = this;
    if (handle instanceof Number)
      handle = +handle;
    clearTimeout(handle);
    return value;
  }
  function failureClear(reason) {
    var handle = this;
    if (handle instanceof Number)
      handle = +handle;
    clearTimeout(handle);
    throw reason;
  }
  Promise.prototype.timeout = function(ms, message) {
    ms = +ms;
    var parent = this.then();
    var ret = parent.then();
    var handle = setTimeout(function timeoutTimeout() {
      afterTimeout(ret, message, parent);
    }, ms);
    return ret._then(successClear, failureClear, undefined, handle, undefined);
  };
};
