class Ransack::Nodes::Condition

def arel_predicate

def arel_predicate
  predicates = attributes.map do |attr|
    attr.attr.send(predicate.arel_predicate, formatted_values_for_attribute(attr))
  end
  if predicates.size > 1
    case combinator
    when 'and'
      Arel::Nodes::Grouping.new(Arel::Nodes::And.new(predicates))
    when 'or'
      predicates.inject(&:or)
    end
  else
    predicates.first
  end
end

def attributes

def attributes
  @attributes ||= []
end

def attributes=(args)

def attributes=(args)
  case args
  when Array
    args.each do |attr|
      attr = Attribute.new(@context, attr)
      self.attributes << attr if attr.valid?
    end
  when Hash
    args.each do |index, attrs|
      attr = Attribute.new(@context, attrs[:name])
      self.attributes << attr if attr.valid?
    end
  else
    raise ArgumentError, "Invalid argument (#{args.class}) supplied to attributes="
  end
end

def build(params)

def build(params)
  params.with_indifferent_access.each do |key, value|
    if key.match(/^(a|v|p|m)$/)
      self.send("#{key}=", value)
    end
  end
  self
end

def build_attribute(name = nil)

def build_attribute(name = nil)
  Attribute.new(@context, name).tap do |attribute|
    self.attributes << attribute
  end
end

def build_value(val = nil)

def build_value(val = nil)
  Value.new(@context, val).tap do |value|
    self.values << value
  end
end

def casted_values_for_attribute(attr)

def casted_values_for_attribute(attr)
  validated_values.map {|v| v.cast_to_type(predicate.type || attr.type)}
end

def combinator

def combinator
  @attributes.size > 1 ? @combinator : nil
end

def combinator=(val)

def combinator=(val)
  @combinator = ['and', 'or'].detect {|v| v == val.to_s} || nil
end

def eql?(other)

def eql?(other)
  self.class == other.class &&
  self.attributes == other.attributes &&
  self.predicate == other.predicate &&
  self.values == other.values &&
  self.combinator == other.combinator
end

def extract(context, key, values)

def extract(context, key, values)
  attributes, predicate = extract_attributes_and_predicate(key)
  if attributes.size > 0
    combinator = key.match(/_(or|and)_/) ? $1 : nil
    condition = self.new(context)
    condition.build(
      :a => attributes,
      :p => predicate.name,
      :m => combinator,
      :v => [values]
    )
    predicate.validate(condition.values) ? condition : nil
  end
end

def extract_attributes_and_predicate(key)

def extract_attributes_and_predicate(key)
  str = key.dup
  name = Ransack.predicate_keys.detect {|p| str.sub!(/_#{p}$/, '')}
  predicate = Predicate.named(name)
  raise ArgumentError, "No valid predicate for #{key}" unless predicate
  attributes = str.split(/_and_|_or_/)
  [attributes, predicate]
end

def first_attribute

def first_attribute
  attributes.first
end

def formatted_values_for_attribute(attr)

def formatted_values_for_attribute(attr)
  casted_values_for_attribute(attr).map do |val|
    val = attr.ransacker.formatter.call(val) if attr.ransacker && attr.ransacker.formatter
    val = predicate.formatter.call(val) if predicate.formatter
    val
  end
end

def hash

def hash
  [attributes, predicate, values, combinator].hash
end

def key

def key
  @key ||= attributes.map(&:name).join("_#{combinator}_") + "_#{predicate.name}"
end

def persisted?

def persisted?
  false
end

def predicate=(predicate)

def predicate=(predicate)
  @predicate = predicate
  predicate
end

def predicate_name

def predicate_name
  predicate.name if predicate
end

def predicate_name=(name)

def predicate_name=(name)
  self.predicate = Predicate.named(name)
end

def valid?

def valid?
  attributes.detect(&:valid?) && predicate && valid_arity? && predicate.validate(values) && valid_combinator?
end

def valid_arity?

def valid_arity?
  values.size <= 1 || predicate.compound || %w(in not_in).include?(predicate.name)
end

def valid_combinator?

def valid_combinator?
  attributes.size < 2 ||
  ['and', 'or'].include?(combinator)
end

def validated_values

def validated_values
  values.select {|v| predicate.validator ? predicate.validator.call(v.value) : v.present?}
end

def value

def value
  predicate.compound ? values.map {|v| cast_value(v)} : cast_value(values.first)
end

def values

def values
  @values ||= []
end

def values=(args)

def values=(args)
  case args
  when Array
    args.each do |val|
      val = Value.new(@context, val)
      self.values << val
    end
  when Hash
    args.each do |index, attrs|
      val = Value.new(@context, attrs[:value])
      self.values << val
    end
  else
    raise ArgumentError, "Invalid argument (#{args.class}) supplied to values="
  end
end