"use strict";

var _Object$keys = require("@babel/runtime-corejs3/core-js-stable/object/keys");
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols");
var _filterInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/filter");
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor");
var _forEachInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/for-each");
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors");
var _Object$defineProperties = require("@babel/runtime-corejs3/core-js-stable/object/define-properties");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
  value: true
});
exports.commitServerChanges = commitServerChanges;
exports.defaultState = defaultState;
exports.estimateAttribute = estimateAttribute;
exports.estimateAttributes = estimateAttributes;
exports.mergeFirstPendingState = mergeFirstPendingState;
exports.popPendingState = popPendingState;
exports.pushPendingState = pushPendingState;
exports.setPendingOp = setPendingOp;
exports.setServerData = setServerData;
var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/typeof"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
var _encode = _interopRequireDefault(require("./encode"));
var _ParseFile = _interopRequireDefault(require("./ParseFile"));
var _ParseObject = _interopRequireDefault(require("./ParseObject"));
var _ParseRelation = _interopRequireDefault(require("./ParseRelation"));
var _TaskQueue = _interopRequireDefault(require("./TaskQueue"));
var _ParseOp = require("./ParseOp");
function ownKeys(object, enumerableOnly) {
  var keys = _Object$keys(object);
  if (_Object$getOwnPropertySymbols) {
    var symbols = _Object$getOwnPropertySymbols(object);
    enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) {
      return _Object$getOwnPropertyDescriptor(object, sym).enumerable;
    })), keys.push.apply(keys, symbols);
  }
  return keys;
}
function _objectSpread(target) {
  for (var i = 1; i < arguments.length; i++) {
    var _context, _context2;
    var source = null != arguments[i] ? arguments[i] : {};
    i % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(source), !0)).call(_context, function (key) {
      (0, _defineProperty2.default)(target, key, source[key]);
    }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context2 = ownKeys(Object(source))).call(_context2, function (key) {
      _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key));
    });
  }
  return target;
} /**
   * @flow
   */
/*:: import type { Op } from './ParseOp';*/
/*:: export type AttributeMap = { [attr: string]: any };*/
/*:: export type OpsMap = { [attr: string]: Op };*/
/*:: export type ObjectCache = { [attr: string]: string };*/
/*:: export type State = {
  serverData: AttributeMap,
  pendingOps: Array<OpsMap>,
  objectCache: ObjectCache,
  tasks: TaskQueue,
  existed: boolean,
};*/
function defaultState() /*: State*/{
  return {
    serverData: {},
    pendingOps: [{}],
    objectCache: {},
    tasks: new _TaskQueue.default(),
    existed: false
  };
}
function setServerData(serverData /*: AttributeMap*/, attributes /*: AttributeMap*/) {
  for (var _attr in attributes) {
    if (typeof attributes[_attr] !== 'undefined') {
      serverData[_attr] = attributes[_attr];
    } else {
      delete serverData[_attr];
    }
  }
}
function setPendingOp(pendingOps /*: Array<OpsMap>*/, attr /*: string*/, op /*: ?Op*/) {
  var last = pendingOps.length - 1;
  if (op) {
    pendingOps[last][attr] = op;
  } else {
    delete pendingOps[last][attr];
  }
}
function pushPendingState(pendingOps /*: Array<OpsMap>*/) {
  pendingOps.push({});
}
function popPendingState(pendingOps /*: Array<OpsMap>*/) /*: OpsMap*/{
  var first = pendingOps.shift();
  if (!pendingOps.length) {
    pendingOps[0] = {};
  }
  return first;
}
function mergeFirstPendingState(pendingOps /*: Array<OpsMap>*/) {
  var first = popPendingState(pendingOps);
  var next = pendingOps[0];
  for (var _attr2 in first) {
    if (next[_attr2] && first[_attr2]) {
      var merged = next[_attr2].mergeWith(first[_attr2]);
      if (merged) {
        next[_attr2] = merged;
      }
    } else {
      next[_attr2] = first[_attr2];
    }
  }
}
function estimateAttribute(serverData /*: AttributeMap*/, pendingOps /*: Array<OpsMap>*/, className /*: string*/, id /*: ?string*/, attr /*: string*/) /*: mixed*/{
  var value = serverData[attr];
  for (var i = 0; i < pendingOps.length; i++) {
    if (pendingOps[i][attr]) {
      if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) {
        if (id) {
          value = pendingOps[i][attr].applyTo(value, {
            className: className,
            id: id
          }, attr);
        }
      } else {
        value = pendingOps[i][attr].applyTo(value);
      }
    }
  }
  return value;
}
function estimateAttributes(serverData /*: AttributeMap*/, pendingOps /*: Array<OpsMap>*/, className /*: string*/, id /*: ?string*/) /*: AttributeMap*/{
  var data = {};
  for (var attr in serverData) {
    data[attr] = serverData[attr];
  }
  for (var i = 0; i < pendingOps.length; i++) {
    for (attr in pendingOps[i]) {
      if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) {
        if (id) {
          data[attr] = pendingOps[i][attr].applyTo(data[attr], {
            className: className,
            id: id
          }, attr);
        }
      } else {
        if ((0, _includes.default)(attr).call(attr, '.')) {
          // convert a.b.c into { a: { b: { c: value } } }
          var fields = attr.split('.');
          var first = fields[0];
          var last = fields[fields.length - 1];
          data[first] = _objectSpread({}, serverData[first]);
          var object = _objectSpread({}, data);
          for (var _i = 0; _i < fields.length - 1; _i++) {
            var key = fields[_i];
            if (!(key in object)) {
              object[key] = {};
            }
            object = object[key];
          }
          object[last] = pendingOps[i][attr].applyTo(object[last]);
        } else {
          data[attr] = pendingOps[i][attr].applyTo(data[attr]);
        }
      }
    }
  }
  return data;
}
function nestedSet(obj, key, value) {
  var path = key.split('.');
  for (var i = 0; i < path.length - 1; i++) {
    if (!(path[i] in obj)) obj[path[i]] = {};
    obj = obj[path[i]];
  }
  if (typeof value === 'undefined') {
    delete obj[path[path.length - 1]];
  } else {
    obj[path[path.length - 1]] = value;
  }
}
function commitServerChanges(serverData /*: AttributeMap*/, objectCache /*: ObjectCache*/, changes /*: AttributeMap*/) {
  for (var _attr3 in changes) {
    var val = changes[_attr3];
    nestedSet(serverData, _attr3, val);
    if (val && (0, _typeof2.default)(val) === 'object' && !(val instanceof _ParseObject.default) && !(val instanceof _ParseFile.default) && !(val instanceof _ParseRelation.default)) {
      var json = (0, _encode.default)(val, false, true);
      objectCache[_attr3] = (0, _stringify.default)(json);
    }
  }
}