#!/usr/bin/python3
import numpy as np
import re
import sys, getopt
import fileinput
import argparse

#--------------------------------------------------------------------------------
# Parse arguments
parser = argparse.ArgumentParser(description='Produce a graph representing CPU activity over time.')
parser.add_argument('-i', '--input' , dest='infile' , type=argparse.FileType('r'), default=sys.stdin, help='input file containing processor activity; if none specified then will use stdin.')
parser.add_argument('-o', '--output', dest='outfile', type=argparse.FileType('w'), default=None, help='output file with any image format extension such as .png or .svg; if none specified then plt.show() will be used')
args = parser.parse_args()

print("----- Processing Halts Output -----")
if not args.outfile:
	print("ERROR : no output file specified and interactive mode not supported", file=sys.stderr)
	sys.exit(1)

#--------------------------------------------------------------------------------
# Process data
class Proc:
	def __init__(self, id, name, address):
		self.name    = name
		self.address = address
		self.id      = id

class Point:
	def __init__(self, time, on):
		self.time = time
		self.on = on

processors = {}
data = {}

#--------------------------------------------------------------------------------
# Parse data
for line in args.infile:
	match = re.match("Processor : ([0-9]+) - (.*) \((0x[0-9a-f]+)\)", line)
	if match :
		id = int(match.group(1))
		processors[id] = Proc(id, match.group(2), match.group(3))
		continue

	match = re.match("PH:([0-9]+) - ([0-9]+) ([0-9]+)", line)
	if match :
		id = int(match.group(1))
		if not id in data:
			data[id] = []
		data[id].append(Point(int(match.group(2)), int(match.group(3))))
		continue

	print("WARNING : line '%s' filterred not matched" % line, file=sys.stderr)

#--------------------------------------------------------------------------------
# Check data
if not data:
	print("ERROR : no data extracted from '%s'" % args.infile, file=sys.stderr)

for d in data:
	if not d in processors:
		print("WARNING : unkown processor '%s'" % d, file=sys.stderr)

	prevT = data[d][0].time
	prevO = data[d][0].on
	for p in data[d][1:]:
		if prevT > p.time:
			print("WARNING : Time is inconsistant for Proc '%s'" % d, file=sys.stderr)

		if prevO == p.on:
			print("WARNING : State is inconsistant for Proc '%s' at %s-%s" % (d, prevT, p.time), file=sys.stderr)

		prevT = p.time
		prevO = p.on


#--------------------------------------------------------------------------------
# Convert data to series
offset = min(data)
series = dict()
for d in data:
	series[d] = ([], [], [])
	for p in data[d]:
		series[d][0].append( p.time )
		series[d][1].append(p.on + d - offset)
		series[d][2].append(d - offset)

#--------------------------------------------------------------------------------
# setup matplotlib
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
plt.style.use('dark_background')

#--------------------------------------------------------------------------------
# setup plot
dots_per_inch = 200
height_inches = 5
width_inches = 12
fig = plt.figure(figsize=(width_inches, height_inches), dpi=dots_per_inch)
print('number of series={}'.format(len(series)))
for s, xy in series.items():
	if s in processors:
		name = '"{}" ({})'.format(processors[s].name, processors[s].address)
	else:
		name = s
	print( '    plotting series {} with {} points'.format(name, len(xy[0])) )
	plt.fill_between(xy[0], xy[1], xy[2], step="post", alpha=0.4)
	plt.step(xy[0], xy[1], where='post')

#--------------------------------------------------------------------------------
# y axis major, minor
ax = plt.gca()
ax.grid(which='major', axis='y', linestyle='-', color='lightgray')
ax.yaxis.set_minor_locator(ticker.AutoMinorLocator())
ax.grid(which='minor', axis='y', linestyle='dotted', color='gray')

#--------------------------------------------------------------------------------
# x axis major, minor
ax.grid(which='major', axis='x', linestyle='-', color='lightgray')
ax.xaxis.set_minor_locator(ticker.AutoMinorLocator())
ax.grid(which='minor', axis='x', linestyle='dotted', color='gray')

#--------------------------------------------------------------------------------
# do the plot
plt.tight_layout()
print("saving figure image %s\n" % args.outfile.name)
plt.savefig(args.outfile.name)