import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { Link } from 'react-router';
import InlineSVG from 'react-inlinesvg';
import classNames from 'classnames';
import * as IDEActions from '../modules/IDE/actions/ide';
import * as toastActions from '../modules/IDE/actions/toast';
import * as projectActions from '../modules/IDE/actions/project';
import { setAllAccessibleOutput } from '../modules/IDE/actions/preferences';
import { logoutUser } from '../modules/User/actions';

import { metaKeyName, } from '../utils/metaKey';

const triangleUrl = require('../images/down-filled-triangle.svg');
const logoUrl = require('../images/p5js-logo-small.svg');

const __process = (typeof global !== 'undefined' ? global : window).process;

class Nav extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      dropdownOpen: 'none'
    };
    this.handleFocus = this.handleFocus.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.clearHideTimeout = this.clearHideTimeout.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.handleClickOutside = this.handleClickOutside.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleNew = this.handleNew.bind(this);
    this.handleDuplicate = this.handleDuplicate.bind(this);
    this.handleShare = this.handleShare.bind(this);
    this.handleDownload = this.handleDownload.bind(this);
    this.handleFind = this.handleFind.bind(this);
    this.handleAddFile = this.handleAddFile.bind(this);
    this.handleAddFolder = this.handleAddFolder.bind(this);
    this.handleFindNext = this.handleFindNext.bind(this);
    this.handleRun = this.handleRun.bind(this);
    this.handleFindPrevious = this.handleFindPrevious.bind(this);
    this.handleStop = this.handleStop.bind(this);
    this.handleStartAccessible = this.handleStartAccessible.bind(this);
    this.handleStopAccessible = this.handleStopAccessible.bind(this);
    this.handleKeyboardShortcuts = this.handleKeyboardShortcuts.bind(this);
    this.handleLogout = this.handleLogout.bind(this);
    this.toggleDropdownForFile = this.toggleDropdown.bind(this, 'file');
    this.handleFocusForFile = this.handleFocus.bind(this, 'file');
    this.setDropdownForNone = this.setDropdown.bind(this, 'none');
    this.toggleDropdownForEdit = this.toggleDropdown.bind(this, 'edit');
    this.handleFocusForEdit = this.handleFocus.bind(this, 'edit');
    this.toggleDropdownForSketch = this.toggleDropdown.bind(this, 'sketch');
    this.handleFocusForSketch = this.handleFocus.bind(this, 'sketch');
    this.toggleDropdownForHelp = this.toggleDropdown.bind(this, 'help');
    this.handleFocusForHelp = this.handleFocus.bind(this, 'help');
    this.toggleDropdownForAccount = this.toggleDropdown.bind(this, 'account');
    this.handleFocusForAccount = this.handleFocus.bind(this, 'account');
    this.closeDropDown = this.closeDropDown.bind(this);
  }

  componentDidMount() {
    document.addEventListener('mousedown', this.handleClick, false);
    document.addEventListener('keydown', this.closeDropDown, false);
  }
  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleClick, false);
    document.removeEventListener('keydown', this.closeDropDown, false);
  }

  setDropdown(dropdown) {
    this.setState({
      dropdownOpen: dropdown
    });
  }

  closeDropDown(e) {
    if (e.keyCode === 27) {
      this.setDropdown('none');
    }
  }

  handleClick(e) {
    if (!this.node) {
      return;
    }
    if (this.node && this.node.contains(e.target)) {
      return;
    }

    this.handleClickOutside();
  }

  handleNew() {
    if (!this.props.unsavedChanges) {
      this.props.showToast(1500);
      this.props.setToastText('Opened new sketch.');
      this.props.newProject();
    } else if (this.props.warnIfUnsavedChanges()) {
      this.props.showToast(1500);
      this.props.setToastText('Opened new sketch.');
      this.props.newProject();
    }
    this.setDropdown('none');
  }

  handleSave() {
    if (this.props.user.authenticated) {
      this.props.saveProject(this.props.cmController.getContent());
    } else {
      this.props.showErrorModal('forceAuthentication');
    }
    this.setDropdown('none');
  }

  handleFind() {
    this.props.cmController.showFind();
    this.setDropdown('none');
  }

  handleFindNext() {
    this.props.cmController.findNext();
    this.setDropdown('none');
  }

  handleFindPrevious() {
    this.props.cmController.findPrev();
    this.setDropdown('none');
  }

  handleAddFile() {
    this.props.newFile(this.props.rootFile.id);
    this.setDropdown('none');
  }

  handleAddFolder() {
    this.props.newFolder(this.props.rootFile.id);
    this.setDropdown('none');
  }

  handleRun() {
    this.props.startSketch();
    this.setDropdown('none');
  }

  handleStop() {
    this.props.stopSketch();
    this.setDropdown('none');
  }

  handleStartAccessible() {
    this.props.setAllAccessibleOutput(true);
    this.setDropdown('none');
  }

  handleStopAccessible() {
    this.props.setAllAccessibleOutput(false);
    this.setDropdown('none');
  }

  handleKeyboardShortcuts() {
    this.props.showKeyboardShortcutModal();
    this.setDropdown('none');
  }

  handleLogout() {
    this.props.logoutUser();
    this.setDropdown('none');
  }

  handleDownload() {
    this.props.autosaveProject();
    projectActions.exportProjectAsZip(this.props.project.id);
    this.setDropdown('none');
  }

  handleDuplicate() {
    this.props.cloneProject();
    this.setDropdown('none');
  }

  handleShare() {
    this.props.showShareModal();
    this.setDropdown('none');
  }

  handleClickOutside() {
    this.setState({
      dropdownOpen: 'none'
    });
  }

  toggleDropdown(dropdown) {
    if (this.state.dropdownOpen === 'none') {
      this.setState({
        dropdownOpen: dropdown
      });
    } else {
      this.setState({
        dropdownOpen: 'none'
      });
    }
  }

  isUserOwner() {
    return this.props.project.owner && this.props.project.owner.id === this.props.user.id;
  }

  handleFocus(dropdown) {
    this.clearHideTimeout();
    this.setDropdown(dropdown);
  }

  clearHideTimeout() {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  }

  handleBlur() {
    this.timer = setTimeout(this.setDropdown.bind(this, 'none'), 10);
  }

  render() {
    const navDropdownState = {
      file: classNames({
        'nav__item': true,
        'nav__item--open': this.state.dropdownOpen === 'file'
      }),
      edit: classNames({
        'nav__item': true,
        'nav__item--open': this.state.dropdownOpen === 'edit'
      }),
      sketch: classNames({
        'nav__item': true,
        'nav__item--open': this.state.dropdownOpen === 'sketch'
      }),
      help: classNames({
        'nav__item': true,
        'nav__item--open': this.state.dropdownOpen === 'help'
      }),
      account: classNames({
        'nav__item': true,
        'nav__item--open': this.state.dropdownOpen === 'account'
      })
    };
    return (
      <nav className="nav" title="main-navigation" ref={(node) => { this.node = node; }}>
        <ul className="nav__items-left" title="project-menu">
          <li className="nav__item-logo">
            <InlineSVG src={logoUrl} alt="p5.js logo" className="svg__logo" />
          </li>
          <li className={navDropdownState.file}>
            <button
              onClick={this.toggleDropdownForFile}
              onBlur={this.handleBlur}
              onFocus={this.clearHideTimeout}
              onMouseOver={() => {
                if (this.state.dropdownOpen !== 'none') {
                  this.setDropdown('file');
                }
              }}
            >
              <span className="nav__item-header">File</span>
              <InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
            </button>
            <ul className="nav__dropdown">
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleNew}
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                >
                  New
                </button>
              </li>
              { __process.env.LOGIN_ENABLED && (!this.props.project.owner || this.isUserOwner()) &&
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleSave}
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                >
                  Save
                  <span className="nav__keyboard-shortcut">{metaKeyName}+s</span>
                </button>
              </li> }
              { this.props.project.id && this.props.user.authenticated &&
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleDuplicate}
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                >
                  Duplicate
                </button>
              </li> }
              { this.props.project.id &&
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleShare}
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                >
                  Share
                </button>
              </li> }
              { this.props.project.id &&
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleDownload}
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                >
                  Download
                </button>
              </li> }
              { this.props.user.authenticated &&
              <li className="nav__dropdown-item">
                <Link
                  to={`/${this.props.user.username}/sketches`}
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                  onClick={this.setDropdownForNone}
                >
                  Open
                </Link>
              </li> }
              { __process.env.EXAMPLES_ENABLED &&
              <li className="nav__dropdown-item">
                <Link
                  to="/p5/sketches"
                  onFocus={this.handleFocusForFile}
                  onBlur={this.handleBlur}
                  onClick={this.setDropdownForNone}
                >
                  Examples
                </Link>
              </li> }
            </ul>
          </li>
          <li className={navDropdownState.edit}>
            <button
              onClick={this.toggleDropdownForEdit}
              onBlur={this.handleBlur}
              onFocus={this.clearHideTimeout}
              onMouseOver={() => {
                if (this.state.dropdownOpen !== 'none') {
                  this.setDropdown('edit');
                }
              }}
            >
              <span className="nav__item-header">Edit</span>
              <InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
            </button>
            <ul className="nav__dropdown" >
              <li className="nav__dropdown-item">
                <button
                  onClick={() => {
                    this.props.cmController.tidyCode();
                    this.setDropdown('none');
                  }}
                  onFocus={this.handleFocusForEdit}
                  onBlur={this.handleBlur}
                >
                  Tidy Code
                  <span className="nav__keyboard-shortcut">{'\u21E7'}+Tab</span>
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleFind}
                  onFocus={this.handleFocusForEdit}
                  onBlur={this.handleBlur}
                >
                  Find
                  <span className="nav__keyboard-shortcut">{metaKeyName}+F</span>
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleFindNext}
                  onFocus={this.handleFocusForEdit}
                  onBlur={this.handleBlur}
                >
                  Find Next
                  <span className="nav__keyboard-shortcut">{metaKeyName}+G</span>
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleFindPrevious}
                  onFocus={this.handleFocusForEdit}
                  onBlur={this.handleBlur}
                >
                  Find Previous
                  <span className="nav__keyboard-shortcut">{'\u21E7'}+{metaKeyName}+G</span>
                </button>
              </li>
            </ul>
          </li>
          <li className={navDropdownState.sketch}>
            <button
              onClick={this.toggleDropdownForSketch}
              onBlur={this.handleBlur}
              onFocus={this.clearHideTimeout}
              onMouseOver={() => {
                if (this.state.dropdownOpen !== 'none') {
                  this.setDropdown('sketch');
                }
              }}
            >
              <span className="nav__item-header">Sketch</span>
              <InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
            </button>
            <ul className="nav__dropdown">
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleAddFile}
                  onFocus={this.handleFocusForSketch}
                  onBlur={this.handleBlur}
                >
                  Add File
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleAddFolder}
                  onFocus={this.handleFocusForSketch}
                  onBlur={this.handleBlur}
                >
                  Add Folder
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleRun}
                  onFocus={this.handleFocusForSketch}
                  onBlur={this.handleBlur}
                >
                  Run
                  <span className="nav__keyboard-shortcut">{metaKeyName}+Enter</span>
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleStop}
                  onFocus={this.handleFocusForSketch}
                  onBlur={this.handleBlur}
                >
                  Stop
                  <span className="nav__keyboard-shortcut">{'\u21E7'}+{metaKeyName}+Enter</span>
                </button>
              </li>
              {/* <li className="nav__dropdown-item">
                <button
                  onClick={this.handleStartAccessible}
                  onFocus={this.handleFocusForSketch}
                  onBlur={this.handleBlur}
                >
                  Start Accessible
                  <span className="nav__keyboard-shortcut">{'\u21E7'}+{metaKeyName}+1</span>
                </button>
              </li>
              <li className="nav__dropdown-item">
                <button
                  onClick={this.handleStopAccessible}
                  onFocus={this.handleFocusForSketch}
                  onBlur={this.handleBlur}
                >
                  Stop Accessible
                  <span className="nav__keyboard-shortcut">{'\u21E7'}+{metaKeyName}+2</span>
                </button>
              </li> */}
            </ul>
          </li>
          <li className={navDropdownState.help}>
            <button
              onClick={this.toggleDropdownForHelp}
              onBlur={this.handleBlur}
              onFocus={this.clearHideTimeout}
              onMouseOver={() => {
                if (this.state.dropdownOpen !== 'none') {
                  this.setDropdown('help');
                }
              }}
            >
              <span className="nav__item-header">Help</span>
              <InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
            </button>
            <ul className="nav__dropdown">
              <li className="nav__dropdown-item">
                <button
                  onFocus={this.handleFocusForHelp}
                  onBlur={this.handleBlur}
                  onClick={this.handleKeyboardShortcuts}
                >
                  Keyboard Shortcuts
                </button>
              </li>
              <li className="nav__dropdown-item">
                <a
                  href="https://p5js.org/reference/"
                  target="_blank"
                  rel="noopener noreferrer"
                  onFocus={this.handleFocusForHelp}
                  onBlur={this.handleBlur}
                  onClick={this.setDropdownForNone}
                >Reference
                </a>
              </li>
              <li className="nav__dropdown-item">
                <Link
                  to="/about"
                  onFocus={this.handleFocusForHelp}
                  onBlur={this.handleBlur}
                  onClick={this.setDropdownForNone}
                >
                  About
                </Link>
              </li>
            </ul>
          </li>
        </ul>
        { __process.env.LOGIN_ENABLED && !this.props.user.authenticated &&
          <ul className="nav__items-right" title="user-menu">
            <li>
              <Link to="/login">
                <span className="nav__item-header">Log in</span>
              </Link>
            </li>
            <span className="nav__item-spacer">or</span>
            <li>
              <Link to="/signup">
                <span className="nav__item-header">Sign up</span>
              </Link>
            </li>
          </ul>}
        { __process.env.LOGIN_ENABLED && this.props.user.authenticated &&
          <ul className="nav__items-right" title="user-menu">
            <li className="nav__item">
              <span>Hello, {this.props.user.username}!</span>
            </li>
            <span className="nav__item-spacer">|</span>
            <li className={navDropdownState.account}>
              <button
                className="nav__item-header"
                onClick={this.toggleDropdownForAccount}
                onBlur={this.handleBlur}
                onFocus={this.clearHideTimeout}
                onMouseOver={() => {
                  if (this.state.dropdownOpen !== 'none') {
                    this.setDropdown('account');
                  }
                }}
              >
                My Account
                <InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
              </button>
              <ul className="nav__dropdown">
                <li className="nav__dropdown-item">
                  <Link
                    to={`/${this.props.user.username}/sketches`}
                    onFocus={this.handleFocusForAccount}
                    onBlur={this.handleBlur}
                    onClick={this.setDropdownForNone}
                  >
                    My sketches
                  </Link>
                </li>
                <li className="nav__dropdown-item">
                  <Link
                    to="/assets"
                    onFocus={this.handleFocusForAccount}
                    onBlur={this.handleBlur}
                    onClick={this.setDropdownForNone}
                  >
                    My assets
                  </Link>
                </li>
                <li className="nav__dropdown-item">
                  <Link
                    to="/account"
                    onFocus={this.handleFocusForAccount}
                    onBlur={this.handleBlur}
                    onClick={this.setDropdownForNone}
                  >
                    Settings
                  </Link>
                </li>
                <li className="nav__dropdown-item">
                  <button
                    onClick={this.handleLogout}
                    onFocus={this.handleFocusForAccount}
                    onBlur={this.handleBlur}
                  >
                    Log out
                  </button>
                </li>
              </ul>
            </li>
          </ul> }
        {/*
        <div className="nav__announce">
          This is a preview version of the editor, that has not yet been officially released.
          It is in development, you can report bugs <a
            href="https://github.com/processing/p5.js-web-editor/issues"
            target="_blank"
            rel="noopener noreferrer"
          >here</a>.
          Please use with caution.
        </div>
      */}
      </nav>
    );
  }
}

