class Eco::Language::Models::Collection

def <(value)

def <(value)
  @items.clear
  self << value
end

def <<(value)

def <<(value)
  @items.concat(into_a(value))
  on_change
  self
end

def attr(attr, value = true, modifier = Language::MatchModifier.new)

def attr(attr, value = true, modifier = Language::MatchModifier.new)
  if !!value == value # boolean?

    present(attr, value)
  else
    return newFrom select { |object|
      attr_val = fetch_attr(object, attr)
      match?(attr_val, value, modifier)
    }
  end
end

def attr?(attr, value = true, modifier = Language::MatchModifier.new)

def attr?(attr, value = true, modifier = Language::MatchModifier.new)
  modifier = modifier.new.reverse
  if !!value == value # boolean?

    present(attr, value).length == length
  else
    obj_vals = attrs(attr)
    return match?(obj_vals, value, modifier)
  end
end

def attr_collection (*attrs)

def attr_collection (*attrs)
  block = ->(method) { attrs_create_method(attrs, method) }
  ATTR_COLLECTION_METHODS.each(&block)
end

def attr_presence (*attrs)

def attr_presence (*attrs)
  block = ->(method) { attrs_create_method(attrs, method) }
  ATTR_PRESENCE_METHODS.each(&block)
end

def attrs(attr)

def attrs(attr)
  map { |object| fetch_attr(object, attr) }
end

def attrs_create_method(attrs, method)

def attrs_create_method(attrs, method)
  attrs.each do |attr|
    attr = attr.to_s
    if method.include?("attr")
      attr_method = method.sub("attr", attr)
    else
      attr_method = "#{attr}_#{method}"
    end
    define_method attr_method do  |*args|
      send(method, attr, *args)
    end
  end
end

def contains(attr, value, modifier = Language::MatchModifier.new)

def contains(attr, value, modifier = Language::MatchModifier.new)
  modifier = modifier.new.pattern
  self.attr(attr, value, modifier)
end

def delete!(value)

def delete!(value)
  self < @items - into_a(value)
end

def each(params: {}, &block)

def each(params: {}, &block)
  return to_enum(:each) unless block
  @items.each(&block)
end

def empty(attr, flag = true)

def empty(attr, flag = true)
  present(attr, !flag)
end

def empty?

def empty?
  count == 0
end

def exclude(attr, value, modifier = Language::MatchModifier.new)

attr dependant methods
def exclude(attr, value, modifier = Language::MatchModifier.new)
  newFrom @items - self.attr(attr, value, modifier)
end

def fetch_attr(object,attr)

def fetch_attr(object,attr)
  object.method(attr).call
end

def group_by(attr = nil, &block)

def group_by(attr = nil, &block)
  return to_h(attr) if attr
  to_a.group_by(&block) if block
end

def initialize(data = [], klass:, factory: nil, handy: Eco::Assets::Language.new)

def initialize(data = [], klass:, factory: nil, handy: Eco::Assets::Language.new)
  raise "Raise klass required, given: #{klass}" if !klass
  @klass   = klass
  @factory = factory
  @handy   = handy
  @items   = to_klass(data)
end

def into_a(value)

def into_a(value)
  value = [].push(value) unless value.is_a?(Enumerable)
  value.to_a
end

def length

def length
  count
end

def match?(*args)

def match?(*args)
  @handy.match?(*args)
end

def merge(data)

def merge(data)
  data = data.to_a unless data.is_a?(Array)
  newFrom to_a + data
end

def new

def new
  self.class.new(to_a, klass: @klass, factory: @factory)
end

def newFrom(data)

def newFrom(data)
  self.class.new(data, klass: @klass, factory: @factory)
end

def on_change

def on_change
  # function to be overriden by children classes

end

def present(attr, flag = true)

def present(attr, flag = true)
  block = ->(o) { !!fetch_attr(o, attr) == !!flag }
  newFrom select(&block)
end

def present_all?(attr, flag = true)

def present_all?(attr, flag = true)
  present(attr, flag).length == length
end

def present_some?(attr, flag = true)

def present_some?(attr, flag = true)
  present(attr, flag).length > 0
end

def remove(attr, value, modifier = Language::MatchModifier.new)

def remove(attr, value, modifier = Language::MatchModifier.new)
  self < exclude(attr, value, modifier)
end

def to_c

def to_c
  Collection.new(self, klass: @klass, factory: @factory)
end

def to_h(attr)

def to_h(attr)
  return {} if !attr
  to_a.group_by { |object| object.method(attr).call }
end

def to_klass(list)

def to_klass(list)
  into_a(list).map do |v|
    v.is_a?(@klass) ? v : @factory&.new(v) || @klass.new(v)
  end
end

def unique_attrs(attr)

def unique_attrs(attr)
  to_h(attr).keys
end

def update(&block)

def update(&block)
  newFrom self.map(&block)
end