var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

import React from 'react';
import PropTypes from 'prop-types';

import { UniformsSettingsForm } from './Uniforms';
import { ScreenInstall, PageApp } from './UI';
import { AppInstallerService } from './AppInstallerService';
import { AppInfoService } from './AppInfoService';
import { selectDefinitionsFromManifest } from './Setting';

function delay(interval, f) {
  if (window && typeof window.setTimeout === 'function') {
    window.setTimeout(f, interval);
  } else {
    f();
  }
}

export var AppInstallerApp = function (_React$Component) {
  _inherits(AppInstallerApp, _React$Component);

  function AppInstallerApp(props) {
    _classCallCheck(this, AppInstallerApp);

    var _this = _possibleConstructorReturn(this, (AppInstallerApp.__proto__ || Object.getPrototypeOf(AppInstallerApp)).call(this, props));

    _this.onSaveSettings = function (settings) {
      _this.setState({ route: '/install' });
      if (!settings) {
        return Promise.resolve({ onStatus: _this.onAfterSaveSettings });
      }

      var _this$props$dpapp = _this.props.dpapp,
          restApi = _this$props$dpapp.restApi,
          appId = _this$props$dpapp.appId,
          instanceId = _this$props$dpapp.instanceId;

      var service = new AppInstallerService({ api: restApi });

      return service.saveSettings(instanceId, appId, settings).then(function () {
        return { onStatus: _this.onAfterSaveSettings };
      });
    };

    _this.onAfterSaveSettings = function (err) {
      var status = err ? 'error' : 'success';

      var _this$props$dpapp$con = _this.props.dpapp.context.toJS(),
          onInstallStatus = _this$props$dpapp$con.onInstallStatus;

      var manifest = _this.state.manifest;
      var _this$props$dpapp2 = _this.props.dpapp,
          restApi = _this$props$dpapp2.restApi,
          instanceId = _this$props$dpapp2.instanceId;


      var service = new AppInstallerService({ api: restApi });
      var installTasks = service.createInstallTasks(instanceId, _this.state.changes);
      var installSteps = 1 + installTasks.length;
      var installProgress = 1;

      _this.setState({ installProgress: installProgress, installSteps: installSteps });

      //execute each task sequentially
      var taskPromise = Promise.resolve(installProgress);

      var _loop = function _loop(task) {
        taskPromise = taskPromise.then(function (progress) {
          return task().then(function () {
            var installProgress = progress + 1;
            _this.setState({ installProgress: installProgress });
            return installProgress;
          });
        });
      };

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = installTasks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var task = _step.value;

          _loop(task);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      taskPromise.then(function (installProgress) {
        _this.setState({ installProgress: installProgress });
        delay(500, function () {
          return _this.props.dpapp.emit(onInstallStatus, { status: status, manifest: manifest });
        });
      });
    };

    _this.initState();
    return _this;
  }

  _createClass(AppInstallerApp, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      var _this2 = this;

      var _props$dpapp$context$ = this.props.dpapp.context.get("app"),
          appId = _props$dpapp$context$.id;

      var _props$dpapp = this.props.dpapp,
          api = _props$dpapp.restApi,
          instanceId = _props$dpapp.instanceId;
      var storage = this.props.dpapp.storage;

      var _props$dpapp$context$2 = this.props.dpapp.context.toJS(),
          installType = _props$dpapp$context$2.installType;

      var appInfoService = new AppInfoService();
      appInfoService.loadManifest({ api: api, appId: appId }).then(function (manifest) {
        return appInfoService.determineAssetEndpoint({ api: api, appId: appId, appVersion: manifest.appVersion }).then(function (assetEndpoint) {
          return { manifest: manifest, assetEndpoint: assetEndpoint };
        });
      }).then(function (state) {
        // load setting values
        if (installType === 'update') {
          return appInfoService.loadSettingValues(state.manifest, storage).then(function (settings) {
            return Object.assign({}, state, { settings: settings });
          });
        }
        return state;
      }).then(function (state) {
        //load changes
        var loadChangesPromise = void 0;

        if (installType === 'update') {
          // if it is an update and the instance is installed, just update settings
          loadChangesPromise = appInfoService.getInstanceInstallStatus({ api: api, instanceId: instanceId }).then(function (isInstalled) {
            return !isInstalled;
          });
        } else {
          loadChangesPromise = Promise.resolve(true);
        }
        return loadChangesPromise.then(function (loadChanges) {
          return loadChanges ? appInfoService.loadManifestChanges({ api: api, appId: appId }) : [];
        }).then(function (changes) {
          return Object.assign({}, state, { changes: changes });
        });
      }).then(function (state) {
        return Object.assign({ error: null, route: '/settings' }, state);
      }).catch(function (error) {
        return { route: '/error', error: error };
      }).then(function (state) {
        return _this2.setState(state);
      });
    }
  }, {
    key: 'initState',
    value: function initState() {
      this.state = {
        manifest: null,
        error: null,
        route: '/loading',
        installProgress: 0,
        installSteps: 1,
        assetEndpoint: '',
        settings: {},
        changes: []
      };
    }

    /**
     * @param {{}} settings
     * @return {Promise.<*>}
     */

  }, {
    key: 'render',
    value: function render() {
      var route = this.state.route;


      if (route === '/error') {
        return React.createElement(
          'div',
          null,
          React.createElement(
            'p',
            null,
            'The app installer encountered an error'
          )
        );
      }

      if (route === '/settings') {
        var manifest = this.state.manifest;

        var definitions = selectDefinitionsFromManifest(manifest);

        var ScreenSettings = this.props.installer;
        var _state = this.state,
            assetEndpoint = _state.assetEndpoint,
            settings = _state.settings;

        var _props$dpapp$context$3 = this.props.dpapp.context.toJS(),
            installType = _props$dpapp$context$3.installType;

        return React.createElement(
          PageApp,
          { icon: assetEndpoint + '/icon.png', description: manifest.description, title: manifest.title, version: manifest.appVersion },
          React.createElement(ScreenSettings, {
            dpapp: this.props.dpapp,
            installType: installType,
            finishInstall: this.onSaveSettings,
            settings: definitions,
            values: settings,
            settingsForm: UniformsSettingsForm
          })
        );
      }

      if (route === '/install') {
        var _state2 = this.state,
            installProgress = _state2.installProgress,
            installSteps = _state2.installSteps,
            _manifest = _state2.manifest,
            _assetEndpoint = _state2.assetEndpoint;

        var progress = Math.round(100 * installProgress / installSteps);

        return React.createElement(
          PageApp,
          { icon: _assetEndpoint + '/icon.png', description: _manifest.description, title: _manifest.title, version: _manifest.appVersion },
          React.createElement(ScreenInstall, { progress: progress })
        );
      }

      if (route === '/loading') {
        return React.createElement(
          'p',
          null,
          'Loading...'
        );
      }

      return null;
    }
  }]);

  return AppInstallerApp;
}(React.Component);
AppInstallerApp.propTypes = {
  dpapp: PropTypes.object.isRequired,
  installer: PropTypes.func.isRequired
};