// @flow
/* eslint-disable class-methods-use-this */
import * as React from "react";
import ReactDOM from "react-dom";

import { of } from "rxjs/observable/of";
import { fromEvent } from "rxjs/observable/fromEvent";
import type { Subscription } from "rxjs";
import { switchMap } from "rxjs/operators";

import { Map as ImmutableMap } from "immutable";

import { RichestMime } from "@nteract/display-area";

import { debounce, merge } from "lodash";

import * as monaco from "monaco-editor";

function normalizeLineEndings(str) {
  if (!str) return str;
  return str.replace(/\r\n|\r/g, "\n");
}

export type MonacoEditorProps = {
  theme: string,
  mode: ?string,
  onChange: (value: string) => void,
  value: string,
  editorFocused: boolean
};

class MonacoEditor extends React.Component<MonacoEditorProps> {
  monaco: ?monaco.IStandaloneCodeEditor;
  monacoContainer: ?HTMLElement;

  static defaultProps = {
    onChange: null,
    editorFocused: false,
    mode: "text/plain"
  };

  constructor(props: MonacoEditorProps): void {
    super(props);
  }

  componentWillMount() {
    (this: any).componentWillReceiveProps = debounce(
      this.componentWillReceiveProps,
      0
    );
  }

  onDidChangeModelContent(e): void {
    this.props.onChange(this.monaco.getValue());
  }

  componentDidMount(): void {
    this.monaco = monaco.editor.create(this.monacoContainer, {
      value: this.props.value,
      language: this.props.mode,
      minimap: {
        enabled: false
      },
      autoIndent: true
    });

    if (this.props.editorFocused) {
      this.monaco.focus();
    }

    this.monaco.onDidChangeModelContent(
      this.onDidChangeModelContent.bind(this)
    );
  }

  componentDidUpdate(prevProps: MonacoEditorProps): void {
    if (!this.monaco) return;
  }

  componentWillReceiveProps(nextProps: MonacoEditorProps) {
    if (this.monaco.getValue() !== nextProps.value) {
      // FIXME: calling setValue resets cursor position in monaco. It shouldn't!
      this.monaco.setValue(nextProps.value);
    }
  }

  componentWillUnmount() {
    if (this.monaco) {
      this.monaco.dispose();
    }
  }

  render(): React$Element<any> {
    return (
      <div
        className="monaco cm-s-composition"
        ref={container => {
          this.monacoContainer = container;
        }}
      />
    );
  }
}

export default MonacoEditor;

@@ -669,16 +669,17 @@
 Change: 
+?
 (value: 
@@ -695,16 +695,16 @@
 %3E void,%0A
-
   value:
@@ -1218,32 +1218,80 @@
 tent(e): void %7B%0A
+    if (this.monaco && this.props.onChange) %7B%0A  
     this.props.o
@@ -1323,16 +1323,22 @@
 lue());%0A
+    %7D%0A
   %7D%0A%0A  c
@@ -1891,24 +1891,24 @@
 torProps) %7B%0A
-
     if (this
@@ -1906,32 +1906,47 @@
  if (this.monaco
+ && this.monaco
 .getValue() !== 

Fix a few more flow errors in monaco