# -*- coding: utf-8 -*-
import os
import re
import time
import glob
import gzip
import time
import string
from datetime import datetime, timedelta
from jinja2 import Environment, FileSystemLoader

import cgi


_ansiColor = re.compile(r'\x1b[^m]*m')


def _mjdmpm2datetime(mjd, mpm):
	"""
	Convert a MJD, MPM pair to a UTC-aware datetime instance.
	"""
	
	unix = mjd*86400.0 + mpm/1000.0 - 3506716800.0
	return datetime.utcfromtimestamp(unix)


def _getMSELog(start, stop):
	startDir = start.replace(hour=0, minute=0, second=0)
	stopDir  = stop.replace(hour=23, minute=59, second=59)
	
	startDir = startDir - timedelta(days=2)
	stopDir  = stopDir  + timedelta(days=2)
	
	currDir = startDir
	logFiles = []
	while currDir <= stopDir:
		logFiles.extend( glob.glob('/FileStore/Miscellaneous/metadata/lwana/observation/%s_done/mselog*.txt' % currDir.strftime("%y%m%d")) )
		currDir = currDir + timedelta(days=1)
	logFiles.sort()
	
	entries = []
	for filename in logFiles:
		fh = open(filename, 'r')
		for line in fh:
			try:
				fields = line.split(None, 4)
				eTime = datetime.strptime("%s %s" % (fields[0], fields[1]), "%y%m%d %H:%M:%S")
				
				if eTime >= start and eTime <= stop:
					entries.append( line )
				elif eTime > stop:
					break
					
			except (IndexError, ValueError):
				pass
				
		fh.close()
		
	if len(entries) == 0:
		entries.append( 'Nothing Found' )
	entries = ''.join(entries)
	entries = filter(lambda x: True if ord(x) < 128 else False, entries)
		
	return entries


def _getMEELog(start, stop):
	logFiles = glob.glob('/FileStore/Miscellaneous/metadata/lwana/observation/*_done/meelog*.txt')
	logFiles.sort()
	
	entries = []
	for filename in logFiles:
		dirName = os.path.dirname(filename)
		dirName = os.path.basename(dirName)
		dirDate = dirName.split('_')[0]
		dirDate = datetime.strptime("%s 00:00:00" % dirDate, "%y%m%d %H:%M:%S")
		
		if dirDate < start:
			continue
			
		fh = open(filename, 'r')
		for line in fh:
			try:
				fields = line.split(None, 2)
				eTime = _mjdmpm2datetime(int(fields[0], 10), int(fields[1], 10))
				if eTime >= start and eTime <= stop:
					entries.append( line )
				elif eTime > stop:
					break
					
			except IndexError:
				pass
				
		fh.close()
		
	if len(entries) == 0:
		entries.append( 'Nothing Found' )
	entries = ''.join(entries)
	
	return entries


def _getStandardLog(subsys, start, stop):
	subsys = subsys.upper()
	startDir = start.replace(hour=0, minute=0, second=0)
	stopDir  = stop.replace(hour=23, minute=59, second=59)
	
	startDir = startDir - timedelta(days=1)
	stopDir  = stopDir  + timedelta(days=1)
	currDir = startDir
	logFiles = []
	while currDir <= stopDir:
		filename = '/FileStore/Miscellaneous/metadata/lwana/subsystem/%s/runtime_%s.gz' % (subsys, currDir.strftime("%y%m%d"))
		if os.path.exists(filename):
			logFiles.append( filename )
		currDir = currDir + timedelta(days=1)
	logFiles.sort()
	
	entries = []
	for filename in logFiles:
		fh = gzip.open(filename, 'r')
		for line in fh:
			try:
				fields = line.split(None, 2)
				eTime = datetime.strptime("%s %s" % (fields[0], fields[1]), "%Y-%m-%d %H:%M:%S")
				if eTime >= start and eTime <= stop:
					entries.append( line )
				elif eTime > stop:
					break
					
			except (IndexError, ValueError):
				pass
				
		fh.close()
	if len(entries) == 0:
		entries.append( 'Nothing Found' )
	entries = ''.join(entries)
	
	if subsys == 'DP':
		control_chars = ''.join(map(unichr, range(127,256)))
		control_char_re = re.compile('[%s]' % re.escape(control_chars))
		entries = control_char_re.sub('?', entries)
		#entries = entries.translate(string.maketrans("",""), control_chars)
		
	return entries


