'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 _immutable = require('immutable');

var _immutable2 = _interopRequireDefault(_immutable);

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

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

var _get2 = _interopRequireDefault(_get);

var _cspaceInput = require('cspace-input');

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

var _PermissionButton = require('../../../styles/cspace-ui/PermissionButton.css');

var _PermissionButton2 = _interopRequireDefault(_PermissionButton);

var _PermissionsInput = require('../../../styles/cspace-ui/PermissionsInput.css');

var _PermissionsInput2 = _interopRequireDefault(_PermissionsInput);

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

var _inputHelpers$pathHel = _cspaceInput.helpers.pathHelpers;
const getPath = _inputHelpers$pathHel.getPath,
      pathPropType = _inputHelpers$pathHel.pathPropType;


const permMessages = (0, _reactIntl.defineMessages)({
  '': {
    'id': 'permissionsInput.perm.none',
    'defaultMessage': 'None'
  },
  RL: {
    'id': 'permissionsInput.perm.read',
    'defaultMessage': 'Read'
  },
  CRUL: {
    'id': 'permissionsInput.perm.write',
    'defaultMessage': 'Write'
  },
  CRUDL: {
    'id': 'permissionsInput.perm.delete',
    'defaultMessage': 'Delete'
  }
});

const serviceTypeMessages = (0, _reactIntl.defineMessages)({
  object: {
    'id': 'permissionsInput.serviceType.object',
    'defaultMessage': 'Objects'
  },
  procedure: {
    'id': 'permissionsInput.serviceType.procedure',
    'defaultMessage': 'Procedures'
  },
  authority: {
    'id': 'permissionsInput.serviceType.authority',
    'defaultMessage': 'Authorities'
  },
  utility: {
    'id': 'permissionsInput.serviceType.utility',
    'defaultMessage': 'Utility Resources'
  },
  security: {
    'id': 'permissionsInput.serviceType.security',
    'defaultMessage': 'Security Resources'
  }
});

const serviceTypes = ['object', 'procedure', 'authority', 'utility', 'security'];

const propTypes = {
  /* eslint-disable react/no-unused-prop-types */
  name: _propTypes2.default.string,
  parentPath: pathPropType,
  subpath: pathPropType,
  /* eslint-enable react/no-unused-prop-types */
  readOnly: _propTypes2.default.bool,
  resourceNames: _propTypes2.default.instanceOf(_immutable2.default.List),
  value: _propTypes2.default.oneOfType([_propTypes2.default.instanceOf(_immutable2.default.List), _propTypes2.default.instanceOf(_immutable2.default.Map)]),
  readPerms: _propTypes2.default.func,
  onCommit: _propTypes2.default.func
};

const contextTypes = {
  intl: _reactIntl.intlShape,
  config: _propTypes2.default.object
};

class PermissionsInput extends _react.Component {
  constructor(props, context) {
    super(props, context);

    this.handleRadioChange = this.handleRadioChange.bind(this);
  }

  componentDidMount() {
    var _props = this.props;
    const resourceNames = _props.resourceNames,
          readPerms = _props.readPerms;
    const config = this.context.config;


    if (!resourceNames && readPerms) {
      readPerms(config);
    }
  }

  getPermsMap() {
    // The services layer gives us a list of resources and action groups. Build a map of resource
    // names to UI permissions.

    let permissionsList = this.props.value;

    if (!permissionsList) {
      return undefined;
    }

    if (!_immutable2.default.List.isList(permissionsList)) {
      permissionsList = _immutable2.default.List.of(permissionsList);
    }

    const perms = {};

    permissionsList.forEach(permission => {
      const resourceName = permission.get('resourceName');
      const actionGroup = permission.get('actionGroup');

      perms[resourceName] = actionGroup;
    });

    return perms;
  }

  updatePerms(updates) {
    const perms = this.getPermsMap() || {};

    Object.assign(perms, updates);

    return _immutable2.default.List(Object.keys(perms).filter(resourceName => !!perms[resourceName]).map(resourceName => _immutable2.default.Map({
      resourceName,
      actionGroup: perms[resourceName]
    })));
  }

  handleRadioChange(event) {
    var _event$target = event.target;
    const recordType = _event$target.name,
          actionGroup = _event$target.value,
          selected = _event$target.checked;
    const onCommit = this.props.onCommit;


    if (selected && onCommit) {
      const config = this.context.config;


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

      const documentName = serviceConfig.documentName,
            servicePath = serviceConfig.servicePath,
            serviceType = serviceConfig.serviceType;


      const resourceName = servicePath;

      const update = {
        [resourceName]: actionGroup
      };

      if (serviceType === 'object' || serviceType === 'procedure' || serviceType === 'authority' || serviceType === 'utility') {
        // For object, procedure, authority, and utility types, also set permissions on the delete
        // workflow transition. (Security records do not have soft-delete).

        const workflowDeleteResourceName = `/${resourceName}/*/workflow/delete`;

        if (actionGroup) {
          update[workflowDeleteResourceName] = actionGroup.includes('D') ? 'CRUDL' : 'RL';
        } else {
          update[workflowDeleteResourceName] = '';
        }
      }

      if (serviceType === 'authority') {
        // Permissions on authorities should be set on both the authorities and their items.

        const itemResourceName = documentName;

        update[itemResourceName] = actionGroup;
      }

      const updatedPerms = this.updatePerms(update);

      onCommit(getPath(this.props), updatedPerms);
    }
  }

