class RdbDashboard
  attr_reader :project, :projects, :project_ids, :options

  VIEW_MODES = [ :card, :compact ]

  def initialize(project, opts, params = nil)
    @project     = project

    @options = { :filters => {} }

    options.merge! default_options
    options.merge! opts

    if params[:include_subprojects]
      options[:include_subprojects] = (params[:include_subprojects] == 'true')
    end

    reload_projects!

    # Init board in sub class
    init if respond_to? :init

    filters.each do |id, filter|
      filter.values = options[:filters][filter.id] if options[:filters][filter.id]
    end
  end

  def reload_projects!
    if options[:include_subprojects]
      @project_ids = subproject_ids([project.id])
    else
      @project_ids = [project.id]
    end
    @projects = Project.where :id => project_ids
  end

  def subproject_ids(ids)
    ids.inject(ids.dup) do |ids, id|
      ids + subproject_ids(Project.where(:parent_id => id).pluck(:id))
    end.uniq
  end

  def setup(params)
    # Update issue view mode
    options[:view] = params[:view].to_sym if params[:view] and RdbDashboard::VIEW_MODES.include? params[:view].to_sym
  end

  def update(params)
    if params[:reset]
      filters.each do |id, filter|
        filter.values = filter.default_values
      end
      options[:filters] = {}
    else
      filters.each do |id, filter|
        filter.update params if params
        options[:filters][filter.id] = filter.values
      end
    end
  end

  def default_options
    { :view => :card }
  end

  def issue_view
    options[:view]
  end

  def issues
    filter(Issue.where(:project_id => project_ids))
  end

  def versions
    Version.where :project_id => project_ids
  end

  def issue_categories
    IssueCategory.where :project_id => project_ids
  end

  def trackers
    Tracker.where(:id => projects.map{|p| p.trackers.pluck(:id)}.uniq)
  end

  def assignees
    Principal.where :id => Member.where(:id=> projects.map{|p| p.member_principals.map(&:id)}.uniq).pluck(:user_id)
  end

  def members
    Member.where(:id => projects.map{|p| p.members.map(&:id)}.uniq)
  end

  def member_principals
    Member.where(:id=> projects.map{|p| p.member_principals.map(&:id)}.uniq)
  end

  def memberships
    Member.where(:id => projects.map{|p| p.memberships.pluck(:id) }.uniq)
  end

  def filter(issues)
    issues = filters.inject(issues) {|issues, filter| filter[1].scope issues }
    filters.inject(issues) {|issues, filter| filter[1].filter issues }
  end

  def abbreviation(project_id)
    project_id = project.id unless project_id

    @abbreviations ||= []
    @abbreviations[project_id] ||= begin
      abbreviation = '#'
      Project.find(project_id).custom_field_values.each do |f|
        abbreviation = f.to_s + '-' if f.to_s.length > 0 and f.custom_field.read_attribute(:name).downcase == 'abbreviation'
      end
      abbreviation
    end
  end

  def id
    self.class.board_type
  end

  def name
    I18n.t :"rdb_#{id}"
  end

  def add_filter(filter)
    filter.board = self
    filters[filter.id.to_s] = filter
  end

  def add_group(group)
    group.board = self
    group_list << group
    groups[group.id.to_s] = group
  end

  def editable?(str = nil)
    @editable ||= !!User.current.allowed_to?(:edit_issues, project)
    str ? (@editable ? str : nil) : @editable
  end

  def filters; @filters ||= HashWithIndifferentAccess.new end
  def groups; @groups ||= HashWithIndifferentAccess.new end
  def group_list; @group_list ||= [] end

  class << self
    def board_type
      @board_type ||= name.downcase.to_s.gsub(/^rdb/, '').to_sym
    end
  end
end
