'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.isModified = exports.isSavePending = exports.isReadPending = exports.getNewData = exports.getData = undefined;

var _immutable = require('immutable');

var _immutable2 = _interopRequireDefault(_immutable);

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

var _get2 = _interopRequireDefault(_get);

var _recordDataHelpers = require('../helpers/recordDataHelpers');

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

var _record = require('../actions/record');

var _idGenerator = require('../actions/idGenerator');

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

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

var newRecordCsid = '';

var getCurrentData = function getCurrentData(state, csid) {
  return state.getIn([csid, 'data', 'current']);
};
var setCurrentData = function setCurrentData(state, csid, data) {
  return state.setIn([csid, 'data', 'current'], data);
};

var getBaselineData = function getBaselineData(state, csid) {
  return state.getIn([csid, 'data', 'baseline']);
};
var setBaselineData = function setBaselineData(state, csid, data) {
  return state.setIn([csid, 'data', 'baseline'], data);
};

var addFieldInstance = function addFieldInstance(state, action) {
  var _action$meta = action.meta,
      csid = _action$meta.csid,
      path = _action$meta.path,
      recordTypeConfig = _action$meta.recordTypeConfig;


  var data = getCurrentData(state, csid);

  if (!data) {
    return state;
  }

  var value = (0, _recordDataHelpers.deepGet)(data, path);
  var list = _immutable2.default.List.isList(value) ? value : _immutable2.default.List.of(value);

  var fieldDescriptor = (0, _get2.default)(recordTypeConfig, ['fields'].concat(_toConsumableArray((0, _configHelpers.dataPathToFieldDescriptorPath)(path))));
  var defaultData = (0, _recordDataHelpers.applyDefaults)(fieldDescriptor);

  var updatedData = (0, _recordDataHelpers.deepSet)(data, path, list.push(defaultData));

  return setCurrentData(state, csid, updatedData);
};

var createNewRecord = function createNewRecord(state, action) {
  var _action$meta2 = action.meta,
      recordTypeConfig = _action$meta2.recordTypeConfig,
      cloneCsid = _action$meta2.cloneCsid;

  // This code assumes that only one new record of any type may be in the process of being
  // edited at any time. The new record's data is stored alongside existing record data, at
  // key ''.

  var data = void 0;

  if (cloneCsid) {
    data = (0, _recordDataHelpers.cloneRecordData)(recordTypeConfig, getCurrentData(state, cloneCsid));
  }

  if (!data) {
    data = (0, _recordDataHelpers.createRecordData)(recordTypeConfig);
  }

  var updatedState = state;

  updatedState = setBaselineData(updatedState, newRecordCsid, data);
  updatedState = setCurrentData(updatedState, newRecordCsid, data);

  return updatedState;
};

var deleteFieldValue = function deleteFieldValue(state, action) {
  var _action$meta3 = action.meta,
      csid = _action$meta3.csid,
      path = _action$meta3.path;


  var data = getCurrentData(state, csid);

  if (!data) {
    return state;
  }

  var updatedData = (0, _recordDataHelpers.deepDelete)(data, path);

  return setCurrentData(state, csid, updatedData);
};

var moveFieldValue = function moveFieldValue(state, action) {
  var _action$meta4 = action.meta,
      csid = _action$meta4.csid,
      path = _action$meta4.path,
      newPosition = _action$meta4.newPosition;


  var data = getCurrentData(state, csid);

  if (!data) {
    return state;
  }

  var listPath = path.slice(0, -1);
  var oldPosition = path[path.length - 1];

  var list = (0, _recordDataHelpers.deepGet)(data, listPath);

  if (!_immutable2.default.List.isList(list)) {
    return state;
  }

  var value = list.get(oldPosition);

  list = list.delete(oldPosition);
  list = list.insert(newPosition, value);

  var updatedData = (0, _recordDataHelpers.deepSet)(data, listPath, list);

  return setCurrentData(state, csid, updatedData);
};

var setFieldValue = function setFieldValue(state, action) {
  var _action$meta5 = action.meta,
      csid = _action$meta5.csid,
      path = _action$meta5.path;


  var data = getCurrentData(state, csid);

  if (!data) {
    return state;
  }

  var newValue = action.payload;
  var updatedData = (0, _recordDataHelpers.deepSet)(data, path, newValue);

  return setCurrentData(state, csid, updatedData);
};