  renderRadioButton(perms, recordType, resourceName, value) {
    const readOnly = this.props.readOnly;


    const className = readOnly ? _PermissionButton2.default.readOnly : _PermissionButton2.default.normal;

    let checked = false;

    if (perms) {
      checked = value ? perms[resourceName] === value : !perms[resourceName];
    }

    return (
      // FIXME: Do I really need for if I'm wrapping the input in the label?
      // eslint-disable-next-line jsx-a11y/label-has-for
      _react2.default.createElement(
        'label',
        { className: className },
        _react2.default.createElement(_reactIntl.FormattedMessage, permMessages[value]),
        _react2.default.createElement('input', {
          checked: checked,
          name: recordType,
          type: 'radio',
          value: value,
          disabled: readOnly,
          onChange: this.handleRadioChange
        }),
        _react2.default.createElement('div', null)
      )
    );
  }

  renderPermRows() {
    var _context = this.context;
    const config = _context.config,
          intl = _context.intl;
    const resourceNames = this.props.resourceNames;


    const perms = this.getPermsMap() || {};

    const recordTypeConfigs = resourceNames.map(resourceName => (0, _configHelpers.getRecordTypeConfigByServicePath)(config, resourceName)).filter(recordTypeConfig => recordTypeConfig && !recordTypeConfig.disabled);

    const sections = [];

    serviceTypes.forEach(serviceType => {
      const rows = [];

      recordTypeConfigs.filter(recordTypeConfig => recordTypeConfig.serviceConfig.serviceType === serviceType).sort((recordTypeConfigA, recordTypeConfigB) => {
        // Primary sort by sortOrder

        let sortOrderA = recordTypeConfigA.sortOrder;
        let sortOrderB = recordTypeConfigB.sortOrder;

        if (typeof sortOrderA !== 'number') {
          sortOrderA = Number.MAX_VALUE;
        }

        if (typeof sortOrderB !== 'number') {
          sortOrderB = Number.MAX_VALUE;
        }

        if (sortOrderA !== sortOrderB) {
          return sortOrderA > sortOrderB ? 1 : -1;
        }

        // Secondary sort by label

        const labelA = intl.formatMessage(recordTypeConfigA.messages.record.collectionName);
        const labelB = intl.formatMessage(recordTypeConfigB.messages.record.collectionName);

        // FIXME: This should be locale aware
        return labelA.localeCompare(labelB);
      }).forEach(recordTypeConfig => {
        const name = recordTypeConfig.name;
        const resourceName = recordTypeConfig.serviceConfig.servicePath;
        const nameMessage = (0, _get2.default)(recordTypeConfig, ['messages', 'record', 'collectionName']);

        const formattedName = nameMessage ? intl.formatMessage(nameMessage) : `[ ${name} ]`;

        rows.push(_react2.default.createElement(
          'div',
          { key: name },
          _react2.default.createElement(
            'div',
            null,
            formattedName
          ),
          _react2.default.createElement(
            'div',
            null,
            this.renderRadioButton(perms, name, resourceName, ''),
            this.renderRadioButton(perms, name, resourceName, 'RL'),
            this.renderRadioButton(perms, name, resourceName, 'CRUL'),
            this.renderRadioButton(perms, name, resourceName, 'CRUDL')
          )
        ));
      });

      sections.push(_react2.default.createElement(
        'section',
        { key: serviceType },
        _react2.default.createElement(
          'header',
          null,
          _react2.default.createElement(
            'h3',
            null,
            _react2.default.createElement(_reactIntl.FormattedMessage, serviceTypeMessages[serviceType])
          ),
          _react2.default.createElement(
            'ul',
            null,
            _react2.default.createElement(
              'li',
              null,
              _react2.default.createElement(_reactIntl.FormattedMessage, permMessages[''])
            ),
            _react2.default.createElement(
              'li',
              null,
              _react2.default.createElement(_reactIntl.FormattedMessage, permMessages.RL)
            ),
            _react2.default.createElement(
              'li',
              null,
              _react2.default.createElement(_reactIntl.FormattedMessage, permMessages.CRUL)
            ),
            _react2.default.createElement(
              'li',
              null,
              _react2.default.createElement(_reactIntl.FormattedMessage, permMessages.CRUDL)
            )
          )
        ),
        rows
      ));
    });

    return sections;
  }

  render() {
    var _props2 = this.props;
    const readOnly = _props2.readOnly,
          resourceNames = _props2.resourceNames;


    if (!resourceNames) {
      return null;
    }

    let value = this.props.value;


    if (value && !_immutable2.default.List.isList(value)) {
      value = _immutable2.default.List.of(value);
    }

    const className = readOnly ? _PermissionsInput2.default.readOnly : _PermissionsInput2.default.common;

    return _react2.default.createElement(
      'div',
      { className: className },
      this.renderPermRows()
    );
  }
}

exports.default = PermissionsInput;
PermissionsInput.propTypes = propTypes;
PermissionsInput.contextTypes = contextTypes;