#!/usr/bin/env python3

# Copyright 2011 VPAC
#
# This file is part of Karaage.
#
# Karaage is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Karaage is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Karaage  If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function

try:
    # Python 3
    import xmlrpc.client as xmlrpclib
except ImportError:
    # Python 2
    import xmlrpclib

import datetime
import sys
import os
import json
import argparse
import logging

try:
    # Python 3
    import configparser
except ImportError:
    # Python 2
    import ConfigParser as configparser


class UsageError(Exception):
    pass


def parse_logs_raw(date, cfg):
    assert cfg['upload'] == 'raw'

    filename = date.strftime('%Y%m%d')

    try:
        f = open(os.path.join(cfg['log_dir'], filename), 'r')
    except IOError:
        raise UsageError(
            'Failed to open log file %s'
            % os.path.join(cfg['log_dir'], filename))

    for line in f:
        if cfg['upload'] == 'raw':
            if cfg['type'] == 'PBS' \
                    and line.find('resources_used.walltime') == -1:
                continue
            yield line

    f.close()


def parse_logs_alogger(date, cfg):
    assert cfg['upload'] == 'alogger'

    from alogger import get_parser
    parser = get_parser(cfg['type'])

    for d in parser.read_log(date, cfg):
        yield json.dumps(d)


def send_logs(data, log_type, cfg):
    data = list(data)

    if len(data) > 0:
        server = xmlrpclib.Server(cfg['WS_URL'])

        summary, output = server.parse_usage(
            cfg['WS_USERNAME'], cfg['WS_PASSWORD'],
            data, str(date), cfg['machine_name'], log_type)

        print(summary)
        for line in output:
            print(line)


def process_logs(date, cfg):
    if cfg['upload'] == 'raw':
        data = parse_logs_raw(date, cfg)
        log_type = cfg['type']

    elif cfg['upload'] == 'alogger':
        data = parse_logs_alogger(date, cfg)
        log_type = 'alogger'

    else:
        raise UsageError("Unknown upload type %s" % cfg['upload'])

    send_logs(data, log_type, cfg)


def get_config(config_file):
    try:
        open(config_file)
    except IOError:
        raise UsageError("No configuration found at %s" % config_file)

    config = configparser.RawConfigParser()

    config.read(config_file)
    cfg = {}
    try:
        for name, value in config.items("kg-send-usage"):
            cfg[name] = value

        if 'type' not in cfg:
            cfg['type'] = 'PBS'

        if 'upload' not in cfg:
            cfg['upload'] = 'raw'

        cfg['WS_URL'] = config.get('karaage', 'url')
        cfg['WS_USERNAME'] = config.get('karaage', 'username')
        cfg['WS_PASSWORD'] = config.get('karaage', 'password')
    except:
        raise UsageError("Failed to parse config at %s" % config_file)

    return cfg


if __name__ == "__main__":

    parser = argparse.ArgumentParser(
        description="Send usage logs to Karaage",
        epilog='Log files must be named YYYMMDD.')

    parser.add_argument(
        "--debug", action="store_true",
        help="Print Debugging Messages")

    parser.add_argument(
        "--config", "-c",
        default="/etc/karaage3/karaage-cluster-tools.cfg",
        help='Configuration file')

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument(
        "--all", "-a", action="store_true",
        help="Read all log files.")
    group.add_argument(
        "--yesterday", "-y", action="store_true",
        help="Process yesterday's log file.")
    group.add_argument(
        "--date", "-d",
        help="Date to read.")

    args = parser.parse_args()

    if args.debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.INFO)

    config_file = args.config

    try:
        cfg = get_config(config_file)

        if args.all:
            file_list = os.listdir(cfg['log_dir'])

            for filename in file_list:
                date = datetime.date(
                    int(filename[:4]), int(filename[4:6]), int(filename[6:]))
                process_logs(date, cfg)

        elif args.yesterday:
            date = datetime.date.today() - datetime.timedelta(days=1)
            process_logs(date, cfg)

        elif args.date:
            date = datetime.datetime.strptime(args.date, '%Y-%m-%d').date()
            process_logs(date, cfg)

        else:
            raise RuntimeError("oops. I mistake made.")

    except UsageError as e:
        print("Error: %s" % e, file=sys.stderr)
        sys.exit(1)

    sys.exit(0)
