'use strict';

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

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

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

var _propTypes2 = _interopRequireDefault(_propTypes);

var _reactIntl = require('react-intl');

var _get = require('lodash/get');

var _get2 = _interopRequireDefault(_get);

var _immutable = require('immutable');

var _immutable2 = _interopRequireDefault(_immutable);

var _qs = require('qs');

var _qs2 = _interopRequireDefault(_qs);

var _CheckboxInput = require('cspace-input/lib/components/CheckboxInput');

var _CheckboxInput2 = _interopRequireDefault(_CheckboxInput);

var _ErrorPage = require('./ErrorPage');

var _ErrorPage2 = _interopRequireDefault(_ErrorPage);

var _RelateButton = require('../record/RelateButton');

var _RelateButton2 = _interopRequireDefault(_RelateButton);

var _SearchResultTitleBar = require('../search/SearchResultTitleBar');

var _SearchResultTitleBar2 = _interopRequireDefault(_SearchResultTitleBar);

var _Pager = require('../search/Pager');

var _Pager2 = _interopRequireDefault(_Pager);

var _SearchResultSummary = require('../search/SearchResultSummary');

var _SearchResultSummary2 = _interopRequireDefault(_SearchResultSummary);

var _SelectBar = require('../search/SelectBar');

var _SelectBar2 = _interopRequireDefault(_SelectBar);

var _SearchResultTableContainer = require('../../containers/search/SearchResultTableContainer');

var _SearchResultTableContainer2 = _interopRequireDefault(_SearchResultTableContainer);

var _SearchToRelateModalContainer = require('../../containers/search/SearchToRelateModalContainer');

var _SearchToRelateModalContainer2 = _interopRequireDefault(_SearchToRelateModalContainer);

var _permissionHelpers = require('../../helpers/permissionHelpers');

var _searchHelpers = require('../../helpers/searchHelpers');

var _searchNames = require('../../constants/searchNames');

var _configHelpers = require('../../helpers/configHelpers');

var _SearchResultPage = require('../../../styles/cspace-ui/SearchResultPage.css');

var _SearchResultPage2 = _interopRequireDefault(_SearchResultPage);

var _PageBody = require('../../../styles/cspace-ui/PageBody.css');

var _PageBody2 = _interopRequireDefault(_PageBody);

var _SearchResultSidebar = require('../../../styles/cspace-ui/SearchResultSidebar.css');

var _SearchResultSidebar2 = _interopRequireDefault(_SearchResultSidebar);

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

// FIXME: Make default page size configurable
/* global window */

const defaultPageSize = 20;

// const stopPropagation = (event) => {
//   event.stopPropagation();
// };

const messages = (0, _reactIntl.defineMessages)({
  relate: {
    'id': 'searchResultPage.relate',
    'defaultMessage': 'Relate\u2026'
  }
});

const propTypes = {
  history: _propTypes2.default.object,
  location: _propTypes2.default.object,
  match: _propTypes2.default.object,
  perms: _propTypes2.default.instanceOf(_immutable2.default.Map),
  preferredPageSize: _propTypes2.default.number,
  search: _propTypes2.default.func,
  selectedItems: _propTypes2.default.instanceOf(_immutable2.default.Map),
  setPreferredPageSize: _propTypes2.default.func,
  setSearchPageAdvanced: _propTypes2.default.func,
  setSearchPageKeyword: _propTypes2.default.func,
  setAllItemsSelected: _propTypes2.default.func,
  onItemSelectChange: _propTypes2.default.func
};

const contextTypes = {
  config: _propTypes2.default.object.isRequired
};

