content: import {Button} from 'flood-ui-kit';
  import {FormattedMessage, injectIntl} from 'react-intl';
  import _ from 'lodash';
  import Dropzone from 'react-dropzone';
  import React from 'react';
  
  import ClientStatusStore from '../../stores/ClientStatusStore';
  import ConfigStore from '../../stores/ConfigStore';
  import connectStores from '../../util/connectStores';
  import CustomScrollbars from '../general/CustomScrollbars';
  import EventTypes from '../../constants/EventTypes';
  import Files from '../icons/Files';
  import GlobalContextMenuMountPoint from '../general/GlobalContextMenuMountPoint';
  import ListViewport from '../general/ListViewport';
  import PriorityMeter from '../general/filesystem/PriorityMeter';
  import SettingsStore from '../../stores/SettingsStore';
  import TableHeading from './TableHeading';
  import Torrent from './Torrent';
  import TorrentActions from '../../actions/TorrentActions';
  import TorrentFilterStore from '../../stores/TorrentFilterStore';
  import TorrentStore from '../../stores/TorrentStore';
  import UIActions from '../../actions/UIActions';
  
  const defaultWidth = 100;
  const defaultPropWidths = {
    name: 200,
    eta: 100,
  };
  
  class TorrentListContainer extends React.Component {
    handleTorrentPriorityChange = null;
  
    lastScrollLeft = 0;
  
    state = {
      tableScrollLeft: 0,
      torrentListViewportSize: null,
    };
  
    componentDidMount() {
      TorrentStore.listen(EventTypes.UI_TORRENT_SELECTION_CHANGE, this.handleTorrentSelectionChange);
      TorrentFilterStore.listen(EventTypes.UI_TORRENTS_FILTER_CHANGE, this.handleTorrentFilterChange);
      global.addEventListener('resize', this.updateTorrentListViewWidth);
    }
  
    componentDidUpdate(prevProps) {
      const {torrentListViewSize: currentTorrentListViewSize} = this.props;
      const isCondensed = currentTorrentListViewSize === 'condensed';
      const wasCondensed = prevProps.torrentListViewSize === 'condensed';
  
      if (this.horizontalScrollRef != null && this.state.torrentListViewportSize == null) {
        this.updateTorrentListViewWidth();
      }
  
      if (this.verticalScrollbarThumb != null) {
        if (!isCondensed && wasCondensed) {
          this.updateVerticalThumbPosition(0);
        } else if (isCondensed) {
          this.updateVerticalThumbPosition(
            (this.getTotalCellWidth() - this.listContainer.clientWidth) * -1 + this.lastScrollLeft,
          );
        }
      }
  
      if (currentTorrentListViewSize !== prevProps.torrentListViewSize && this.listViewportRef != null) {
        this.listViewportRef.measureItemHeight();
      }
    }
  
    componentWillUnmount() {
      TorrentStore.unlisten(EventTypes.UI_TORRENT_SELECTION_CHANGE, this.handleTorrentSelectionChange);
      TorrentFilterStore.unlisten(EventTypes.UI_TORRENTS_FILTER_CHANGE, this.handleTorrentFilterChange);
      global.removeEventListener('resize', this.updateTorrentListViewWidth);
    }
  
    handleClearFiltersClick() {
      TorrentFilterStore.clearAllFilters();
    }
  
    getContextMenuItems(torrent) {
      const {intl} = this.props;
      const clickHandler = this.handleContextMenuItemClick;
  
      return [
        {
          action: 'start',
          clickHandler,
          label: intl.formatMessage({
            id: 'torrents.list.context.start',
            defaultMessage: 'Start',
          }),
        },
        {
          action: 'stop',
          clickHandler,
          label: intl.formatMessage({
            id: 'torrents.list.context.stop',
            defaultMessage: 'Stop',
          }),
        },
        {
          action: 'remove',
          clickHandler,
          label: intl.formatMessage({
            id: 'torrents.list.context.remove',
            defaultMessage: 'Remove',
          }),
        },
        {
          action: 'check-hash',
          clickHandler,
          label: intl.formatMessage({
            id: 'torrents.list.context.check.hash',
            defaultMessage: 'Check Hash',
          }),
        },
        {
          type: 'separator',
        },
        {
          action: 'set-taxonomy',
          clickHandler,
          label: intl.formatMessage({
            id: 'torrents.list.context.set.tags',
            defaultMessage: 'Set Tags',
          }),
        },
        {
          action: 'move',
          clickHandler,
          label: intl.formatMessage({
            id: 'torrents.list.context.move',
            defaultMessage: 'Set Torrent Location',
          }),
        },
        {
          type: 'separator',
        },
        {
          action: 'torrent-details',
          clickHandler: (action, event) => {
            clickHandler(action, event, torrent);
          },
          label: intl.formatMessage({
            id: 'torrents.list.context.details',
            defaultMessage: 'Torrent Details',
          }),
        },
        {
          action: 'torrent-download-tar',
          clickHandler: (action, event) => {
            clickHandler(action, event, torrent);
          },
          label: intl.formatMessage({
            id: 'torrents.list.context.download',
            defaultMessage: 'Download',
          }),
        },
        {
          action: 'set-priority',
          clickHandler,
          dismissMenu: false,
          label: intl.formatMessage({
            id: 'torrents.list.context.priority',
            defaultMessage: 'Priority',
          }),
          labelAction: (
            <PriorityMeter
              id={torrent.hash}
              key={torrent.hash}
              bindExternalChangeHandler={this.bindExternalPriorityChangeHandler}
              level={torrent.priority}
              maxLevel={3}
              priorityType="torrent"
              onChange={this.handleTorrentPriorityChange}
              showLabel={false}
            />
          ),
        },
      ];
    }
  
    handleContextMenuItemClick = (action, event, torrent) => {
      const selectedTorrents = TorrentStore.getSelectedTorrents();
      switch (action) {
        case 'check-hash':
          TorrentActions.checkHash(selectedTorrents);
          break;
        case 'set-taxonomy':
          UIActions.displayModal({id: 'set-taxonomy'});
          break;
        case 'start':
          TorrentActions.startTorrents(selectedTorrents);
          break;
        case 'stop':
          TorrentActions.stopTorrents(selectedTorrents);
          break;
        case 'remove':
          UIActions.displayModal({id: 'remove-torrents'});
          break;
        case 'move':
          UIActions.displayModal({id: 'move-torrents'});
          break;
        case 'torrent-details':
          this.handleDetailsClick(torrent, event);
          break;
        case 'torrent-download-tar':
          this.handleTorrentDownload(torrent, event);
          break;
        case 'set-priority':
          this.handleTorrentPriorityChange(event);
          break;
        default:
          break;
      }
    };
  
    handleDetailsClick = (torrent, event) => {
      UIActions.handleDetailsClick({
        hash: torrent.hash,
        event,
      });
  
      UIActions.displayModal({
        id: 'torrent-details',
        options: {hash: torrent.hash},
      });
    };
  
    handleTorrentDownload(torrent, event) {
      event.preventDefault();
      const baseURI = ConfigStore.getBaseURI();
      const link = document.createElement('a');
      link.download = torrent.isMultiFile ? `${torrent.name}.tar` : torrent.name;
      link.href = `${baseURI}api/download?hash=${torrent.hash}`;
      link.style.display = 'none';
      document.body.appendChild(link);
      link.click();
    }
  
    handleDoubleClick(torrent, event) {
      this.handleDetailsClick(torrent, event);
    }
  
    handleContextMenuClick = (torrent, event) => {
      event.preventDefault();
  
      UIActions.displayContextMenu({
        id: 'torrent-list-item',
        clickPosition: {
          x: event.clientX,
          y: event.clientY,
        },
        items: this.getContextMenuItems(torrent),
      });
    };
  
    handleFileDrop = files => {
      const destination =
        SettingsStore.getFloodSettings('torrentDestination') || SettingsStore.getClientSettings('directoryDefault') || '';
  
      const isBasePath = false;
  
      const start = SettingsStore.getFloodSettings('startTorrentsOnLoad');
  
      const fileData = new FormData();
  
      files.forEach(file => {
        fileData.append('torrents', file);
      });
  
      fileData.append('destination', destination);
      fileData.append('isBasePath', isBasePath);
      fileData.append('start', start);
      fileData.append('tags', '');
  
      TorrentActions.addTorrentsByFiles(fileData, destination);
    };
  
    handleTorrentFilterChange = () => {
      if (this.listViewportRef != null) {
        this.listViewportRef.scrollToTop();
      }
    };
  
    handleTorrentSelectionChange = () => {
      this.forceUpdate();
    };
  
    getEmptyTorrentListNotification() {
      let clearFilters = null;
  
      if (TorrentFilterStore.isFilterActive()) {
        clearFilters = (
          <div className="torrents__alert__action">
            <Button onClick={this.handleClearFiltersClick} priority="tertiary">
              <FormattedMessage id="torrents.list.clear.filters" defaultMessage="Clear filters" />
            </Button>
          </div>
        );
      }
  
      return (
        <div className="torrents__alert__wrapper">
          <div className="torrents__alert">
            <FormattedMessage id="torrents.list.no.torrents" defaultMessage="No torrents to display." />
          </div>
          {clearFilters}
        </div>
      );
    }
  
    getCellWidth(slug) {
      const value = this.props.torrentListColumnWidths[slug] || defaultPropWidths[slug] || defaultWidth;
  
      return value;
    }
  
    getListWrapperStyle(options = {}) {
      if (options.isCondensed && !options.isListEmpty) {
        const totalCellWidth = this.getTotalCellWidth();
  
        if (totalCellWidth >= this.state.torrentListViewportSize) {
          return {width: `${totalCellWidth}px`};
        }
      }
  
      return null;
    }
  
    getTotalCellWidth() {
      return this.props.displayedProperties.reduce((accumulator, {id, visible}) => {
        if (!visible) {
          return accumulator;
        }
  
        return accumulator + this.getCellWidth(id);
      }, 0);
    }
  
    getVerticalScrollbarThumb = (props, onMouseUp) => {
      return (
        <div {...props}>
          <div
            className="scrollbars__thumb scrollbars__thumb--horizontal scrollbars__thumb--surrogate"
            onMouseUp={onMouseUp}
            ref={ref => {
              this.verticalScrollbarThumb = ref;
            }}
            role="button"
            tabIndex={0}
          />
        </div>
      );
    };
  
    bindExternalPriorityChangeHandler = priorityChangeHandler => {
      this.handleTorrentPriorityChange = priorityChangeHandler;
    };
  
    handleTableHeadingCellClick(slug) {
      const currentSort = TorrentFilterStore.getTorrentsSort();
  
      let nextDirection = 'asc';
  
      if (currentSort.property === slug) {
        nextDirection = currentSort.direction === 'asc' ? 'desc' : 'asc';
      }
  
      const sortBy = {
        property: slug,
        direction: nextDirection,
      };
  
      SettingsStore.saveFloodSettings({id: 'sortTorrents', data: sortBy});
      UIActions.setTorrentsSort(sortBy);
    }
  
    handleTorrentClick(hash, event) {
      UIActions.handleTorrentClick({hash, event});
    }
  
    handleTorrentPriorityChange(hash, level) {
      TorrentActions.setPriority(hash, level);
    }
  
    handleHorizontalScroll = event => {
      if (this.verticalScrollbarThumb != null) {
        const {clientWidth, scrollLeft, scrollWidth} = event.target;
        this.lastScrollLeft = scrollLeft;
        this.updateVerticalThumbPosition((scrollWidth - clientWidth) * -1 + scrollLeft);
      }
    };
  
    handleHorizontalScrollStop = () => {
      this.setState({tableScrollLeft: this.lastScrollLeft});
    };
  
    handlePropWidthChange = newPropWidths => {
      SettingsStore.saveFloodSettings({
        id: 'torrentListColumnWidths',
        data: {...this.props.torrentListColumnWidths, ...newPropWidths},
      });
    };
  
    /* eslint-disable react/sort-comp */
    updateTorrentListViewWidth = _.debounce(
      () => {
        if (this.horizontalScrollRef != null) {
          this.setState({
            torrentListViewportSize: this.horizontalScrollRef.scrollbarRef.getClientWidth(),
          });
        }
      },
      100,
      {trailing: true},
    );
    /* eslint-enable react/sort-comp */
  
    updateVerticalThumbPosition = offset => {
      this.verticalScrollbarThumb.style.transform = `translateX(${offset}px)`;
    };
  
    renderListItem = index => {
      const selectedTorrents = TorrentStore.getSelectedTorrents();
      const {displayedProperties, torrentListViewSize, torrentListColumnWidths, torrents} = this.props;
      const torrent = torrents[index];
      const {hash} = torrent;
  
      return (
        <Torrent
          defaultPropWidths={defaultPropWidths}
          defaultWidth={defaultWidth}
          handleClick={this.handleTorrentClick}
          handleDetailsClick={this.handleDetailsClick}
          handleDoubleClick={this.handleDoubleClick}
          handleRightClick={this.handleContextMenuClick}
          index={index}
          isCondensed={torrentListViewSize === 'condensed'}
          key={hash}
          columns={displayedProperties}
          propWidths={torrentListColumnWidths}
          isSelected={selectedTorrents.includes(hash)}
          torrent={torrent}
        />
      );
    };
  
    render() {
      const {displayedProperties, torrentListColumnWidths, isClientConnected, torrentListViewSize, torrents} = this.props;
      let content = null;
      let torrentListHeading = null;
      const isCondensed = torrentListViewSize === 'condensed';
      const isListEmpty = torrents.length === 0;
      const listWrapperStyle = this.getListWrapperStyle({
        isCondensed,
        isListEmpty,
      });
  
      if (!isClientConnected) {
        content = (
          <div className="torrents__alert__wrapper">
            <div className="torrents__alert">
              <FormattedMessage id="torrents.list.cannot.connect" defaultMessage="Cannot connect to rTorrent." />
            </div>
          </div>
        );
      } else if (isListEmpty) {
        content = this.getEmptyTorrentListNotification();
      } else {
        content = (
          <ListViewport
            getVerticalThumb={this.getVerticalScrollbarThumb}
            itemRenderer={this.renderListItem}
            listClass="torrent__list"
            listLength={torrents.length}
            ref={ref => {
              this.listViewportRef = ref;
            }}
            scrollContainerClass="torrent__list__scrollbars--vertical"
          />
        );
  
        if (isCondensed) {
          torrentListHeading = (
            <TableHeading
              columns={displayedProperties}
              defaultWidth={defaultWidth}
              defaultPropWidths={defaultPropWidths}
              onCellClick={this.handleTableHeadingCellClick}
              onWidthsChange={this.handlePropWidthChange}
              propWidths={torrentListColumnWidths}
              scrollOffset={this.state.tableScrollLeft}
              sortProp={TorrentFilterStore.getTorrentsSort()}
            />
          );
        }
      }
  
      return (
        <Dropzone
          activeClassName="dropzone--is-dragging"
          className="dropzone dropzone--with-overlay torrents"
          ref={ref => {
            this.listContainer = ref;
          }}
          onDrop={this.handleFileDrop}
          disableClick
          disablePreview>
          <CustomScrollbars
            className="torrent__list__scrollbars--horizontal"
            onScrollStop={this.handleHorizontalScrollStop}
            nativeScrollHandler={this.handleHorizontalScroll}
            ref={ref => {
              this.horizontalScrollRef = ref;
            }}>
            <div className="torrent__list__wrapper" style={listWrapperStyle}>
              <GlobalContextMenuMountPoint id="torrent-list-item" />
              {torrentListHeading}
              {content}
            </div>
          </CustomScrollbars>
  
          <div className="dropzone__overlay">
            <div className="dropzone__copy">
              <div className="dropzone__icon">
                <Files />
              </div>
              <FormattedMessage id="torrents.list.drop" defaultMessage="Drop files here to add them to rTorrent." />
            </div>
          </div>
        </Dropzone>
      );
    }
  }
  
  const ConnectedActionBar = connectStores(injectIntl(TorrentListContainer), () => {
    return [
      {
        store: ClientStatusStore,
        event: EventTypes.CLIENT_CONNECTION_STATUS_CHANGE,
        getValue: ({store}) => {
          return {
            isClientConnected: store.getIsConnected(),
          };
        },
      },
      {
        store: SettingsStore,
        event: EventTypes.SETTINGS_CHANGE,
        getValue: ({store}) => {
          return {
            displayedProperties: store.getFloodSettings('torrentDetails'),
            torrentListColumnWidths: store.getFloodSettings('torrentListColumnWidths'),
            torrentListViewSize: store.getFloodSettings('torrentListViewSize'),
          };
        },
      },
      {
        store: TorrentStore,
        event: [EventTypes.UI_TORRENTS_LIST_FILTERED, EventTypes.CLIENT_TORRENTS_REQUEST_SUCCESS],
        getValue: ({store}) => {
          return {
            torrents: store.getTorrents(),
          };
        },
      },
    ];
  });
  
  export default ConnectedActionBar;
  