"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.isActionRequestCodomain = exports.isActionRequestDomain = exports.isRequest = exports.isCommand = exports.isEventGuardDomain = exports.isEventGuardCodomain = exports.isModelUpdateCodomain = exports.isModelUpdateDomain = exports.isActionGuardCodomain = exports.isActionGuardDomain = exports.isActionResponse = exports.isEventFactoryCodomain = exports.isEventFactoryDomain = exports.isDefaultActionResponseHandlerConfig = exports.isEntryComponent = exports.isEntryComponentFactory = exports.checkStateEntryComponentFnMustReturnComponent = exports.isArrayUpdateOperations = exports.isUpdateOperation = exports.isOpTest = exports.isOpCopy = exports.isOpMove = exports.isOpReplace = exports.isOpRemove = exports.isOpAdd = exports.isOpNone = exports.isJsonPointer = exports.isFsmTransitions = exports.isFsmEvents = exports.isFsmSettings = exports.isFsmEntryComponents = exports.isEventGuard = exports.isFsmModel = exports.isEventData = exports.isEvent = exports.isState = exports.isSinkName = exports.isTransitionName = exports.isEventName = undefined;
exports.checkTargetStatesDefinedInTransitionsMustBeMappedToComponent = checkTargetStatesDefinedInTransitionsMustBeMappedToComponent;
exports.checkOriginStatesDefinedInTransitionsMustBeMappedToComponent = checkOriginStatesDefinedInTransitionsMustBeMappedToComponent;
exports.checkEventDefinedInTransitionsMustBeMappedToEventFactory = checkEventDefinedInTransitionsMustBeMappedToEventFactory;
exports.checkIsObservable = checkIsObservable;

var _ramda = require("ramda");

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

var _properties = require("../properties");

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

////////
// Types FSM
var isEventName = exports.isEventName = (0, _ramda.both)(_utils.isString, _types.isNotEmpty);
var isTransitionName = exports.isTransitionName = (0, _ramda.both)(_utils.isString, _types.isNotEmpty);
var isSinkName = exports.isSinkName = (0, _ramda.both)(_utils.isString, _types.isNotEmpty);
var isState = exports.isState = (0, _ramda.both)(_utils.isString, _types.isNotEmpty);
// NOTE : cant check at this level type of arguments
//`Event :: Sources -> Settings -> Source EventData`
var isEvent = exports.isEvent = _utils.isFunction;
//`EventData :: * | Null`
var isEventData = exports.isEventData = _ramda.T;
//`FSM_Model :: Object`
var isFsmModel = exports.isFsmModel = _utils.isObject;

// `EventGuard :: Model -> EventData -> Boolean`
var isEventGuard = exports.isEventGuard = (0, _ramda.either)(_ramda.isNil, _utils.isFunction);
// `ActionRequest :: Record {
//   driver :: SinkName | Null
//   request :: (FSM_Model -> EventData) -> Request | Null
// } | Null`
var isActionRequest = (0, _utils.isStrictRecord)({
  driver: (0, _ramda.either)(_ramda.isNil, isSinkName),
  request: (0, _ramda.either)(_ramda.isNil, _utils.isFunction)
});

// `ActionGuard :: ActionResponse -> Boolean`
var isActionGuard = _utils.isFunction;

// `TransEval :: Record {
//   action_guard :: ActionGuard
//   target_state :: State
//   model_update :: FSM_Model -> EventData -> ActionResponse -> [UpdateOperation]
// }`
var isModelUpdate = _utils.isFunction;
var isTransEval = (0, _utils.isStrictRecord)({
  action_guard: isActionGuard,
  target_state: isState,
  model_update: _utils.isFunction
});

// `Transition :: Record {
//   event_guard :: EventGuard
//   action_request :: ActionRequest
//   re_entry :: Boolean | Null
//   transition_evaluation :: [TransEval]
// }`
var isTransition = (0, _utils.isStrictRecord)({
  event_guard: isEventGuard,
  re_entry: (0, _ramda.either)(_ramda.isNil, _utils.isBoolean),
  action_request: (0, _ramda.either)(_ramda.isNil, isActionRequest),
  transition_evaluation: (0, _utils.isArrayOf)(isTransEval)
});

//`TransitionOptions :: Record {
//  origin_state :: State
//  event :: EventName
//  target_states :: [Transition]
//}`
var isTransitionOptions = (0, _utils.isStrictRecord)({
  origin_state: isState,
  event: isEventName,
  target_states: (0, _ramda.both)((0, _utils.isArrayOf)(isTransition), _types.isNotEmpty)
});

