define(["exports", "core/pubsubhub", "deps/regenerator"], function (exports, _pubsubhub) {
  "use strict";

  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.biblioDB = undefined;

  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;
  };

  function _asyncToGenerator(fn) {
    return function () {
      var gen = fn.apply(this, arguments);
      return new Promise(function (resolve, reject) {
        function step(key, arg) {
          try {
            var info = gen[key](arg);
            var value = info.value;
          } catch (error) {
            reject(error);
            return;
          }

          if (info.done) {
            resolve(value);
          } else {
            return Promise.resolve(value).then(function (value) {
              step("next", value);
            }, function (err) {
              step("throw", err);
            });
          }
        }

        return step("next");
      });
    };
  }

  var ALLOWED_TYPES = new Set(["alias", "reference"]);
  // Database initialization, tracked by "readyPromise"
  var readyPromise = new Promise(function (resolve, reject) {
    var request = void 0;
    try {
      request = window.indexedDB.open("respec-biblio", 1);
    } catch (err) {
      return reject(err);
    }
    request.onerror = function () {
      reject(new DOMException(request.error.message, request.error.name));
    };
    request.onsuccess = function () {
      resolve(request.result);
    };
    request.onupgradeneeded = function () {
      var db = request.result;
      Array.from(db.objectStoreNames).map(function (storeName) {
        return db.deleteObjectStore(storeName);
      });
      var promisesToCreateSchema = [new Promise(function (resolve, reject) {
        try {
          var store = db.createObjectStore("alias", { keyPath: "id" });
          store.createIndex("aliasOf", "aliasOf", { unique: false });
          store.transaction.oncomplete = resolve;
        } catch (err) {
          reject(err);
        }
      }), new Promise(function (resolve, reject) {
        try {
          db.createObjectStore("reference", { keyPath: "id" }).transaction.oncomplete = resolve;
        } catch (err) {
          reject(err);
        }
      })];
      Promise.all(promisesToCreateSchema).catch(reject);
    };
  });

  var biblioDB = exports.biblioDB = {
    get ready() {
      return readyPromise;
    },
    find: function find(id) {
      var _this = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
        return regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return _this.isAlias(id);

              case 2:
                if (!_context.sent) {
                  _context.next = 6;
                  break;
                }

                _context.next = 5;
                return _this.resolveAlias(id);

              case 5:
                id = _context.sent;

              case 6:
                return _context.abrupt("return", _this.get("reference", id));

              case 7:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, _this);
      }))();
    },
    has: function has(type, id) {
      var _this2 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
        var db;
        return regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                if (ALLOWED_TYPES.has(type)) {
                  _context2.next = 2;
                  break;
                }

                throw new TypeError("Invalid type: " + type);

              case 2:
                if (id) {
                  _context2.next = 4;
                  break;
                }

                throw new TypeError("id is required");

              case 4:
                _context2.next = 6;
                return _this2.ready;

              case 6:
                db = _context2.sent;
                return _context2.abrupt("return", new Promise(function (resolve, reject) {
                  var objectStore = db.transaction([type], "readonly").objectStore(type);
                  var range = IDBKeyRange.only(id);
                  var request = objectStore.openCursor(range);
                  request.onsuccess = function () {
                    resolve(!!request.result);
                  };
                  request.onerror = function () {
                    reject(new DOMException(request.error.message, request.error.name));
                  };
                }));

              case 8:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, _this2);
      }))();
    },
    isAlias: function isAlias(id) {
      var _this3 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee3() {
        var db;
        return regeneratorRuntime.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                if (id) {
                  _context3.next = 2;
                  break;
                }

                throw new TypeError("id is required");

              case 2:
                _context3.next = 4;
                return _this3.ready;

              case 4:
                db = _context3.sent;
                return _context3.abrupt("return", new Promise(function (resolve, reject) {
                  var objectStore = db.transaction(["alias"], "readonly").objectStore("alias");
                  var range = IDBKeyRange.only(id);
                  var request = objectStore.openCursor(range);
                  request.onsuccess = function () {
                    resolve(!!request.result);
                  };
                  request.onerror = function () {
                    reject(new DOMException(request.error.message, request.error.name));
                  };
                }));

              case 6:
              case "end":
                return _context3.stop();
            }
          }
        }, _callee3, _this3);
      }))();
    },
    resolveAlias: function resolveAlias(id) {
      var _this4 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee4() {
        var db;
        return regeneratorRuntime.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                if (id) {
                  _context4.next = 2;
                  break;
                }

                throw new TypeError("id is required");

              case 2:
                _context4.next = 4;
                return _this4.ready;

              case 4:
                db = _context4.sent;
                return _context4.abrupt("return", new Promise(function (resolve, reject) {
                  var objectStore = db.transaction("alias", "readonly").objectStore("alias");
                  var range = IDBKeyRange.only(id);
                  var request = objectStore.openCursor(range);
                  request.onsuccess = function () {
                    if (request.result === null) {
                      return resolve(null);
                    }
                    resolve(request.result.value.aliasOf);
                  };
                  request.onerror = function () {
                    reject(new DOMException(request.error.message, request.error.name));
                  };
                }));

              case 6:
              case "end":
                return _context4.stop();
            }
          }
        }, _callee4, _this4);
      }))();
    },
    get: function get(type, id) {
      var _this5 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee5() {
        var db;
        return regeneratorRuntime.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                if (ALLOWED_TYPES.has(type)) {
                  _context5.next = 2;
                  break;
                }

                throw new TypeError("Invalid type: " + type);

              case 2:
                if (id) {
                  _context5.next = 4;
                  break;
                }

                throw new TypeError("id is required");

              case 4:
                _context5.next = 6;
                return _this5.ready;

              case 6:
                db = _context5.sent;
                return _context5.abrupt("return", new Promise(function (resolve, reject) {
                  var objectStore = db.transaction([type], "readonly").objectStore(type);
                  var range = IDBKeyRange.only(id);
                  var request = objectStore.openCursor(range);
                  request.onsuccess = function () {
                    if (request.result === null) {
                      return resolve(null);
                    }
                    resolve(request.result.value);
                  };
                  request.onerror = function () {
                    reject(new DOMException(request.error.message, request.error.name));
                  };
                }));

              case 8:
              case "end":
                return _context5.stop();
            }
          }
        }, _callee5, _this5);
      }))();
    },
    addAll: function addAll(data) {
      var _this6 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee6() {
        var aliasesAndRefs, promisesToAdd;
        return regeneratorRuntime.wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                if (data) {
                  _context6.next = 2;
                  break;
                }

                return _context6.abrupt("return");

              case 2:
                aliasesAndRefs = {
                  alias: new Set(),
                  reference: new Set()
                };

                Object.keys(data).filter(function (key) {
                  if (typeof data[key] === "string") {
                    var msg = "Legacy SpecRef entries are not supported: [[" + key + "]]. ";
                    msg += "Please update it at https://github.com/tobie/specref/";
                    (0, _pubsubhub.pub)("error", msg);
                    return false;
                  }
                  return true;
                }).map(function (id) {
                  return Object.assign({ id: id }, data[id]);
                }).reduce(function (collector, obj) {
                  if (obj.aliasOf) {
                    collector.alias.add(obj);
                  } else {
                    collector.reference.add(obj);
                  }
                  return collector;
                }, aliasesAndRefs);
                promisesToAdd = Object.keys(aliasesAndRefs).map(function (type) {
                  return Array.from(aliasesAndRefs[type]).map(function (details) {
                    return _this6.add(type, details);
                  });
                }).reduce(function (collector, promises) {
                  return collector.concat(promises);
                }, []);
                _context6.next = 7;
                return Promise.all(promisesToAdd);

              case 7:
              case "end":
                return _context6.stop();
            }
          }
        }, _callee6, _this6);
      }))();
    },
    add: function add(type, details) {
      var _this7 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee7() {
        var db, isInDB;
        return regeneratorRuntime.wrap(function _callee7$(_context7) {
          while (1) {
            switch (_context7.prev = _context7.next) {
              case 0:
                if (ALLOWED_TYPES.has(type)) {
                  _context7.next = 2;
                  break;
                }

                throw new TypeError("Invalid type: " + type);

              case 2:
                if (!((typeof details === "undefined" ? "undefined" : _typeof(details)) !== "object")) {
                  _context7.next = 4;
                  break;
                }

                throw new TypeError("details should be an object");

              case 4:
                if (!(type === "alias" && !details.hasOwnProperty("aliasOf"))) {
                  _context7.next = 6;
                  break;
                }

                throw new TypeError("Invalid alias object.");

              case 6:
                _context7.next = 8;
                return _this7.ready;

              case 8:
                db = _context7.sent;
                _context7.next = 11;
                return _this7.has(type, details.id);

              case 11:
                isInDB = _context7.sent;
                return _context7.abrupt("return", new Promise(function (resolve, reject) {
                  var store = db.transaction([type], "readwrite").objectStore(type);
                  // update or add, depending of already having it in db
                  var request = isInDB ? store.put(details) : store.add(details);
                  request.onsuccess = resolve;
                  request.onerror = function () {
                    reject(new DOMException(request.error.message, request.error.name));
                  };
                }));

              case 13:
              case "end":
                return _context7.stop();
            }
          }
        }, _callee7, _this7);
      }))();
    },
    close: function close() {
      var _this8 = this;

      return _asyncToGenerator(regeneratorRuntime.mark(function _callee8() {
        var db;
        return regeneratorRuntime.wrap(function _callee8$(_context8) {
          while (1) {
            switch (_context8.prev = _context8.next) {
              case 0:
                _context8.next = 2;
                return _this8.ready;

              case 2:
                db = _context8.sent;

                db.close();

              case 4:
              case "end":
                return _context8.stop();
            }
          }
        }, _callee8, _this8);
      }))();
    }
  };
});
//# sourceMappingURL=biblio-db.js.map