
var fs = require('fs')
var isstream = require('isstream')


function contentLength (req, options, done) {
  if (options.headers.get('transfer-encoding') === 'chunked' ||
      options.headers.get('content-length') !== undefined) {
    return done()
  }

  if (options.body && !options.multipart) {
    if (isstream(options.body)) {
      contentLengthAsync(options.body, done)
    }
    else {
      done(contentLengthSync(options.body))
    }
  }
  else if (req._src) {
    contentLengthAsync(req._src, done)
  }
  else if (options.multipart) {
    contentLengthMultipart(options.body, done)
  }
}

function contentLengthSync (body) {
  var length = 0
  if (typeof body === 'string') {
    length = Buffer.byteLength(body)
  }
  else if (Array.isArray(body)) {
    length = body.reduce(function (a, b) {return a + b.length}, 0)
  }
  else if (Buffer.isBuffer(body)) {
    length = body.length
  }

  return length
}

function contentLengthAsync (body, done) {
  // file stream
  if (body.hasOwnProperty('fd')) {
    fs.stat(body.path, function (err, stats) {
      if (err) return done(0)
      done(stats.size)
    })
  }
  // http response
  else if (body.hasOwnProperty('httpVersion')) {
    done(parseInt(body.headers['content-length']))
  }
  // request
  else if (body.hasOwnProperty('httpModule')) {
    body.on('response', function (res) {
      done(parseInt(res.headers['content-length']))
    })
  }
  // request-next
  else if (body.hasOwnProperty('_client')) {
    body.on('response', function (res) {
      done(parseInt(res.headers.get('content-length')) || 0)
    })
  }
  else {
    done(0)
  }
}

function contentLengthMultipart (body, done) {
  var length = 0
  body._items.forEach(function (item) {
    length += contentLengthSync(item)
  })
  if (!body._streams.length) return done(length)

  // should be parallel
  ;(function loop (index) {
    if (index === body._streams.length) {
      return done(length)
    }
    var stream = body._streams[index]
    if (stream._knownLength) {
      length += stream._knownLength
      loop(++index)
    }
    else {
      contentLengthAsync(stream, function (len) {
        length += len
        loop(++index)
      })
    }
  }(0))
}

module.exports = contentLength


var isstream = require('isstream')
  , length = require('request-length')


function contentLength (req, options, done) {
  if (options.headers.get('transfer-encoding') === 'chunked' ||
      options.headers.get('content-length') !== undefined) {
    return done()
  }

  if (options.body && !options.multipart) {
    if (isstream(options.body)) {
      length.async(options.body, done)
    }
    else {
      done(length.sync(options.body))
    }
  }
  else if (req._src) {
    length.async(req._src, done)
  }
  else if (options.multipart) {
    length.multipart(options.body, done)
  }
}

module.exports = contentLength

Move content-length logic into separate module