#!/usr/bin/env python
##**************************************************************
##
## Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
## University of Wisconsin-Madison, WI.
## 
## Licensed under the Apache License, Version 2.0 (the "License"); you
## may not use this file except in compliance with the License.  You may
## obtain a copy of the License at
## 
##    http://www.apache.org/licenses/LICENSE-2.0
## 
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##**************************************************************

import sys
import os
import getopt
import time

class SiteSummary:
	name = None
	hours = None
	jobs = None
	def __init__(self):
		self.hours = {}
		self.jobs = {}

def Usage():
	msg = """
USAGE: condor_router_history [OPTIONS]
 --show_records             (show individual records in addition to summary)
 --show_iwd                 (when showing records, include working directory)
 --age=<days>               (how many days ago end time should be)
 --days=<days>              (how many days report should cover)
 --start="YYYY-MM-DD HH:MM" (date of start time of report)
"""
	sys.stderr.write(msg)

def ReadHistoryFile(history_file,class_ads):
	F = open(history_file,"r")

	current_ad = {}

	while 1:
		line = F.readline()
		if not line:
			break

		if line.find("***") == 0:
			cluster = current_ad.get("clusterid")
			proc = current_ad.get("procid")
			if cluster and proc:
				class_ads[cluster + "." + proc] = current_ad
			current_ad = {}
			continue

		fields = line.split("=",1)
		if len(fields) == 2:
			attribute = fields[0].lower().strip()
			value = fields[1].strip()
			current_ad[attribute] = value

	cluster = current_ad.get("clusterid")
	proc = current_ad.get("procid")
	if cluster and proc:
		class_ads[cluster + "." + proc] = current_ad

def ShowSummary(site_summaries):
	sorted_summary = []

	total = SiteSummary()
	total.name = "TOTAL"

	for site in site_summaries.keys():
		site_info = site_summaries[site]
		sort_val = site_info.hours.get("C")
		sorted_summary.append([sort_val,site_info])
		for key in site_info.hours.keys():
			if key not in  total.hours:
				total.hours[key] = 0
			total.hours[key] += site_info.hours[key]
		for key in site_info.jobs.keys():
			if key not in total.jobs:
				total.jobs[key] = 0
			total.jobs[key] += site_info.jobs[key]

	sorted_summary.sort()
	sorted_summary.reverse()
	sorted_summary.append([0,total])

	print("%-15s %5s %7s %7s" % ("Site", "Hours", "Jobs", "Runs"))
	print("%-15s %5s %7s %5s" % ("", "", "Completed", "Aborted"))
	print("-------------------------------------------------------")

	for sort_val,site_info in sorted_summary:
		c_hours = int(round(site_info.hours.get("C",0)))
		c_jobs = site_info.jobs.get("C",0)
		x_jobs = 0
		for code in site_info.jobs.keys():
			if code == "C": continue
			x_jobs += site_info.jobs[code]
		if site_info.name == "TOTAL":
			print("-------------------------------------------------------")
		print("%-15s %5s %7s %5s" % (site_info.name, c_hours, c_jobs, x_jobs))


long_options = [
	"help",
	"show_records",
	"days=",
	"age=",
	"start=",
	"show_iwd"
]

report_period = 60*60*24
end_timestamp = time.time()
show_records = 0
start_timestamp = None
show_iwd = 0

try:
    options,args = getopt.getopt(sys.argv[1:],"h",long_options)
    for option,value in options:
        if option == "--help" or option == "-h":
            Usage()
            os._exit(0)
        if option == "--age":
            end_timestamp = time.time() - 3600*24*float(value)
        if option == "--start":
            t = time.strptime(value,"%Y-%m-%d %H:%M")
            a = []
            for i in t:
                a.append(i)
            a[8] = -1 #unknown daylight savings time
            start_timestamp = time.mktime(a)
        if option == "--days":
            report_period = 3600*24*float(value)
        if option == "--show_records":
            show_records = 1
        if option == "--show_iwd":
            show_iwd = 1
except Exception as e:
    sys.stderr.write("Command line argument error: %s\n" % (e))
    Usage()
    sys.exit(1)

show_summary = not show_records

if not start_timestamp:
	start_timestamp = end_timestamp - report_period

spool_dir = os.popen("condor_config_val SPOOL").read()
spool_dir = spool_dir.strip()
if not spool_dir:
	sys.stderr.write("Cannot find spool directory with 'condor_config_val SPOOL'\n")
	sys.exit(1)

start_time_desc = time.strftime("%Y-%m-%d %H:%M",time.localtime(start_timestamp))
end_time_desc = time.strftime("%Y-%m-%d %H:%M",time.localtime(end_timestamp))

print("Routed job history from " + start_time_desc + " to " + end_time_desc)
print()

if show_records:
	print("JobID", "Status", "Site", "Runtime", end = ' ')
	if show_iwd:
		print("IWD", end = ' ')
	print()

class_ads = {}

for fname in os.listdir(spool_dir):
	if fname.find("history") == 0:
		history_file = os.path.join(spool_dir,fname)
		mtime = os.stat(history_file)[8]
		if mtime < start_timestamp:
			continue

		ReadHistoryFile(history_file,class_ads)

site_summaries = {}

for jobid in class_ads.keys():
	ad = class_ads[jobid]

	route = ad.get("routename")
	if not route:
		#for backward compatibility
		route = ad.get("routedfromroute")
		if not route:
			continue

	route = route.replace('"','')

	cdate = float(ad.get("completiondate"))
	if cdate < start_timestamp:
		continue
	if cdate > end_timestamp:
		continue

	jobstatus = ad.get("jobstatus")
	job_status_codes = "UIRXCHE"
	status_code = job_status_codes[int(jobstatus)]

	remote_walltime = ad.get("remotewallclocktime",0)
	remote_walltime = int(round(float(remote_walltime)))

	site_sum = site_summaries.get(route)
	if not site_sum:
		site_sum = SiteSummary()
		site_sum.name = route
		site_summaries[route] = site_sum
	if not site_sum.hours.get(status_code):
		site_sum.hours[status_code] = 0
	site_sum.hours[status_code] += remote_walltime/3600

	if not site_sum.jobs.get(status_code):
		site_sum.jobs[status_code] = 0
	site_sum.jobs[status_code] += 1

	if show_iwd:
		iwd = ad.get("submit_iwd","")
		if len(iwd) > 1:
			if iwd[0] == '"' and iwd[-1] == '"':
				iwd = iwd[1:-1]
	if show_records:
		print(jobid, status_code, route, remote_walltime, end = ' ')
		if show_iwd:
			print(iwd, end = ' ')
		print()

if show_summary:
	ShowSummary(site_summaries)
