#!/usr/bin/python2 -s
#
# Copyright (C) 2008 by Alexander Koenig
# Copyright (C) 2008, 2015 by Adrian Reber
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import sys
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import time
import gzip
import getopt
import os

start = time.clock()

logfile = None
dest = None
offset = 0
configuration = '/etc/mirrormanager/mirrormanager2.cfg'
embargoed_countries = []


def usage():
    print "mirrorlist_statistics.py analyzes mirrorlist_server.py logfiles"
    print "and draws piecharts"
    print
    print "Usage:"
    print "  mirrorlist_statistics.py [OPTION]..."
    print
    print "Options:"
    print "  -c, --config=CONFIG   Configuration file to use"
    print "                        (default=/etc/mirrormanager/mirrormanager2.cfg)"
    print "  -l, --log=LOGFILE     gzipped logfile which should be used as input"
    print "  -d, --dest=DIRECTORY  output directory"
    print "  -o, --offset=DAYS     number of days which should be subtracted"
    print "                        from today's date and be used as basis for log analysis"
    print "  -h, --help            show this help; then exit"
    print


def parse_args():
    global logfile
    global dest
    global offset
    global configuration
    global embargoed_countries
    opts, args = getopt.getopt(sys.argv[1:], "c:l:d:ho:",
                               ["conf=", "log=", "dest=", "help", "offset"])
    for option, argument in opts:
        if option in ("-c", "--conf"):
            configuration = argument
        if option in ("-l", "--log"):
            logfile = argument
        if option in ("-d", "--dest"):
            dest = argument
        if option in ("-o", "--offset"):
            offset = int(argument)
        if option in ("-h", "--help"):
            usage()
            sys.exit(0)

    if not os.access(configuration, os.R_OK):
        print "Cannot access configuration file: " + configuration
        print "Exiting"
        sys.exit(-1)

    d = dict()
    with open(configuration) as config_file:
        exec(compile(config_file.read(), configuration, 'exec'), d)

    if 'EMBARGOED_COUNTRIES' in d:
        if isinstance(d['EMBARGOED_COUNTRIES'], list):
            embargoed_countries = d['EMBARGOED_COUNTRIES']


parse_args()


if logfile is None or dest is None:
    usage()
    sys.exit(-1)


def sort_dict(dict):
    """ Sort dictionary by values and reverse. """
    items = dict.items()
    sorteditems = sorted([[v[1], v[0]] for v in items])
    sorteditems.reverse()
    return sorteditems


y1, m1, d1, x1, x2, x3, x4, x5, x6 = time.localtime()


# this works only if offset < d1
if d1 > offset:
    d1 = d1 - offset

countries = {}
accesses = 0
repositories = {}
archs = {}
i = 0


for line in gzip.open(logfile):
    arguments = line.split()
    try:
        y, m, d = arguments[3][:10].split('-')
    except:
        continue
    if not ((int(y) == y1) and (int(m) == m1) and (int(d) == d1)):
        continue
    try:
        if arguments[5][:2] in embargoed_countries:
            countries['N/'] += 1
        else:
            countries[arguments[5][:2]] += 1
    except:
        if arguments[5][:2] in embargoed_countries:
            countries['N/'] = 1
        else:
            countries[arguments[5][:2]] = 1
    try:
        archs[arguments[9]] += 1
    except:
        archs[arguments[9]] = 1
    try:
        repositories[arguments[7][:len(arguments[7]) - 1]] += 1
    except:
        repositories[arguments[7][:len(arguments[7]) - 1]] = 1
    accesses += 1
    continue


def do_pie(prefix, dict, accesses):
    plt.figure(1, figsize=(8, 8))
    ax = plt.axes([0.1, 0.1, 0.8, 0.8])

    labels = []
    fracs = []
    rest = 0

    for item in dict.keys():
        frac = dict[item]

        if (float(frac) / float(accesses) > 0.01):
            labels.append(item)
            fracs.append(frac)
        else:
            rest += frac

    i = 0
    changed = False
    for x in labels:
        if x == 'undef':
            fracs[i] += rest
            labels[i] = 'other'
            changed = True
        i += 1

    if not changed:
        labels.append('other')
        fracs.append(rest)

    plt.pie(
        fracs,
        labels=labels,
        autopct='%1.1f%%',
        pctdistance=0.75,
        shadow=True)
    plt.savefig('%s%s-%d-%02d-%02d.png' % (dest, prefix, y1, m1, d1))
    plt.close(1)


def background(html, css_class, toggle):
    html.write('\t<tr')
    if toggle:
        html.write(' class="%s"' % css_class)
        toggle = False
    else:
        toggle = True
    html.write('>\n\t')
    return toggle


def do_html(prefix, dict, accesses):
    html = open('%s%s-%d-%02d-%02d.txt' % (dest, prefix, y1, m1, d1), 'w')
    html.write('<h2>Details</h2>\n')
    html.write('<table align="center">\n')
    html.write('<tr id="matrixtitle"><th>Mirror Name</th><th>%</th>')
    html.write('<th>#Requests</th></tr>\n')

    toggle = False

    for item in sort_dict(dict):
        size = item[0]
        toggle = background(html, 'matrix_even', toggle)
        html.write('<td>%s</td>\n' % (item[1]))
        html.write('\t<td align="right">%05.4lf %%</td>\n' %
                   ((float(size) / float(accesses)) * 100))
        html.write('<td align="right">')
        html.write('%d' % (size))
        html.write('</td></tr>\n')

    # print the overall information
    background(html, 'total', True)
    html.write('<th>Total</th><th>\n')
    html.write('</th><th align="right">%d' % (accesses))
    html.write('</th></tr>\n')

    html.write('</table>\n')
    end = time.clock()
    html.write(
        '<p>Last updated: %s GMT' %
        time.strftime(
            "%a, %d %b %Y %H:%M:%S",
            time.gmtime()))
    html.write(' (runtime %ss)</p>\n' % (end - start))


do_pie('countries', countries, accesses)
do_pie('archs', archs, accesses)
do_pie('repositories', repositories, accesses)


do_html('countries', countries, accesses)
do_html('archs', archs, accesses)
do_html('repositories', repositories, accesses)
