#!/usr/bin/ruby -w
# Encoding: UTF-8
# frozen_string_literal: true
# =========================================================================== #
# === Colours::RGB
#
# The Colours::RBG class can be used to convert a RGB value into its
# corresponding hex format. However had these days it is not as widely
# used anymore within the colours project, excluding those cases where
# this is indeed necessary.
#
# Code in this .rb file here in general can be used for RGB-related
# functionality. A good example for what can be done with this is to
# convert a HTML colour, such as "slateblue", into its RGB
# representation.
# =========================================================================== #
# require 'colours/rgb/rgb.rb'
# =========================================================================== #
require 'colours/base/base.rb'

module Colours

class RGB < Base # === Colours::RGB

  require 'colours/html_colours/hash_html_colours.rb'

  # ========================================================================= #
  # === DEFAULT_VALUES
  # ========================================================================= #
  DEFAULT_VALUES = [255, 0, 0]

  # ========================================================================= #
  # === DEFAULT_VALUE
  # ========================================================================= #
  DEFAULT_VALUE = 0

  # ========================================================================= #
  # === initialize
  #
  # Keep in mind that the first argument could be something like:
  #
  #   [106, 90, 205]
  #
  # In that case, we need to handle this situation differently.
  # ========================================================================= #
  def initialize(
      original_input = ARGV,
      run_already    = true
    )
    reset
    set_commandline_arguments(
      original_input
    )
    run if run_already
  end

  # ========================================================================= #
  # === reset                                                     (reset tag)
  # ========================================================================= #
  def reset
    # ======================================================================= #
    # === @hexstring
    # ======================================================================= #
    @hexstring = nil
    # ======================================================================= #
    # Use default values for RGB - all 0.
    # ======================================================================= #
    @r = 0
    @g = 0
    @b = 0
  end

  # ========================================================================= #
  # === set_rgb
  # ========================================================================= #
  def set_rgb(r,g,b)
    set_r(r)
    set_g(g)
    set_b(b)
  end

  # ========================================================================= #
  # === set_r
  # ========================================================================= #
  def set_r(i = DEFAULT_VALUES[0])
    i = i.to_i
    check_validity_of(i)
    @r = i
  end

  # ========================================================================= #
  # === set_g
  # ========================================================================= #
  def set_g(i = nil)
    i = DEFAULT_VALUE if i.nil?
    i = i.to_i
    check_validity_of(i)
    @g = i
  end

  # ========================================================================= #
  # === set_b
  # ========================================================================= #
  def set_b(i = nil)
    i = DEFAULT_VALUE if i.nil?
    i = i.to_i
    check_validity_of(i)
    @b = i
  end

  # ========================================================================= #
  # === lighten
  #
  # This method will lighten up a colour.
  #
  # Usage example:
  #
  #   Colours::RgbToHex.new('#ffffff').lighten # => "#232323"
  #
  # ========================================================================= #
  def lighten(i = 35)
    add(i) # Hardcoded to add +35 to each of R, G and B.
  end

  # ========================================================================= #
  # === check_validity_of
  #
  # We check if the input is higher than 255, in which case we give back
  # an ArgumentError.
  # ========================================================================= #
  def check_validity_of(i)
    if i.to_i > 255
      raise ArgumentError,
        'Error: RGB values can not be higher than 255.' 
    end
  end

  # ========================================================================= #
  # === do_the_conversion
  # ========================================================================= #
  def do_the_conversion
    @hexstring = '#%02x%02x%02x'.upcase % rgb()
    return @hexstring
  end; alias update_hexstring do_the_conversion # === update_hexstring

  # ========================================================================= #
  # === b?
  # ========================================================================= #
  def b?
    @b
  end; alias b b? # === b

  # ========================================================================= #
  # === g?
  # ========================================================================= #
  def g?
    @g
  end; alias g g? # === g

  # ========================================================================= #
  # === r?
  # ========================================================================= #
  def r?
    @r
  end; alias r r? # === r

  # ========================================================================= #
  # === determine_rgb_values_from_the_commandline_arguments
  # ========================================================================= #
  def determine_rgb_values_from_the_commandline_arguments(
      _ = commandline_arguments?
    )
    first = _.first
    if first.is_? Array
      set_r(first[0])
      set_g(first[1])
      set_b(first[2])
    end
  end

  # ========================================================================= #
  # === rgb
  # ========================================================================= #
  def rgb
    [ @r, @g, @b ]
  end

  # ========================================================================= #
  # === hexstring?
  # ========================================================================= #
  def hexstring?
    @hexstring
  end; alias hexstring hexstring? # === hexstring

  # ========================================================================= #
  # === add
  #
  # This method can be used to lighten a R,G,B colour in general. We
  # also use another method for this, though, called .lighten().
  # ========================================================================= #
  def add(i = 1)
    i = i.to_i
    @r += i
    @g += i
    @b += i
    update_hexstring
  end

  # ========================================================================= #
  # === run
  # ========================================================================= #
  def run
    determine_rgb_values_from_the_commandline_arguments
    do_the_conversion
  end

  # ========================================================================= #
  # === Colours::RgbToHex[]
  #
  # Easier access to the conversion facility.
  #
  # Usage example:
  #
  #   Colours::RgbToHex[22,33,44] # => "#16212C"
  #
  # ========================================================================= #
  def self.[](
      r = 255,
      g =   0,
      b =   0
    )
    _ = new(r,g,b)
    return '#%02x%02x%02x'.upcase % _.rgb
  end

