#!/usr/bin/ruby
# coding: utf-8
require 'yaml'
require 'logger'

basedir = '/home/sks/sks-status.gwolf.org'
Log = Logger.new(File.join(basedir, 'running.log'), 'weekly', 4)
Log.level = Logger::INFO
work_html = File.join(basedir, 'index.%s.html' % (Time.now.strftime('%Y%m%d%H%M%S') ))
html = File.join(basedir, 'index.html')
gnuplot = File.join(basedir, 'results.gnuplot')
gnuplot_success = File.join(basedir, 'results-success.gnuplot')
gnuplot_histogram = File.join(basedir, 'results-histogram.gnuplot')
gp_data = File.join(basedir, 'results.data')
gp_hist = File.join(basedir, 'results.histogram')

Log.info('Starting index generation')
# We take only those samples that have a valid yaml data file
samples = Dir.glob(File.join(basedir, '20*/walk-sks.yaml')).
            map {|s| s.gsub(/\/walk-sks.yaml$/, '')}.sort
Log.info('%d samples found' % samples.size)

ht_fh = open(work_html, 'w')
gnup_fh = open(gnuplot, 'w')
gnup_succ_fh = open(gnuplot_success, 'w')
gnup_hist_fh = open(gnuplot_histogram, 'w')
data_fh = open(gp_data, 'w')
data_hist_fh = open(gp_hist, 'w')

ht_fh.puts('<html><head>',
        '<meta content="text/html; charset=utf8" http-equiv="Content-Type">',
        '<title>Livelihood statistics of the SKS keyserver network</title>',
        '<link rel="stylesheet" href="/style.css" />',
        '</head>',
        '<body><h1>Livelihood statistics of the SKS keyserver network</h1>',
        '<p>Page generated: ', Time.now.to_s, '</p>',
        '<p>%d total samples</p>' % samples.size,
        '<p>Generated from the following scripts: <a href="walk_sks.rb">walk_sks.rb</a> ',
        '(collect samples), <a href="mkindex.rb">mkindex.rb</a> (builds the overview page)</p>',
        '<p>Sources for the Gnuplot graphic: <a href="results.gnuplot">Plot definition</a>, <a href="results.data">data</a>. ',
        'You can also get the <a href="running.log">log for the last data collection runs</a>.</p>',
        '<div class="plots">',
        '   <div class="results-main">',
        '      <p>Full plot</p>',
        '      <a href="results.svg"><img src="results.svg" width="700" height="700" /></a></div>',
        '   <div class="results-success">',
        '      <p>Only successful connections</p>',
        '      <a href="results-success.svg"><img src="results-success.svg" width="300" height="300" /></a></div>',
        '   <div class="results-histogram">',
        '      <p>Histogram of successful connections</p>',
        '      <a href="results-histogram.svg"><img src="results-histogram.svg" width="300" height="300" /></a></div>',
        '</div>',
        '<p class="key">Key to the following table: [sample number]. <span class="date">[date]</span> [image links] ',
        '<span class="success">Success</span>',
        '<span class="unreach">Unreachable</span>',
        '<span class="timeout">Timeout</span>',
        '<span class="socketerror">Socket error</span>',
        '<span class="nomethod">No method</span>',
        '<span class="exception">Exception</span></p>',
        '<ol>')
Log.debug('HTML initial hunk generated')

