<commit_before>class Cart
  include ActiveModel::Validations
  extend ActiveModel::Naming

  validates :reserver_id, :start_date, :due_date, :presence => true

  validate :start_date_before_due_date?, :not_in_past?,
           :allowable_number_category?, :allowable_number_equipment_model?,
           :duration_allowed?, :no_overdue_reservations?, :available?

  attr_accessor :reserver_id, :items, :start_date, :due_date
  attr_reader   :errors

  def initialize
    @errors = ActiveModel::Errors.new(self)
    @items = []
    @start_date = Date.today
    @due_date = Date.today
    @reserver_id = nil
  end

  def persisted?
    false
  end

  ## Functions for error handling

  def read_attribute_for_validation(attr)
    send(attr)
  end

  def Cart.human_attribute_name(attr, options = {})
    attr
  end

  def Cart.lookup_ancestors
    [self]
  end

  ## End of functions for error handling

  def add_equipment_model(equipment_model)
    current_item = nil
    @items.find do |item|
      current_item = item if item.equipment_model_id == equipment_model.id
    end
    if current_item
      current_item.increment_quantity
    else
      current_item = CartItem.new(equipment_model.id)
      @items << current_item
    end
    if !current_item.available?(@start_date..@due_date)
      errors.add(:start_date, "is before item is available")
    end
    return current_item if self.valid?
    self.valid?
  end

  def remove_equipment_model(equipment_model)
    current_item = nil
    @items.find do |item|
      current_item = item if item.equipment_model_id == equipment_model.id
    end
    current_item.decrement_quantity
    if current_item.quantity == 0
      @items.delete(current_item)
    end
    current_item
  end

  def get_cart_items
    items = []
    @items.each do |item|
      items << item.details
    end
    items
  end

  def total_items
    @items.sum{ |item| item.quantity }
  end

  def empty?
    @items.empty?
  end

  def set_start_date(date)
    @start_date = date
    fix_due_date
  end

  def set_due_date(date)
    @due_date = date
    fix_due_date
  end

  def set_reserver_id(user_id)
    @reserver_id = user_id
  end

  def duration #in days
    @due_date - @start_date + 1
  end

  def reserver
    reserver = User.find(@reserver_id)
  end

  def fix_due_date
    if @start_date > @due_date
      @due_date = @start_date
    end
  end

  ## VALIDATIONS ##

  ## Date Validations

  # Checks all date-related validations
  def valid_dates?
    valid = true
    valid = false if !not_in_past?
    valid = false if !start_date_before_due_date?
    valid = false if !duration_allowed?
    valid = false if !available?
    valid
  end

  # Checks that neither start date nor due date are in the past
  def not_in_past?
    in_past = false
    if start_date < Date.today
      in_past = true
      errors.add(:start_date, "Start date cannot be before today")
    end
    if due_date < Date.today
      in_past = true
      errors.add(:due_date, "Due date cannot be before today")
    end
    return !in_past
  end

  # Checks that start date is before due date
  def start_date_before_due_date?
    if start_date > due_date
      errors.add(:due_date, "Due date cannot be before start date.")
      return false
    end
    return true
  end

  # Check that the duration is not longer than the maximum checkout length for any of the item
  def duration_allowed?
    is_too_long = false
    @items.each do |item|
      eq_model = item.equipment_model
      category = eq_model.category
      unless category.max_checkout_length.nil? || self.duration <= category.max_checkout_length
        errors.add(:items, "You can only check out " + eq_model.name + " for " + category.max_checkout_length.to_s + " days")
        is_too_long = true
      end
    end
    !is_too_long
  end

  # Check that all items are available
  def available?
    available = true
    return false if start_date.nil? or due_date.nil?
    @items.each do |item|
      if !item.available?(start_date..due_date)
        errors.add(:items, item.name + " is not available for all or part of the reservation length.")
        available = false
      end
    end
    available
  end

  ## Item validations

  #Check that the reserver does not exceeds the maximum number of any equipment models
  def allowable_number_equipment_model?
    too_many = false
    reserver_model_counts = reserver.checked_out_models
    @items.each do |item|
      #If the reserver has none of the model checked out, count = 0
      eq_model = item.equipment_model
      curr_model_count = reserver_model_counts[eq_model.id]
      curr_model_count ||= 0
      # This thing with unrestricted makes me upset
      if eq_model.maximum_per_user != "unrestricted"
        unless eq_model.maximum_per_user >= item.quantity + curr_model_count
          errors.add(:items, reserver.name + " has too many of " + eq_model.name)
          too_many = true<commit_msg>added a new validation for cart -for items that should be renewed rather than have a new reservation<commit_after>class Cart
  include ActiveModel::Validations
  extend ActiveModel::Naming

  validates :reserver_id, :start_date, :due_date, :presence => true

  validate :start_date_before_due_date?, :not_in_past?,
           :allowable_number_category?, :allowable_number_equipment_model?,
           :duration_allowed?, :no_overdue_reservations?, :available?

  attr_accessor :reserver_id, :items, :start_date, :due_date
  attr_reader   :errors

  def initialize
    @errors = ActiveModel::Errors.new(self)
    @items = []
    @start_date = Date.today
    @due_date = Date.today
    @reserver_id = nil
  end

  def persisted?
    false
  end

  ## Functions for error handling

  def read_attribute_for_validation(attr)
    send(attr)
  end

  def Cart.human_attribute_name(attr, options = {})
    attr
  end

  def Cart.lookup_ancestors
    [self]
  end

  ## End of functions for error handling

  def add_equipment_model(equipment_model)
    current_item = nil
    @items.find do |item|
      current_item = item if item.equipment_model_id == equipment_model.id
    end
    if current_item
      current_item.increment_quantity
    else
      current_item = CartItem.new(equipment_model.id)
      @items << current_item
    end
    if !current_item.available?(@start_date..@due_date)
      errors.add(:start_date, "is before item is available")
    end
    return current_item if self.valid?
    self.valid?
  end

  def remove_equipment_model(equipment_model)
    current_item = nil
    @items.find do |item|
      current_item = item if item.equipment_model_id == equipment_model.id
    end
    current_item.decrement_quantity
    if current_item.quantity == 0
      @items.delete(current_item)
    end
    current_item
  end

  def get_cart_items
    items = []
    @items.each do |item|
      items << item.details
    end
    items
  end

  def total_items
    @items.sum{ |item| item.quantity }
  end

  def empty?
    @items.empty?
  end

  def set_start_date(date)
    @start_date = date
    fix_due_date
  end

  def set_due_date(date)
    @due_date = date
    fix_due_date
  end

  def set_reserver_id(user_id)
    @reserver_id = user_id
  end

  def duration #in days
    @due_date - @start_date + 1
  end

  def reserver
    reserver = User.find(@reserver_id)
  end

  def fix_due_date
    if @start_date > @due_date
      @due_date = @start_date
    end
  end
  
  #Check if the user should renew models
  def renewable_reservations
    user_reservations = reserver.reservations
    renewable_reservations = []
    @items.each do |item|
      cart_item_count = item.quantity #renew up to this many of the item
      matching_reservations = user_reservations.each do |res|
        if (res.due_date.to_date == @start_date &&
           res.equipment_model_id == item.equipment_model_id &&
           cart_item_count > 0 &&
           res.is_eligible_for_renew?)
          renewable_reservations << res
          cart_item_count-= 1
        end
      end
    end
    return renewable_reservations
  end
  

  ## VALIDATIONS ##

  ## Date Validations

  # Checks all date-related validations
  def valid_dates?
    valid = true
    valid = false if !not_in_past?
    valid = false if !start_date_before_due_date?
    valid = false if !duration_allowed?
    valid = false if !available?
    valid
  end

  # Checks that neither start date nor due date are in the past
  def not_in_past?
    in_past = false
    if start_date < Date.today
      in_past = true
      errors.add(:start_date, "Start date cannot be before today")
    end
    if due_date < Date.today
      in_past = true
      errors.add(:due_date, "Due date cannot be before today")
    end
    return !in_past
  end

  # Checks that start date is before due date
  def start_date_before_due_date?
    if start_date > due_date
      errors.add(:due_date, "Due date cannot be before start date.")
      return false
    end
    return true
  end

  # Check that the duration is not longer than the maximum checkout length for any of the item
  def duration_allowed?
    is_too_long = false
    @items.each do |item|
      eq_model = item.equipment_model
      category = eq_model.category
      unless category.max_checkout_length.nil? || self.duration <= category.max_checkout_length
        errors.add(:items, "You can only check out " + eq_model.name + " for " + category.max_checkout_length.to_s + " days")
        is_too_long = true
      end
    end
    !is_too_long
  end

  # Check that all items are available
  def available?
    available = true
    return false if start_date.nil? or due_date.nil?
    @items.each do |item|
      if !item.available?(start_date..due_date)
        errors.add(:items, item.name + " is not available for all or part of the reservation length.")
        available = false
      end
    end
    available
  end

  ## Item validations
  #Check if the user should renew their 
  def no_renewable_models
    reservations_to_renew = renewable_reservations
    
    eq_model_names = reservations_to_renew.collect {|r| EquipmentModel.find(r.equipment_model_id).name}.uniq
    
    unless reservations_to_renew.empty?
      eq_model_names.each do |eq_model_name|
        errors.add(:items, reserver.name +" should renew " + eq_model_name)
      end
    end
  end
  
  #Check that the reserver does not exceeds the maximum number of any equipment models
  def allowable_number_equipment_model?
    too_many = false
    reserver_model_counts = reserver.checked_out_models
    @items.each do |item|
      #If the reserver has none of the model checked out, count = 0
      eq_model = item.equipment_model
      curr_model_count = reserver_model_counts[eq_model.id]
      curr_model_count ||= 0
      # This thing with unrestricted makes me upset
      if eq_model.maximum_per_user != "unrestricted"
        unless eq_model.maximum_per_user >= item.quantity + curr_model_count
          errors.add(:items, reserver.name + " has too many of " + eq_model.name)
          too_many = true
{'fraction_non_alphanumeric': 0.07247822931785196, 'fraction_numerical': 0.00090711175616836, 'mean_word_length': 2.9095744680851063, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4848161', 'n_tokens_mistral': 3654, 'n_tokens_neox': 3478, 'n_words': 975}