# frozen_string_literal: true
class GuidancePresenter
attr_accessor :plan
attr_accessor :guidance_groups
def initialize(plan)
@plan = plan
@guidance_groups = plan.guidance_groups.where(published: true)
end
def any?(org: nil, question: nil)
if org.nil?
if question.present?
# check each annotation/guidance group for a response to this question
# Would be nice not to have to crawl the entire list each time we want to know
# this
anno = orgs.reduce(false) do |found, o|
found || guidance_annotations?(org: o, question: question)
end
if !anno
return orgs.reduce(anno) do |found, o|
found || guidance_groups_by_theme?(org: o, question: question)
end
else
return anno
end
else # question.nil?
return hashified_annotations? || hashified_guidance_groups?
end
end
guidance_annotations?(org: org, question: question) ||
guidance_groups_by_theme?(org: org, question: question)
end
# filters through the orgs with annotations and guidance groups to create a
# set of tabs with display names and any guidance/annotations to show
#
# question - The question to which guidance pretains
#
# Returns an array of tab hashes. These
def tablist(question)
# start with orgs
# filter into hash with annotation_presence, main_group presence, and
display_tabs = []
orgs.each do |org|
annotations = guidance_annotations(org: org, question: question)
groups = guidance_groups_by_theme(org: org, question: question)
main_groups = groups.select { |group| group.optional_subset == false }
subsets = groups.reject { |group| group.optional_subset == false }
if annotations.present? || main_groups.present? # annotations and main group
# Tab with org.abbreviation
display_tabs << { name: org.abbreviation, groups: main_groups,
annotations: annotations }
end
if subsets.present?
subsets.each_pair do |group, theme|
display_tabs << { name: group.name.truncate(15), groups: { group => theme } }
end
end
end
display_tabs
end
private
# Returns an Array of orgs according to the guidance related to plan
# Note the Array is sorted in the following order:
# First funder org (if the template from the plan is a customization of another)
# Second template owner's org
# The orgs from every guidance group selected for this plan
def orgs
return @orgs if defined?(@orgs)
@orgs = []
orgs_from_annotations.each { |org| @orgs << org unless org_found(@orgs, org) }
orgs_from_guidance_groups.each { |org| @orgs << org unless org_found(@orgs, org) }
@orgs
end
def org_found(orgs, org)
orgs.find do |lookup_org|
lookup_org.id == org.id
end.present?
end
# Returns true if exists any guidance_group applicable to the org and question passed
def guidance_groups_by_theme?(org: nil, question: nil)
return false unless question.respond_to?(:themes)
return false unless hashified_guidance_groups.has_key?(org)
result = guidance_groups_by_theme(org: org, question: question)
.detect do |gg, theme_hash|
if theme_hash.present?
theme_hash.detect { |theme, guidances| guidances.present? }
else
false
end
end
result.present?
end
# Returns true if exists any annotation applicable to the org and question passed
def guidance_annotations?(org: nil, question: nil)
return false unless question.respond_to?(:id)
return false unless hashified_annotations.has_key?(org)
hashified_annotations[org].find do |annotation|
(annotation.question_id == question.id) && (annotation.type == "guidance")
end.present?
end
# Returns a hash of guidance groups for an org and question passed with the following
# structure:
# { guidance_group: { theme: [guidance, ...], ... }, ... }
def guidance_groups_by_theme(org: nil, question: nil)
raise ArgumentError unless question.respond_to?(:themes)
question = Question.includes(:themes).find(question.id)
return {} unless hashified_guidance_groups.has_key?(org)
hashified_guidance_groups[org].each_key.reduce({}) do |acc, gg|
filtered_gg = hashified_guidance_groups[org][gg].each_key.reduce({}) do |acc, theme|
if question.themes.include?(theme)
acc[theme] = hashified_guidance_groups[org][gg][theme]
end
acc
end
acc[gg] = filtered_gg if filtered_gg.present?
acc
end
end
# Returns a collection of annotations (type guidance) for an org and question passed
def guidance_annotations(org: nil, question: nil)
raise ArgumentError unless question.respond_to?(:id)
return [] unless hashified_annotations.has_key?(org)
hashified_annotations[org].select do |annotation|
(annotation.question_id == question.id) && (annotation.type == "guidance")
end
end
def orgs_from_guidance_groups
return @orgs_from_guidance_groups if defined?(@orgs_from_guidance_groups)
@orgs_from_guidance_groups = Org.joins(:guidance_groups)
.where(guidance_groups: { id: guidance_groups.ids })
.distinct("orgs.id")
@orgs_from_guidance_groups
end
def orgs_from_annotations
return @orgs_from_annotations if defined?(@orgs_from_annotations)
@orgs_from_annotations = []
if plan.template.customization_of.present?
family_id = plan.template.customization_of
@orgs_from_annotations << Template.find_by(family_id: family_id).org
end
@orgs_from_annotations << plan.template.org
@orgs_from_annotations
end
def hashified_guidance_groups
@hashified_guidance_groups ||= hashify_guidance_groups
end
def hashified_guidance_groups?
result = hashified_guidance_groups.detect do |org, gg_hash|
if gg_hash.present?
gg_hash.detect do |gg, theme_hash|
if theme_hash.present?
theme_hash.detect { |theme, guidances| guidances.present? }
else
false
end
end
else
false
end
end
result.present?
end
def hashified_annotations
@hashified_annotations ||= hashify_annotations
end
def hashified_annotations?
hashified_annotations.detect { |org, annotations| annotations.present? }.present?
end
# Hashifies guidance groups for a plan according to the distinct orgs into the
# following structure:
# { org: { guidance_group: { theme: [guidance, ...], ... }, ... }, ... }
def hashify_guidance_groups
hashified_guidances = hashify_guidances
orgs_from_guidance_groups.reduce({}) do |acc, org|
org_guidance_groups = hashified_guidances.each_key.select do |gg|
gg.org_id == org.id
end
acc[org] = org_guidance_groups.reduce({}) do |acc, gg|
acc[gg] = hashified_guidances[gg]
acc
end
acc
end
end
# Hashifies guidances from a collection of guidance_groups passed into the following
# structure:
# { guidance_group: { theme: [guidance, ...], ... }, ... }
def hashify_guidances
guidance_groups.reduce({}) do |acc, gg|
themes = Theme.includes(:guidances)
.joins(:guidances)
.merge(Guidance.where(guidance_group_id: gg.id, published: true))
acc[gg] = themes.reduce({}) do |acc, theme|
acc[theme] = theme.guidances
acc
end
acc
end
end
def hashify_annotations
orgs_from_annotations.reduce({}) do |acc, org|
annotations = Annotation.where(org_id: org.id,
question_id: plan.template.question_ids)
acc[org] = annotations.select { |annotation| annotation.org_id = org.id }
acc
end
end
end