'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

require('./CodeTester.css');

var _Editor = require('../Editor/Editor');

var _Editor2 = _interopRequireDefault(_Editor);

var _Console = require('../Console/Console');

var _Console2 = _interopRequireDefault(_Console);

var _InstructionsPanel = require('../InstructionsPanel/InstructionsPanel');

var _InstructionsPanel2 = _interopRequireDefault(_InstructionsPanel);

var _CodeTesterHeader = require('../CodeTesterHeader/CodeTesterHeader');

var _CodeTesterHeader2 = _interopRequireDefault(_CodeTesterHeader);

var _EditModeTabs = require('../EditModeTabs/EditModeTabs');

var _EditModeTabs2 = _interopRequireDefault(_EditModeTabs);

var _helpers = require('./helpers');

var _helpers2 = require('../../helpers');

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

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var CodeTester = function (_Component) {
  _inherits(CodeTester, _Component);

  function CodeTester(props) {
    _classCallCheck(this, CodeTester);

    var _this = _possibleConstructorReturn(this, (CodeTester.__proto__ || Object.getPrototypeOf(CodeTester)).call(this, props));

    _this.state = {
      code: '',
      lintedCode: '',
      consoleLogs: [],
      consoleVisible: props.showConsole,
      consoleStyle: {
        right: '-40%'
      },
      testsVisible: false,
      selectedTabIndex: 0,
      lintErrLineNums: []
    };
    _this.handleLintedCode = _this.handleLintedCode.bind(_this);
    _this.handleConsoleLog = _this.handleConsoleLog.bind(_this);
    _this.handleToggleConsole = _this.handleToggleConsole.bind(_this);
    _this.handleLintErrors = _this.handleLintErrors.bind(_this);
    _this.handleRunClick = _this.handleRunClick.bind(_this);
    _this.handlePaste = _this.handlePaste.bind(_this);
    _this.openConsole = _this.openConsole.bind(_this);
    _this.updateCode = _this.updateCode.bind(_this);
    _this.renderEditorPanel = _this.renderEditorPanel.bind(_this);
    _this.toggleInstructions = _this.toggleInstructions.bind(_this);
    _this.onTabSelect = _this.onTabSelect.bind(_this);
    return _this;
  }

  _createClass(CodeTester, [{
    key: 'onTabSelect',
    value: function onTabSelect(selectedTabIndex, prevIndex, event) {
      var cb = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};

      this.setState({ editMode: selectedTabIndex === 2, selectedTabIndex: selectedTabIndex }, cb);
    }
  }, {
    key: 'handleLintedCode',
    value: function handleLintedCode(lintedCode) {
      // This function is only called if code passes linting rules
      var prevCode = this.state.lintedCode;
      // setState causes a re-render, so we need to make sure the code is different
      // from the code we already have.
      if (lintedCode !== prevCode) {
        this.setState({ lintedCode: lintedCode });
        this.props.onLintedCode(lintedCode);
      }
    }
  }, {
    key: 'updateCode',
    value: function updateCode(code) {
      /* This function is called when any code is entered,
        whether it passes linting rules or not.
      */
      var _props = this.props,
          handleBoilerplateChange = _props.handleBoilerplateChange,
          onAnyCode = _props.onAnyCode;
      var _state = this.state,
          prevCode = _state.code,
          editMode = _state.editMode;

      if (prevCode !== code) {
        this.setState({ code: code });
        onAnyCode(code);
      }
      if (editMode) {
        handleBoilerplateChange(code);
      }
    }
  }, {
    key: 'toggleInstructions',
    value: function toggleInstructions() {
      this.setState({ testsVisible: !this.state.testsVisible });
    }
  }, {
    key: 'handleToggleConsole',
    value: function handleToggleConsole() {
      var consoleVisible = this.state.consoleVisible;

      this.openConsole(!consoleVisible);
    }
  }, {
    key: 'openConsole',
    value: function openConsole(toOpen) {
      this.setState(function (_ref) {
        var consoleStyle = _ref.consoleStyle;
        return {
          consoleVisible: toOpen,
          consoleStyle: Object.assign({}, consoleStyle, { right: toOpen ? '0%' : '-40%' })
        };
      });
    }
  }, {
    key: 'handleConsoleLog',
    value: function handleConsoleLog(logs) {
      this.setState({ consoleLogs: logs });
    }
  }, {
    key: 'handleRunClick',
    value: function handleRunClick() {
      var _this2 = this;

      this.onTabSelect(1, null, null, function () {
        _this2.TestRunnerRef.handleNewCode();
      });
    }
  }, {
    key: 'handlePaste',
    value: function handlePaste(e) {
      var _props2 = this.props,
          disablePasting = _props2.disablePasting,
          onPaste = _props2.onPaste;


      if (disablePasting) {
        e.preventDefault();
      }
      onPaste(e);
    }
  }, {
    key: 'handleLintErrors',
    value: function handleLintErrors(lintErrLineNums) {
      this.setState({ lintErrLineNums: lintErrLineNums });
    }
  }, {
    key: 'renderEditorPanel',
    value: function renderEditorPanel() {
      var _props3 = this.props,
          initialCode = _props3.initialCode,
          instructions = _props3.instructions,
          handleInstructionsChange = _props3.handleInstructionsChange,
          handleTestSpecChange = _props3.handleTestSpecChange,
          handleReset = _props3.handleReset,
          showLints = _props3.showLints,
          testSpec = _props3.testSpec,
          hideEditorButtons = _props3.hideEditorButtons,
          headerText = _props3.headerText,
          subHeaderText = _props3.subHeaderText;
      var editMode = this.state.editMode;

      return editMode ? _react2.default.createElement(_EditModeTabs2.default, {
        initialCode: initialCode,
        showLints: showLints,
        instructions: instructions,
        testSpec: testSpec,
        handleInstructionsChange: handleInstructionsChange,
        handleTestSpecChange: handleTestSpecChange,
        handleBoilerplateChange: this.updateCode,
        handleLintedBoilerplateCode: this.handleLintedCode,
        handleReset: handleReset
      }) : _react2.default.createElement(
        'div',
        null,
        _react2.default.createElement(_CodeTesterHeader2.default, { headerText: headerText, subHeaderText: subHeaderText }),
        _react2.default.createElement(_Editor2.default, {
          code: initialCode,
          onValidCode: this.handleLintedCode,
          onAnyCode: this.updateCode,
          onLintErrors: this.handleLintErrors,
          onPaste: this.handlePaste,
          showLints: showLints,
          handleReset: handleReset,
          hideButtons: hideEditorButtons
        })
      );
    }
  }, {
    key: 'renderRunButton',
    value: function renderRunButton(lintLineNumber) {
      return lintLineNumber.length ? _react2.default.createElement(
        'button',
        { className: 'btn btn-lg btn-danger', disabled: true },
        'Run'
      ) : _react2.default.createElement(
        'button',
        { className: 'btn btn-lg btn-info', onClick: this.handleRunClick },
        'Run'
      );
    }
  }, {
    key: 'render',
    value: function render() {
      var _this3 = this;

      var _state2 = this.state,
          lintedCode = _state2.lintedCode,
          consoleStyle = _state2.consoleStyle,
          selectedTabIndex = _state2.selectedTabIndex,
          consoleVisible = _state2.consoleVisible,
          consoleLogs = _state2.consoleLogs,
          lintErrLineNums = _state2.lintErrLineNums;
      var _props4 = this.props,
          onTestResults = _props4.onTestResults,
          testSpec = _props4.testSpec,
          instructions = _props4.instructions,
          autoRun = _props4.autoRun,
          iFrameUrl = _props4.iFrameUrl,
          testHandlerUrl = _props4.testHandlerUrl,
          onError = _props4.onError,
          infiniteLoopTimeout = _props4.infiniteLoopTimeout,
          submitEnabled = _props4.submitEnabled,
          onTestRunnerSubmitClick = _props4.onTestRunnerSubmitClick,
          hideEditorButtons = _props4.hideEditorButtons,
          markdownOptions = _props4.markdownOptions,
          className = _props4.className,
          toggleEditMode = _props4.toggleEditMode,
          handleReset = _props4.handleReset,
          editMode = _props4.editMode,
          handleUrlInput = _props4.handleUrlInput,
          handleGithubSubmit = _props4.handleGithubSubmit,
          committing = _props4.committing;


      return _react2.default.createElement(
        'div',
        { className: 'CodeTester ' + className },
        _react2.default.createElement(_InstructionsPanel2.default, {
          handleUrlInput: handleUrlInput,
          handleGithubSubmit: handleGithubSubmit,
          editMode: editMode,
          tabIndex: selectedTabIndex,
          onTabSelect: this.onTabSelect,
          instructions: instructions,
          markdownOptions: markdownOptions,
          testSpec: testSpec,
          lintedCode: lintedCode,
          onTestResults: onTestResults,
          handleConsoleLog: this.handleConsoleLog,
          autoRun: autoRun,
          iFrameUrl: iFrameUrl,
          testHandlerUrl: testHandlerUrl,
          onError: onError,
          infiniteLoopTimeout: infiniteLoopTimeout,
          submitEnabled: submitEnabled,
          onTestRunnerSubmitClick: onTestRunnerSubmitClick,
          toggleEditMode: toggleEditMode,
          handleReset: handleReset,
          onTestRunnerRef: function onTestRunnerRef(ref) {
            return _this3.TestRunnerRef = ref;
          },
          committing: committing
        }),
        _react2.default.createElement(
          'div',
          { className: 'right-code' },
          _react2.default.createElement(
            'div',
            { className: 'console-panel' },
            _react2.default.createElement(_Console2.default, {
              style: consoleStyle,
              logs: consoleLogs,
              onToggleConsole: this.handleToggleConsole,
              show: consoleVisible
              // eslint-disable-next-line
              , onError: this.openConsole.bind(this, true)
            })
          ),
          _react2.default.createElement(
            'div',
            { className: 'right-panel-main' },
            this.renderEditorPanel()
          ),
          _react2.default.createElement(
            'div',
            { className: 'test-panel' },
            (0, _helpers2.renderIf)(lintErrLineNums.length)(_react2.default.createElement(
              'h5',
              { className: 'syntax-message m-0' },
              'Syntax error: line ' + _lodash2.default.first(lintErrLineNums)
            )),
            this.renderRunButton(lintErrLineNums),
            _react2.default.createElement(
              'button',
              { className: 'btn btn-lg btn-success', onClick: onTestRunnerSubmitClick },
              'Submit'
            )
          )
        )
      );
    }
  }]);

  return CodeTester;
}(_react.Component);

