class GuidanceService
attr_accessor :plan
attr_accessor :guidance_groups
def initialize(plan)
@plan = plan
@guidance_groups = plan.guidance_groups.where(published: true)
end
# 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
if !defined?(@orgs)
@orgs = []
org_found = lambda{ |orgs, org| return orgs.find{ |lookup_org| lookup_org.id == org.id }.present? }
orgs_from_annotations.each{ |org| @orgs << org unless org_found.call(@orgs, org) }
orgs_from_guidance_groups.each{ |org| @orgs << org unless org_found.call(@orgs, org) }
end
return @orgs
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) {|found, o| found || guidance_annotations?(org: o, question: question)}
if !anno
return orgs.reduce(anno) {|found, o| found || guidance_groups_by_theme?(org: o, question: question)}
else
return anno
end
else # question.nil?
return hashified_annotations? || hashified_guidance_groups?
end
end
return guidance_annotations?(org: org, question: question) ||
guidance_groups_by_theme?(org: org, question: question)
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
return 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)
return hashified_annotations[org].find{ |annotation| (annotation.question_id == question.id) && (annotation.type == "guidance")}.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)
return hashified_guidance_groups[org].each_key.reduce({}) do |acc, gg|
filtered_gg = hashified_guidance_groups[org][gg].each_key.reduce({}) do |acc, theme|
acc[theme] = hashified_guidance_groups[org][gg][theme] if question.themes.include?(theme)
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)
return hashified_annotations[org].select{ |annotation| (annotation.question_id == question.id) && (annotation.type == "guidance")}
end
private
def orgs_from_guidance_groups
if !defined?(@orgs_from_guidance_groups)
@orgs_from_guidance_groups = Org.joins(:guidance_groups).where("guidance_groups.id": guidance_groups.map(&:id)).distinct("orgs.id")
end
return @orgs_from_guidance_groups
end
def orgs_from_annotations
if !defined?(@orgs_from_annotations)
@orgs_from_annotations = []
@orgs_from_annotations << Template.find_by(family_id: plan.template.customization_of).org if plan.template.customization_of.present?
@orgs_from_annotations << plan.template.org
end
return @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
return result.present?
end
def hashified_annotations
@hashified_annotations ||= hashify_annotations
end
def hashified_annotations?
return 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
return orgs_from_guidance_groups.reduce({}) do |acc, org|
org_guidance_groups = hashified_guidances.each_key.select{ |gg| gg.org_id == org.id }
acc[org] = org_guidance_groups.reduce({}){ |acc, gg| acc[gg] = hashified_guidances[gg]; acc }
acc
end
end
# Hashifies guidances from a collection of guidance_groups passed into the following structure:
# { guidance_group: { theme: [guidance, ...], ... }, ... }
def hashify_guidances
return 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
return 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