class SearchResultPage extends _react.Component {
  constructor() {
    super();

    this.getSearchToRelateSubjects = this.getSearchToRelateSubjects.bind(this);
    this.handleCheckboxClick = this.handleCheckboxClick.bind(this);
    this.handleCheckboxCommit = this.handleCheckboxCommit.bind(this);
    this.handleEditSearchLinkClick = this.handleEditSearchLinkClick.bind(this);
    this.handleModalCancelButtonClick = this.handleModalCancelButtonClick.bind(this);
    this.handleModalCloseButtonClick = this.handleModalCloseButtonClick.bind(this);
    this.handlePageChange = this.handlePageChange.bind(this);
    this.handlePageSizeChange = this.handlePageSizeChange.bind(this);
    this.handleRelateButtonClick = this.handleRelateButtonClick.bind(this);
    this.handleRelationsCreated = this.handleRelationsCreated.bind(this);
    this.handleSortChange = this.handleSortChange.bind(this);
    this.renderCheckbox = this.renderCheckbox.bind(this);
    this.renderFooter = this.renderFooter.bind(this);
    this.renderHeader = this.renderHeader.bind(this);
    this.shouldShowCheckbox = this.shouldShowCheckbox.bind(this);

    this.state = {
      isSearchToRelateModalOpen: false
    };
  }

  componentDidMount() {
    if (!this.normalizeQuery()) {
      var _props = this.props;
      const location = _props.location,
            setPreferredPageSize = _props.setPreferredPageSize;


      if (setPreferredPageSize) {
        const search = location.search;


        const query = _qs2.default.parse(search.substring(1));

        setPreferredPageSize(parseInt(query.size, 10));
      }

      this.search();
    }
  }

  componentDidUpdate(prevProps) {
    var _props2 = this.props;
    const location = _props2.location,
          match = _props2.match,
          perms = _props2.perms;
    const prevLocation = prevProps.location,
          prevMatch = prevProps.match,
          prevPerms = prevProps.perms;
    const params = match.params;
    const prevParams = prevMatch.params;


    if (perms !== prevPerms || params.recordType !== prevParams.recordType || params.vocabulary !== prevParams.vocabulary || params.csid !== prevParams.csid || params.subresource !== prevParams.subresource || location.search !== prevLocation.search) {
      if (!this.normalizeQuery()) {
        const setPreferredPageSize = this.props.setPreferredPageSize;


        if (setPreferredPageSize) {
          const search = location.search;


          const query = _qs2.default.parse(search.substring(1));

          setPreferredPageSize(parseInt(query.size, 10));
        }

        this.search();
      }
    }
  }

  getListType(searchDescriptor) {
    const config = this.context.config;


    return (0, _searchHelpers.getListType)(config, searchDescriptor);
  }

  getSearchDescriptor() {
    // FIXME: Make the search descriptor consistently an Immutable. Currently only the advanced
    // search condition is an Immutable. The whole search descriptor gets converted to an Immutable
    // when stored in the Redux store, but components expect it to be an object (except for the
    // advanced search condition, which is always Immutable). This is confusing.

    // FIXME: Refactor this into a wrapper component that calculates the search descriptor from
    // location and params, and passes it into a child. This will eliminate the multiple calls to
    // this method from the various render methods in this class.

    var _props3 = this.props;
    const location = _props3.location,
          match = _props3.match;
    const params = match.params;
    const search = location.search;


    const query = _qs2.default.parse(search.substring(1));

    const searchQuery = Object.assign({}, query, {
      p: parseInt(query.p, 10) - 1,
      size: parseInt(query.size, 10)
    });

    const advancedSearchCondition = query.as;

    if (advancedSearchCondition) {
      searchQuery.as = JSON.parse(advancedSearchCondition);
    }

    const searchDescriptor = {
      searchQuery
    };

    ['recordType', 'vocabulary', 'csid', 'subresource'].forEach(param => {
      const value = params[param];

      if (typeof value !== 'undefined') {
        searchDescriptor[param] = value;
      }
    });

    return _immutable2.default.fromJS(searchDescriptor);
  }

  getSearchToRelateSubjects() {
    const selectedItems = this.props.selectedItems;
    const config = this.context.config;


    if (!selectedItems) {
      return null;
    }

    const searchDescriptor = this.getSearchDescriptor();

    const recordType = searchDescriptor.get('recordType');
    const serviceType = (0, _get2.default)(config, ['recordTypes', recordType, 'serviceConfig', 'serviceType']);
    const itemRecordType = serviceType === 'utility' ? undefined : recordType;

    const titleColumnName = (0, _configHelpers.getFirstColumnName)(config, recordType);

    return selectedItems.valueSeq().map(item => ({
      csid: item.get('csid'),
      recordType: itemRecordType || (0, _configHelpers.getRecordTypeNameByServiceObjectName)(config, item.get('docType')),
      title: item.get(titleColumnName)
    })).toJS();
  }

