text: 'use strict';
  
  var React = require('react');
  
  var simpleGet = key => data => data[key];
  var keyGetter = keys => data => keys.map(key => data[key]);
  
  var isEmpty = value => value === undefined || value === null || value === '';
  
  var getCellValue =
    ({ prop, defaultContent, render }, row) =>
      // Return `defaultContent` if the value is empty.
      !isEmpty(prop) && isEmpty(row[prop]) ? defaultContent :
        // Use the render function for the value.
        render ? render(row[prop], row) :
        // Otherwise just return the value.
        row[prop];
  
  var getCellClass =
    ({ prop, className }, row) =>
      !isEmpty(prop) && isEmpty(row[prop]) ? 'empty-cell' :
        typeof className === 'function' ? className(row[prop], row) :
        className;
  
  function buildSortProps(col, sortBy, onSort) {
    var order, nextOrder, sortEvent;
    if(!col.hasOwnProperty('sort') && !col.sort) {
      order = sortBy.prop === col.prop ? sortBy.order : 'none';
      nextOrder = order === 'ascending' ? 'descending' : 'ascending';
      sortEvent = onSort.bind(null, { prop: col.prop, order: nextOrder }, col.type);
    } else {
      order = '';
      nextOrder = '';
    }
  
    return {
      'onClick': sortEvent ? sortEvent : null,
      // Fire the sort event on enter.
      'onKeyDown': e => { if (e.keyCode === 13) sortEvent(); },
      // Prevents selection with mouse.
      'onMouseDown': e => e.preventDefault(),
      'tabIndex': 0,
      'aria-sort': order,
      'aria-label': `${col.title}: activate to sort column ${nextOrder}`
    };
  }
  
  var Table = React.createClass({
  
    propTypes: {
      keys: React.PropTypes.oneOfType([
        React.PropTypes.arrayOf(React.PropTypes.string),
        React.PropTypes.string
      ]).isRequired,
      columns: React.PropTypes.arrayOf(React.PropTypes.shape({
        title: React.PropTypes.string.isRequired,
        prop: React.PropTypes.oneOfType([
          React.PropTypes.string,
          React.PropTypes.number
        ]),
        render: React.PropTypes.func,
        sortable: React.PropTypes.bool,
        defaultContent: React.PropTypes.string,
        width: React.PropTypes.oneOfType([
          React.PropTypes.string,
          React.PropTypes.number
        ]),
        className: React.PropTypes.oneOfType([
          React.PropTypes.string,
          React.PropTypes.func
        ])
      })).isRequired,
      dataArray: React.PropTypes.arrayOf(React.PropTypes.oneOfType([
        React.PropTypes.array,
        React.PropTypes.object
      ])).isRequired,
      buildRowOpts: React.PropTypes.func,
      sortBy: React.PropTypes.shape({
        prop: React.PropTypes.oneOfType([
          React.PropTypes.string,
          React.PropTypes.number
        ]),
        order: React.PropTypes.oneOf([ 'ascending', 'descending' ])
      }),
      onSort: React.PropTypes.func
    },
  
    getDefaultProps() {
      return {
        buildRowOpts: () => ({}),
        sortBy: {}
      };
    },
  
    componentDidMount() {
      // If no width was specified, then set the width that the browser applied
      // initially to avoid recalculating width between pages.
      for (var i = 0; i < this.props.columns.length; i++) {
        var thDom = this.refs[`th-${i}`].getDOMNode();
        if (!thDom.style.width) {
          thDom.style.width = `${thDom.offsetWidth}px`;
        }
      }
    },
  
    render() {
      var { columns, keys, buildRowOpts, sortBy, onSort } = this.props;
  
      var headers = columns.map((col, idx) => {
        var sortProps, order;
        // Only add sorting events if the column has a property and is sortable.
        if (col.sortable !== false && 'prop' in col) {
          sortProps = buildSortProps(col, sortBy, onSort);
          order = sortProps['aria-sort'];
        }
  
        return (
          <th
            ref={`th-${idx}`}
            key={idx}
            style={{width: col.width}}
            role="columnheader"
            scope="col"
            {...sortProps}>
            <span>{col.title}</span>
            {typeof order !== 'undefined' ?
              <span className={`sort-icon sort-${order}`} aria-hidden="true" /> :
              null}
          </th>
        );
      });
  
      var getKeys = Array.isArray(keys) ? keyGetter(keys) : simpleGet(keys);
      var rows = this.props.dataArray.map(
        row =>
          <tr key={getKeys(row)} {...buildRowOpts(row)}>
            {columns.map(
              (col, i) =>
                <td key={i} className={getCellClass(col, row)}>
                  {getCellValue(col, row)}
                </td>
            )}
          </tr>);
  
      return (
        <div className="data-table-container">
          <table className={this.props.className}>
            <caption className="sr-only" role="alert" aria-live="polite">
              {`Sorted by ${sortBy.prop}: ${sortBy.order} order`}
            </caption>
            <thead>
              <tr>
                {headers}
              </tr>
            </thead>
            <tbody>
              {rows.length > 0 ? rows :
                <tr>
                  <td colSpan={columns.length} className="text-center">No data</td>
                </tr>}
            </tbody>
          </table>
        </div>
      );
    }
  
  });
  
  module.exports = Table;
  