module Birdwatcher
  module Util
    HUMAN_PREFIXES = %w(TB GB MB KB B).freeze

    def self.time_ago_in_words(time)
      return "a very very long time ago" if time.year < 1800
      secs = Time.now - time
      return "just now" if secs > -1 && secs < 1
      return "" if secs <= -1
      pair = ago_in_words_pair(secs)
      ary = ago_in_words_singularize(pair)
      ary.size == 0 ? "" : ary.join(" and ") << " ago"
    end

    def self.ago_in_words_pair(secs)
      [[60, :seconds], [60, :minutes], [24, :hours], [100_000, :days]].map{ |count, name|
        if secs > 0
          secs, n = secs.divmod(count)
          "#{n.to_i} #{name}"
        end
      }.compact.reverse[0..1]
    end

    def self.ago_in_words_singularize(pair)
      if pair.size == 1
        pair.map! {|part| part[0, 2].to_i == 1 ? part.chomp("s") : part }
      else
        pair.map! {|part| part[0, 2].to_i == 1 ? part.chomp("s") : part[0, 2].to_i == 0 ? nil : part }
      end
      pair.compact
    end

    def self.parse_time(time)
      ::Chronic.parse(time)
    end

    def self.strip_html(string)
      string.to_s.gsub(/<\/?[^>]*>/, "")
    end

    def self.strip_control_characters(string)
      string = string.to_s.uncolorize
      string.split("").delete_if do |char|
        char.ascii_only? and (char.ord < 32 or char.ord == 127)
      end.join("")
    end

    def self.escape_html(string)
      CGI.escapeHTML(string.to_s)
    end

    def self.unescape_html(string)
      CGI.unescapeHTML(string.to_s)
    end

    def self.pluralize(count, singular, plural)
      count == 1 ? "1 #{singular}" : "#{count} #{plural}"
    end

    def self.excerpt(text, max_length, omission = "...")
      text = text.gsub(/\s/, " ").split(" ").map(&:strip).join(" ")
      return text if text.length < max_length
      text[0..max_length] + omission
    end

    def self.number_to_human_size(number)
      s = number.to_f
      i = HUMAN_PREFIXES.length - 1
      while s > 512 && i > 0
        i -= 1
        s /= 1024
      end
      ((s > 9 || s.modulo(1) < 0.1 ? "%d" : "%.1f") % s) + HUMAN_PREFIXES[i]
    end

    def self.suppress_output(&block)
      original_stdout = $stdout
      $stdout = fake = StringIO.new
      begin
        yield
      ensure
        $stdout = original_stdout
      end
      fake.string
    end

    def self.suppress_warnings(&block)
      warn_level = $VERBOSE
      $VERBOSE = nil
      result = block.call
      $VERBOSE = warn_level
      result
    end
  end
end
