'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.newKernelEpic = exports.acquireKernelInfoEpic = exports.watchExecutionStateEpic = undefined;
exports.setLanguageInfo = setLanguageInfo;
exports.acquireKernelInfo = acquireKernelInfo;
exports.newKernelObservable = newKernelObservable;

var _Rx = require('rxjs/Rx');

var _Rx2 = _interopRequireDefault(_Rx);

var _spawnteract = require('spawnteract');

var _uuid = require('uuid');

var uuid = _interopRequireWildcard(_uuid);

var _electron = require('electron');

var _enchannelZmqBackend = require('enchannel-zmq-backend');

var _messaging = require('../kernel/messaging');

var _actions = require('../actions');

var _constants = require('../constants');

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function setLanguageInfo(langInfo) {
  return {
    type: _constants.SET_LANGUAGE_INFO,
    langInfo
  };
}

function acquireKernelInfo(channels) {
  const message = (0, _messaging.createMessage)('kernel_info_request');

  const obs = channels.shell.childOf(message).ofMessageType('kernel_info_reply').first().pluck('content', 'language_info').map(setLanguageInfo);
  // TODO: After a timeout, send kernel_info_request again
  //       the retry may be better architecturally out of this function
  //       though, by retrying this function entirely.

  return _Rx2.default.Observable.create(observer => {
    const subscription = obs.subscribe(observer);
    channels.shell.next(message);
    return subscription;
  });
}

function newKernelObservable(kernelSpecName, cwd) {
  return _Rx2.default.Observable.create(observer => {
    (0, _spawnteract.launch)(kernelSpecName, { cwd }).then(c => {
      const { config, spawn, connectionFile, kernelSpec } = c;

      const identity = uuid.v4();
      // TODO: I'm realizing that we could trigger on when the underlying sockets
      //       are ready with these subjects to let us know when the kernels
      //       are *really* ready
      const channels = {
        shell: (0, _enchannelZmqBackend.createShellSubject)(identity, config),
        iopub: (0, _enchannelZmqBackend.createIOPubSubject)(identity, config),
        control: (0, _enchannelZmqBackend.createControlSubject)(identity, config),
        stdin: (0, _enchannelZmqBackend.createStdinSubject)(identity, config)
      };

      observer.next((0, _actions.setNotebookKernelInfo)({
        name: kernelSpecName,
        spec: kernelSpec
      }));

      observer.next({
        type: _constants.NEW_KERNEL,
        channels,
        connectionFile,
        spawn,
        kernelSpecName,
        kernelSpec
      });
    });
  });
}

const watchExecutionStateEpic = exports.watchExecutionStateEpic = action$ => action$.ofType(_constants.NEW_KERNEL).switchMap(action => _Rx2.default.Observable.merge(action.channels.iopub.filter(msg => msg.header.msg_type === 'status').map(msg => (0, _actions.setExecutionState)(msg.content.execution_state)), _Rx2.default.Observable.of((0, _actions.setExecutionState)('idle'))));

const acquireKernelInfoEpic = exports.acquireKernelInfoEpic = action$ => action$.ofType(_constants.NEW_KERNEL).switchMap(action => {
  /* istanbul ignore if -- used for interactive debugging */
  if (process.env.DEBUG) {
    window.channels = action.channels;
  }
  return acquireKernelInfo(action.channels);
});

const newKernelEpic = exports.newKernelEpic = action$ => action$.ofType(_constants.LAUNCH_KERNEL).do(action => {
  if (!action.kernelSpecName) {
    throw new Error('newKernel needs a kernelSpecName');
  }
  _electron.ipcRenderer.send('nteract:ping:kernel', action.kernelSpecName);
}).mergeMap(action => newKernelObservable(action.kernelSpecName, action.cwd)).catch(error => _Rx2.default.Observable.of({
  type: _constants.ERROR_KERNEL_LAUNCH_FAILED,
  payload: error,
  error: true
}));