Nav.propTypes = {
  newProject: PropTypes.func.isRequired,
  showToast: PropTypes.func.isRequired,
  setToastText: PropTypes.func.isRequired,
  saveProject: PropTypes.func.isRequired,
  autosaveProject: PropTypes.func.isRequired,
  cloneProject: PropTypes.func.isRequired,
  user: PropTypes.shape({
    authenticated: PropTypes.bool.isRequired,
    username: PropTypes.string,
    id: PropTypes.string
  }).isRequired,
  project: PropTypes.shape({
    id: PropTypes.string,
    owner: PropTypes.shape({
      id: PropTypes.string
    })
  }),
  logoutUser: PropTypes.func.isRequired,
  showShareModal: PropTypes.func.isRequired,
  showErrorModal: PropTypes.func.isRequired,
  unsavedChanges: PropTypes.bool.isRequired,
  warnIfUnsavedChanges: PropTypes.func.isRequired,
  showKeyboardShortcutModal: PropTypes.func.isRequired,
  cmController: PropTypes.shape({
    tidyCode: PropTypes.func,
    showFind: PropTypes.func,
    findNext: PropTypes.func,
    findPrev: PropTypes.func,
    getContent: PropTypes.func
  }),
  startSketch: PropTypes.func.isRequired,
  stopSketch: PropTypes.func.isRequired,
  setAllAccessibleOutput: PropTypes.func.isRequired,
  newFile: PropTypes.func.isRequired,
  newFolder: PropTypes.func.isRequired,
  rootFile: PropTypes.shape({
    id: PropTypes.string.isRequired
  }).isRequired
};

Nav.defaultProps = {
  project: {
    id: undefined,
    owner: undefined
  },
  cmController: {}
};

function mapStateToProps(state) {
  return {
    project: state.project,
    user: state.user,
    unsavedChanges: state.ide.unsavedChanges,
    rootFile: state.files.filter(file => file.name === 'root')[0]
  };
}

const mapDispatchToProps = {
  ...IDEActions,
  ...projectActions,
  ...toastActions,
  logoutUser,
  setAllAccessibleOutput
};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Nav));
export { Nav as NavComponent };