#!/usr/bin/env python

import pygame, pygame.display, pygame.event, pygame.time, pygame.font
from pygame.locals import *

# initialize PyGame
pygame.init()

# setup screen
screen = pygame.display.set_mode( (640, 480), DOUBLEBUF )
pygame.display.set_caption( 'Client' )
# screen updates
pygame.time.set_timer( USEREVENT, 100 ) #33 == 30fps

class ClientClass:
	def __init__( self, screen ):
		
		# filter events
		badevents = [NOEVENT, ACTIVEEVENT, KEYUP, MOUSEMOTION, MOUSEBUTTONDOWN, MOUSEBUTTONUP, JOYAXISMOTION, JOYBALLMOTION, JOYHATMOTION, JOYBUTTONDOWN ,JOYBUTTONUP, VIDEORESIZE, SYSWMEVENT, NUMEVENTS]
		goodevents = [KEYDOWN, QUIT, USEREVENT ]
		pygame.event.set_blocked( badevents )
		
		self.running = 1
		self.screen = screen
		self.widgets = []
		
	def loop( self ):
		while self.running:
			event = pygame.event.wait()
			if event.type == QUIT: self.running = 0
			elif event.type == KEYDOWN:
				self.widgets[0].append( "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ", (0xFF, 0x00, 0xFF, 0xFF) )
			for w in self.widgets:
				w.draw( self.screen )
			pygame.display.update()
			#pygame.event.pump()

class PageClass:
	def __init__( self, x, y, w, h, background=(0, 0, 0, 0), size=24 ):
		self.x = x
		self.y = y
		self.w = w
		self.h = h
		self.background = background
		self.font = pygame.font.Font( None, size )
		self.lines = []
		self.dirty = 0
		self.height = 0
		self.append( "PageClass" )
	
	def append( self, newtext, foreground=(0xFF, 0xFF, 0xFF, 0xFF) ):
		# append each line separately
		for line in newtext.splitlines():
				self.appendline( line, foreground )
	
	def fits( self, text ):
		# size of the text
		(fw, fh) = self.font.size( text )
		# too wide
		if fw > self.w: return 0
		return 1
	
	def appendline( self, newtext, foreground ):
		# remove trailing whitespace
		newtext = newtext.rstrip()
		
		# find largest piece of text that will fit on one line
		pt = len( newtext )
		while not self.fits( newtext[:pt] ):
			#print "."
			pt = newtext.rfind( " ", 0, pt )
			
			# no spaces left
			if pt == -1:
				# break on text
				pt = len( newtext )
				while not self.fits( newtext[:pt] ):
					# not even one letter will fit
					if pt == 1: raise Exception
					pt -= 1
				
		thistext = newtext[:pt] + " "
		newtext = newtext[pt:]
		
		# make a new surface
		surface = self.font.render( thistext, 1, foreground, self.background )
		self.lines.insert( 0, surface )
		self.height += surface.get_height()
		
		# discard invisible lines
		nh = self.height - self.lines[-1].get_height()
		while( nh > self.h ):
			#print 'discarding...'
			del self.lines[-1]
			self.height = nh
			nh -= self.lines[-1].get_height()
		
		# leftover wrapped text
		if len( newtext ) > 0:
			self.appendline( newtext, foreground )
		
		self.dirty = 1
	
	def draw( self, screen ):
		# clip our drawing
		screen.set_clip( (self.x, self.y, self.w, self.h) )
		# start at the bottom
		y = self.y + self.h
		# each line... first is at bottom
		for surface in self.lines:
			sw = surface.get_width()
			sh = surface.get_height()
			# upper left corner
			y -= sh
			# blit it to the screen
			screen.blit( surface, (self.x, y) )
			# fill in the right edge
			screen.fill( self.background, (self.x + sw, y, self.w - sw, sh ) )
		
		# blank space above
		if y > self.y:
			# fill it in
			screen.fill( self.background, (self.x, self.y, self.w, y - self.y) )

client = ClientClass( screen )
page = PageClass( 0, 0, 400, 250, (64, 64, 64, 0) )
client.widgets.append( page )
client.loop()

#clean up
pygame.time.set_timer( USEREVENT, 0 )
pygame.quit()
