# ====================================================================================
# Arrays
# ====================================================================================

# Arrays are incredibly powerful in Ruby. Learn to use them well.

puts ''
puts ''
puts '================================'
puts ''

# ====================================================================================
# Enumerable ranges and .to_a
# ====================================================================================

puts "Create an array with the numbers 1 to 10."
one_to_ten = (1..10).to_a
puts one_to_ten

# ====================================================================================
# Finding elements
# ====================================================================================

puts "Create a new array that only contains even numbers from the previous array."
evens = one_to_ten.find_all do |number|
  number % 2 == 0
end
puts evens

# ====================================================================================
# Rejecting elements
# ====================================================================================

puts "Create a new array that rejects odd numbers."
also_even = one_to_ten.reject do |number|
  number % 2 != 0
end
puts also_even

# ====================================================================================
# Array transform using the map function.
# ====================================================================================

puts "Create an array that doubles every number."
doubled = one_to_ten.map do |number|
  number * 2
end
puts doubled

# ====================================================================================
# Combining array functions.
# ====================================================================================

puts "Create an array that selects only odd numbers and then multiply those by 10."
odd_doubled = one_to_ten.find_all do |number|
  number % 2 != 0
end.map do |odd_number|
  odd_number * 10
end
puts odd_doubled

# ====================================================================================
# Product function.
# ====================================================================================

puts "All combination of numbers 1 to 10."
all_combinations = one_to_ten.product(one_to_ten)
puts all_combinations

# ====================================================================================
# Uniq and sort function.
# ====================================================================================

puts "All uniq combinations of numbers."
puts "For example: [1, 2] is the same as [2, 1]."
uniq_combinations =
  one_to_ten.product(one_to_ten)
            .map do |unsorted_number|
              unsorted_number.sort
            end.uniq
puts uniq_combinations

# ====================================================================================
# Example of an advanced array transform.
# ====================================================================================

puts "All unique Pythagorean Triples between 1 and 100 sorted by area of the triangle."

one_to_hundred = (1..100).to_a

triples =
  one_to_hundred.product(one_to_hundred).map do |width, height|
              [width, height, Math.sqrt(width ** 2 + height ** 2)]
            end.find_all do |_, _, hypotenuse|
              hypotenuse.to_i == hypotenuse
            end.map do |triangle|
              triangle.map(&:to_i)
            end.uniq do |triangle|
              triangle.sort
            end.map do |width, height, hypotenuse|
              [width, height, hypotenuse, (width * height) / 2]
            end.sort_by do |_, _, _, area|
              area
            end

triples.each do |width, height, hypotenuse, _|
  puts "(#{width}, #{height}, #{hypotenuse})"
end

puts ''
puts '================================'
puts ''
puts ''

# ====================================================================================
# Example of an sorting.
# ====================================================================================

things_to_sort = [
  { type: :background, order: 1 },
  { type: :foreground, order: 1 },
  { type: :foreground, order: 2 }
]

# For a simple sort, you can use sort_by
results = things_to_sort.sort_by do |hash|
  hash[:order]
end

puts "Simple sort:"
puts results

# for a more complicated sort, you can provide a block that returns
# -1, 0, 1 for a left and right operand
results = things_to_sort.sort do |l, r|
  sort_result = 0
  puts "here is l: #{l}"
  puts "here is r: #{r || "nil"}"
  # if either value is nil/false return 0
  if !l || !r
    sort_result = 0
  # if the type of "left" is background and the
  # type of "right" is foreground, then return
  # -1 (which means "left" is less than "right"
  elsif l[:type] == :background && r[:type] == :foreground
    sort_result = -1
  # if the type of "left" is foreground and the
  # type of "right" is background, then return
  #  1 (which means "left" is greater than "right"
  elsif l[:type] == :foreground && r[:type] == :background
    sort_result = 1
  # if "left" and "right"'s type are the same, then
  # use the order as the tie breaker
  elsif l[:order] < r[:order]
    sort_result = -1
  elsif l[:order] > r[:order]
    sort_result = 1
  # returning 0 means both values are equal
  else
    sort_result = 0
  end
  sort_result
end.to_a

puts "Custom sort:"
puts results

# ====================================================================================
# Api documention for Array that is worth commiting to memory because arrays are so
# awesome in Ruby: https://docs.ruby-lang.org/en/2.0.0/Array.html
# ====================================================================================
