import { emptyNotebook, emptyCodeCell, appendCell } from 'commutable';
import { readFileObservable } from '../../utils/fs';
import { newKernel } from '../actions';

const Rx = require('rxjs/Rx');
const commutable = require('commutable');

const path = require('path');

const Observable = Rx.Observable;

export const LOAD = 'LOAD';
export const SET_NOTEBOOK = 'SET_NOTEBOOK';
export const NEW_NOTEBOOK = 'NEW_NOTEBOOK';

export const load = (filename) => ({ type: LOAD, filename });

export const newNotebook = (kernelSpecName, cwd) => ({
  type: NEW_NOTEBOOK,
  kernelSpecName,
  cwd: cwd || process.cwd(),
});

// Expects notebook to be JS Object or Immutable.js
export const notebookLoaded = (filename, notebook) => ({
  type: SET_NOTEBOOK,
  filename,
  notebook,
});

export const extractNewKernel = (filename, notebook) => {
  const cwd = (filename && path.dirname(path.resolve(filename))) || process.cwd();
  const kernelName = notebook.getIn(
    ['metadata', 'kernelspec', 'name'], notebook.getIn(
      ['metadata', 'language_info', 'name'],
        'python3'));
  return newKernel(kernelName, cwd);
};

export const convertRawNotebook = (filename, data) => ({
  filename,
  notebook: commutable.fromJS(JSON.parse(data)),
});

export const loadEpic = actions =>
  actions.ofType(LOAD)
    .do(action => {
      // If there isn't a filename, save-as it instead
      if (!action.filename) {
        throw new Error('load needs a filename');
      }
    })
    // Switch map since we want the last load request to be the lead
    .switchMap(action =>
      readFileObservable(action.filename)
        .map((data) => convertRawNotebook(action.filename, data))
        .flatMap(({ filename, notebook }) =>
          Observable.of(
            notebookLoaded(filename, notebook),
            extractNewKernel(filename, notebook),
          )
        )
        .catch((err) =>
          Observable.of({ type: 'ERROR', payload: err, error: true })
        )
    );

const starterNotebook = appendCell(emptyNotebook, emptyCodeCell);
export const newNotebookEpic = action$ =>
  action$.ofType(NEW_NOTEBOOK)
    .switchMap(action =>
      Observable.of(
        {
          type: 'SET_NOTEBOOK',
          notebook: starterNotebook,
        },
        newKernel(action.kernelSpecName, action.cwd),
      )
    );

@@ -763,24 +763,321 @@
 ebook,%0A%7D);%0A%0A
+/**%0A  * Creates a new kernel based on the language info in the notebook.%0A  *%0A  * @param  %7BString%7D  filename  The filename of the notebook being loaded%0A  * @param  %7BImmutable%3CMap%3E%7D  notebook  The notebook to extract langauge info from%0A  *%0A  * @returns  %7BActionObservable%7D  A NEW_KERNEL action%0A  */%0A
 export const
@@ -1409,130 +1409,535 @@
 %7D;%0A%0A
-export const convertRawNotebook = (filename, data) =%3E (%7B%0A  filename,%0A  notebook: commutable.fromJS(JSON.parse(data)),%0A%7D);%0A
+/**%0A  * Converts a notebook from JSON to an Immutable.Map.%0A  *%0A  * @param  %7BString%7D  filename The filename of the notebook to convert%0A  * @param  %7BString%7D  data  The raw JSON of the notebook%0A  *%0A  * @returns  %7BObject%7D  The filename and notebook in Immutable.Map form%0A  */%0Aexport const convertRawNotebook = (filename, data) =%3E (%7B%0A  filename,%0A  notebook: commutable.fromJS(JSON.parse(data)),%0A%7D);%0A%0A/**%0A  * Loads a notebook and launches its kernel.%0A  *%0A  * @param  %7BActionObservable%7D  A LOAD action with the notebook filename %0A  */
 %0Aexp
@@ -2661,24 +2661,122 @@
   )%0A    );%0A%0A
+/**%0A  * Sets a new empty notebook.%0A  *%0A  * @param  %7BActionObservable%7D  A NEW_NOTEBOOK action%0A  */%0A
 const starte

Add initial docs for loading epics