CodeTester.propTypes = {
  autoRun: _propTypes2.default.bool,
  editMode: _propTypes2.default.bool,
  toggleEditMode: _propTypes2.default.func,
  handleUrlInput: _propTypes2.default.func,
  handleGithubSubmit: _propTypes2.default.func,
  handleBoilerplateChange: _propTypes2.default.func,
  handleInstructionsChange: _propTypes2.default.func,
  handleReset: _propTypes2.default.func,
  handleTestSpecChange: _propTypes2.default.func,
  infiniteLoopTimeout: _propTypes2.default.number,
  initialCode: _propTypes2.default.string,
  instructions: _propTypes2.default.string,
  iFrameUrl: _propTypes2.default.string.isRequired,
  onAnyCode: _propTypes2.default.func,
  onError: _propTypes2.default.func,
  onLintedCode: _propTypes2.default.func,
  onTestResults: _propTypes2.default.func,
  onTestRunnerSubmitClick: _propTypes2.default.func,
  showConsole: _propTypes2.default.bool,
  showLints: _propTypes2.default.bool,
  submitEnabled: _propTypes2.default.bool,
  testSpec: _propTypes2.default.string.isRequired,
  testHandlerUrl: _propTypes2.default.string,
  className: _propTypes2.default.string,
  hideEditorButtons: _propTypes2.default.bool,
  markdownOptions: _propTypes2.default.objectOf(_propTypes2.default.bool),
  headerText: _propTypes2.default.string,
  subHeaderText: _propTypes2.default.string,
  committing: _propTypes2.default.bool,
  onPaste: _propTypes2.default.func,
  disablePasting: _propTypes2.default.bool
};

