"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.decorateTransitionsWithLog = exports.decorateActionRequest = exports.decorateEventGuard = exports.decorateEventsWithLog = exports.isEntryComponentCodomain = exports.isEntryComponentDomain = exports.decorateStateEntryWithLog = exports.tapEventStreamOutput = undefined;
exports.chainModelUpdates = chainModelUpdates;
exports.makeDefaultActionResponseProcessing = makeDefaultActionResponseProcessing;
exports.checkActionResponseIsSuccess = checkActionResponseIsSuccess;

var _ramda = require("ramda");

var _utils = require("../../utils");

var _types = require("./types");

// Allows to compose model update functions (a la monad chain operation)
function chainModelUpdates(arrayModelUpdateFn) {
  return function chainedModelUpdates(model, eventData, actionResponse) {
    return (0, _ramda.flatten)((0, _ramda.map)(function (modelUpdateFn) {
      return modelUpdateFn(model, eventData, actionResponse);
    }, arrayModelUpdateFn));
  };
}

// Shortcut to avoid defining over and over the same action response (success, error) logic
function makeDefaultActionResponseProcessing(config) {
  (0, _utils.assertContract)(_types.isDefaultActionResponseHandlerConfig, [config], 'Configuration for action response handling must be of the shape :: {' + '  success : {target_state : <state>, udpate_model : <model update fn>,' + '  error : {target_state : <state>, udpate_model : <model update fn>}');

  var _config$success = config.success,
      successTargetState = _config$success.target_state,
      successModelUpdate = _config$success.model_update,
      _config$error = config.error,
      errorTargetState = _config$error.target_state,
      errorModelUpdate = _config$error.model_update;


  return [{
    action_guard: checkActionResponseIsSuccess,
    target_state: successTargetState,
    model_update: successModelUpdate
  }, {
    action_guard: _ramda.T,
    target_state: errorTargetState,
    model_update: errorModelUpdate
  }];
}

function checkActionResponseIsSuccess(model, actionResponse) {
  void model;
  var err = actionResponse.err;

  return !err;
}

// Decorators to add log, contract checking, and tracing capabilities to fsm functions
var tapEventStreamOutput = exports.tapEventStreamOutput = function tapEventStreamOutput(eventName) {
  return {
    after: function after(result) {
      return result.tap(console.warn.bind(console, "Incoming user event! " + eventName + ": "));
    }
  };
};

var decorateStateEntryWithLog = exports.decorateStateEntryWithLog = (0, _ramda.mapObjIndexed)(function (stateEntryComponent, state) {
  return stateEntryComponent ? (0, _utils.decorateWith)([(0, _utils.assertFunctionContractDecoratorSpecs)({
    checkDomain: isEntryComponentDomain,
    checkCodomain: isEntryComponentCodomain
  }), (0, _utils.logFnTrace)(".STATE. " + state, ['model'])], stateEntryComponent) : null;
});

var isEntryComponentDomain = exports.isEntryComponentDomain = _types.isFsmModel;
var isEntryComponentCodomain = exports.isEntryComponentCodomain = _utils.isFunction;

var decorateEventsWithLog = exports.decorateEventsWithLog = (0, _ramda.mapObjIndexed)(function (eventFactory, eventName) {
  return (0, _utils.decorateWith)([(0, _utils.assertFunctionContractDecoratorSpecs)({
    checkDomain: _types.isEventFactoryDomain,
    checkCodomain: _types.isEventFactoryCodomain
  }), (0, _utils.logFnTrace)('Event factory', ['sources', 'settings']), tapEventStreamOutput(eventName)], eventFactory);
});

var decorateEventGuard = exports.decorateEventGuard = (0, _utils.decorateWith)([(0, _utils.assertFunctionContractDecoratorSpecs)({
  checkDomain: _types.isEventGuardDomain,
  checkCodomain: _types.isEventGuardCodomain
}), (0, _utils.logFnTrace)('Event guard', ['FSM_Model', 'EventData'])]);

var decorateActionRequest = exports.decorateActionRequest = (0, _utils.decorateWith)([(0, _utils.assertFunctionContractDecoratorSpecs)({
  checkDomain: _types.isActionRequestDomain,
  checkCodomain: _types.isActionRequestCodomain
}), (0, _utils.logFnTrace)('action request', ['FSM_Model', 'EventData'])]);

var decorateActionGuard = (0, _utils.decorateWith)([(0, _utils.assertFunctionContractDecoratorSpecs)({
  checkDomain: _types.isActionGuardDomain,
  checkCodomain: _types.isActionGuardCodomain
}), (0, _utils.logFnTrace)('action guard', ['model', 'actionResponse'])]);

var decorateModelUpdate = (0, _utils.decorateWith)([(0, _utils.assertFunctionContractDecoratorSpecs)({
  checkDomain: _types.isModelUpdateDomain,
  checkCodomain: _types.isModelUpdateCodomain
}), (0, _utils.logFnTrace)('model update', ['FSM_Model', 'EventData', 'ActionResponse', 'Settings'])]);

var decorateTransEval = (0, _ramda.evolve)({
  target_state: _ramda.identity,
  action_guard: (0, _ramda.cond)([[_ramda.isNil, (0, _ramda.always)(null)], [_ramda.T, decorateActionGuard]]),
  model_update: decorateModelUpdate
});

var decorateTransition = (0, _ramda.evolve)({
  re_entry: _ramda.identity,
  transition_evaluation: (0, _ramda.map)(decorateTransEval),
  event_guard: (0, _ramda.cond)([[_ramda.isNil, (0, _ramda.always)(null)], [_ramda.T, decorateEventGuard]]),
  action_request: (0, _ramda.cond)([[_ramda.isNil, (0, _ramda.always)(null)], [_ramda.T, (0, _ramda.evolve)({
    driver: _ramda.identity,
    request: decorateActionRequest
  })]])
});

var decorateTransitionsWithLog = exports.decorateTransitionsWithLog = (0, _ramda.mapObjIndexed)((0, _ramda.evolve)({
  origin_state: _ramda.identity,
  event: _ramda.identity,
  target_states: (0, _ramda.map)(decorateTransition)
}));