  isResultRelatable(searchDescriptor) {
    const config = this.context.config;


    const recordType = searchDescriptor.get('recordType');
    const subresource = searchDescriptor.get('subresource');

    const serviceType = (0, _get2.default)(config, ['recordTypes', recordType, 'serviceConfig', 'serviceType']);

    return subresource !== 'terms' && (serviceType === 'procedure' || serviceType === 'object' || recordType === 'procedure' || recordType === 'object');
  }

  closeModal() {
    this.setState({
      isSearchToRelateModalOpen: false
    });
  }

  normalizeQuery() {
    var _props4 = this.props;
    const history = _props4.history,
          location = _props4.location,
          preferredPageSize = _props4.preferredPageSize;
    const search = location.search;


    const query = _qs2.default.parse(search.substring(1));

    if (history) {
      const normalizedQueryParams = {};

      const pageSize = parseInt(query.size, 10);

      if (isNaN(pageSize) || pageSize < 1) {
        const normalizedPageSize = preferredPageSize || defaultPageSize;

        normalizedQueryParams.size = normalizedPageSize.toString();
      } else if (pageSize > 2500) {
        // Services layer max is 2500
        normalizedQueryParams.size = '2500';
      } else if (pageSize.toString() !== query.size) {
        normalizedQueryParams.size = pageSize.toString();
      }

      const pageNum = parseInt(query.p, 10);

      if (isNaN(pageNum) || pageNum < 1) {
        normalizedQueryParams.p = '1';
      } else if (pageNum.toString() !== query.p) {
        normalizedQueryParams.p = pageNum.toString();
      }

      if (Object.keys(normalizedQueryParams).length > 0) {
        const newQuery = Object.assign({}, query, normalizedQueryParams);
        const queryString = _qs2.default.stringify(newQuery);

        history.replace({
          pathname: location.pathname,
          search: `?${queryString}`
        });

        return true;
      }
    }

    return false;
  }

  shouldShowCheckbox(item) {
    const perms = this.props.perms;
    const config = this.context.config;


    return item.get('workflowState') !== 'locked' && (0, _permissionHelpers.canRelate)((0, _configHelpers.getRecordTypeNameByUri)(config, item.get('uri')), perms, config);
  }

  handleCheckboxClick(event) {
    // DRYD-252: Elaborate workaround for Firefox. When a checkbox is a child of an a, clicking on
    // the checkbox navigates to the link. So we have to handle the checkbox click, and prevent the
    // default. This prevents the navigation, but also prevents the checkbox state from changing.
    // So we also have to manually commit the change. The Firefox bug has been open for 17 years
    // now. https://bugzilla.mozilla.org/show_bug.cgi?id=62151

    event.preventDefault();
    event.stopPropagation();

    const checkbox = event.currentTarget.querySelector('input[type="checkbox"]');
    const index = checkbox.name;

    window.setTimeout(() => {
      this.handleCheckboxCommit([index], !checkbox.checked);
    }, 0);
  }

  handleCheckboxCommit(path, value) {
    const index = parseInt(path[0], 10);
    const selected = value;

    const onItemSelectChange = this.props.onItemSelectChange;
    const config = this.context.config;


    if (onItemSelectChange) {
      const searchDescriptor = this.getSearchDescriptor();
      const listType = this.getListType(searchDescriptor);

      onItemSelectChange(config, _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME, searchDescriptor, listType, index, selected);
    }
  }

  handleEditSearchLinkClick() {
    // Transfer this search descriptor's search criteria to advanced search.

    var _props5 = this.props;
    const setSearchPageAdvanced = _props5.setSearchPageAdvanced,
          setSearchPageKeyword = _props5.setSearchPageKeyword;


    if (setSearchPageKeyword || setSearchPageAdvanced) {
      const searchDescriptor = this.getSearchDescriptor();
      const searchQuery = searchDescriptor.get('searchQuery');

      if (setSearchPageKeyword) {
        setSearchPageKeyword(searchQuery.get('kw'));
      }

      if (setSearchPageAdvanced) {
        setSearchPageAdvanced(searchQuery.get('as'));
      }
    }
  }