CodeTester.defaultProps = {
  onTestResults: function onTestResults(passCount, failCount, testDuration) {}, // eslint-disable-line no-unused-vars
  onLintedCode: function onLintedCode(code) {}, // eslint-disable-line no-unused-vars
  onAnyCode: function onAnyCode(code) {}, // eslint-disable-line no-unused-vars
  initialCode: '',
  instructions: '',
  autoRun: false,
  showLints: true,
  editMode: false,
  submitEnabled: true,
  onError: function onError(err) {
    var message = _lodash2.default.get(err, 'message') ? err.message : 'Unknown';
    console.error('Code Tester Error: ', message);
  },
  infiniteLoopTimeout: 3000,
  showConsole: false,
  hideEditorButtons: false,
  markdownOptions: {},
  className: '',
  testHandlerUrl: '',
  committing: false,
  headerText: '',
  subHeaderText: '',
  toggleEditMode: _helpers.defaultFunc,
  handleUrlInput: _helpers.defaultFunc,
  handleGithubSubmit: _helpers.defaultFunc,
  handleBoilerplateChange: _helpers.defaultFunc,
  handleInstructionsChange: _helpers.defaultFunc,
  handleReset: _helpers.defaultFunc,
  handleTestSpecChange: _helpers.defaultFunc,
  onTestRunnerSubmitClick: _helpers.defaultFunc,
  onPaste: _helpers.defaultFunc,
  disablePasting: false
};

exports.default = CodeTester;