# -*- Mode: Python; tab-width: 4 -*-

#			
# medusa status extension
#

import string
import time
import regex

import asyncore
import http_server
import medusa_gif
import producers

START_TIME = int(time.time())

class status_extension:
	hit_counter = http_server.counter()

	def __init__ (self, objects, regexp='/status\(/.*\)?'):
		self.objects = objects
		self.regexp = regex.compile (regexp)

	def __repr__ (self):
		return '<Status Extension (%d hits) at %x>' % (
			self.hits,
			id(self)
			)

	def match (self, request):
		path = request.uri[0]
		return self.regexp.match (path) == len(path)

	def handle_request (self, request):
		pass
		
	# Possible Targets:
	# /status
	# /status/channel_list
	# /status/medusa.gif

	# can we have 'clickable' objects?
	# [yes, we can use id(x) and do a linear search]

	# Dynamic producers:
	# HTTP/1.0: we must close the channel, because it's dynamic output
	# HTTP/1.1: we can use the chunked transfer-encoding, and leave
	#   it open.

	def handle_request (self, request):
		[path, params, query, fragment] = request.uri
		self.hit_counter.increment()
		if path == '/status':
			up_time = string.join (english_time (int(time.time()) - START_TIME))
			request['Content-Type'] = 'text/html'
			request.push (
				'<html><body>\r\n<h1>Medusa Status Reports</h1>'
				'<b>Up:</b> %s' % up_time
				)
			for i in range(len(self.objects)):
				request.push (self.objects[i].status())
				request.push ('<hr>\r\n')
			request.push (
				'<p><a href="/status/channel_list">Channel List</a>'
				'<hr>'
				'<img src="/status/medusa.gif" align=right width=97 height=61>'
				'</body></html>'
				)
		elif path == '/status/channel_list':
			request['Content-Type'] = 'text/html'
			request.push ('<html><body>')
			request.push(channel_list_producer())
			request.push (
				'<hr>'
				'<img src="/status/medusa.gif" align=right width=97 height=61>'
				'</body></html>'
				)
		elif path == '/status/medusa.gif':
			request['Content-Type'] = 'image/gif'
			request['Content-Length'] = len(medusa_gif.data)
			request.push (medusa_gif.data)
		else:
			channel.send_reply (404, path)

class lines_producer:
	def __init__ (self, lines):
		self.lines = lines

	def ready (self):
		return len(self.lines)

	def more (self):
		if self.lines:
			chunk = self.lines[:50]
			self.lines = self.lines[50:]
			return string.join (chunk, '\r\n') + '\r\n'
		else:
			return ''

class channel_list_producer (lines_producer):
	def __init__ (self):
		channel_reprs = map (
			lambda x: '&lt;' + repr(x)[1:-1] + '&gt;',
			asyncore.socket_map.keys()
			)
		channel_reprs.sort()
		lines_producer.__init__ (
			self,
			['<h1>Active Channel List</h1>',
			 '<pre>'
			 ] + channel_reprs + [
				 '</pre>',
				 '<p><a href="/status">Status Report</a>'
				 ]
			)


# this really needs a full-blown quoter...
def sanitize (s):
	if '<' in s:
		s = string.join (string.split (s, '<'), '&lt;')
	if '>' in s:
		s = string.join (string.split (s, '>'), '&gt;')
	return s

def html_reprs (list, front='', back=''):
	reprs = map (
		lambda x,f=front,b=back: '%s%s%s' % (f,x,b),
		map (lambda x: sanitize(repr(x)), list)
		)
	reprs.sort()
	return reprs

# for example, tera, giga, mega, kilo
# p_d (n, (1024, 1024, 1024, 1024))
# smallest divider goes first - for example
# minutes, hours, days
# p_d (n, (60, 60, 24))

def progressive_divide (n, parts):
	result = []
	for part in parts:
		n, rem = divmod (n, part)
		result.append (rem)
	result.append (n)
	return result

# b,k,m,g,t
def split_by_units (n, units, dividers, format_string):
	divs = progressive_divide (n, dividers)
	result = []
	for i in range(len(units)):
		if divs[i]:
			result.append (format_string % (divs[i], units[i]))
	result.reverse()
	return result

def english_bytes (n):
	return split_by_units (
		n,
		('','k','M','G','T'),
		(1024, 1024, 1024, 1024, 1024),
		'%d %sb'
		)

def english_time (n):
	return split_by_units (
		n,
		('secs', 'mins', 'hours', 'days', 'weeks', 'years'),
		(         60,     60,      24,     7,       52),
		'%d %s'
		)