class Infobar::Display

def self.default_style

def self.default_style
  {
    done_fill:     ?░,
    done_fg_color: 22,
    done_bg_color: 40,
    todo_fill:     ' ',
    todo_fg_color: 40,
    todo_bg_color: 22,
  }
end

def as_styles

def as_styles
  defined? @as_styles or self.as_styles = {}
  @as_styles
end

def as_styles=(styles)

def as_styles=(styles)
  @as_styles = styles.to_h.symbolize_keys_recursive
  @as_styles.default_proc = proc { style.subhash(/\Adone_/) }
end

def carriage_return

def carriage_return
  output << ?\r
  self
end

def clear

def clear
  carriage_return
  output << ' ' * columns
  carriage_return
  @frequency.reset
  self
end

def columns

def columns
  Tins::Terminal.columns
end

def frequency=(duration)

def frequency=(duration)
  @frequency = Infobar::Frequency.new(duration)
end

def initialize

def initialize
  self.output    = $stdout
  self.input     = $stdin
  self.frequency = 0.05
  @show          = true
  @style         = self.class.default_style.dup
end

def input

def input
  if show?
    @input
  else
    NULL
  end
end

def layout_bar(message, counter)

def layout_bar(message, counter)
  cols = columns
  todo = message.to_str.center cols, replace_character
  if counter.total > 0
    max_done_length = counter.progressed * cols
    total_done = 0
    counter.as.each_with_index do |(name, count), i|
      style_name = name.to_s.to_sym
      done_fill     = as_styles[style_name].fetch(:done_fill) { @style[:done_fill] }
      done_fg_color = as_styles[style_name].fetch(:done_fg_color) { @style[:done_fg_color] }
      done_bg_color = as_styles[style_name].fetch(:done_bg_color) { @style[:done_bg_color] }
      as_progressed = count / counter.total.to_f
      as_done = as_progressed * cols
      total_done += as_done
      if counter.done? && i == counter.as.size - 1 && total_done <= max_done_length
        done = todo.dup
        todo = ''
      else
        done = todo.slice!(0, as_done)
      end
      done.gsub!(replace_character, done_fill[0])
      output << color(done_fg_color, on_color(done_bg_color, done))
    end
  end
  if todo.present?
    todo.gsub!(replace_character, @style[:todo_fill][0])
    output << color(@style[:todo_fg_color], on_color(@style[:todo_bg_color], todo))
  end
end

def newline

def newline
  output << $/
  self
end

def output

def output
  if show?
    @output
  else
    NULL
  end
end

def output=(io)

def output=(io)
  @output = io
  @output.ask_and_send(:respond_to?, :sync=, true)
end

def replace_character

def replace_character
  "\uFFFC"
end

def reset(clear: true)

def reset(clear: true)
  clear && self.clear
  self.style = self.class.default_style
  self
end

def show?

def show?
  @show
end

def style=(new_style)

def style=(new_style)
  @style.update(**new_style)
end

def update(message: nil, counter: nil, force: false, **options)

def update(message: nil, counter: nil, force: false, **options)
  force and @frequency.reset
  @frequency.call do
    carriage_return
    self.style = options
    message = infobar.convert_to_message(message)
    layout_bar(message, counter)
  end
end