dates = {}
date_idx = 0
last_date = ''
hist = {}
samples.each_with_index do |f, num|
  Log.info('%d/%d processed (current: %s)' % [num,samples.size, f]) if num%100 == 0
  datadir = f
  yaml = File.join(datadir, 'walk-sks.yaml')
  # The SVG is output to be consumed from the browser -- Drop the
  # local basedir from it
  svg_full = File.join(datadir, 'walk-sks.dot.svg').gsub(/^#{basedir}/,'')
  svg_green = File.join(datadir, 'walk-sks.green.dot.svg').gsub(/^#{basedir}/,'')

  # We have too many samples -- During the first months, I took up to
  # 24 samples a day!
  #
  # Currently, I am outputting all of them "lumped together" in their daily column.
  this_date = File.basename(f)
  this_date = '%s.%s.%s' % [this_date[0..3], this_date[4..5], this_date[6..7] ]
  if last_date != this_date
    date_idx += 1
    dates[date_idx] = this_date
    last_date = this_date
  end

  ht_fh.puts('<li class="datarow"><span class="date">%s</span>
    Graphs: <a href="%s">Full</a> (<a href="%s">src</a>); <a href="%s">Success</a> (<a href="%s">src</a>). 
    Values: ' %
             [this_date, svg_full, svg_full.gsub(/.svg$/,''), svg_green, svg_green.gsub(/.svg$/,'')])

  # The YAML file includes two components: "Servers" and "Status".
  # Servers are used to build the snapshot SVGs, painting that
  # particular snapshot; this script uses Status, representing each of
  # the servers' status. It is a hash, with the following keys, and with
  # the list of servers in that status:
  # - R: ENETUNREACH, ECONNREFUSED
  # - T: Net::OpenTimeout
  # - S: SocketError, OpenURI::HTTPError
  # - N: NoMethodError
  # - ?: Other exception
  # - .: Success
  status = YAML.load(open(yaml))[1]
  totals = {'.' => 0, 'R' => 0, 'T' => 0, 'S' => 0, 'N' => 0, '?' => 0}
  status.keys.each {|s| totals[s] = status[s].size}

  ht_fh.puts('<span class="datapoint success">%d</span>
              <span class="datapoint unreach">%d</span>
              <span class="datapoint timeout">%d</span>
              <span class="datapoint socketerror">%d</span> 
              <span class="datapoint nomethod">%d</span> 
              <span class="datapoint exception">%d</span>' % %w(. R T S N ?).map{|k| totals[k]})

  data_row =  %w(. R T S N ?).map{|k| totals[k]}
  data_row.unshift(date_idx)
  # Fill the results only, to prepare the histogram
  hist[totals['.']] ||= 0
  hist[totals['.']] += 1
  data_fh.puts(data_row.join("\t"))
end
ht_fh.puts('</dl></body>')
ht_fh.close()
File.rename(work_html, html)
data_fh.close()
Log.info('HTML generation completed, proceeding with graphs')

data_hist_fh.puts hist.keys.sort.map{|k| "%d\t%d" % [k, hist[k]]}
data_hist_fh.close()

gnup_hist_fh.puts %q(reset
set term svg
data='%s'
set yrange[0:100]
plot data using 1:2 title "Number of successful connections" linetype rgb "#008800"
) % [gp_hist]

gnupg_common = %q(reset
set term svg
data='%s'

set xlabel 'Sampling date'
set ylabel 'Number of responses'
set xtics nomirror
set ytics nomirror
set border 1+2
set style line 12 lc rgb '#808080' lt 0 lw 1
set grid back ls 12
set yrange [0:850]
set xtics rotate by -30
set xtics(%s)

) % [gp_data, dates.keys.select {|d| d%100 == 1}.sort.map { |d| '"%s" %d' % [dates[d], d] }.join(', ') ]


gnup_fh.puts(gnupg_common)
gnup_succ_fh.puts(gnupg_common)

gnup_fh.puts('plot data using 1:7 title "Exception"    with points pointsize 0.2 linetype rgb "#000000" linewidth 2, \
     data using 1:6 title "No method"    with points pointsize 0.2 linetype rgb "#000088" linewidth 2, \
     data using 1:5 title "Socket error" with points pointsize 0.2 linetype rgb "#884400" linewidth 2, \
     data using 1:4 title "Timeout"      with points pointsize 0.2 linetype rgb "#880000" linewidth 2, \
     data using 1:3 title "Unreachable"  with points pointsize 0.2 linetype rgb "#888800" linewidth 2, \
     data using 1:2 title "Success"      with points pointsize 0.3 pointtype 5  linetype rgb "#008800" linewidth 2')
gnup_fh.close()

gnup_succ_fh.puts('plot data using 1:2 title "Servers successfully contacted" with points pointsize 0.3 pointtype 5 linetype rgb "#008800"')
gnup_succ_fh.close()

Log.info('Gnuplot definitions generated.')
