#!/usr/bin/env ruby
# coding: utf-8

require 'rubygems'
require 'bundler/setup'
Bundler.require(:doc)

require 'yaml'

output = "<table>\n"
output << <<-TAB.lines.map(&:strip).join
  <tr>
    <th>Adapter</th><th>Required gems</th>
    <th style="writing-mode:tb">MRI support<sup>1</sup></th>
    <th style="writing-mode:tb">JRuby support<sup>1</sup></th>
    <th style="writing-mode:tb">Multi-thread safe<sup>2</sup></th>
    <th style="writing-mode:tb">Multi-process safe<sup>3</sup></th>
    <th style="writing-mode:tb">Atomic increment<sup>4</sup></th>
    <th style="writing-mode:tb">Atomic create<sup>5</sup></th>
    <th style="writing-mode:tb">Native expires<sup>6</sup></th>
    <th style="writing-mode:tb">Persistent</th>
    <th style="writing-mode:tb">Key Traversal</th>
    <th style="writing-mode:tb">Bulk read<sup>7</sup></th>
    <th style="writing-mode:tb">Bulk write<sup>8</sup></th>
    <th>Description</th>
  </tr>
TAB
output << "\n\n"

footnotes = {
  "platform" => <<-EOF,
  Indicates that the adapter is expected to work on this platform.  Most adapters will at least
  work on MRI, but some are curently considered unstable, in which case they are not supported
  on any platform.
  EOF
  "multi-thread safe" => <<-EOF,
  Make adapters thread-safe by using `Moneta::Lock` or by passing the option `threadsafe: true` to
  `Moneta#new`. There is also `Moneta::Pool` which can be used to share a store between multiple
  threads if the store is multi-process safe. I recommend to add the option `:threadsafe` to
  ensure thread-safety since for example under JRuby and Rubinius even the basic datastructures
  are not thread safe due to the lack of a global interpreter lock (GIL). This differs from MRI
  where some adapters might appear thread safe already but only due to the GIL.
  EOF
  "multi-process safe" => <<-EOF,
  Share a Moneta store between multiple processes using `Moneta::Shared` (See below).
  EOF
  "atomic increment" => <<-EOF,
  If a store provides atomic increment it can be used with `Moneta::Semaphore`. You can add weak
  `#increment` support using the `Moneta::WeakIncrement` proxy.
  EOF
  "atomic create" => <<-EOF,
  If a store provides atomic creation it can be used with `Moneta::Mutex`. You can add weak
  `#create` support using the `Moneta::WeakCreate` proxy.
  EOF
  "native expires" => <<-EOF,
  Add expiration support by using `Moneta::Expires` or by passing the option `expires: true` to
  `Moneta#new`.
  EOF
  "bulk read" => <<-EOF,
  This indicates that there is some performance gain when fetching
  multiple values at once using `#values_at`/`#fetch_values` or `#slice`.
  For instance, the `MGET` instruction in Redis, or the ability to retrieve
  several rows in one query in SQL.
  EOF
  "bulk write" => <<-EOF
  This indicates that there is some performance gain when storing multiple
  key/value pairs at once using `#merge!`/`#update`.
  EOF
}

YAML.parse_stream(File.read(File.join(File.dirname(File.dirname(__FILE__)), 'feature_matrix.yaml'))) do |document|
  feature_group = document.to_ruby

  output << %{<tr><th colspan="2">#{feature_group['group']}</th><th colspan="12"></th></tr>\n\n}

  feature_group['notes'].each do |k,v|
    footnotes[k] = v
  end

  feature_group['backends'].each do |backend|
    output << '<tr>'
    output << "<td>#{backend['adapter']}</td>"
    output << "<td>#{backend['gems'] || '-'}</td>"

    features = backend['features'] | (feature_group['features'] || [])
    features += backend['platforms'] || []
    %w{MRI JRuby threadsafe multiprocess increment create expires persist each_key bulk_read bulk_write}.each do |feature|
      supported = if features.include? feature
                    "yes"
                  elsif backend['unknown'] && backend['unknown'].include?(feature)
                    "unknown"
                  else
                    "no"
                  end

      note = if backend['notes'] && backend['notes'][feature]
               "<sup>#{footnotes.keys.index(backend['notes'][feature]) + 1}</sup>"
             else
               ''
             end

      mark = case supported
              when "yes"
               "✓"
              when "no"
                "✗"
              when "unknown"
                '?'
              end

      colour = case supported
               when "yes"
                 '#5F5'
               when "no"
                 '#F44'
               when "unknown"
                 '#55F'
               end

      output << %{<td style="text-align:center;background:#{colour}">#{mark}#{note}</td>}
    end

    html_description = if backend['description']
                         Kramdown::Document.new(backend['description']).to_html.match('<p>(.*)</p>')[1]
                       else
                         ''
                       end
    output << "<td>#{html_description}</td>"

    output << '</tr>'
    output << "\n\n"
  end


end

output << "</table>\n\n"

footnotes.each_value.each_with_index do |note, idx|
  output << "#{idx+1}. #{note.lines.map(&:strip).join(" ")}\n"
end

readme = File.open('README.md', 'r+')
new_readme = readme.read.sub(/(name="backend-matrix".*?\n).*?(------)/m, "\\1\n#{output}\n\\2")
readme.rewind
readme << new_readme
readme.truncate(readme.tell)

