'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.disallowSoftDelete = exports.disallowDelete = exports.disallowCreate = exports.canAdmin = exports.canCreateNew = exports.canSoftDelete = exports.canUnrelate = exports.canRelate = exports.canList = exports.canDelete = exports.canUpdate = exports.canRead = exports.canCreate = exports.getPermissions = exports.mergeActionGroup = undefined;

var _immutable = require('immutable');

var _immutable2 = _interopRequireDefault(_immutable);

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

var _get2 = _interopRequireDefault(_get);

var _set = require('lodash/set');

var _set2 = _interopRequireDefault(_set);

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

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

const mergeActionGroup = exports.mergeActionGroup = (perms, path, actionGroup) => {
  const existingActionGroup = (0, _get2.default)(perms, path);

  let mergedActionGroup;

  if (existingActionGroup) {
    const existingActionCodes = new Set(existingActionGroup.split(''));
    const actionCodes = new Set(actionGroup.split(''));

    mergedActionGroup = ['C', 'R', 'U', 'D', 'L'].reduce((merged, actionCode) => existingActionCodes.has(actionCode) || actionCodes.has(actionCode) ? `${merged}${actionCode}` : merged, '');
  } else {
    mergedActionGroup = actionGroup;
  }

  (0, _set2.default)(perms, path, mergedActionGroup);

  return mergedActionGroup;
};

const getPermissions = exports.getPermissions = (config, accountPermsData) => {
  const perms = {};

  let accountPerms = (0, _get2.default)(accountPermsData, ['ns2:account_permission', 'permission']);

  if (accountPerms) {
    if (!Array.isArray(accountPerms)) {
      accountPerms = [accountPerms];
    }

    let canAdmin = false;
    let canCreateNew = false;

    accountPerms.forEach(permission => {
      const actionGroup = permission.actionGroup,
            resourceName = permission.resourceName;


      const resourceNameParts = resourceName.split('/');

      let servicePath;
      let transitionName;

      if (resourceNameParts.length === 1) {
        servicePath = resourceNameParts[0];
      } else if (resourceNameParts.length === 2) {
        servicePath = resourceName;
      } else if (resourceNameParts.length === 5 && resourceNameParts[3] === 'workflow') {
        servicePath = resourceNameParts[1];
        transitionName = resourceNameParts[4];
      }

      if (servicePath) {
        const recordTypeConfig = (0, _configHelpers.getRecordTypeConfigByServicePath)(config, servicePath);

        if (recordTypeConfig) {
          const name = recordTypeConfig.name;


          if (transitionName) {
            mergeActionGroup(perms, [name, 'transition', transitionName], actionGroup);
          } else {
            const mergedActionGroup = mergeActionGroup(perms, [name, 'data'], actionGroup);
            const serviceType = (0, _get2.default)(recordTypeConfig, ['serviceConfig', 'serviceType']);

            // Track if any object, authority, or procedure record can be created. This is used to
            // determine if the Create New navigation item should be shown.

            if (mergedActionGroup.indexOf('C') >= 0 && (serviceType === 'object' || serviceType === 'authority' || serviceType === 'procedure')) {
              canCreateNew = true;
            }

            // Track if any vocabulary or security record can be created or updated. This is used
            // to determine if the Admin navigation item should be shown.

            if (mergedActionGroup.indexOf('L') >= 0 && (serviceType === 'security' || name === 'vocabulary')) {
              canAdmin = true;
            }
          }
        }
      }
    });

    perms.canCreateNew = canCreateNew;
    perms.canAdmin = canAdmin;
  }

  return _immutable2.default.fromJS(perms);
};

const can = (recordType, permissions, actionCode) => {
  if (!permissions) {
    return false;
  }
  const actions = permissions.getIn([recordType, 'data']);

  return !!actions && actions.indexOf(actionCode) >= 0;
};

const canTransition = (recordType, permissions, transitionName) => {
  if (!permissions) {
    return false;
  }

  const actions = permissions.getIn([recordType, 'transition', transitionName]);

  // A transition from the UI is always an update (PUT).

  return !!actions && actions.indexOf('U') >= 0;
};

const canCreate = exports.canCreate = (recordType, permissions) => can(recordType, permissions, 'C');
const canRead = exports.canRead = (recordType, permissions) => can(recordType, permissions, 'R');
const canUpdate = exports.canUpdate = (recordType, permissions) => can(recordType, permissions, 'U');
const canDelete = exports.canDelete = (recordType, permissions) => can(recordType, permissions, 'D');
const canList = exports.canList = (recordType, permissions) => can(recordType, permissions, 'L');

// In order to create a relation, the UI requires that permissions of some level (by default,
// update) exist on the member records. (This is not enforced in the services layer.)
const canRelate = exports.canRelate = (recordType, permissions, config) => {
  if (!canCreate('relation', permissions)) {
    return false;
  }

  const relationMemberPerm = config && config.relationMemberPerm || 'U';

  return can(recordType, permissions, relationMemberPerm);
};

const canUnrelate = exports.canUnrelate = (recordType, permissions, config) => {
  if (!canDelete('relation', permissions)) {
    return false;
  }

  const relationMemberPerm = config && config.relationMemberPerm || 'U';

  return can(recordType, permissions, relationMemberPerm);
};

const canSoftDelete = exports.canSoftDelete = (recordType, permissions) => canTransition(recordType, permissions, 'delete');

const canCreateNew = exports.canCreateNew = permissions => permissions && !!permissions.get('canCreateNew');

const canAdmin = exports.canAdmin = permissions => permissions && !!permissions.get('canAdmin');

const disallow = (recordType, permissions, actionCode) => {
  if (can(recordType, permissions, actionCode)) {
    const dataPerms = permissions.getIn([recordType, 'data']);

    return permissions.setIn([recordType, 'data'], dataPerms.replace(actionCode, ''));
  }

  return permissions;
};

const disallowTransition = (recordType, permissions, transitionName) => {
  if (canTransition(recordType, permissions, transitionName)) {
    const transitionPerms = permissions.getIn([recordType, 'transition', transitionName]);

    return permissions.setIn([recordType, 'transition', transitionName], transitionPerms.replace('U', ''));
  }

  return permissions;
};

const disallowCreate = exports.disallowCreate = (recordType, permissions) => disallow(recordType, permissions, 'C');
const disallowDelete = exports.disallowDelete = (recordType, permissions) => disallow(recordType, permissions, 'D');

const disallowSoftDelete = exports.disallowSoftDelete = (recordType, permissions) => disallowTransition(recordType, permissions, 'delete');