'use strict';

const EventEmitter = require('events').EventEmitter;
const Log          = require('ipfs-log');
const Index        = require('./Index');
const Cache        = require('./Cache');

class Store {
  constructor(ipfs, id, dbname, options) {
    this.id = id;
    this.dbname = dbname;
    this.events = new EventEmitter();

    if(!options) options = {};
    if(!options.Index) Object.assign(options, { Index: Index });
    if(!options.cacheFile) Object.assign(options, { cacheFile: null });

    this.options = options;
    this._index = new this.options.Index(this.id);
    this._oplog = null;
    this._ipfs = ipfs;
    this._lastWrite = null;
  }

  use() {
    this.events.emit('load', this.dbname);
    this._oplog = new Log(this._ipfs, this.id, this.dbname, this.options);
    return Cache.loadCache(this.options.cacheFile).then(() => {
      const cached = Cache.get(this.dbname);
      if(cached) {
        return Log.fromIpfsHash(this._ipfs, cached)
          .then((log) => this._oplog.join(log))
          .then((merged) => this._index.updateIndex(this._oplog, merged))
          .then(() => this.events.emit('readable', this.dbname))
          .then(() => this.events);
      }

      return Promise.resolve(this.events);
    });
  }

  close() {
    this.events.emit('close', this.dbname);
  }

  sync(hash) {
    if(!hash || hash === this._lastWrite)
      return Promise.resolve([]);

    const oldCount = this._oplog.items.length;
    let newItems = [];
    this.events.emit('load', this.dbname);
    return Log.fromIpfsHash(this._ipfs, hash)
      .then((log) => this._oplog.join(log))
      .then((merged) => newItems = merged)
      .then(() => Log.getIpfsHash(this._ipfs, this._oplog))
      .then((hash) => Cache.set(this.dbname, hash))
      .then(() => this._index.updateIndex(this._oplog, newItems))
      .then(() => {
        if(newItems.length > 0)
          this.events.emit('readable', this.dbname);
      })
      .then(() => newItems)
  }

  delete() {
    this._index = new this.options.Index(this.id);
    if(this._oplog)
      this._oplog.clear();
  }

  _addOperation(data) {
    let result, logHash;
    if(this._oplog) {
      return this._oplog.add(data)
        .then((res) => {
          result = res;
          Object.assign(result.payload, { hash: res.hash })
          return result;
        })
        .then(() => Log.getIpfsHash(this._ipfs, this._oplog))
        .then((hash) => logHash = hash)
        .then(() => this._lastWrite = logHash)
        .then(() => Cache.set(this.dbname, logHash))
        .then(() => this._index.updateIndex(this._oplog, [result]))
        .then(() => this.events.emit('data', this.dbname, logHash))
        .then(() => result.hash);
    }
  }
}

module.exports = Store;

@@ -1171,31 +1171,24 @@
 n(() =%3E this
-.events
 );%0A      %7D%0A%0A
@@ -1220,23 +1220,16 @@
 lve(this
-.events
 );%0A    %7D

Return self instead of events