#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import bz2
import tempfile
# so that time function with use american locale
for env in ("LANG", "LC_ALL", "LANGUAGE",):
    os.environ[env] = "en_US.UTF-8"

import time
import calendar

sys.path.insert(0, "../lib")
from entropy.const import etpConst
from entropy.client.interfaces import Client
import entropy.tools
import entropy.dep


def _print_help():
    sys.stdout.write(
        "entropy-repository-statistics <machine name> <repository id> <branch> <arch> <product> <repository dir> <output file>\n\n")

def _handle_stat_lines(entropy_client, target_month, target_year,
                       changelog_file):

    target_year_month = "%s%s" % (target_year, target_month)

    date_format_string = etpConst['changelog_date_format']
    in_range = False
    commit_lines = []
    date_header = "Date: "
    atom_header = "Name: "
    commit_header = "commit"

    with open(changelog_file, "r") as changelog_f:
        line = changelog_f.readline()
        commit_line = ""
        do_break = False

        while line:

            if line.startswith(date_header):
                # extract date and check it maches this_month
                date_str = line.lstrip(date_header).strip()
                time_obj = time.strptime(date_str, date_format_string)
                if (time_obj.tm_year == target_year) and \
                    (time_obj.tm_mon == target_month):
                    in_range = True
                elif in_range:
                    # left the range, not worth parsing further, we're done
                    in_range = False
                    do_break = True

            if in_range and line.startswith(atom_header):
                atom = line.lstrip(atom_header).strip()
                atom = entropy.dep.remove_entropy_revision(atom)
                atom = entropy.dep.remove_tag(atom)
                pkg_key = entropy.dep.dep_getkey(atom)
                split_data = entropy.dep.catpkgsplit(atom)
                if split_data is not None:
                    etp_cat, etp_name, ver, rev = split_data
                    if rev != "r0":
                        ver += "-"+rev

            if line.startswith(commit_header):
                if in_range:
                    commit_lines.append(commit_line)
                commit_line = line
            else:
                commit_line += line

            if do_break:
                break
            line = changelog_f.readline()

    return commit_lines

def _calculate_stats(target_month, target_year, stat_lines):
    stats = {
        'bumps': len(stat_lines),
        'recompiles': 0,
        'revisions': 0,
        'bumps/day': 0,
    }

    package_ids = []
    revisions = set()
    for stat_line in stat_lines:
        commit_line = stat_line.split("\n")[0].lstrip("commit").strip()
        revision, package_id, pkg_hash = commit_line.split(";")
        revisions.add(revision)
        package_ids.append(int(package_id))

    package_ids.sort()
    if package_ids:
        stats['recompiles'] = abs(package_ids[-1] - package_ids[0])
    stats['revisions'] = len(revisions)

    days_in_month = calendar.monthrange(target_year, target_month)[1]
    stats['bumps/day'] = round(float(stats['bumps']) / days_in_month, 2)

    return stats

def _generate_statistics(entropy_client, machine, repository_id, branch,
    arch, product, repository_dir, output_file):

    tmp_fd = None
    changelog_file = None
    try:
        tmp_fd, changelog_file = tempfile.mkstemp()
        compressed_changelog_file = os.path.join(repository_dir,
            etpConst['changelog_filename_compressed'])

        entropy.tools.uncompress_file(compressed_changelog_file,
            changelog_file, bz2.BZ2File)

        target_month = int(os.getenv("ETP_M", int(time.strftime("%m")) - 1))
        target_year = int(os.getenv("ETP_Y", time.strftime("%Y")))
        if target_month == 0:
            target_month = 12
            target_year -= 1
        stat_lines = _handle_stat_lines(entropy_client,
            target_month, target_year, changelog_file)
    finally:
        if tmp_fd is not None:
            os.close(tmp_fd)
        if changelog_file is not None:
            os.remove(changelog_file)

    stats = _calculate_stats(target_month, target_year, stat_lines)

    # header
    header_str = """\
Sabayon Entropy build server statistics
Year:       %s
Month:      %s
-------------------------------------------------------------------------------
Machine:    %s
Repository: %s
Branch:     %s
Arch:       %s
Product:    %s
-------------------------------------------------------------------------------
Package bumps:  %s
Recompiles:     %s
Revisions:      %s
Bumps/day:      %s
""" % (target_year, target_month, machine, repository_id, branch, arch, product,
        stats['bumps'], stats['recompiles'], stats['revisions'],
        stats['bumps/day'])

    with open(output_file, "w") as out_f:
        out_f.write(header_str)
        out_f.write(("="*79) + "\n\n")

        # changelog
        for line in stat_lines:
            out_f.write(line)
        out_f.flush()


if __name__ == "__main__":
    args = sys.argv[1:]
    if len(args) != 7:
        _print_help()
        raise SystemExit(1)

    # this expects that:
    # "equo update" is called

    entropy_client = None
    try:
        entropy_client = Client()
        machine, repository_id, branch, arch, product, \
            repository_dir, output_file = args
        rc = _generate_statistics(entropy_client,
            machine, repository_id, branch, arch, product,
            repository_dir, output_file)
        raise SystemExit(rc)
    finally:
        if entropy_client is not None:
            entropy_client.shutdown()