// `StateEntryComponent :: FSM_Model -> Component`
var isStateEntryComponent = _utils.isFunction;
// `StateEntryComponents :: HashMap State StateEntryComponent`
var isFsmEntryComponents = exports.isFsmEntryComponents = (0, _ramda.both)((0, _utils.isHashMap)(isState, isStateEntryComponent), _types.isNotEmpty);

// FSM_Settings :: Record {
//   initial_model :: FSM_Model
//   init_event_data :: Event_Data
//   sinkNames :: [SinkName]
// }`
var isFsmSettings = exports.isFsmSettings = (0, _utils.isStrictRecord)({
  initial_model: isFsmModel,
  init_event_data: isEventData,
  sinkNames: (0, _ramda.either)(_utils.isEmptyArray, (0, _utils.isArrayOf)(isSinkName)),
  debug: (0, _ramda.either)(_ramda.isNil, _utils.isBoolean)
});

// `Events :: (HashMap EventName Event) | {}`
var isFsmEvents = exports.isFsmEvents = (0, _utils.isHashMap)(isEventName, isEvent);
var isFsmTransitions = exports.isFsmTransitions = (0, _ramda.allPass)([(0, _utils.isHashMap)(isTransitionName, isTransitionOptions), (0, _ramda.complement)(_ramda.isEmpty), (0, _ramda.pipe)(_ramda.values, (0, _ramda.any)((0, _ramda.propEq)('event', _properties.INIT_EVENT_NAME)))]);

function checkTargetStatesDefinedInTransitionsMustBeMappedToComponent(events, transitions, entryComponents, fsmSettings) {
  return (0, _ramda.pipe)(_ramda.values, (0, _ramda.map)((0, _ramda.prop)('target_states')), _ramda.flatten, (0, _ramda.map)((0, _ramda.prop)('transition_evaluation')), _ramda.flatten, (0, _ramda.map)((0, _ramda.prop)('target_state')), (0, _ramda.map)((0, _ramda.flip)(_ramda.prop)(entryComponents)), (0, _ramda.all)(_ramda.identity))(transitions);
}

function checkOriginStatesDefinedInTransitionsMustBeMappedToComponent(events, transitions, entryComponents, fsmSettings) {
  return (0, _ramda.pipe)(_ramda.values, (0, _ramda.map)((0, _ramda.prop)('origin_state')), (0, _ramda.filter)((0, _ramda.complement)((0, _ramda.equals)(_properties.INIT_STATE))), (0, _ramda.map)((0, _ramda.flip)(_ramda.prop)(entryComponents)), (0, _ramda.all)(_ramda.identity))(transitions);
}

function checkEventDefinedInTransitionsMustBeMappedToEventFactory(events, transitions, entryComponents, fsmSettings) {
  var check = (0, _ramda.pipe)(_ramda.values, (0, _ramda.map)((0, _ramda.prop)('event')), (0, _ramda.filter)((0, _ramda.complement)((0, _ramda.equals)(_properties.INIT_EVENT_NAME))), (0, _ramda.map)((0, _ramda.flip)(_ramda.prop)(events)), (0, _ramda.all)(_ramda.identity))(transitions);

  return check;
}

function checkIsObservable(obj) {
  return !!obj.subscribe;
}

// `JSON_Patch :: Op_Add | Op_Remove | Op_Replace | Op_Move | Op_Copy | Op_Test | Op_None`
// `Op_Add :: Record { op: "add", path: JSON_Pointer, value : *}`
// `Op_Remove :: Record { op: "remove", path: JSON_Pointer}`
// `Op_Replace :: Record { op: "replace", path: JSON_Pointer, value: *}`
// `Op_Move :: Record { op: "move", from: JSON_Pointer, path: JSON_Pointer}`
// `Op_Copy :: Record { op: "copy", from: JSON_Pointer, path: JSON_Pointer}`
// `Op_Test :: Record { op: "test", path: JSON_Pointer, value: *}`
// `Op_None :: {} | Null`

