text: 'use strict';
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  /* Copyright (c) 2013 Rod Vagg, MIT License */
  
  var xtend = require('xtend'),
      AbstractIterator = require('./abstract-iterator'),
      AbstractChainedBatch = require('./abstract-chained-batch');
  
  function AbstractLevelDOWN(location) {
    if (!arguments.length || location === undefined) throw new Error('constructor requires at least a location argument');
  
    if (typeof location != 'string') throw new Error('constructor requires a location string argument');
  
    this.location = location;
  }
  
  AbstractLevelDOWN.prototype.open = function (options, callback) {
    if (typeof options == 'function') callback = options;
  
    if (typeof callback != 'function') throw new Error('open() requires a callback argument');
  
    if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) != 'object') options = {};
  
    if (typeof this._open == 'function') return this._open(options, callback);
  
    process.nextTick(callback);
  };
  
  AbstractLevelDOWN.prototype.close = function (callback) {
    if (typeof callback != 'function') throw new Error('close() requires a callback argument');
  
    if (typeof this._close == 'function') return this._close(callback);
  
    process.nextTick(callback);
  };
  
  AbstractLevelDOWN.prototype.get = function (key, options, callback) {
    var err;
  
    if (typeof options == 'function') callback = options;
  
    if (typeof callback != 'function') throw new Error('get() requires a callback argument');
  
    if (err = this._checkKeyValue(key, 'key', this._isBuffer)) return callback(err);
  
    if (!this._isBuffer(key)) key = String(key);
  
    if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) != 'object') options = {};
  
    if (typeof this._get == 'function') return this._get(key, options, callback);
  
    process.nextTick(function () {
      callback(new Error('NotFound'));
    });
  };
  
  AbstractLevelDOWN.prototype.put = function (key, value, options, callback) {
    var err;
  
    if (typeof options == 'function') callback = options;
  
    if (typeof callback != 'function') throw new Error('put() requires a callback argument');
  
    if (err = this._checkKeyValue(key, 'key', this._isBuffer)) return callback(err);
  
    if (err = this._checkKeyValue(value, 'value', this._isBuffer)) return callback(err);
  
    if (!this._isBuffer(key)) key = String(key);
  
    // coerce value to string in node, don't touch it in browser
    // (indexeddb can store any JS type)
    if (!this._isBuffer(value) && !process.browser) value = String(value);
  
    if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) != 'object') options = {};
  
    if (typeof this._put == 'function') return this._put(key, value, options, callback);
  
    process.nextTick(callback);
  };
  
  AbstractLevelDOWN.prototype.del = function (key, options, callback) {
    var err;
  
    if (typeof options == 'function') callback = options;
  
    if (typeof callback != 'function') throw new Error('del() requires a callback argument');
  
    if (err = this._checkKeyValue(key, 'key', this._isBuffer)) return callback(err);
  
    if (!this._isBuffer(key)) key = String(key);
  
    if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) != 'object') options = {};
  
    if (typeof this._del == 'function') return this._del(key, options, callback);
  
    process.nextTick(callback);
  };
  
  AbstractLevelDOWN.prototype.batch = function (array, options, callback) {
    if (!arguments.length) return this._chainedBatch();
  
    if (typeof options == 'function') callback = options;
  
    if (typeof callback != 'function') throw new Error('batch(array) requires a callback argument');
  
    if (!Array.isArray(array)) return callback(new Error('batch(array) requires an array argument'));
  
    if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) != 'object') options = {};
  
    var i = 0,
        l = array.length,
        e,
        err;
  
    for (; i < l; i++) {
      e = array[i];
      if ((typeof e === 'undefined' ? 'undefined' : _typeof(e)) != 'object') continue;
  
      if (err = this._checkKeyValue(e.type, 'type', this._isBuffer)) return callback(err);
  
      if (err = this._checkKeyValue(e.key, 'key', this._isBuffer)) return callback(err);
  
      if (e.type == 'put') {
        if (err = this._checkKeyValue(e.value, 'value', this._isBuffer)) return callback(err);
      }
    }
  
    if (typeof this._batch == 'function') return this._batch(array, options, callback);
  
    process.nextTick(callback);
  };
  
  //TODO: remove from here, not a necessary primitive
  AbstractLevelDOWN.prototype.approximateSize = function (start, end, callback) {
    if (start == null || end == null || typeof start == 'function' || typeof end == 'function') {
      throw new Error('approximateSize() requires valid `start`, `end` and `callback` arguments');
    }
  
    if (typeof callback != 'function') throw new Error('approximateSize() requires a callback argument');
  
    if (!this._isBuffer(start)) start = String(start);
  
    if (!this._isBuffer(end)) end = String(end);
  
    if (typeof this._approximateSize == 'function') return this._approximateSize(start, end, callback);
  
    process.nextTick(function () {
      callback(null, 0);
    });
  };
  
  AbstractLevelDOWN.prototype._setupIteratorOptions = function (options) {
    var self = this;
  
    options = xtend(options);['start', 'end', 'gt', 'gte', 'lt', 'lte'].forEach(function (o) {
      if (options[o] && self._isBuffer(options[o]) && options[o].length === 0) delete options[o];
    });
  
    options.reverse = !!options.reverse;
  
    // fix `start` so it takes into account gt, gte, lt, lte as appropriate
    if (options.reverse && options.lt) options.start = options.lt;
    if (options.reverse && options.lte) options.start = options.lte;
    if (!options.reverse && options.gt) options.start = options.gt;
    if (!options.reverse && options.gte) options.start = options.gte;
  
    if (options.reverse && options.lt && !options.lte || !options.reverse && options.gt && !options.gte) options.exclusiveStart = true; // start should *not* include matching key
  
    return options;
  };
  
  AbstractLevelDOWN.prototype.iterator = function (options) {
    if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) != 'object') options = {};
  
    options = this._setupIteratorOptions(options);
  
    if (typeof this._iterator == 'function') return this._iterator(options);
  
    return new AbstractIterator(this);
  };
  
  AbstractLevelDOWN.prototype._chainedBatch = function () {
    return new AbstractChainedBatch(this);
  };
  
  AbstractLevelDOWN.prototype._isBuffer = function (obj) {
    return Buffer.isBuffer(obj);
  };
  
  AbstractLevelDOWN.prototype._checkKeyValue = function (obj, type) {
  
    if (obj === null || obj === undefined) return new Error(type + ' cannot be `null` or `undefined`');
  
    if (this._isBuffer(obj)) {
      if (obj.length === 0) return new Error(type + ' cannot be an empty Buffer');
    } else if (String(obj) === '') return new Error(type + ' cannot be an empty String');
  };
  
  module.exports.AbstractLevelDOWN = AbstractLevelDOWN;
  module.exports.AbstractIterator = AbstractIterator;
  module.exports.AbstractChainedBatch = AbstractChainedBatch;