# frozen_string_literal: true
# Private: Takes a list of Sections and sorts them in the correct display order based on
# the number, modifiable, and id attributes.
#
# Examples:
#
# SectionSorter.new(*@phase.sections).sort! # => Array of sorted Sections
#
#
class SectionSorter
##
# Access the array of Sections
#
# Returns Array
attr_accessor :sections
##
# Initialize a new SectionSorter
#
# sections - A set of Section records
#
def initialize(*sections)
@sections = sections
end
# Re-order {#sections} into the correct order.
#
# Returns Array of Sections
def sort!
if all_sections_unmodifiable?
sort_as_homogenous_group
elsif all_sections_modifiable?
sort_as_homogenous_group
else
# If there are duplicates in the #1 position
if duplicate_number_values.include?(1)
mod_1 = sections.select { |section| section.modifiable? && section.number == 1 }
# There should only be, if any, one prefixed modifiable Section
prefix = mod_1.shift
# In the off-chance that there is more than one prefix Section, stick them
# after the unmodifiable block
erratic = mod_1
# Collect the unmodifiable Section ids in the order the should be displayed
unmodifiable = sections
.select { |section| section.unmodifiable? }
.sort_by { |section| [section.number, section.id] }
# Then any additional Sections that come after the main block...
modifiable = sections
.select { |section| section.modifiable? && section.number > 1 }
.sort_by { |section| [section.number, section.id] }
# Create one Array with all of the ids in the correct order.
self.sections = [prefix] + unmodifiable + erratic + modifiable
else
prefix = sections.detect { |s| s.modifiable? && s.number == 1 }
remaining_sections = sections - [prefix]
unmodifiable = remaining_sections.select(&:unmodifiable?)
.sort_by { |s| [s.number, s.id] }
modifiable = remaining_sections.select(&:modifiable?)
.sort_by { |s| [s.number, s.id] }
self.sections = [prefix] + unmodifiable + modifiable
end
sections.uniq.compact
end
end
private
def modifiable_values
@modifiable_values ||= sections.map(&:modifiable?).uniq
end
def number_values_with_count
@number_values_with_count ||= begin
hash = Hash.new { |hash, key| hash[key] = 0 }
sections.map(&:number).each { |number| hash[number] += 1 }
hash
end
end
def duplicate_number_values
@duplicate_number_values ||= number_values_with_count.select do |number, count|
count > 1
end.keys
end
def all_sections_unmodifiable?
modifiable_values == [false]
end
def all_sections_modifiable?
modifiable_values == [true]
end
def sort_as_homogenous_group
sections.sort_by { |section| [section.number, section.id] }
end
end