var isJsonPointer = exports.isJsonPointer = _utils.isString;
var isOpNone = exports.isOpNone = (0, _ramda.both)(_utils.isObject, _ramda.isEmpty);
var isOpAdd = exports.isOpAdd = (0, _utils.isStrictRecord)({
  op: (0, _ramda.both)(_utils.isString, (0, _ramda.equals)('add')),
  path: isJsonPointer,
  value: _ramda.T
});
var isOpRemove = exports.isOpRemove = (0, _utils.isStrictRecord)({
  op: (0, _ramda.both)(_utils.isString, (0, _ramda.equals)('remove')),
  path: isJsonPointer
});
var isOpReplace = exports.isOpReplace = (0, _utils.isStrictRecord)({
  op: (0, _ramda.both)(_utils.isString, (0, _ramda.equals)('replace')),
  path: isJsonPointer,
  value: _ramda.T
});
var isOpMove = exports.isOpMove = (0, _utils.isStrictRecord)({
  op: (0, _ramda.both)(_utils.isString, (0, _ramda.equals)('move')),
  path: isJsonPointer
});
var isOpCopy = exports.isOpCopy = (0, _utils.isStrictRecord)({
  op: (0, _ramda.both)(_utils.isString, (0, _ramda.equals)('copy')),
  path: isJsonPointer
});
var isOpTest = exports.isOpTest = (0, _utils.isStrictRecord)({
  op: (0, _ramda.both)(_utils.isString, (0, _ramda.equals)('test')),
  path: isJsonPointer,
  value: _ramda.T
});
// Works but evaluates all the functions...
// export const isUpdateOperation = converge(any(identity), isOpAdd, isOpRemove, isOpReplace,
// isOpMove, isOpCopy, isOpTest, isOpNone)
var isUpdateOperation = exports.isUpdateOperation = (0, _ramda.cond)([[isOpNone, _ramda.T], [isOpAdd, _ramda.T], [isOpRemove, _ramda.T], [isOpReplace, _ramda.T], [isOpMove, _ramda.T], [isOpCopy, _ramda.T], [isOpTest, _ramda.T]]);
var isArrayUpdateOperations = exports.isArrayUpdateOperations = (0, _ramda.either)(_utils.isEmptyArray, (0, _utils.isArrayOf)(isUpdateOperation));

var checkStateEntryComponentFnMustReturnComponent = exports.checkStateEntryComponentFnMustReturnComponent = _utils.isComponent;

var isEntryComponentFactory = exports.isEntryComponentFactory = (0, _ramda.either)(_ramda.isNil, _utils.isFunction);
var isEntryComponent = exports.isEntryComponent = (0, _ramda.either)(_ramda.isNil, _utils.isFunction);

var isDefaultActionResponseHandlerConfig = exports.isDefaultActionResponseHandlerConfig = (0, _utils.isStrictRecord)({
  success: (0, _utils.isStrictRecord)({ target_state: isState, model_update: isModelUpdate }),
  error: (0, _utils.isStrictRecord)({ target_state: isState, model_update: isModelUpdate })
});

// Type contracts
var isEventFactoryDomain = exports.isEventFactoryDomain = (0, _ramda.both)(_types.isSources, (0, _ramda.flip)(_types.isSettings));
var isEventFactoryCodomain = exports.isEventFactoryCodomain = _utils.isObservable;
var isActionResponse = exports.isActionResponse = _ramda.T;
var isActionGuardDomain = exports.isActionGuardDomain = (0, _ramda.both)(isFsmModel, (0, _ramda.flip)(isActionResponse));
var isActionGuardCodomain = exports.isActionGuardCodomain = _utils.isBoolean;
var isModelUpdateDomain = exports.isModelUpdateDomain = function isModelUpdateDomain(model, eventData, actionResponse, settings) {
  return isFsmModel(model) && isEventData(eventData) && isActionResponse(actionResponse) && (0, _types.isSettings)(settings);
};
var isModelUpdateCodomain = exports.isModelUpdateCodomain = isArrayUpdateOperations;
var isEventGuardCodomain = exports.isEventGuardCodomain = _utils.isBoolean;
var isEventGuardDomain = exports.isEventGuardDomain = (0, _ramda.both)(isFsmModel, (0, _ramda.flip)(isEventData));
var isCommand = exports.isCommand = _utils.isString;
var isRequest = exports.isRequest = (0, _utils.isStrictRecord)({
  command: isCommand,
  context: (0, _ramda.either)(_ramda.isNil, _ramda.T), // optional
  payload: (0, _ramda.either)(_ramda.isNil, _ramda.T) // optional
});
var isActionRequestDomain = exports.isActionRequestDomain = (0, _ramda.both)(isFsmModel, (0, _ramda.flip)(isEventData));
var isActionRequestCodomain = exports.isActionRequestCodomain = isRequest;