end

# =========================================================================== #
# === Colours.convert_this_rgb_value_into_a_html_colour
#
# This method will convert a given RGB value (input assumed to be an Array)
# into the corresponding HTML colour.
#
# Note that the first input argument, called `i`, can also be read as
# R (aka red). So the whole input line becomes "r, g, b", which makes
# this quite trivial to remember.
# =========================================================================== #
def self.convert_this_rgb_value_into_a_html_colour(i, g = nil, b = nil)
  if i.is_a?(Numeric) and g and b
    i = [i, g, b] # Re-compose the given input in this case, as only one Array was provided.
  end
  _ = ::Colours.hash_html_colours?
  possible_matches = _.select {|key, inner_array|
    (i[0] == inner_array[0]) and
    (i[1] == inner_array[1]) and
    (i[2] == inner_array[2])
  }
  possible_matches.keys.first
end

# =========================================================================== #
# === Colours.convert_this_html_colour_into_an_array_of_rgb_values
#
# This method will take a String as input, a HTML colour such as 'slateblue',
# and proceed to return an Array containing three entries (R, G, B) as
# its value.
#
# For RGB colours we specify the code like this:
#
#   38;2;$R;$G;$B
#
# Thus:
#
#   \e[38;2;R;G;Bm
#
# =========================================================================== #
def self.convert_this_html_colour_into_an_array_of_rgb_values(
    html_colour = :random
  )
  require 'colours/html_colours/random_html_colour.rb'
  case html_colour
  # ========================================================================= #
  # === :random
  # ========================================================================= #
  when :random
    html_colour = return_random_html_colour
  end
  if ::Colours.include_this_html_colour? html_colour
    pointer = ::Colours.hash_html_colours?[html_colour.to_s] # <- Must be an input-String.
    [ pointer[0], pointer[1], pointer[2] ] # <- Build the Array here.
  else # else it is not included
    nil
  end
end; self.instance_eval { alias convert_html_colour_to_rgb_array convert_this_html_colour_into_an_array_of_rgb_values } # === Colours.convert_html_colour_to_rgb_array

# =========================================================================== #
# === Colours.return_random_rgb
# =========================================================================== #
def self.return_random_rgb
  [random_value?, random_value?, random_value?]
end; self.instance_eval { alias return_rgb_as_array return_random_rgb } # === Colours.return_rgb_as_array

# =========================================================================== #
# === return_random_rgb
# =========================================================================== #
def return_random_rgb
  Colours.return_random_rgb
end; alias return_rgb_as_array return_random_rgb # === return_rgb_as_array

# =========================================================================== #
# === rgb_value_as_escape_code_string
# =========================================================================== #
def rgb_value_as_escape_code_string(
    array = [
      random_value?,
      random_value?,
      random_value?
    ],
    g = nil,
    b = nil
  )
end; alias build_this_rgb_string rgb_value_as_escape_code_string # === build_this_rgb_string
     alias rgb_value_as_string   rgb_value_as_escape_code_string # === rgb_value_as_string
     alias rgb                   rgb_value_as_escape_code_string # === rgb
     alias rgb_format            rgb_value_as_escape_code_string # === rgb_format
     alias rgb_as_string         rgb_value_as_escape_code_string # === rgb_as_string
     alias colour_to_rgb_value   rgb_value_as_escape_code_string # === colour_to_rgb_value

# =========================================================================== #
# === convert_this_rgb_value_to_that_hexadecimal_representation
# =========================================================================== #
def convert_this_rgb_value_to_that_hexadecimal_representation(
    r, g = nil, b = nil
  )
  Colours.convert_this_rgb_value_to_that_hexadecimal_representation(r, g, b)
end; alias rgb_to_hex convert_this_rgb_value_to_that_hexadecimal_representation # === rgb_to_hex
     alias to_hex     convert_this_rgb_value_to_that_hexadecimal_representation # === to_hex