def _getDRLogs(drN, start, stop):
	startDir = start.replace(hour=0, minute=0, second=0)
	stopDir  = stop.replace(hour=23, minute=59, second=59)
	
	startDir = startDir - timedelta(days=14)
	stopDir  = stopDir  + timedelta(days=14)
	currDir = startDir
	logFiles = []
	while currDir <= stopDir:
		logFiles.extend( glob.glob('/FileStore/Miscellaneous/metadata/lwana/subsystem/DR%i/runtime_%s_*.gz' % (drN, currDir.strftime("%y%m%d"))) )
		currDir = currDir + timedelta(days=1)
	logFiles.sort()
	
	entries = []
	for filename in logFiles:
		fh = gzip.open(filename, 'r')
		block = {'dt':None, 'data':[]}
		
		for line in fh:
			line = _ansiColor.sub('', line)
			try:
				fields = line.split(None, 2)
				eTime = datetime.strptime("%s %s" % (fields[0], fields[1]), "%Y-%m-%d %H:%M:%S.%f")
				
				if block['dt'] is not None:
					eTimeOld = block['dt']
					dataOld = block['data']
					if eTimeOld >= start and eTimeOld <= stop:
						entries.extend( dataOld )
					elif eTimeOld > stop:
						break
						
				block = {'dt':eTime, 'data': [line,]}
				
			except ValueError:
				block['data'].append(line)
			except IndexError:
				pass
				
		fh.close()
		
		if block['dt'] is not None:
			eTime = block['dt']
			data = block['data']
			if eTime >= start and eTime <= stop:
				entries.extend( data )
				
	if len(entries) == 0:
		entries.append( 'Nothing Found' )
	entries = ''.join(entries)
	
	return entries


def _getLightningLogs(start, stop):
	startDir = start.replace(hour=0, minute=0, second=0)
	stopDir  = stop.replace(hour=23, minute=59, second=59)
	
	startDir = startDir - timedelta(days=1)
	stopDir  = stopDir  + timedelta(days=1)
	currDir = startDir
	logFiles = []
	while currDir <= stopDir:
		filename = '/FileStore/Miscellaneous/metadata/lwana/subsystem/LDT/lightning_%s.gz' % currDir.strftime("%y%m%d")
		if os.path.exists(filename):
			logFiles.append(filename)
		currDir = currDir + timedelta(days=1)
	logFiles.sort()
	
	entries = []
	for filename in logFiles:
		fh = gzip.open(filename, 'r')
		for line in fh:
			fields = line.split(None, 3)
			eTime = datetime.strptime("%s %s" % (fields[0], fields[1]), "[%Y-%m-%d %H:%M:%S.%f]")
			if eTime >= start and eTime <= stop:
				entries.append( line )
			elif eTime > stop:
				break
		fh.close()
		
	if len(entries) == 0:
		entries.append( 'Nothing Found' )
	entries = ''.join(entries)
	
	return entries


