text: module.exports = Level
  
  var IDB = require('idb-wrapper')
  var AbstractLevelDOWN = require('abstract-leveldown').AbstractLevelDOWN
  var util = require('util')
  var Iterator = require('./iterator')
  var isBuffer = require('isbuffer')
  var xtend = require('xtend')
  var toBuffer = require('typedarray-to-buffer')
  
  function Level(location) {
    if (!(this instanceof Level)) return new Level(location)
    if (!location) throw new Error("constructor requires at least a location argument")
    this.IDBOptions = {}
    this.location = location
  }
  
  util.inherits(Level, AbstractLevelDOWN)
  
  Level.prototype._open = function(options, callback) {
    var self = this
      
    var idbOpts = {
      storeName: this.location,
      autoIncrement: false,
      keyPath: null,
      onStoreReady: function () {
        callback && callback(null, self.idb)
      }, 
      onError: function(err) {
        callback && callback(err)
      }
    }
    
    xtend(idbOpts, options)
    this.IDBOptions = idbOpts
    this.idb = new IDB(idbOpts)
  }
  
  Level.prototype._get = function (key, options, callback) {
    this.idb.get(key, function (value) {
      if (value === undefined) {
        // 'NotFound' error, consistent with LevelDOWN API
        return callback(new Error('NotFound'))
      }
      // by default return buffers, unless explicitly told not to
      var asBuffer = true
      if (options.asBuffer === false) asBuffer = false
      if (options.raw) asBuffer = false
      if (asBuffer) {
        if (value instanceof Uint8Array) value = toBuffer(value)
        else value = new Buffer(String(value))
      }
      return callback(null, value, key)
    }, callback)
  }
  
  Level.prototype._del = function(id, options, callback) {
    this.idb.remove(id, callback, callback)
  }
  
  Level.prototype._put = function (key, value, options, callback) {
    if (value instanceof ArrayBuffer) {
      value = toBuffer(new Uint8Array(value))
    }
    var obj = this.convertEncoding(key, value, options)
    if (Buffer.isBuffer(obj.value)) {
      if (typeof value.toArrayBuffer === 'function') {
        obj.value = new Uint8Array(value.toArrayBuffer())
      } else {
        obj.value = new Uint8Array(value)
      }
    }
    this.idb.put(obj.key, obj.value, function() { callback() }, callback)
  }
  
  Level.prototype.convertEncoding = function(key, value, options) {
    if (options.raw) return {key: key, value: value}
    if (value) {
      var stringed = value.toString()
      if (stringed === 'NaN') value = 'NaN'
    }
    var valEnc = options.valueEncoding
    var obj = {key: key, value: value}
    if (value && (!valEnc || valEnc !== 'binary')) {
      if (typeof obj.value !== 'object') {
        obj.value = stringed
      }
    }
    return obj
  }
  
  Level.prototype.iterator = function (options) {
    if (typeof options !== 'object') options = {}
    return new Iterator(this.idb, options)
  }
  
  Level.prototype._batch = function (array, options, callback) {
    var op
    var i
    var k
    var copiedOp
    var currentOp
    var modified = []
    
    if (array.length === 0) return setTimeout(callback, 0)
    
    for (i = 0; i < array.length; i++) {
      copiedOp = {}
      currentOp = array[i]
      modified[i] = copiedOp
      
      var converted = this.convertEncoding(currentOp.key, currentOp.value, options)
      currentOp.key = converted.key
      currentOp.value = converted.value
  
      for (k in currentOp) {
        if (k === 'type' && currentOp[k] == 'del') {
          copiedOp[k] = 'remove'
        } else {
          copiedOp[k] = currentOp[k]
        }
      }
    }
  
    return this.idb.batch(modified, function(){ callback() }, callback)
  }
  
  Level.prototype._close = function (callback) {
    this.idb.db.close()
    callback()
  }
  
  Level.prototype._approximateSize = function (start, end, callback) {
    var err = new Error('Not implemented')
    if (callback)
      return callback(err)
  
    throw err
  }
  
  Level.prototype._isBuffer = function (obj) {
    return Buffer.isBuffer(obj)
  }
  
  Level.destroy = function (db, callback) {
    if (typeof db === 'object') {
      var prefix = db.IDBOptions.storePrefix || 'IDBWrapper-'
      var dbname = db.location
    } else {
      var prefix = 'IDBWrapper-'
      var dbname = db
    }
    var request = indexedDB.deleteDatabase(prefix + dbname)
    request.onsuccess = function() {
      callback()
    }
    request.onerror = function(err) {
      callback(err)
    }
  }
  
  var checkKeyValue = Level.prototype._checkKeyValue = function (obj, type) {
    if (obj === null || obj === undefined)
      return new Error(type + ' cannot be `null` or `undefined`')
    if (obj === null || obj === undefined)
      return new Error(type + ' cannot be `null` or `undefined`')
    if (isBuffer(obj) && obj.byteLength === 0)
      return new Error(type + ' cannot be an empty ArrayBuffer')
    if (String(obj) === '')
      return new Error(type + ' cannot be an empty String')
    if (obj.length === 0)
      return new Error(type + ' cannot be an empty Array')
  }
  