'use strict';

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

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

exports.default = Field;

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

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

var _propTypes2 = _interopRequireDefault(_propTypes);

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

var _immutable = require('immutable');

var _immutable2 = _interopRequireDefault(_immutable);

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

var _get2 = _interopRequireDefault(_get);

var _warning = require('warning');

var _warning2 = _interopRequireDefault(_warning);

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

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

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 Label = _cspaceInput.components.Label;


const defaultViewConfigKey = 'view';

const renderLabel = (fieldDescriptor, providedLabelMessage, recordData, props) => {
  const fieldConfig = fieldDescriptor[_configHelpers.configKey];
  const message = providedLabelMessage || (0, _get2.default)(fieldConfig, ['messages', 'name']);

  if (!message) {
    return null;
  }

  const configuredProps = {};

  if ('required' in fieldConfig) {
    configuredProps.required = (0, _configHelpers.isFieldRequired)(fieldDescriptor, recordData);
  }

  if ('readOnly' in fieldConfig) {
    configuredProps.readOnly = fieldConfig.readOnly;
  }

  return _react2.default.createElement(
    Label,
    _extends({}, props, configuredProps),
    _react2.default.createElement(_reactIntl.FormattedMessage, message)
  );
};

const propTypes = {
  labelMessage: _propTypes2.default.object,
  viewType: _propTypes2.default.string,

  // Code in this component doesn't use these props, but the propTypes need to exist, because
  // users of this component may check for them to determine if those props should be passed.
  // We want to receive all the props that our base components may need, and then we'll handle
  // distributing them to the base components that accept them.

  /* eslint-disable react/no-unused-prop-types */
  name: _propTypes2.default.string,
  // The value prop will be validated by the base component, so allow anything here.
  value: _propTypes2.default.any,
  parentPath: _propTypes2.default.array,
  subpath: pathPropType,
  tabular: _propTypes2.default.bool,
  label: _propTypes2.default.node,
  readOnly: _propTypes2.default.bool,
  onAddInstance: _propTypes2.default.func,
  onCommit: _propTypes2.default.func,
  onMoveInstance: _propTypes2.default.func,
  onRemoveInstance: _propTypes2.default.func,
  onSortInstances: _propTypes2.default.func
  /* eslint-enable react/no-unused-prop-types */
};

const contextTypes = {
  config: _propTypes2.default.object,
  intl: _reactIntl.intlShape,
  recordData: _propTypes2.default.instanceOf(_immutable2.default.Map),
  recordType: _propTypes2.default.string
};

function Field(props, context) {
  const config = context.config,
        intl = context.intl,
        recordData = context.recordData,
        recordType = context.recordType;
  const labelMessage = props.labelMessage,
        viewType = props.viewType;


  const fullPath = getPath(props);

  // Filter out numeric parts of the path, since they indicate repeating instances that won't be
  // present in the field descriptor.

  const path = (0, _configHelpers.dataPathToFieldDescriptorPath)(fullPath);
  const fields = (0, _get2.default)(config, ['recordTypes', recordType, 'fields']);

  process.env.NODE_ENV !== 'production' ? (0, _warning2.default)(fields, `No field descriptor found for the record type ${recordType}. The field with path ${path} will not be rendered.`) : void 0;

  if (!fields) {
    return null;
  }

  const field = (0, _get2.default)(fields, path);

  process.env.NODE_ENV !== 'production' ? (0, _warning2.default)(field, `The path ${path} is not present in the field descriptors for the record type ${recordType}. The field will not be rendered.`) : void 0;

  if (!field) {
    return null;
  }

  const fieldConfig = field[_configHelpers.configKey];
  const viewConfigKey = viewType === 'search' ? 'searchView' : defaultViewConfigKey;
  const viewConfig = fieldConfig[viewConfigKey] || fieldConfig[defaultViewConfigKey];
  const BaseComponent = viewConfig.type;
  const configuredProps = viewConfig.props || {};
  const providedProps = {};

  const basePropTypes = BaseComponent.propTypes;

  Object.keys(props).forEach(propName => {
    if (propName in basePropTypes) {
      providedProps[propName] = props[propName];
    }
  });

  const effectiveReadOnly = providedProps.readOnly || configuredProps.readOnly;
  const computedProps = {};

  if (fieldConfig.repeating && viewType !== 'search') {
    computedProps.repeating = fieldConfig.repeating;
  }

  if ('label' in basePropTypes) {
    computedProps.label = renderLabel(field, labelMessage, recordData, {
      readOnly: effectiveReadOnly
    });
  }

  if ('formatValue' in basePropTypes) {
    const valueMessage = (0, _get2.default)(fieldConfig, ['messages', 'value']);

    if (valueMessage) {
      computedProps.formatValue = value => intl.formatMessage(valueMessage, { value });
    }
  }

  if ('renderChildInputLabel' in basePropTypes) {
    computedProps.renderChildInputLabel = childInput => {
      const childName = childInput.props.name;
      const childLabelMessage = childInput.props.labelMessage;
      const childField = field[childName];

      return childField && renderLabel(childField, childLabelMessage, recordData, {
        key: childName,
        readOnly: effectiveReadOnly
      });
    };
  }

  if ('viewType' in basePropTypes) {
    computedProps.viewType = viewType;
  }

  const effectiveProps = Object.assign({}, computedProps, configuredProps, providedProps, {
    readOnly: effectiveReadOnly
  });

  return _react2.default.createElement(BaseComponent, effectiveProps);
}

Field.contextTypes = contextTypes;
Field.propTypes = propTypes;