text: "use strict";
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
      var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
      if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
      else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
      return c > 3 && r && Object.defineProperty(target, key, r), r;
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  var device_util = require("./device_util");
  var doc_1 = require("./doc");
  var engine_1 = require("./engine");
  var environment_util_1 = require("./environment_util");
  var tensor_1 = require("./tensor");
  var tensor_util_1 = require("./tensor_util");
  var TEST_EPSILON_FLOAT32_ENABLED = 1e-3;
  var TEST_EPSILON_FLOAT32_DISABLED = 1e-1;
  var Environment = (function () {
      function Environment(features) {
          this.features = {};
          this.registry = {};
          if (features != null) {
              this.features = features;
          }
          if (this.get('DEBUG')) {
              console.warn('Debugging mode is ON. The output of every math call will ' +
                  'be downloaded to CPU and checked for NaNs. ' +
                  'This significantly impacts performance.');
          }
      }
      Environment.setBackend = function (backendType, safeMode) {
          if (safeMode === void 0) { safeMode = false; }
          if (!(backendType in exports.ENV.registry)) {
              throw new Error("Backend type '" + backendType + "' not found in registry");
          }
          exports.ENV.initBackend(backendType, safeMode);
      };
      Environment.getBackend = function () {
          exports.ENV.initDefaultBackend();
          return exports.ENV.currentBackend;
      };
      Environment.disposeVariables = function () {
          exports.ENV.engine.disposeVariables();
      };
      Environment.memory = function () {
          return exports.ENV.engine.memory();
      };
      Environment.tidy = function (nameOrFn, fn, gradMode) {
          if (gradMode === void 0) { gradMode = false; }
          return exports.ENV.engine.tidy(nameOrFn, fn, gradMode);
      };
      Environment.dispose = function (container) {
          var tensors = tensor_util_1.getTensorsInContainer(container);
          tensors.forEach(function (tensor) { return tensor.dispose(); });
      };
      Environment.keep = function (result) {
          return exports.ENV.engine.keep(result);
      };
      Environment.time = function (f) {
          return exports.ENV.engine.time(f);
      };
      Environment.prototype.get = function (feature) {
          if (feature in this.features) {
              return this.features[feature];
          }
          this.features[feature] = this.evaluateFeature(feature);
          return this.features[feature];
      };
      Environment.prototype.getFeatures = function () {
          return this.features;
      };
      Environment.prototype.set = function (feature, value) {
          this.features[feature] = value;
      };
      Environment.prototype.getBestBackendType = function () {
          var _this = this;
          if (Object.keys(this.registry).length === 0) {
              throw new Error('No backend found in registry.');
          }
          var sortedBackends = Object.keys(this.registry)
              .map(function (name) {
              return { name: name, entry: _this.registry[name] };
          })
              .sort(function (a, b) {
              return b.entry.priority - a.entry.priority;
          });
          return sortedBackends[0].name;
      };
      Environment.prototype.evaluateFeature = function (feature) {
          if (feature === 'DEBUG') {
              return false;
          }
          else if (feature === 'IS_BROWSER') {
              return typeof window !== 'undefined';
          }
          else if (feature === 'IS_NODE') {
              return (typeof process !== 'undefined') &&
                  (typeof process.versions.node !== 'undefined');
          }
          else if (feature === 'IS_CHROME') {
              return environment_util_1.isChrome();
          }
          else if (feature === 'BACKEND') {
              return this.getBestBackendType();
          }
          else if (feature === 'WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') {
              var webGLVersion = this.get('WEBGL_VERSION');
              if (webGLVersion === 0) {
                  return 0;
              }
              return environment_util_1.getWebGLDisjointQueryTimerVersion(webGLVersion, this.get('IS_BROWSER'));
          }
          else if (feature === 'WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE') {
              return this.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0 &&
                  !device_util.isMobile();
          }
          else if (feature === 'WEBGL_VERSION') {
              if (environment_util_1.isWebGLVersionEnabled(2, this.get('IS_BROWSER'))) {
                  return 2;
              }
              else if (environment_util_1.isWebGLVersionEnabled(1, this.get('IS_BROWSER'))) {
                  return 1;
              }
              return 0;
          }
          else if (feature === 'WEBGL_RENDER_FLOAT32_ENABLED') {
              return environment_util_1.isRenderToFloatTextureEnabled(this.get('WEBGL_VERSION'), this.get('IS_BROWSER'));
          }
          else if (feature === 'WEBGL_DOWNLOAD_FLOAT_ENABLED') {
              return environment_util_1.isDownloadFloatTextureEnabled(this.get('WEBGL_VERSION'), this.get('IS_BROWSER'));
          }
          else if (feature === 'WEBGL_GET_BUFFER_SUB_DATA_ASYNC_EXTENSION_ENABLED') {
              return environment_util_1.isWebGLGetBufferSubDataAsyncExtensionEnabled(this.get('WEBGL_VERSION'), this.get('IS_BROWSER'));
          }
          else if (feature === 'TEST_EPSILON') {
              if (this.get('WEBGL_RENDER_FLOAT32_ENABLED')) {
                  return TEST_EPSILON_FLOAT32_ENABLED;
              }
              return TEST_EPSILON_FLOAT32_DISABLED;
          }
          throw new Error("Unknown feature " + feature + ".");
      };
      Environment.prototype.setFeatures = function (features) {
          this.features = features;
      };
      Environment.prototype.reset = function () {
          this.features = environment_util_1.getFeaturesFromURL();
          if (this.globalEngine != null) {
              this.globalEngine = null;
          }
      };
      Environment.prototype.initBackend = function (backendType, safeMode) {
          if (safeMode === void 0) { safeMode = false; }
          this.currentBackend = backendType;
          var backend = this.findBackend(backendType);
          this.globalEngine = new engine_1.Engine(backend, safeMode, this.get('DEBUG'));
      };
      Environment.prototype.findBackend = function (name) {
          if (!(name in this.registry)) {
              return null;
          }
          return this.registry[name].backend;
      };
      Environment.prototype.registerBackend = function (name, factory, priority, setTensorTrackerFn) {
          var _this = this;
          if (priority === void 0) { priority = 1; }
          if (name in this.registry) {
              console.warn(name + " backend was already registered. Reusing existing backend");
              if (setTensorTrackerFn != null) {
                  setTensorTrackerFn(function () { return _this.engine; });
              }
              return false;
          }
          try {
              var backend = factory();
              this.registry[name] = { backend: backend, priority: priority };
              return true;
          }
          catch (err) {
              console.warn("Registration of backend " + name + " failed");
              console.warn(err.stack || err.message);
              return false;
          }
      };
      Environment.prototype.removeBackend = function (name) {
          if (!(name in this.registry)) {
              throw new Error(name + " backend not found in registry");
          }
          this.registry[name].backend.dispose();
          delete this.registry[name];
      };
      Object.defineProperty(Environment.prototype, "engine", {
          get: function () {
              this.initDefaultBackend();
              return this.globalEngine;
          },
          enumerable: true,
          configurable: true
      });
      Environment.prototype.initDefaultBackend = function () {
          if (this.globalEngine == null) {
              this.initBackend(this.get('BACKEND'), false);
          }
      };
      __decorate([
          doc_1.doc({ heading: 'Environment' })
      ], Environment, "setBackend", null);
      __decorate([
          doc_1.doc({ heading: 'Environment' })
      ], Environment, "getBackend", null);
      __decorate([
          doc_1.doc({ heading: 'Environment' })
      ], Environment, "disposeVariables", null);
      __decorate([
          doc_1.doc({ heading: 'Performance', subheading: 'Memory' })
      ], Environment, "memory", null);
      __decorate([
          doc_1.doc({ heading: 'Performance', subheading: 'Memory' })
      ], Environment, "tidy", null);
      __decorate([
          doc_1.doc({ heading: 'Performance', subheading: 'Memory' })
      ], Environment, "dispose", null);
      __decorate([
          doc_1.doc({ heading: 'Performance', subheading: 'Memory' })
      ], Environment, "keep", null);
      __decorate([
          doc_1.doc({ heading: 'Performance', subheading: 'Timing' })
      ], Environment, "time", null);
      return Environment;
  }());
  exports.Environment = Environment;
  function getGlobalNamespace() {
      var ns;
      if (typeof (window) !== 'undefined') {
          ns = window;
      }
      else if (typeof (process) !== 'undefined') {
          ns = process;
      }
      else {
          throw new Error('Could not find a global object');
      }
      return ns;
  }
  function getOrMakeEnvironment() {
      var ns = getGlobalNamespace();
      if (ns.ENV == null) {
          ns.ENV = new Environment(environment_util_1.getFeaturesFromURL());
          tensor_1.setTensorTracker(function () { return ns.ENV.engine; });
      }
      return ns.ENV;
  }
  exports.ENV = getOrMakeEnvironment();
  //# sourceMappingURL=environment.js.map