"use strict";

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

var _react = _interopRequireWildcard(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 _cspaceRefname = require("cspace-refname");

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

var _cspaceLayout = require("cspace-layout");

var _HierarchySiblingListContainer = _interopRequireDefault(require("../../containers/record/HierarchySiblingListContainer"));

var _HierarchyReparentNotifierContainer = _interopRequireDefault(require("../../containers/record/HierarchyReparentNotifierContainer"));

var _UntypedHierarchyEditor = _interopRequireDefault(require("./UntypedHierarchyEditor"));

var _TypedHierarchyEditor = _interopRequireDefault(require("./TypedHierarchyEditor"));

var _relationListHelpers = require("../../helpers/relationListHelpers");

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

function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

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

const findParent = (csid, relations) => {
  const broaderRelation = (0, _relationListHelpers.findBroaderRelation)(csid, relations);

  if (broaderRelation) {
    return _immutable.default.Map({
      relCsid: broaderRelation.get('csid'),
      csid: broaderRelation.getIn(['object', 'csid']),
      refName: broaderRelation.getIn(['object', 'refName']),
      type: broaderRelation.get('relationshipMetaType')
    });
  }

  return null;
};

const findChildren = (csid, relations) => (0, _relationListHelpers.findNarrowerRelations)(csid, relations).sort((relationA, relationB) => {
  const displayNameA = (0, _cspaceRefname.getDisplayName)(relationA.getIn(['subject', 'refName'])) || '';
  const displayNameB = (0, _cspaceRefname.getDisplayName)(relationB.getIn(['subject', 'refName'])) || '';

  if (displayNameA && displayNameB) {
    return displayNameA.localeCompare(displayNameB);
  }

  if (!displayNameA && !displayNameB) {
    return 0;
  }

  if (displayNameA) {
    return -1;
  }

  return 1;
}).map(relation => _immutable.default.Map({
  relCsid: relation.get('csid'),
  refName: relation.getIn(['subject', 'refName']),
  type: relation.get('relationshipMetaType')
}));

function createHierarchy(csid, value) {
  const relations = (0, _relationListHelpers.normalizeRelationList)(value);
  return _immutable.default.fromJS({
    parent: findParent(csid, relations) || _immutable.default.Map(),
    children: findChildren(csid, relations)
  });
}

const propTypes = {
  csid: _propTypes.default.string,
  messages: _propTypes.default.shape({
    siblings: _propTypes.default.object
  }),

  /* eslint-disable react/no-unused-prop-types */
  name: _propTypes.default.string,
  parentPath: pathPropType,
  subpath: pathPropType,
  readOnly: _propTypes.default.bool,

  /* eslint-enable react/no-unused-prop-types */
  isRecordModified: _propTypes.default.bool,
  showParent: _propTypes.default.bool,
  showChildren: _propTypes.default.bool,
  showSiblings: _propTypes.default.bool,
  value: _propTypes.default.oneOfType([_propTypes.default.instanceOf(_immutable.default.List), _propTypes.default.instanceOf(_immutable.default.Map), _propTypes.default.array, _propTypes.default.object]),
  parentTypeOptionListName: _propTypes.default.string,
  childTypeOptionListName: _propTypes.default.string,
  onCommit: _propTypes.default.func
};
const defaultProps = {
  showParent: true,
  showChildren: true,
  showSiblings: true
};
const contextTypes = {
  config: _propTypes.default.shape({
    recordTypes: _propTypes.default.object
  }),
  recordType: _propTypes.default.string,
  vocabulary: _propTypes.default.string
};

class HierarchyInput extends _react.Component {
  constructor(props) {
    super(props);
    const {
      csid,
      value
    } = props;
    this.state = {
      csid,
      value,
      hierarchy: createHierarchy(csid, value)
    };
    this.handleAddChild = this.handleAddChild.bind(this);
    this.handleRemoveChild = this.handleRemoveChild.bind(this);
    this.handleCommit = this.handleCommit.bind(this);
  }

  static getDerivedStateFromProps(props, state) {
    const {
      csid,
      value
    } = props;
    const {
      csid: oldCsid,
      value: oldValue
    } = state;

    if (oldCsid !== csid || oldValue !== value) {
      return {
        csid,
        value,
        hierarchy: createHierarchy(csid, value)
      };
    }

    return null;
  }

  getRelationItems(hierarchy) {
    const {
      csid
    } = this.props;
    const children = hierarchy.get('children');
    const childRelationItems = children.map(child => _immutable.default.fromJS({
      csid: child.get('relCsid'),
      predicate: 'hasBroader',
      relationshipMetaType: child.get('type'),
      subject: {
        refName: child.get('refName')
      },
      object: {
        csid: csid || _relationListHelpers.placeholderCsid
      }
    }));
    const parent = hierarchy.get('parent');

    const parentRelationItem = _immutable.default.fromJS({
      csid: parent.get('relCsid'),
      predicate: 'hasBroader',
      relationshipMetaType: parent.get('type'),
      subject: {
        csid: csid || _relationListHelpers.placeholderCsid
      },
      object: {
        csid: parent.get('csid'),
        refName: parent.get('refName')
      }
    });

    return childRelationItems.push(parentRelationItem);
  }

  handleAddChild() {
    const {
      onCommit
    } = this.props;

    if (onCommit) {
      const {
        hierarchy
      } = this.state;
      let children = hierarchy.get('children');

      if (children.size === 0) {
        // The UI renders a single blank input event if there are no children, so adding a child
        // should result in two children, not one.
        children = children.push(_immutable.default.Map());
      }

      const updatedHierarchy = hierarchy.set('children', children.push(_immutable.default.Map()));
      onCommit(getPath(this.props), this.getRelationItems(updatedHierarchy));
    }
  }

  handleRemoveChild(position) {
    const {
      onCommit
    } = this.props;

    if (onCommit) {
      const {
        hierarchy
      } = this.state;
      const children = hierarchy.get('children');
      const updatedHierarchy = hierarchy.set('children', children.delete(position));
      onCommit(getPath(this.props), this.getRelationItems(updatedHierarchy));
    }
  }

  handleCommit(path, value) {
    const {
      onCommit
    } = this.props;

    if (onCommit) {
      const {
        hierarchy
      } = this.state;
      const updatedHierarchy = hierarchy.setIn(path, value);
      onCommit(getPath(this.props), this.getRelationItems(updatedHierarchy));
    }
  }

  renderHierarchy() {
    const {
      csid,
      messages,
      parentTypeOptionListName,
      childTypeOptionListName,
      isRecordModified,
      readOnly,
      showParent,
      showChildren
    } = this.props;

    if (!showParent && !showChildren) {
      return undefined;
    }

    const {
      config,
      recordType,
      vocabulary
    } = this.context;
    const {
      hierarchy
    } = this.state;
    const serviceType = (0, _get.default)(config, ['recordTypes', recordType, 'serviceConfig', 'serviceType']);
    const HierarchyEditor = serviceType === 'object' ? _TypedHierarchyEditor.default : _UntypedHierarchyEditor.default;
    return /*#__PURE__*/_react.default.createElement(HierarchyEditor, {
      csid: csid,
      messages: messages,
      parentTypeOptionListName: parentTypeOptionListName,
      childTypeOptionListName: childTypeOptionListName,
      recordType: recordType,
      vocabulary: vocabulary,
      value: hierarchy,
      readOnly: readOnly,
      isRecordModified: isRecordModified,
      showParent: showParent,
      showChildren: showChildren,
      onCommit: this.handleCommit,
      onAddChild: this.handleAddChild,
      onRemoveChild: this.handleRemoveChild
    });
  }

  renderReparentNotifier() {
    const {
      csid
    } = this.props;
    const {
      hierarchy
    } = this.state;
    const {
      config
    } = this.context;
    const newChildRefNames = hierarchy.get('children').filter(child => !child.get('relCsid')).map(child => child.get('refName'));
    return /*#__PURE__*/_react.default.createElement(_HierarchyReparentNotifierContainer.default, {
      config: config,
      csid: csid,
      childRefNames: newChildRefNames
    });
  }

  renderSiblings() {
    const {
      csid,
      messages,
      showSiblings
    } = this.props;

    if (!showSiblings) {
      return undefined;
    }

    const {
      config,
      recordType
    } = this.context;
    const {
      hierarchy
    } = this.state;
    return /*#__PURE__*/_react.default.createElement(_HierarchySiblingListContainer.default, {
      config: config,
      csid: csid,
      parentCsid: hierarchy.getIn(['parent', 'csid']),
      recordType: recordType,
      title: /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, messages.siblings)
    });
  }

  render() {
    return /*#__PURE__*/_react.default.createElement(_cspaceLayout.Row, null, this.renderHierarchy(), this.renderSiblings(), this.renderReparentNotifier());
  }

}

exports.default = HierarchyInput;
HierarchyInput.propTypes = propTypes;
HierarchyInput.defaultProps = defaultProps;
HierarchyInput.contextTypes = contextTypes;