#!/usr/bin/env ruby
require 'json'
require 'set'

# JSON file needs Emojibase-formatted entries, see https://emojibase.dev
# Also see customizer.rb in this directory.

json_in = ARGF.read

my_emoji = JSON.parse(json_in)

# Output target format example (taken from original dev test data)
#
#     FC.data = {
#         groups: [
#             { title: "People"  , emoji: "😀", range: [0,2] },
#             { title: "Natural" , emoji: "🌴", range: [4,5] },
#             { title: "Activity", emoji: "🧭", range: [6,6] },
#             { title: "Things"  , emoji: "📻️", range: [0,0] },
#         ],
#         tags: {
#             "face": [0,1,2,4],
#             "wacky": [1],
#             "cool": [2],
#             "bear": [3,6],
#             "pig": [4],
#             "owl": [5],
#             "animal": [3,4,5],
#             "teddy": [6],
#         },
#         emoji: [
#             "😀", // 0 grinning face
#             "🤪", // 1 wacky face
#             "😎", // 2 cool face with sunglasses
#             "🐻", // 3 bear
#             "🐷", // 4 pig face
#             "🦉", // 5 owl
#             "🧸", // 6 teddy bear
#         ],
#     };

# Begin!
puts "FC.data = {"

# Make group list. For screen real estate, I've combined some of the groups
# together (original_groups). These groups become selectable "tab" filters in
# the final interface.
my_groups = [
  # Official group names:
  #     0  Smileys & Emotion
  #     1  People & Body
  #     2  Components
  #     3  Animals & Nature
  #     4  Food & Drink
  #     5  Travel & Places
  #     6  Activities
  #     7  Objects
  #     8  Symbols
  #     9  Flags
  { title: "People"  , emoji: "😀", from_groups: [0,1], range: [nil,0] },
  { title: "Natural" , emoji: "🌴", from_groups: [3,4], range: [nil,0] },
  { title: "Activity", emoji: "🧭", from_groups: [5,6], range: [nil,0] },
  { title: "Things"  , emoji: "📻️", from_groups: [7,8], range: [nil,0] },
]

# Find first and last (range) emoji for each group
my_emoji.each_with_index do |e, i|
  #puts "#{i} #{e["group"]}"
  # is this group one of the from_groups?
  g = my_groups.find { |g| g[:from_groups].include?(e["group"]) }
  if g
   # puts "#{i} vs #{g[:range][0]} - #{g[:range][1]}"
    if g[:range][0] === nil
      g[:range][0] = i # first!
    end
    if i > g[:range][1]
      g[:range][1] = i # maybe last
    end
  end
end

# Print groups (not just turning the whole thing over
# to JSON.generate because I want to have explicit
# control over the pretty-printing as a compactness vs.
# readability balance. Since this output is really JS,
# not strict JSON, I can have trailing commas and all
# that good stuff, which simplifies things quite a bit.
group_strs = []
my_groups.each do |g|
  g.delete(:from_groups)
  group_strs.push "  #{JSON.generate(g)}"
end
puts "groups: [\n#{group_strs.join(",\n")}\n],"

# Remove tags that are in an entry's label
my_emoji.each do |e|
  new_tags = e["tags"].filter do |t|
    !e["label"].include?(t)
  end
  e["tags"] = new_tags
end

# Get all "word" usage counts from all tags and labels
word_usage = {}
my_emoji.each do |e|
  these_words = e["tags"].to_set
  these_words.merge e["label"].split(' ')

  these_words.each do |word|
    if word_usage.key?(word)
      word_usage[word] += 1
    else
      word_usage[word] = 1
    end
  end
end


# Word parameters to adjust for best results
# Both of these will work with 1 or higher
min_word_usage_count = 4
min_word_length = 4

if !ENV['MIN_WORD_USAGE_COUNT'].nil?
  min_word_usage_count = ENV['MIN_WORD_USAGE_COUNT'].to_i
end

if !ENV['MIN_WORD_LENGTH'].nil?
  min_word_length = ENV['MIN_WORD_LENGTH'].to_i
end

# TODO allow input of the above in ARGV to override the defaults so I can
# automate the 25 or so permutations and get the output bytes for comparison to
# see which one is smallest. THEN change the defaults to match!
    
# Convert word list to array and enforce parameters
word_usage_list = []
word_usage.each do |word,count|
  if count >= min_word_usage_count &&
      word.length >= min_word_length
    word_usage_list.push [word,count]
  end
end

# Sort by usage count so more frequent words have lower index numbers
# (literally just for the savings of a shorter number of digits)
word_usage_list.sort_by! { |w| w[1] }.reverse!

# Turn usage list into array (just the word (0th position))
my_words = word_usage_list.map { |w| w[0] }

line_len = 0
first = true
print "words: '"
my_words.each_with_index do |w|
  if line_len + w.length > 70
    # don't add to a long line, start a new one
    print "'\n+'"
    line_len = 0
  end
  if first
    first = false
  else
    print ' '
  end
  print w
  line_len += w.length
end
puts "',"

# Replace any words from list in labels with, e.g. $15, $256
#
# Surprisingly, there are NO tags or labels with '$' in them
# (see check_for_dollar_tags.rb)
my_labels = []
my_emoji.each do |e|
  label_strings = []
  e['label'].split(' ').each do |word|
    idx = my_words.find_index(word)
    if idx.nil?
      # not in word list, push verbatim word
      label_strings.push(word)
    else
      label_strings.push("$#{idx}")
    end
  end
  my_labels.push label_strings.join(' ')
end

# Make tag reference list:
#   - exclude if tag can be found in the label
#   - in the word list: use number
#   - not in word list: use verbatim string
my_tags = []
my_emoji.each do |e|
  these_tags = []
  e["tags"].each do |t|
    if e["label"].include?(t)
      puts "already in label: #{t}"
      next # it's already a word in the label
    end
    idx = my_words.find_index(t)
    if idx.nil?
      # not in word list, push verbatim tag
      these_tags.push(t)
    else
      these_tags.push("$#{idx}")
    end
  end
  my_tags.push these_tags.join(' ')
end

# Print emoji
# Collate in the labels and tags.
# As an array of arrays in this index order
#   0: emoji glyph
#   1: label string
#   2: tag string
# Example: ['X','winking $0',[2,'fart',17]]
#
line_len = 0
puts "emoji: ["
my_emoji.each_with_index do |e, i|
  str = "['#{e['emoji']}','#{my_labels[i]}','#{my_tags[i]}'],"
  if line_len + str.length > 80
    # don't add to a long line, start a new one
    puts
    line_len = 0
  end
  print str
  line_len += str.length
end

puts
puts "]  // End of FC.data.emoji"
puts "}; // End of FC.data"
