concord-consortium/rigse

View on GitHub
rails/app/services/navigation_service.rb

Summary

Maintainability
A
1 hr
Test Coverage
class NavItem
  attr_accessor :id
  attr_accessor :label
  attr_accessor :url
  attr_accessor :type
  attr_accessor :onClick
  attr_accessor :popOut
  attr_accessor :sort
  attr_accessor :selected
  attr_accessor :iconName
  attr_accessor :children

  def defaults
    {
      type: NavigationService::LINK_TYPE,
      sort: NavigationService::DEFAULT_SORT
    }
  end

  def initialize(props)
    attributes = self.defaults.merge(props)
    attributes.each { |k,v| instance_variable_set("@#{k}", v) }
  end

  def merge(nav_item)
    props = nav_item.to_h
    props.delete(:children)
    props.each { |k,v| instance_variable_set("@#{k}", v) }
  end
  
  def to_h
    hash = instance_variables.each_with_object({}) do |var, hash|
      if instance_variable_get(var)
        v = instance_variable_get(var)
        hash[var.to_s.delete("@").to_sym] = v
      end
    end
    if @children
      hash[:children] = @children.map { |c| c.to_h }
    end
    hash
  end

end

class NavigationService
  ROOT_SECTION = "__ROOT__"
  ROOT_PATH = "/"
  DEFAULT_SORT = 5
  SECTION_TYPE = "SECTION"
  LINK_TYPE = "LINK"
  attr_accessor :name
  attr_accessor :greeting
  attr_accessor :selected_section
  attr_accessor :links
  attr_accessor :sections

  def initialize(viewHelper, params={})
    @user = params[:user]
    @greeting = params[:greeting] || default_greeting
    @request_path = params[:request_path] || ROOT_PATH
    @selected_section = params[:selected_section] || ROOT_SECTION
    @name = params[:name] || default_name
    @help = params[:help] || default_help
    @root = NavItem.new ({
      id: ROOT_SECTION,
      label: "",
      type: SECTION_TYPE,
      children: []
    })
    @sections = {
      ROOT_SECTION => @root
    }
    @links = []
  end

  def default_name
    "guest"
  end

  def default_greeting
    "Welcome,"
  end

  def default_help
    {
      label: "help",
      url: "/help",
      id: "/help",
      type: LINK_TYPE,
      popOut: true
    }
  end

  def parent_id_for(id)
    parent_paths =  id.split("/")
    if parent_paths.size > 0
      parent_id = id.split("/")[0...-1].join("/")
    end
    if(parent_id.blank?)
      parent_id = ROOT_SECTION
    end
    parent_id
  end

  def parent_for(id)
    return @sections[parent_id_for(id)]
  end

  def remove_item(id)
    parent = parent_for(id)
    if parent
      parent.children.reject! {|i| i.id == id}
      parent.children.sort_by! { |a| a.sort }
    end
    @sections.delete(id)
    @links.delete(id)
  end

  def add_link(item)
    if link = @links.find {|l| l.id == item.id}
      link.merge(item)
    else
      link = item
      @links.push item
    end
    parent = parent_for(link.id)
    parent_id = parent_id_for(link.id)
    if !parent
      parent = add_item({type: SECTION_TYPE, id: parent_id})
    end
    unless parent.children.find { |c| c.id == link.id }
      parent.children.push link
      parent.children.sort_by! { |a| a.sort ||0}
    end
    return link
  end

  def add_section(item)
    if section = @sections[item.id]
      section.merge(item)
    else
      section = item
      section.children ||= []
      section.label ||= item.id.split("/").last.capitalize
      @sections[item.id] = item
    end
    parent = parent_for(section.id)
    parent_id = parent_id_for(section.id)
    if !parent
      parent = add_item({type: SECTION_TYPE, id: parent_id})
    end
    unless parent.children.find { |c| c.id == section.id }
      parent.children.push section
    end
    return section
  end
  # id: "/",
  # label: ""
  # sort: 1,
  # type: "section",
  # children: []
  def add_item(item_spec)
    item = NavItem.new(item_spec)
    unless(item.type)
      item.type = item.url ? LINK_TYPE : SECTION_TYPE
    end
    case item.type
    when LINK_TYPE
      add_link(item)
    when SECTION_TYPE
      add_section(item)
    end
  end

  def item_to_hash(item)
    return_hash = item.to_h
    if item.children
      return_hash[:children] = item.children.map { |c| item_to_hash(c) }
    end
    if item.url
      return_hash[:url] = item.url
    end
    return_hash
  end

  def to_hash
    {
      name: @name,
      help: @help,
      greeting: @greeting,
      selected_section: @selected_section,
      request_path: @request_path,
      links: @root.children.map { |section| item_to_hash(section) }
    }
  end

  def update_selection
    if @request_path == ROOT_PATH
      @selected_section = ROOT_SECTION
    end
    @links.each do |link|
      if @request_path =~ %r[#{link.url}$]
        link.selected = true
        @selected_section = link.id || ROOT_SECTION
      end
    end
  end

  def to_json
    to_hash.to_json
  end

end