import {run} from '@cycle/core';
import {Observable, Subject} from 'rx';
import {makeDOMDriver, div} from '@cycle/dom';
import ace from 'brace';
import 'brace/mode/javascript';
import 'brace/theme/monokai';

import view from './scratchpad/view';

import vm from 'vm';

function startAceEditor (code$) {
  function updateCode (editor) {
    return (_, ev) => {
      code$.onNext({code: editor.getSession().getValue()});
    };
  }

  return ({code}) => {
    var editor = ace.edit('editor');
    editor.getSession().setMode('ace/mode/javascript');
    editor.setTheme('ace/theme/monokai');
    editor.getSession().setOptions({
      tabSize: 2
    });

    editor.setValue(code);
    editor.clearSelection();
    editor.on('input', updateCode(editor));
  };
}

export default function Scratchpad (DOM, props) {
  let sources, sinks;

  const code$ = new Subject();

  const error$ = new Subject();

  error$.forEach(console.log.bind(console));

  props.delay(100).subscribe(startAceEditor(code$));

  props.delay(100).merge(code$).forEach(({code}) => {
    if (sources) {
      sources.dispose();
    }

    if (sinks) {
      sinks.dispose();
    }

    const context = {div, Observable, error$};

    const wrappedCode = `
      try {
        ${code}

        error$.onNext('');
      } catch (e) {
        error$.onNext(e);
      }
    `;

    try {
      vm.runInNewContext(wrappedCode, context);
    } catch (e) {
      error$.onNext(e);
    }

    console.log('running cycle app with', code);

    if (typeof context.main !== 'function') {
      return;
    }

    const userDrivers = {
      DOM: makeDOMDriver('.result')
    };

    const userApp = run(context.main, userDrivers);

    sources = userApp.sources;
    sinks = userApp.sinks;
  });

  return {
    DOM: props.combineLatest(error$.startWith('')).map(view)
  };
}

@@ -38,85 +38,125 @@
 rt %7B
-Observable, Subject%7D from 'rx';%0Aimport %7BmakeDOMDriver, div%7D from '@cycle/dom'
+makeDOMDriver, h, div%7D from '@cycle/dom';%0Aimport %7BObservable, Subject%7D from 'rx';%0Aconst babel = require('babel-core')
 ;%0Aim
@@ -302,16 +302,199 @@
  'vm';%0A%0A
+function transformES6 (error$) %7B%0A  return (%7Bcode%7D) =%3E %7B%0A    try %7B%0A      return babel.transform(code);%0A    %7D catch (e) %7B%0A      error$.onNext(e);%0A      return %7Bcode: ''%7D;%0A    %7D%0A  %7D;%0A%7D%0A%0A
 function
@@ -1223,27 +1223,16 @@
   props.
-delay(100).
 merge(co
@@ -1234,16 +1234,56 @@
 ge(code$
+).debounce(100).map(transformES6(error$)
 ).forEac
@@ -1421,16 +1421,19 @@
  = %7Bdiv,
+ h,
  Observa
@@ -1885,29 +1885,53 @@
     %7D;%0A%0A    
-const
+let userApp;%0A%0A    try %7B%0A     
  userApp = r
@@ -1961,17 +1961,86 @@
 ivers);%0A
-%0A
+    %7D catch (e) %7B%0A      error$.onNext(e);%0A    %7D%0A%0A    if (userApp) %7B%0A  
     sour
@@ -2062,16 +2062,18 @@
 ources;%0A
+  
     sink
@@ -2091,16 +2091,22 @@
 .sinks;%0A
+    %7D%0A
   %7D);%0A%0A 

Add ES6 support with Babel, closes #2