# =========================================================================== #
# === Colours.random_html_colour_with_this_text
#
# The first argument is the text that we wish to display.
#
# Usage example:
#
#   puts Colours.random_html_colour_with_this_text 'foo bar'
#
# =========================================================================== #
def self.random_html_colour_with_this_text(
      use_this_text = ''
    )
  "#{rgb_value_as_escape_code_string}#{use_this_text}#{restore?}"
end

# =========================================================================== #
# === Colours.rgb_print
#
# The first argument to this method should be an Array.
#
# We will print here. If you need a newline appended, you have to do
# so on your own, by appending a \n onto the text variable given to
# this method - or use Colours.rgb_puts() instead.
#
# Specific usage examples:
#   Colours.rgb_print ["100", "247", "63"], 'Hello '
#   Colours.rgb_print ["100", "247", "25"], 'World!'
# =========================================================================== #
def self.rgb_print(
    array = %w( 100 247 63 ),
    text  = 'Hello world!'
  )
  print "#{rgb_value_as_escape_code_string(array)}#{text}#{REVERT}"
end

# =========================================================================== #
# === Colours.rgb_puts
#
# First argument should be an Array.
#
# We will use puts here.
#
# Specific usage examples:
#   Colours.rgb_puts ["100", "247", "63"], 'Hello '
#   Colours.rgb_puts ["100", "247", "25"], 'World!'
# =========================================================================== #
def self.rgb_puts(
    array = %w( 100 247 63 ),
    text  = 'Hello world!'
  )
  rgb_print(array, "#{text}\n")
end

# =========================================================================== #
# === Colours.return_this_text_in_random_colour
#
# Invocation example:
#
#   puts Colours.return_this_text_in_random_colour('Hello World!')
#
# =========================================================================== #
def self.return_this_text_in_random_colour(
    show_this_text = ''
  )
  use_this_colour = ::Colours.random_colour?
  "#{rgb(use_this_colour)}#{show_this_text}#{restore?}"
end; self.instance_eval { alias return_this_in_random_colour return_this_text_in_random_colour } # === Colours.return_this_in_random_colour

# =========================================================================== #
# === Colours.write_this_in_random_colour
#
# Usage example:
#   Colours.write_this_in_random_colour 'hi there'
# =========================================================================== #
def self.write_this_in_random_colour(
    i = ''
  )
  e return_this_text_in_random_colour(i)
end; self.instance_eval { alias output_in_a_random_colour write_this_in_random_colour } # === Colours.write_this_in_random_colour

# =========================================================================== #
# === Colours.convert_this_rgb_value_to_that_hexadecimal_representation
#
# This method will convert RGB values to their hexadecimal (hex)
# representation.
#
# Invocation example:
#
#   Colours.convert_this_rgb_value_to_that_hexadecimal_representation([240, 248, 255]) # => "F0F8FF"
#   Colours.rgb_to_hex(255,0,0) # => "FF0000"
#   Colours.rgb_to_hex('255255255')
#   Colours.rgb_to_hex(:slateblue)
#
# =========================================================================== #
def self.convert_this_rgb_value_to_that_hexadecimal_representation(
    r, g = nil, b = nil
  )
  hash = ::Colours.hash_html_colours?
  if r.is_a?(Symbol) and g.nil? and b.nil? and
     is_this_a_html_colour?(r)
    return hash[r.to_s][3]
  end
  if r.is_a?(String) and !r.include?('#') and g.nil? and b.nil?
    # ======================================================================= #
    # In this case assume input such as '255255255'
    # ======================================================================= #
    splitted = r.split(/(...)/).reject(&:empty?)
    r, g, b = splitted
  end
  if r.is_a?(Array) and (r.size > 1) and g.nil? and b.nil?
    # ======================================================================= #
    # In this case the user supplied only a single Array as input.
    # ======================================================================= #
    this_html_colour = ::Colours.convert_this_rgb_value_into_a_html_colour(r)
  else
    this_html_colour = ::Colours.convert_this_rgb_value_into_a_html_colour(r, g, b)
  end
  if this_html_colour
    hash[this_html_colour][3]
  else
    nil
  end
end; self.instance_eval { alias rgb_to_hex                     convert_this_rgb_value_to_that_hexadecimal_representation } # === Colours.rgb_to_hex
     self.instance_eval { alias to_hex                         convert_this_rgb_value_to_that_hexadecimal_representation } # === Colours.to_hex
     self.instance_eval { alias return_hexvalue_of_this_colour convert_this_rgb_value_to_that_hexadecimal_representation } # === Colours.return_hexvalue_of_this_colour

