module Aruba
  # The ANSIColor module can be used for namespacing and mixed into your own
  # classes.
  module AnsiColor
    # :stopdoc:
    ATTRIBUTES = [
      [ :clear        ,   0 ],
      [ :reset        ,   0 ],     # synonym for :clear
      [ :bold         ,   1 ],
      [ :dark         ,   2 ],
      [ :italic       ,   3 ],     # not widely implemented
      [ :underline    ,   4 ],
      [ :underscore   ,   4 ],     # synonym for :underline
      [ :blink        ,   5 ],
      [ :rapid_blink  ,   6 ],     # not widely implemented
      [ :negative     ,   7 ],     # no reverse because of String#reverse
      [ :concealed    ,   8 ],
      [ :strikethrough,   9 ],     # not widely implemented
      [ :black        ,  30 ],
      [ :red          ,  31 ],
      [ :green        ,  32 ],
      [ :yellow       ,  33 ],
      [ :blue         ,  34 ],
      [ :magenta      ,  35 ],
      [ :cyan         ,  36 ],
      [ :white        ,  37 ],
      [ :on_black     ,  40 ],
      [ :on_red       ,  41 ],
      [ :on_green     ,  42 ],
      [ :on_yellow    ,  43 ],
      [ :on_blue      ,  44 ],
      [ :on_magenta   ,  45 ],
      [ :on_cyan      ,  46 ],
      [ :on_white     ,  47 ]
    ].freeze

    ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
    # :startdoc:

    # Returns true, if the coloring function of this module
    # is switched on, false otherwise.
    def self.coloring?
      @coloring
    end

    # Turns the coloring on or off globally, so you can easily do
    # this for example:
    #  Cucumber::Term::ANSIColor::coloring = STDOUT.isatty
    def self.coloring=(val)
      @coloring = val
    end
    self.coloring = true

    ATTRIBUTES.each do |c, v|
      define_method(c) do |string|
        result = ''
        result << "\e[#{v}m" if Aruba::AnsiColor.coloring?
        if block_given?
          result << yield
        elsif string
          result << string
        elsif respond_to?(:to_str)
          result << to_str
        else
          return result #only switch on
        end
        result << "\e[0m" if Aruba::AnsiColor.coloring?
        result
      end
    end

    # Regular expression that is used to scan for ANSI-sequences while
    # uncoloring strings.
    COLORED_REGEXP = /\e\[(?:[34][0-7]|[0-9])?m/

    def self.included(klass)
      if klass == String
        ATTRIBUTES.delete(:clear)
        ATTRIBUTE_NAMES.delete(:clear)
      end
    end

    # Returns an uncolored version of the string, that is all
    # ANSI-sequences are stripped from the string.
    def uncolored(string = nil) # :yields:
      if block_given?
        yield.gsub(COLORED_REGEXP, '')
      elsif string
        string.gsub(COLORED_REGEXP, '')
      elsif respond_to?(:to_str)
        to_str.gsub(COLORED_REGEXP, '')
      else
        ''
      end
    end

    # Returns an array of all Aruba::Platforms::AnsiColor attributes as symbols.
    def attributes
      ATTRIBUTE_NAMES
    end
  end
end

module Aruba
  class Colorizer
    include Aruba::AnsiColor
  end
end
