import inherits from 'inherits';
import Adapter from './adapter';
import TaskQueue from './taskqueue';
import { clone } from 'pouchdb-utils';
import parseAdapter from './parseAdapter';

// OK, so here's the deal. Consider this code:
//     var db1 = new PouchDB('foo');
//     var db2 = new PouchDB('foo');
//     db1.destroy();
// ^ these two both need to emit 'destroyed' events,
// as well as the PouchDB constructor itself.
// So we have one db object (whichever one got destroy() called on it)
// responsible for emitting the initial event, which then gets emitted
// by the constructor, which then broadcasts it to any other dbs
// that may have been created with the same name.
function prepareForDestruction(self) {

  var destructionListeners = self.constructor._destructionListeners;

  function onDestroyed() {
    self.removeListener('closed', onClosed);
    self.constructor.emit('destroyed', self.name);
  }

  function onConstructorDestroyed() {
    self.removeListener('destroyed', onDestroyed);
    self.removeListener('closed', onClosed);
    self.emit('destroyed');
  }

  function onClosed() {
    self.removeListener('destroyed', onDestroyed);
    destructionListeners.delete(self.name);
  }

  self.once('destroyed', onDestroyed);
  self.once('closed', onClosed);

  // in setup.js, the constructor is primed to listen for destroy events
  if (!destructionListeners.has(self.name)) {
    destructionListeners.set(self.name, []);
  }
  destructionListeners.get(self.name).push(onConstructorDestroyed);
}

inherits(PouchDB, Adapter);
function PouchDB(name, opts) {
  // In Node our test suite only tests this for PouchAlt unfortunately
  /* istanbul ignore if */
  if (!(this instanceof PouchDB)) {
    return new PouchDB(name, opts);
  }

  var self = this;
  opts = opts || {};

  if (name && typeof name === 'object') {
    opts = name;
    name = opts.name;
    delete opts.name;
  }

  this.__opts = opts = clone(opts);

  self.auto_compaction = opts.auto_compaction;
  self.prefix = PouchDB.prefix;

  if (typeof name !== 'string') {
    throw new Error('Missing/invalid DB name');
  }

  var prefixedName = (opts.prefix || '') + name;
  var backend = parseAdapter(prefixedName, opts);

  opts.name = backend.name;
  opts.adapter = opts.adapter || backend.adapter;

  self.name = name;
  self._adapter = opts.adapter;
  PouchDB.emit('debug', ['adapter', 'Picked adapter: ', opts.adapter]);

  if (!PouchDB.adapters[opts.adapter] ||
      !PouchDB.adapters[opts.adapter].valid()) {
    throw new Error('Invalid Adapter: ' + opts.adapter);
  }

  Adapter.call(self);
  self.taskqueue = new TaskQueue();

  self.adapter = opts.adapter;

  PouchDB.adapters[opts.adapter].call(self, opts, function (err) {
    if (err) {
      return self.taskqueue.fail(err);
    }
    prepareForDestruction(self);

    self.emit('created', self);
    PouchDB.emit('created', self.name);
    self.taskqueue.ready(self);
  });

}

export default PouchDB;
