#!/usr/bin/env python3

# accumulates project statistics

import json
import sqlite3
import sys
import time


def strtime(time):
    years = 0
    days = 0
    hours = 0
    mins = 0
    timestr = ""
    if time > 31536000:
        years = int(time / 31536000)
        time = time - (31536000 * years)
    if time > 86400:
        days = int(time / 86400)
        time = time - (86400 * days)
    if time > 3600:
        hours = int(time / 3600)
        time = time - (3600 * hours)
    if time > 60:
        mins = int(time / 60)
        time = time - (60 * mins)
    if years > 0:
        return "{}y {}d {:02d}h {:02d}min {:02d}s".format(years, days, hours, mins, int(time))
    if days > 0:
        return "{}d {:02d}h {:02d}min {:02d}s".format(days, hours, mins, int(time))
    return "{:02d}h {:02d}min {:02d}s".format(hours, mins, int(time))


def setup_db(c):
    c.execute("CREATE TABLE IF NOT EXISTS projects (id INTEGER PRIMARY KEY, name TEXT, last_update INTEGER)")
    c.execute("CREATE TABLE IF NOT EXISTS stats (projectid INTEGER, host TEXT, wu INTEGER, time INTEGER)")


def get_updates(c):
    rows = c.fetchall()
    if len(rows) == 0:
        print("No data")
        return
    print("Hours since last update:")
    now = int(time.time())
    for row in rows:
        h = (now - row[2]) / 3600.0
        print(f"\t{row[1]}:\t{h:.2f}")


def show_totals(p, c):
    for proj in sorted(p.keys()):
        print(proj)
        d = c.execute("SELECT sum(wu), sum(time) FROM stats WHERE projectid=?", [ p[proj] ]).fetchone()
        print(f"    Total CPU time: {strtime(d[1])}")
        print(f"    Total WUs returned: {d[0]}")


# open db connection
conn = sqlite3.connect('projectstats.db')
c = conn.cursor()

# try a select. if it fails, we need to create the tables.
try:
    # pull double duty: if this succeeds and we've been asked for the
    # last updated stats, we're ready to go
    c.execute("SELECT * FROM projects ORDER BY name")
except:
    setup_db(c)
    c.execute("SELECT * FROM projects ORDER BY name")

# if we're being asked for update stats, handle that
if len(sys.argv) > 1 and sys.argv[1] == "-u":
    get_updates(c)
    sys.exit(0)
# no? then it's time to generate some stats. first thing: turn the
# list of projects into a map
projects = { proj[1]: proj[0] for proj in c.fetchall() }
# if we're being asked for totals, handle that
if len(sys.argv) > 1 and sys.argv[1] == "-t":
    show_totals(projects, c)
    sys.exit(0)


# get data
line = sys.stdin.readline()
# vivify the data and scan it
data = json.loads(line)
err = False
for rec in data:
    # set err and display problem if an error is found
    if rec['err'] is not None:
        print(f"{rec['host']}: {rec['err']}")
        err = True
        continue
    # add new projects if we find them
    if rec['proj'] not in projects:
        print(f"found unknown project '{rec['proj']}'; adding")
        c.execute("INSERT INTO projects VALUES (NULL, ?, ?)", [rec['proj'], 0])
        conn.commit()
        projects[rec['proj']] = c.lastrowid
    # insert the record
    c.execute("INSERT INTO stats VALUES (?,?,?,?)",
              [ projects[rec['proj']], rec['host'], rec['matches'], rec['cputime'] ])
    c.execute("UPDATE projects SET last_update=? WHERE id=?", [ int(time.time()), projects[rec['proj']] ])
    conn.commit()

show_totals(projects, c)
