var encodings = require('./lib/encodings')

module.exports = Codec

function Codec (opts) {
  if (!(this instanceof Codec)) {
    return new Codec(opts)
  }
  this.opts = opts || {}
  this.encodings = encodings
}

Codec.prototype._encoding = function (encoding) {
  if (typeof encoding === 'string') encoding = encodings[encoding]
  if (!encoding) encoding = encodings.id
  return encoding
}

Codec.prototype._keyEncoding = function (opts, batchOpts) {
  return this._encoding((batchOpts && batchOpts.keyEncoding) ||
                        (opts && opts.keyEncoding) ||
                        this.opts.keyEncoding)
}

Codec.prototype._valueEncoding = function (opts, batchOpts) {
  return this._encoding((batchOpts && (batchOpts.valueEncoding || batchOpts.encoding)) ||
                        (opts && (opts.valueEncoding || opts.encoding)) ||
                        (this.opts.valueEncoding || this.opts.encoding))
}

Codec.prototype.encodeKey = function (key, opts, batchOpts) {
  return this._keyEncoding(opts, batchOpts).encode(key)
}

Codec.prototype.encodeValue = function (value, opts, batchOpts) {
  return this._valueEncoding(opts, batchOpts).encode(value)
}

Codec.prototype.decodeKey = function (key, opts) {
  return this._keyEncoding(opts).decode(key)
}

Codec.prototype.decodeValue = function (value, opts) {
  return this._valueEncoding(opts).decode(value)
}

Codec.prototype.encodeBatch = function (ops, opts) {
  var self = this

  return ops.map(function (_op) {
    var op = {
      type: _op.type,
      key: self.encodeKey(_op.key, opts, _op)
    }
    if (self.keyAsBuffer(opts, _op)) op.keyEncoding = 'binary'
    if (_op.prefix) op.prefix = _op.prefix
    if ('value' in _op) {
      op.value = self.encodeValue(_op.value, opts, _op)
      if (self.valueAsBuffer(opts, _op)) op.valueEncoding = 'binary'
    }
    return op
  })
}

var ltgtKeys = ['lt', 'gt', 'lte', 'gte', 'start', 'end']

Codec.prototype.encodeLtgt = function (ltgt) {
  var self = this
  var ret = {}
  Object.keys(ltgt).forEach(function (key) {
    ret[key] = ltgtKeys.indexOf(key) > -1
      ? self.encodeKey(ltgt[key], ltgt)
      : ltgt[key]
  })
  return ret
}

Codec.prototype.createStreamDecoder = function (opts) {
  var self = this

  if (opts.keys && opts.values) {
    return function (key, value) {
      return {
        key: self.decodeKey(key, opts),
        value: self.decodeValue(value, opts)
      }
    }
  } else if (opts.keys) {
    return function (key) {
      return self.decodeKey(key, opts)
    }
  } else if (opts.values) {
    return function (_, value) {
      return self.decodeValue(value, opts)
    }
  } else {
    return function () {}
  }
}

Codec.prototype.keyAsBuffer = function (opts) {
  return this._keyEncoding(opts).buffer
}

Codec.prototype.valueAsBuffer = function (opts) {
  return this._valueEncoding(opts).buffer
}
