module AASM

def self.included(base) #:nodoc:

:nodoc:
initialize persistence for the state machine
make sure to load class methods as well
provide a state machine for the including class
def self.included(base) #:nodoc:
  base.extend AASM::ClassMethods
  # do not overwrite existing state machines, which could have been created by
  # inheritance, see class method inherited
  AASM::StateMachineStore.register(base)
  AASM::Persistence.load_persistence(base)
  super
end

def aasm(name=:default)

this is the entry point for all instance-level access to AASM
def aasm(name=:default)
  unless AASM::StateMachineStore.fetch(self.class, true).machine(name)
    raise AASM::UnknownStateMachineError.new("There is no state machine with the name '#{name}' defined in #{self.class.name}!")
  end
  @aasm ||= Concurrent::Map.new
  @aasm[name.to_sym] ||= AASM::InstanceBase.new(self, name.to_sym)
end

def aasm_failed(state_machine_name, event_name, old_state, failures = [])

def aasm_failed(state_machine_name, event_name, old_state, failures = [])
  if self.respond_to?(:aasm_event_failed)
    self.aasm_event_failed(event_name, old_state.name)
  end
  if AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.whiny_transitions
    raise AASM::InvalidTransition.new(self, event_name, state_machine_name, failures)
  else
    false
  end
end

def aasm_fire_event(state_machine_name, event_name, options, *args, &block)

def aasm_fire_event(state_machine_name, event_name, options, *args, &block)
  event = self.class.aasm(state_machine_name).state_machine.events[event_name]
  begin
    old_state = aasm(state_machine_name).state_object_for_name(aasm(state_machine_name).current_state)
    fire_default_callbacks(event, *process_args(event, aasm(state_machine_name).current_state, *args))
    if may_fire_to = event.may_fire?(self, *args)
      fire_exit_callbacks(old_state, *process_args(event, aasm(state_machine_name).current_state, *args))
      if new_state_name = event.fire(self, {:may_fire => may_fire_to}, *args)
        aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args, &block)
      else
        aasm_failed(state_machine_name, event_name, old_state, event.failed_callbacks)
      end
    else
      aasm_failed(state_machine_name, event_name, old_state, event.failed_callbacks)
    end
  rescue StandardError => e
    event.fire_callbacks(:error, self, e, *process_args(event, aasm(state_machine_name).current_state, *args)) ||
    event.fire_global_callbacks(:error_on_all_events, self, e, *process_args(event, aasm(state_machine_name).current_state, *args)) ||
    raise(e)
    false
  ensure
    event.fire_callbacks(:ensure, self, *process_args(event, aasm(state_machine_name).current_state, *args))
    event.fire_global_callbacks(:ensure_on_all_events, self, *process_args(event, aasm(state_machine_name).current_state, *args))
  end
end

def aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args)

def aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args)
  persist = options[:persist]
  new_state = aasm(state_machine_name).state_object_for_name(new_state_name)
  callback_args = process_args(event, aasm(state_machine_name).current_state, *args)
  new_state.fire_callbacks(:before_enter, self, *callback_args)
  new_state.fire_callbacks(:enter, self, *callback_args) # TODO: remove for AASM 4?
  persist_successful = true
  if persist
    persist_successful = aasm(state_machine_name).set_current_state_with_persistence(new_state_name)
    if persist_successful
      yield if block_given?
      event.fire_callbacks(:before_success, self, *callback_args)
      event.fire_transition_callbacks(self, *process_args(event, old_state.name, *args))
      event.fire_callbacks(:success, self, *callback_args)
    end
  else
    aasm(state_machine_name).current_state = new_state_name
    yield if block_given?
  end
  binding_event = event.options[:binding_event]
  if binding_event
    __send__("#{binding_event}#{'!' if persist}")
  end
  if persist_successful
    old_state.fire_callbacks(:after_exit, self, *callback_args)
    new_state.fire_callbacks(:after_enter, self, *callback_args)
    event.fire_callbacks(
      :after,
      self,
      *process_args(event, old_state.name, *args)
    )
    event.fire_global_callbacks(
      :after_all_events,
      self,
      *process_args(event, old_state.name, *args)
    )
    self.aasm_event_fired(event.name, old_state.name, aasm(state_machine_name).current_state) if self.respond_to?(:aasm_event_fired)
  else
    self.aasm_event_failed(event.name, old_state.name) if self.respond_to?(:aasm_event_failed)
  end
  persist_successful
end

def fire_default_callbacks(event, *processed_args)

def fire_default_callbacks(event, *processed_args)
  event.fire_global_callbacks(
    :before_all_events,
    self,
    *processed_args
  )
  # new event before callback
  event.fire_callbacks(
    :before,
    self,
    *processed_args
  )
end

def fire_exit_callbacks(old_state, *processed_args)

def fire_exit_callbacks(old_state, *processed_args)
  old_state.fire_callbacks(:before_exit, self, *processed_args)
  old_state.fire_callbacks(:exit, self, *processed_args)
end

def initialize_dup(other)

def initialize_dup(other)
  @aasm = Concurrent::Map.new
  super
end

def process_args(event, from_state, *args)

the event given the from_state
element from args if it is a valid to_state for
Takes args and a from state and removes the first
def process_args(event, from_state, *args)
  # If the first arg doesn't respond to to_sym then
  # it isn't a symbol or string so it can't be a state
  # name anyway
  return args unless args.first.respond_to?(:to_sym)
  if event.transitions_from_state(from_state).map(&:to).flatten.include?(args.first)
    return args[1..-1]
  end
  return args
end