"use strict";

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

var _react = _interopRequireDefault(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

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

var _immutable = _interopRequireDefault(require("immutable"));

var _get = _interopRequireDefault(require("lodash/get"));

var _warning = _interopRequireDefault(require("warning"));

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

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

var _configContextInputs = require("../../helpers/configContextInputs");

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

function _extends() { _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; }; return _extends.apply(this, arguments); }

const {
  getPath,
  pathPropType
} = _cspaceInput.helpers.pathHelpers;
const {
  Label
} = _cspaceInput.components;

const renderLabel = (fieldDescriptor, providedLabelMessage, recordData, props) => {
  const fieldConfig = fieldDescriptor[_configHelpers.configKey];
  const message = providedLabelMessage || (0, _get.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 _react.default.createElement(Label, _extends({}, props, configuredProps), _react.default.createElement(_reactIntl.FormattedMessage, message));
};

const propTypes = {
  labelMessage: _propTypes.default.object,
  viewType: _propTypes.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: _propTypes.default.string,
  // The value prop will be validated by the base component, so allow anything here.
  value: _propTypes.default.any,
  parentPath: _propTypes.default.array,
  subpath: pathPropType,
  tabular: _propTypes.default.bool,
  label: _propTypes.default.node,
  readOnly: _propTypes.default.bool,
  onAddInstance: _propTypes.default.func,
  onCommit: _propTypes.default.func,
  onMoveInstance: _propTypes.default.func,
  onRemoveInstance: _propTypes.default.func,
  onSortInstances: _propTypes.default.func
  /* eslint-enable react/no-unused-prop-types */

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

function Field(props, context) {
  const {
    config,
    intl,
    recordData,
    recordType
  } = context;
  const {
    labelMessage,
    viewType
  } = props;
  const recordTypeConfig = context.recordTypeConfig || (0, _get.default)(config, ['recordTypes', recordType]);
  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, _get.default)(recordTypeConfig, 'fields');
  process.env.NODE_ENV !== "production" ? (0, _warning.default)(fields, "No field descriptor found for the record type ".concat(recordType, ". The field with path ").concat(path, " will not be rendered.")) : void 0;

  if (!fields) {
    return null;
  }

  const field = (0, _get.default)(fields, path);
  process.env.NODE_ENV !== "production" ? (0, _warning.default)(field, "The path ".concat(path, " is not present in the field descriptors for the record type ").concat(recordType, ". The field will not be rendered.")) : void 0;

  if (!field) {
    return null;
  }

  const fieldConfig = field[_configHelpers.configKey];
  const isSearch = viewType === 'search';
  const viewConfig = isSearch ? fieldConfig.searchView || fieldConfig.view : fieldConfig.view;
  let BaseComponent = viewConfig.type;

  if (isSearch && !fieldConfig.searchView && BaseComponent === _configContextInputs.StructuredDateInput) {
    // If a search view was not explicitly configured, and the view is a StructuredDateInput,
    // automatically make the search view a DateInput.
    BaseComponent = _configContextInputs.DateInput;
  }

  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, _get.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 _react.default.createElement(BaseComponent, effectiveProps);
}

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