def application(environ, start_response):
	# Mark the current time
	t0 = time.time()
	
	status = '200 OK'
	response = b''
	
	# Deal with inputs - 'first' marker
	form_env = environ.copy()
       	form_env['QUERY_STRING'] = ''
        form = cgi.FieldStorage(fp=environ['wsgi.input'],
                                environ=form_env,
                                keep_blank_values=True)
	firstTime = form.getfirst('first', "1")
	
	# Deal with inputs - start and stop date/times first
	startDate = form.getfirst('startDate', None)
	startTime = form.getfirst('startTime', None)
	stopDate  = form.getfirst('stopDate',  None)
	stopTime  = form.getfirst('stopTime',  None)
	## Test conversions
	try:
		junk = datetime.strptime("%s 00:00" % startDate, "%Y-%m-%d %H:%M")
	except ValueError:
		startDate = None
	try:
		junk = datetime.strptime("2015-05-01 %s" % startTime, "%Y-%m-%d %H:%M")
	except ValueError:
		startTime = None
	try:
		junk = datetime.strptime("%s 00:00" % stopDate, "%Y-%m-%d %H:%M")
	except ValueError:
		stopDate = None
	try:
		junk = datetime.strptime("2015-05-01 %s" % stopTime, "%Y-%m-%d %H:%M")
	except ValueError:
		stopTime = None
	## Do we have a valid time range?
	validTime = True
	validTime &= startDate is not None and startDate != ''
	validTime &= startTime is not None and startTime != ''
	validTime &= stopDate  is not None and stopDate  != ''
	validTime &= stopTime  is not None and stopTime  != ''
	
	# Deal with inputs - which subsystems to query
	mse = form.getfirst('mse', False) == 'on'
	mee = form.getfirst('mee', False) == 'on'
	asp = form.getfirst('asp', False) == 'on'
	dp  = form.getfirst('dp',  False) == 'on'
	dr1 = form.getfirst('dr1', False) == 'on'
	dr2 = form.getfirst('dr2', False) == 'on'
	dr3 = form.getfirst('dr3', False) == 'on'
	dr4 = form.getfirst('dr4', False) == 'on'
	dr5 = form.getfirst('dr5', False) == 'on'
	shl = form.getfirst('shl', False) == 'on'
	ldt = form.getfirst('ldt', False) == 'on'
	## Are we querying at least one log?
	validLogs = False
	validLogs |= mse
	validLogs |= mee
	validLogs |= asp
	validLogs |= dp
	validLogs |= dr1
	validLogs |= dr2
	validLogs |= dr3
	validLogs |= dr4
	validLogs |= dr5
	validLogs |= shl
	validLogs |= ldt
	
	# Make sure that we have enough information to proceed
	if not validTime or not validLogs:
		## If this isn't the first time the form has been send, generate an 
		## error code to let the user know what is going on
		if int(firstTime, 10):
			errors = []
			valid = True
		else:
			errors = []
			if not validTime:
				errors.append( "Invalid start/stop date/time to display" )
			if not validLogs:
				errors.append( "Must select at least one log type to display" )
			valid = False
			
		## Render
		path = os.path.join(os.path.dirname(__file__), 'templates')
		env = Environment(loader=FileSystemLoader(path))
		template = env.get_template('index.html')
		
		t1 = time.time()
		response = template.render(startDate=startDate, startTime=startTime, stopDate=stopDate, stopTime=stopTime, 
							mse=mse, mee=mee, asp=asp, dp=dp, dr1=dr1, dr2=dr2, dr3=dr3, dr4=dr4, dr5=dr5, shl=shl, ldt=ldt, 
							valid=valid, errors=errors, time=t1-t0).encode('utf-8')
							
	else:
		## Convert the date and time strings into datetime instances
		start = datetime.strptime("%s %s" % (startDate, startTime), "%Y-%m-%d %H:%M")
		stop  = datetime.strptime("%s %s" % (stopDate,  stopTime ), "%Y-%m-%d %H:%M")
		
		## Read the logs
		### MCS/Scheduler
		if mse:
			tL0 = time.time()
			mseLog = _getMSELog(start, stop)
			mseLogTime = time.time() - tL0
		else:
			mseLog = None
			mseLogTime = 0.0
		### MCS/Executive
		if mee:
			tL0 = time.time()
			meeLog = _getMEELog(start, stop)
			meeLogTime = time.time() - tL0
		else:
			meeLog = None
			meeLogTime = 0.0
		### ASP
		if asp:
			tL0 = time.time()
			aspLog = _getStandardLog('ASP', start, stop)
			aspLogTime = time.time() - tL0
		else:
			aspLog = None
			aspLogTime = 0.0
		### DP
		if dp:
			tL0 = time.time()
			dpLog = _getStandardLog('DP', start, stop)
			dpLogTime = time.time() - tL0
		else:
			dpLog = None
			dpLogTime = 0.0
		### DR1
		if dr1:
			tL0 = time.time()
			dr1Log = _getDRLogs(1, start, stop)
			dr1LogTime = time.time() - tL0
		else:
			dr1Log = None
			dr1LogTime = None
		### DR2
		if dr2:
			tL0 = time.time()
			dr2Log = _getDRLogs(2, start, stop)
			dr2LogTime = time.time() - tL0
		else:
			dr2Log = None
			dr2LogTime = 0.0
		### DR3
		if dr3:
			tL0 = time.time()
			dr3Log = _getDRLogs(3, start, stop)
			dr3LogTime = time.time() - tL0
		else:
			dr3Log = None
			dr3LogTime = 0.0
		### DR4
		if dr4:
			tL0 = time.time()
			dr4Log = _getDRLogs(4, start, stop)
			dr4LogTime = time.time() - tL0
		else:
			dr4Log = None
			dr4LogTime = 0.0
		### DR5
		if dr5:
			tL0 = time.time()
			dr5Log = _getDRLogs(5, start, stop)
			dr5LogTime = time.time() - tL0
		else:
			dr5Log = None
			dr5LogTime = 0.0
		### SHL
		if shl:
			tL0 = time.time()
			shlLog = _getStandardLog('SHL', start, stop)
			shlLogTime = time.time() - tL0
		else:
			shlLog = None
			shlLogTime = 0.0
		### LDT
		if ldt:
			tL0 = time.time()
			ldtLog = _getLightningLogs(start, stop)
			ldtLogTime = time.time() - tL0
		else:
			ldtLog = None
			ldtLogTime = 0.0
			
		## Render
		path = os.path.join(os.path.dirname(__file__), 'templates')
		env = Environment(loader=FileSystemLoader(path))
		template = env.get_template('results.html')
		
		t1 = time.time()
		response = template.render(startDate=startDate, startTime=startTime, stopDate=stopDate, stopTime=stopTime,
							mseLog=mseLog, meeLog=meeLog, aspLog=aspLog, dpLog=dpLog, dr1Log=dr1Log, 
							dr2Log=dr2Log, dr3Log=dr3Log, dr4Log=dr4Log, dr5Log=dr5Log, shlLog=shlLog, ldtLog=ldtLog, 
							mseLogTime=mseLogTime, meeLogTime=meeLogTime, aspLogTime=aspLogTime, dpLogTime=dpLogTime, 
							dr1LogTime=dr1LogTime, dr2LogTime=dr2LogTime, dr3LogTime=dr3LogTime, dr4LogTime=dr4LogTime,
							dr5LogTime=dr5LogTime, shlLogTime=shlLogTime, ldtLogTime=ldtLogTime, 
							time=t1-t0).encode('utf-8')
		
	response_headers = [('Content-Type', 'text/html'),
                            ('Content-Length', str(len(response)))
                           ]
        start_response(status, response_headers)
        return [response]