  handleModalCancelButtonClick() {
    this.closeModal();
  }

  handleModalCloseButtonClick() {
    this.closeModal();
  }

  handlePageChange(pageNum) {
    var _props6 = this.props;
    const history = _props6.history,
          location = _props6.location;


    if (history) {
      const search = location.search;


      const query = _qs2.default.parse(search.substring(1));

      query.p = (pageNum + 1).toString();

      const queryString = _qs2.default.stringify(query);

      history.push({
        pathname: location.pathname,
        search: `?${queryString}`
      });
    }
  }

  handlePageSizeChange(pageSize) {
    var _props7 = this.props;
    const history = _props7.history,
          location = _props7.location,
          setPreferredPageSize = _props7.setPreferredPageSize;


    if (setPreferredPageSize) {
      setPreferredPageSize(pageSize);
    }

    if (history) {
      const search = location.search;


      const query = _qs2.default.parse(search.substring(1));

      query.p = '1';
      query.size = pageSize.toString();

      const queryString = _qs2.default.stringify(query);

      history.push({
        pathname: location.pathname,
        search: `?${queryString}`
      });
    }
  }

  handleRelateButtonClick() {
    this.setState({
      isSearchToRelateModalOpen: true
    });
  }

  handleRelationsCreated() {
    this.closeModal();
  }

  handleSortChange(sort) {
    var _props8 = this.props;
    const history = _props8.history,
          location = _props8.location;


    if (history) {
      const search = location.search;


      const query = _qs2.default.parse(search.substring(1));

      query.sort = sort;

      const queryString = _qs2.default.stringify(query);

      history.push({
        pathname: location.pathname,
        search: `?${queryString}`
      });
    }
  }

  search() {
    const search = this.props.search;
    const config = this.context.config;


    const searchDescriptor = this.getSearchDescriptor();
    const listType = this.getListType(searchDescriptor);

    if (search) {
      search(config, _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME, searchDescriptor, listType);
    }
  }

  renderCheckbox({ rowData, rowIndex }) {
    const selectedItems = this.props.selectedItems;


    if (this.shouldShowCheckbox(rowData)) {
      const itemCsid = rowData.get('csid');
      const selected = selectedItems ? selectedItems.has(itemCsid) : false;

      return _react2.default.createElement(_CheckboxInput2.default, {
        embedded: true,
        name: `${rowIndex}`,
        value: selected

        // DRYD-252: Elaborate workaround for Firefox, part II. Use this onClick instead of the
        // onCommit and onClick below.
        , onClick: this.handleCheckboxClick
        // onCommit={this.handleCheckboxCommit}
        // Prevent clicking on the checkbox from selecting the record.
        // onClick={stopPropagation}
      });
    }

    return null;
  }

  renderHeader({ searchError, searchResult }) {
    var _props9 = this.props;
    const selectedItems = _props9.selectedItems,
          setAllItemsSelected = _props9.setAllItemsSelected;
    const config = this.context.config;


    const searchDescriptor = this.getSearchDescriptor();
    const listType = this.getListType(searchDescriptor);

    let selectBar;

    if (!searchError && this.isResultRelatable(searchDescriptor)) {
      const selectedCount = selectedItems ? selectedItems.size : 0;

      const relateButton = _react2.default.createElement(_RelateButton2.default, {
        disabled: selectedCount < 1,
        key: 'relate',
        label: _react2.default.createElement(_reactIntl.FormattedMessage, messages.relate),
        name: 'relate',
        onClick: this.handleRelateButtonClick
      });

      selectBar = _react2.default.createElement(_SelectBar2.default, {
        buttons: [relateButton],
        config: config,
        listType: listType,
        searchDescriptor: searchDescriptor,
        searchName: _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME,
        searchResult: searchResult,
        selectedItems: selectedItems,
        setAllItemsSelected: setAllItemsSelected,
        showCheckboxFilter: this.shouldShowCheckbox
      });
    }

    return _react2.default.createElement(
      'header',
      null,
      _react2.default.createElement(_SearchResultSummary2.default, {
        config: config,
        listType: listType,
        searchDescriptor: searchDescriptor,
        searchError: searchError,
        searchResult: searchResult,
        onEditSearchLinkClick: this.handleEditSearchLinkClick,
        onPageSizeChange: this.handlePageSizeChange
      }),
      selectBar
    );
  }

