class ActiveSupport::Callbacks::Filters::Around

def self.build(callback_sequence, user_callback, user_conditions, chain_config)

def self.build(callback_sequence, user_callback, user_conditions, chain_config)
  if chain_config.key?(:terminator) && user_conditions.any?
    halting_and_conditional(callback_sequence, user_callback, user_conditions)
  elsif chain_config.key? :terminator
    halting(callback_sequence, user_callback)
  elsif user_conditions.any?
    conditional(callback_sequence, user_callback, user_conditions)
  else
    simple(callback_sequence, user_callback)
  end
end

def self.conditional(callback_sequence, user_callback, user_conditions)

def self.conditional(callback_sequence, user_callback, user_conditions)
  callback_sequence.around do |env, &run|
    target = env.target
    value  = env.value
    if user_conditions.all? { |c| c.call(target, value) }
      user_callback.call(target, value) {
        env = run.call env
        env.value
      }
      env
    else
      run.call env
    end
  end
end

def self.halting(callback_sequence, user_callback)

def self.halting(callback_sequence, user_callback)
  callback_sequence.around do |env, &run|
    target = env.target
    value  = env.value
    if env.halted
      run.call env
    else
      user_callback.call(target, value) {
        env = run.call env
        env.value
      }
      env
    end
  end
end

def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)

def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
  callback_sequence.around do |env, &run|
    target = env.target
    value  = env.value
    halted = env.halted
    if !halted && user_conditions.all? { |c| c.call(target, value) }
      user_callback.call(target, value) {
        env = run.call env
        env.value
      }
      env
    else
      run.call env
    end
  end
end

def self.simple(callback_sequence, user_callback)

def self.simple(callback_sequence, user_callback)
  callback_sequence.around do |env, &run|
    user_callback.call(env.target, env.value) {
      env = run.call env
      env.value
    }
    env
  end
end