var handleRecordReadFulfilled = function handleRecordReadFulfilled(state, action) {
  var data = _immutable2.default.fromJS(action.payload.data);
  var csid = action.meta.csid;

  var updatedState = state.deleteIn([csid, 'isReadPending']);

  updatedState = setBaselineData(updatedState, csid, data);
  updatedState = setCurrentData(updatedState, csid, data);

  return updatedState;
};

var handleRecordSaveFulfilled = function handleRecordSaveFulfilled(state, action) {
  var response = action.payload;
  var csid = action.meta.csid;

  var updatedState = state.deleteIn([csid, 'isSavePending']);

  if (response.status === 201 && response.headers.location) {
    // A new record was created. There won't be any data in the response. Copy the data in the
    // slot for the new record csid to the data slot for the new record. This prevents the form
    // data from blinking out when the browser is directed to the new csid, as it would otherwise
    // find no data until the read call to the REST API completed.

    var location = response.headers.location;
    var createdRecordCsid = location.substring(location.lastIndexOf('/') + 1);

    updatedState = updatedState.set(createdRecordCsid, updatedState.get(newRecordCsid));

    updatedState = setBaselineData(updatedState, createdRecordCsid, getCurrentData(updatedState, createdRecordCsid));

    return updatedState;
  }

  var data = _immutable2.default.fromJS(response.data);

  updatedState = setBaselineData(updatedState, csid, data);
  updatedState = setCurrentData(updatedState, csid, data);

  return updatedState;
};

var handleCreateIDFulfilled = function handleCreateIDFulfilled(state, action) {
  var _action$meta6 = action.meta,
      csid = _action$meta6.csid,
      path = _action$meta6.path;


  var data = getCurrentData(state, csid);

  if (!data) {
    return state;
  }

  var newValue = action.payload.data;
  var updatedData = (0, _recordDataHelpers.deepSet)(data, path, newValue);

  return setCurrentData(state, csid, updatedData);
};

exports.default = function () {
  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _immutable2.default.Map();
  var action = arguments[1];

  switch (action.type) {
    case _record.ADD_FIELD_INSTANCE:
      return addFieldInstance(state, action);
    case _record.CREATE_NEW_RECORD:
      return createNewRecord(state, action);
    case _record.DELETE_FIELD_VALUE:
      return deleteFieldValue(state, action);
    case _record.MOVE_FIELD_VALUE:
      return moveFieldValue(state, action);
    case _record.SET_FIELD_VALUE:
      return setFieldValue(state, action);
    case _record.RECORD_READ_STARTED:
      return state.setIn([action.meta.csid, 'isReadPending'], true);
    case _record.RECORD_READ_FULFILLED:
      return handleRecordReadFulfilled(state, action);
    case _record.RECORD_READ_REJECTED:
      return state.setIn([action.meta.csid, 'error'], _immutable2.default.fromJS(action.payload)).deleteIn([action.meta.csid, 'isReadPending']);
    case _record.RECORD_SAVE_STARTED:
      return state.setIn([action.meta.csid, 'isSavePending'], true);
    case _record.RECORD_SAVE_FULFILLED:
      return handleRecordSaveFulfilled(state, action);
    case _record.RECORD_SAVE_REJECTED:
      return state.setIn([action.meta.csid, 'error'], _immutable2.default.fromJS(action.payload)).deleteIn([action.meta.csid, 'isSavePending']);
    case _record.REVERT_RECORD:
      return setCurrentData(state, action.meta.csid, getBaselineData(state, action.meta.csid));
    case _idGenerator.CREATE_ID_FULFILLED:
      return handleCreateIDFulfilled(state, action);
    default:
      return state;
  }
};

var getData = exports.getData = function getData(state, csid) {
  return getCurrentData(state, csid);
};

var getNewData = exports.getNewData = function getNewData(state) {
  return getData(state, newRecordCsid);
};

var isReadPending = exports.isReadPending = function isReadPending(state, csid) {
  return state.getIn([csid, 'isReadPending']);
};

var isSavePending = exports.isSavePending = function isSavePending(state, csid) {
  return state.getIn([csid, 'isSavePending']);
};

var isModified = exports.isModified = function isModified(state, csid) {
  return (
    // Do a reference equality test between the current and baseline data. This will not detect if
    // a change is made, then another change is made that undoes the first. But it's more efficient
    // than a deep value equality test.
    getCurrentData(state, csid) !== getBaselineData(state, csid)
  );
};