  renderFooter({ searchResult }) {
    if (searchResult) {
      const config = this.context.config;


      const searchDescriptor = this.getSearchDescriptor();
      const listType = this.getListType(searchDescriptor);
      const listTypeConfig = config.listTypes[listType];
      const listNodeName = listTypeConfig.listNodeName;


      const list = searchResult.get(listNodeName);

      const totalItems = parseInt(list.get('totalItems'), 10);
      const pageNum = parseInt(list.get('pageNum'), 10);
      const pageSize = parseInt(list.get('pageSize'), 10);
      const lastPage = Math.max(0, isNaN(totalItems) ? 0 : Math.ceil(totalItems / pageSize) - 1);

      return _react2.default.createElement(
        'footer',
        null,
        _react2.default.createElement(_Pager2.default, {
          currentPage: pageNum,
          lastPage: lastPage,
          pageSize: pageSize,
          onPageChange: this.handlePageChange,
          onPageSizeChange: this.handlePageSizeChange
        })
      );
    }

    return null;
  }

  render() {
    const history = this.props.history;
    const config = this.context.config;
    const isSearchToRelateModalOpen = this.state.isSearchToRelateModalOpen;


    const searchDescriptor = this.getSearchDescriptor();
    const listType = this.getListType(searchDescriptor);

    const recordType = searchDescriptor.get('recordType');
    const vocabulary = searchDescriptor.get('vocabulary');
    const csid = searchDescriptor.get('csid');
    const subresource = searchDescriptor.get('subresource');

    const validation = (0, _configHelpers.validateLocation)(config, { recordType, vocabulary, csid, subresource });

    if (validation.error) {
      return _react2.default.createElement(_ErrorPage2.default, { error: validation.error });
    }

    const isResultRelatable = this.isResultRelatable(searchDescriptor);

    let searchToRelateModal;

    if (isResultRelatable) {
      searchToRelateModal = _react2.default.createElement(_SearchToRelateModalContainer2.default, {
        allowedServiceTypes: ['object', 'procedure'],
        subjects: this.getSearchToRelateSubjects,
        config: config,
        isOpen: isSearchToRelateModalOpen,
        defaultRecordTypeValue: 'collectionobject',
        onCancelButtonClick: this.handleModalCancelButtonClick,
        onCloseButtonClick: this.handleModalCloseButtonClick,
        onRelationsCreated: this.handleRelationsCreated
      });
    }

    return _react2.default.createElement(
      'div',
      { className: _SearchResultPage2.default.common },
      _react2.default.createElement(_SearchResultTitleBar2.default, {
        config: config,
        searchDescriptor: searchDescriptor,
        searchName: _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME,
        updateDocumentTitle: true
      }),
      _react2.default.createElement(
        'div',
        { className: _PageBody2.default.common },
        _react2.default.createElement(_SearchResultTableContainer2.default, {
          config: config,
          history: history,
          listType: listType,
          searchName: _searchNames.SEARCH_RESULT_PAGE_SEARCH_NAME,
          searchDescriptor: searchDescriptor,
          recordType: recordType,
          showCheckboxColumn: isResultRelatable,
          renderCheckbox: this.renderCheckbox,
          renderHeader: this.renderHeader,
          renderFooter: this.renderFooter,
          onSortChange: this.handleSortChange
        }),
        _react2.default.createElement('div', { className: _SearchResultSidebar2.default.common })
      ),
      searchToRelateModal
    );
  }
}

exports.default = SearchResultPage;
SearchResultPage.propTypes = propTypes;
SearchResultPage.contextTypes = contextTypes;