# =========================================================================== #
# === Colours.html_colour_to_rgb_value
#
# This method will return a String, representing the RGB values.
#
# It will, other than that, not make any other modifications; in particular
# it will NOT append a trailing "m" token.
#
# By default the R, G, B values will be separated via a ';' token. If
# you don't want this then modify it e. g. via:  .tr(';',',').
#
# Usage examples:
#
#   Colours.html_colour_to_rgb_value('slateblue') # => "106;90;205"
#   Colours.html_colour_to_rgb_value('crimson')   # => "220;20;60"
#   Colours.html_colour_to_rgb(:steelblue)        # => "70;130;180"
#
# =========================================================================== #
def self.html_colour_to_rgb_value(
    this_html_colour = 'slateblue'
  )
  _ = ::Colours.convert_this_html_colour_into_an_array_of_rgb_values(this_html_colour.to_sym)
  return "#{_[0]};#{_[1]};#{_[2]}"
end; self.instance_eval { alias colour_to_rgb_value                   html_colour_to_rgb_value } # === Colours.colour_to_rgb_value
     self.instance_eval { alias convert_html_colour_to_rgb_value      html_colour_to_rgb_value } # === Colours.convert_html_colour_to_rgb_value
     self.instance_eval { alias html_colour_to_stringified_rgb_values html_colour_to_rgb_value } # === Colours.html_colour_to_stringified_rgb_values
     self.instance_eval { alias html_colour_to_rgb                    html_colour_to_rgb_value } # === Colours.html_colour_to_rgb

# =========================================================================== #
# === Colours.rgb_value_as_escape_code_string
#
# This method will take a R,G,B value and show us a String representation
# =========================================================================== #
def self.rgb_value_as_escape_code_string(
    array = [
      random_value?,
      random_value?,
      random_value?
    ],
    g = nil,
    b = nil
  )
  if array.is_a? Symbol
    array = array.to_s
  end
  if array.is_a?(Array) and (array.size == 3)
    r = array[0]
    g = array[1]
    b = array[2]
  elsif array.is_a?(String) and g.nil? and b.nil?
    # ======================================================================= #
    # In this case we will assume a HTML colour. We thus have to
    # determine its rgb value.
    # ======================================================================= #
    if ::Colours.is_this_html_colour_included?(array)
      set_last_colour_used(array)
      r, g, b = ::Colours.convert_this_html_colour_into_an_array_of_rgb_values(array)
    else
      e 'The input is not a HTML colour:'
      pp array
    end
  end
  # ========================================================================= #
  # The String that we build up in this method will have the ANSI escape
  # code on the left side.
  # ========================================================================= #
  return "#{left?}#{r};#{g};#{b}m"
end; self.instance_eval { alias build_this_rgb_string rgb_value_as_escape_code_string } # === Colours.build_this_rgb_string
     self.instance_eval { alias rgb_value_as_string   rgb_value_as_escape_code_string } # === Colours.rgb_value_as_string
     self.instance_eval { alias rgb                   rgb_value_as_escape_code_string } # === Colours.rgb
     self.instance_eval { alias rgb_format            rgb_value_as_escape_code_string } # === Colours.rgb_format
     self.instance_eval { alias rgb_as_string         rgb_value_as_escape_code_string } # === Colours.rgb_as_string
     self.instance_eval { alias colour_to_rgb_value   rgb_value_as_escape_code_string } # === Colours.colour_to_rgb_value

end

if __FILE__ == $PROGRAM_NAME
  alias e puts
  array = [240, 248, 255]
  # ========================================================================= #
  # === Testing the RGB-functionality of the Colours project next.
  # ========================================================================= #
  e 'Testing the RGB-functionality of the Colours project next.'
  pp ::Colours.convert_this_html_colour_into_an_array_of_rgb_values
  _ = 'royalblue'; e _+':'
  pp ::Colours.convert_this_html_colour_into_an_array_of_rgb_values _
  pp '[240, 248, 255] -> '+
     ::Colours.convert_this_rgb_value_into_a_html_colour(array)
  pp ::Colours.rgb_value_as_escape_code_string
  pp ::Colours.colour_to_rgb_value('slateblue')
  pp ::Colours.colour_to_rgb_value('crimson')
  e
  e ::Colours.rgb(122,56,141)+'Hello world!'
  e ::Colours.colour_to_rgb_value('slateblue')
  e ::Colours.rgb('slateblue')
  e 'R;G;B value: '+::Colours.colour_to_rgb_value('slateblue').inspect  
  e
  e 'Next, the array '+array.inspect+' will be converted to the following'
  e 'hexadecimal representation:'+::Colours.rev
  e
  e "  #{Colours.convert_this_rgb_value_to_that_hexadecimal_representation(array)}"
  e    
end