text: // @flow
  import * as React from "react";
  import Head from "next/head";
  import Router from "next/router";
  
  import CodeMirrorEditor from "@nteract/editor";
  import { BinderConsole } from "./consoles";
  import { Display } from "@nteract/display-area";
  import { KernelUI } from "./kernelUI";
  import { Outputs } from "@nteract/core/components";
  import { connect } from "react-redux";
  import { actions } from "../redux";
  import objectPath from "object-path";
  import * as utils from "../utils";
  
  const NTERACT_LOGO_URL =
    "https://media.githubusercontent.com/media/nteract/logos/master/nteract_logo_cube_book/exports/images/svg/nteract_logo_wide_purple_inverted.svg";
  
  class Main extends React.Component<*, *> {
    constructor(props) {
      super(props);
      this.state = {
        gitrefValue: props.gitref,
        repoValue: props.repo,
        sourceValue: props.source
      };
    }
    componentDidMount() {
      const { activateServer } = this.props;
      const { gitrefValue: gitref, repoValue: repo } = this.state;
      const serverId = utils.makeServerId({ gitref, repo });
      activateServer({ serverId, repo, gitref });
    }
  
    componentDidUpdate(prevProps) {
      // When the gitref or repo change, update the URL params
      if (
        this.props.gitref !== prevProps.gitref ||
        this.props.repo !== prevProps.repo
      ) {
        const newLocation = {
          pathname: Router.pathname,
          query: {
            gitref: this.props.gitref,
            repo: this.props.repo
          }
        };
  
        Router.push(
          // We have to specify both the `href` (what it really is)
          newLocation,
          // and what location we want the users to see `as`
          newLocation,
          // in order to change the URL without running getInitialProps
          // ref: https://github.com/zeit/next.js#shallow-routing
          { shallow: true }
          // While still providing something that is copy-pastable in the URL bar
        );
      }
    }
  
    handleEditorChange = source => {
      this.setState({ sourceValue: source });
    };
    handleRepoChange = event => {
      this.setState({ repoValue: event.target.value });
    };
    handleGitrefChange = event => {
      this.setState({ gitrefValue: event.target.value });
    };
    handleKernelChange = event => {
      const { currentServerId: serverId, setActiveKernel } = this.props;
      setActiveKernel({ serverId, kernelName: event.target.value });
    };
    killKernel = kernelName => {
      const { serverId, killKernel } = this.props;
      killKernel({ serverId, kernelName });
    };
    restartKernel = kernelName => {
      const { serverId, restartKernel } = this.props;
      restartKernel({ serverId, kernelName });
    };
    handleFormSubmit = event => {
      const {
        currentServerId: oldServerId,
        activateServer,
        submitBinderForm
      } = this.props;
      const { gitrefValue: gitref, repoValue: repo } = this.state;
      event.preventDefault();
      const serverId = utils.makeServerId({ gitref, repo });
  
      activateServer({ gitref, repo, serverId, oldServerId });
      submitBinderForm({ gitref, repo });
    };
    handleSourceSubmit = () => {
      const { currentServerId, currentKernelName, runSource } = this.props;
      const { sourceValue: source } = this.state;
      runSource({
        serverId: currentServerId,
        kernelName: currentKernelName,
        source
      });
    };
    render() {
      const {
        currentKernel,
        codeMirrorMode,
        currentKernelName,
        currentServer,
        platform,
        showPanel,
        setShowPanel
      } = this.props;
      const { repoValue, gitrefValue, sourceValue } = this.state;
      return (
        <React.Fragment>
          <Head>
            <link rel="dns-prefetch" href="https://mybinder.org" />
            <link
              rel="prefetch"
              href="https://mybinder.org/static/logo.svg?v=f9f0d927b67cc9dc99d788c822ca21c0"
            />
            {/*
              prefetch our little sample graphic for an extra touch of ✨
            */}
            <link rel="prefetch" href="https://bit.ly/storybot-vdom" />
            <link
              rel="prefetch"
              href="https://media.giphy.com/media/xUPGcguWZHRC2HyBRS/giphy.gif"
            />
          </Head>
          <header>
            <div className="left">
              <img
                src={NTERACT_LOGO_URL}
                alt="nteract logo"
                className="nteract-logo"
              />
  
              <button
                onClick={this.handleSourceSubmit}
                className="play"
                disabled={!currentKernel}
                title={`run cell (${platform === "macOS" ? "⌘-" : "Ctrl-"}⏎)`}
              >
                ▶ Run
              </button>
              <button onClick={() => setShowPanel(!showPanel)}>
                {showPanel ? "Hide" : "Show"} logs
              </button>
            </div>
            {currentServer && currentKernel ? (
              <KernelUI
                status={currentKernel.status}
                kernelspecs={
                  currentServer.kernelSpecs &&
                  currentServer.kernelSpecs.kernelSpecByKernelName
                    ? currentServer.kernelSpecs.kernelSpecByKernelName
                    : {}
                }
                currentKernel={currentKernelName}
                onChange={this.handleKernelChange}
              />
            ) : null}
          </header>
  
          {showPanel ? (
            <BinderConsole
              onGitrefChange={this.handleGitrefChange}
              onRepoChange={this.handleRepoChange}
              onFormSubmit={this.handleFormSubmit}
              logs={
                currentServer && currentServer.messages
                  ? currentServer.messages
                  : []
              }
              repo={repoValue}
              gitref={gitrefValue}
            />
          ) : null}
  
          <div className="play-editor">
            <CodeMirrorEditor
              // TODO: these should have defaultProps on the codemirror editor
              cellFocused
              editorFocused
              channels={
                currentKernel && currentKernel.channel
                  ? currentKernel.channel
                  : null
              }
              tip
              completion
              theme="light"
              // TODO: This is the notebook implementation leaking into the editor
              //       component. It shouldn't be here, I won't refactor it as part
              //       of the current play PR though.
              id="not-really-a-cell"
              onFocusChange={() => {}}
              focusAbove={() => {}}
              focusBelow={() => {}}
              // END TODO for notebook leakage
              // TODO: kernelStatus should be allowed to be null or undefined,
              //       resulting in thought of as either idle or not connected by
              //       default. This is primarily used for determining if code
              //       completion should be enabled
              kernelStatus={
                currentKernel ? currentKernel.status : "not connected"
              }
              options={{
                lineNumbers: true,
                extraKeys: {
                  "Ctrl-Space": "autocomplete",
                  "Ctrl-Enter": this.handleSourceSubmit,
                  "Cmd-Enter": this.handleSourceSubmit
                },
                cursorBlinkRate: 0,
                mode: codeMirrorMode
              }}
              value={sourceValue}
              onChange={this.handleEditorChange}
            />
          </div>
  
          <div className="play-outputs">
            <Outputs>
              <Display
                outputs={
                  currentKernel && currentKernel.outputs
                    ? currentKernel.outputs
                    : []
                }
                expanded
              />
            </Outputs>
          </div>
  
          <style jsx>{`
            --header-height: 42px;
            --editor-width: 52%;
  
            header {
              display: flex;
              justify-content: space-between;
              background-color: black;
            }
  
            header img {
              height: calc(var(--header-height) - 16px);
              width: 80px;
              margin-left: 10px;
              padding: 0px 20px 0px 10px;
            }
  
            header img,
            header button,
            header div {
              vertical-align: middle;
            }
  
            header button {
              padding: 0px 16px;
              border: none;
              outline: none;
              border-radius: unset;
              background-color: rgba(0, 0, 0, 0);
              color: white;
              height: var(--header-height);
              font-family: Monaco, monospace;
            }
  
            header button:active,
            header button:focus {
              background-color: rgba(255, 255, 255, 0.1);
            }
  
            header button:hover {
              background-color: rgba(255, 255, 255, 0.2);
              color: #d7d7d7;
            }
  
            header button:disabled {
              background-color: rgba(255, 255, 255, 0.1);
              color: rgba(255, 255, 255, 0.1);
            }
  
            .play-editor {
              width: var(--editor-width);
              position: absolute;
              left: 0;
              height: 100%;
            }
  
            .play-editor :global(.CodeMirror) {
              height: 100%;
            }
  
            .play-outputs {
              width: calc(100% - var(--editor-width));
              position: absolute;
              right: 0;
            }
  
            .play-outputs :global(*) {
              font-family: Monaco, monospace;
            }
  
            .play-editor > :global(*) {
              height: 100%;
            }
            :global(.CodeMirror) {
              height: 100%;
            }
          `}</style>
  
          <style jsx global>{`
            body {
              margin: 0;
            }
          `}</style>
        </React.Fragment>
      );
    }
  }
  
  const mapStateToProps = state => {
    return {
      repo: state.ui.repo,
      gitref: state.ui.gitref,
      source: state.ui.source,
      platform: state.ui.platform,
      showPanel: state.ui.showPanel,
      currentServerId: state.ui.currentServerId,
      currentKernelName: state.ui.currentKernelName,
      codeMirrorMode: state.ui.codeMirrorMode,
      currentKernel: objectPath.get(state, [
        "entities",
        "serversById",
        state.ui.currentServerId,
        "server",
        "activeKernelsByName",
        state.ui.currentKernelName,
        "kernel"
      ]),
      currentServer: objectPath.get(state, [
        "entities",
        "serversById",
        state.ui.currentServerId,
        "server"
      ])
    };
  };
  
  const mapDispatchToProps = {
    activateServer: actions.activateServer,
    submitBinderForm: actions.submitBinderForm,
    setShowPanel: actions.setShowPanel,
    runSource: actions.runSource,
    setActiveKernel: actions.setActiveKernel
  };
  
  export default connect(mapStateToProps, mapDispatchToProps)(Main);
  