#!/usr/bin/python
#
#	released under the terms of the GPL v 2.0 (or later, at your opinion)
#	(c) 2005,2006 Roland Lezuo <roland.lezuo@chello.at>
#
# a gnome-screensaver compatible hack using gnomego.board to draw games from .sgf files
#

__author__ = "Roland Lezuo <roland.lezuo@chello.at>"

import logging
logger = logging.getLogger("sgf-screensaver")

import gnomego.board
import gnomego.preferences
import gnomego.sgfparser
import sys
import gtk
import pango
import os
import time
import random
import zipfile
import gettext

# implements an empty game
class NoneGame:
	def __init__(self):
		self._meta = gnomego.sgfparser.SGFGameMeta()
		self._meta.__str__ = lambda: gettext.gettext("Error loading file")
	def get_metadata(self):
		return self._meta
	def get_white_stones(self):
		return []
	def get_black_stones(self):
		return []
	def get_move_history(self):
		return {}
	# False means game is over
	def step(*a):
		return False


class Game:
	_delay = 10			# after end of one game, how long to pause (in single steps)

	# path_to_sgfs is a list of pathnames, in each path all zip files are treated as archives containing .sgf files
	# for each newFile a radnom file from a random zip archive will be read
	# one can also put single sgf files into searchpathes
	def __init__(self, path):
		self._sgffiles = []
		self._zipfiles = []
		for p in path:
			logging.info("Walking " + str(p))
			# we walk the whole directory structure and scan for files
			for root,dirs,files in os.walk(p):
				for f in files:
					logging.info(f)
					if zipfile.is_zipfile(os.path.join(root, f)):
						zn = os.path.join(root, f)
						self._zipfiles.append( (zn, zipfile.ZipFile(zn)) )
					else:
						self._sgffiles.append(os.path.join(root, f))
		# count the number of files in total
		self._partition = []
		self._nrfiles = len(self._sgffiles)
		self._partition.append(self._nrfiles)
		# iterate all zip archives and count theire entries, FIXME: this also counts directories, which is not what we want
		# but most probably there are lots of files in .zip archives so the few directory won't hurt too much
		for zn, zf in self._zipfiles:
			self._nrfiles += len(zf.namelist())
			self._partition.append(self._nrfiles)

		# self._partition can be queried to figure out in where to search for a given file number
		self._parser = gnomego.sgfparser.SGFParser()
		self._newFile()


	def _newFile(self):
		self._game = NoneGame()
		self._delaycount = 0
		fn = 'None'
		# try to parse the file
		success = False
		try:
			newfile = random.randint(0, self._nrfiles-1)
			#check where to search for the given file
			if newfile < self._partition[0]:
				# we choose to take a plain .sgf file, read contents:
				fn = self._sgffiles[newfile]
				f = open(fn, 'r')
				bytes = f.read()
				self._fn = ('', fn, bytes)
			else:
				# the file is part of some zip archive, find out which
				i = 0
				logging.debug(newfile)
				logging.debug(self._partition)
				while newfile > self._partition[i+1]: i += 1
				# self._zipfiles[i] containts file we want, adopt index
				zn, zf = self._zipfiles[i]
				newfile_i = newfile - self._partition[i]
				fn = zf.namelist()[newfile_i]
				bytes = zf.read(fn)
				self._fn = (zn, fn, bytes)

			logging.info("FILENAME:" + str(fn))
			self._size = 19

			self._parser.parseString(self._fn[2])
			self._game = gnomego.sgfparser.GnomeGoGame(self._parser.getSGFGame(0))
			logger.info("Loaded game")
		except Exception,e:
			logger.critical(fn + " " + str(e))
		except:
			logger.critical(fn + " unknown exception")

	def step(self):
		# game returns false when at end
		if not self._game.step():
			self._delaycount += 1
			global board
			board.set_movenumbers(False)
		if self._delaycount == self._delay:
			self._newFile()
			global board
			board.set_movenumbers(True)
	
	def get_white_stones(self):
		return self._game.get_white_stones()
	def get_black_stones(self):
		return self._game.get_black_stones()
	def get_move_history(self):
		return self._game.get_move_history()
	def get_captures(self):
		return ''
	def get_size(self):
		return self._size
	def get_metadata(self):
		return str(self._game.get_metadata())
	# return either plain sgf filename, or ziparchive:filename
	def get_filename(self):
		zn, fn, bytes = self._fn
		if zn == '':
			return fn
		else:
			return str(zn)+":"+str(fn)
def main():
	remote = False
	try:
		xwinid = os.environ['XSCREENSAVER_WINDOW']
		dis = os.environ['DISPLAY']	
		remote = True
	except:
		logger.info("no remote window defined in env, creating our own")


	display = None
	if remote:
		# try to attach to the remote window
		display = gtk.gdk.Display(dis)
		logger.debug("get remote winow for display " + str(display) + " with id " + xwinid)
		rw = gtk.gdk.window_foreign_new_for_display(display, int(xwinid, 16))
		if rw:
			logger.debug("got remote winow")
		else:
			logger.critical("error getting remote window")
			sys.exit(-1)

		drawable = rw
	else:
		# create out own window
		w = gtk.Window()
		w.resize(800,800)
		w.show()
		drawable = w.window
		display = gtk.gdk.Display(':0.0')	#FIXME
	
	pref = gnomego.preferences.GnomeGoPref()
	path = pref.get_string('sgfpath')

	path2 = path.split(':')
	logging.debug(path2)
	game = Game(path2)

	screenx,screeny = drawable.get_size()

	if screenx < screeny:
		y_off = (screeny - screenx)/2
		x_off = 0
		screeny = screenx
	else:
		x_off = (screenx - screeny)/2
		y_off = 0
		screenx = screeny
	size = 19
	scale = 2.0
	(x,y) = gnomego.board.get_size(size, scale)
	pixmap = gtk.gdk.Pixmap(drawable, x, y)

	logger.debug('creating pango_ctx')
	#hmm they simply renamed that one, try both names
	try:
		pango_ctx = gtk.gdk.pango_context_get_for_screen(display.get_default_screen())
	except:
		pango_ctx = gtk.gdk.gdk_pango_context_get_for_screen(display.get_default_screen())
	logger.debug('have a pango ctx')

	
	global board
	board = gnomego.board.Board(pixmap, game, size, scale, False, True, False, pango_ctx, pref.installed_prefix)

	try:
		c = gconf.client_get_default()
		logger.debug(str(c))
	except:
		logger.warning("Exception: gconf.client_get_default")
		pass
		

	backcolor = pref.get_string('boardcolor')
	backimg =   pref.get_string('boardimg')

	logger.debug('got gconf values')
	try:
		board.set_background_color(gtk.gdk.color_parse(backcolor))
	except:
		pass
	board.set_background_image(backimg)

	# most probabyl we die here because our remote window gets destroyed, well at least we are dead
	# so no gtk.main_quit() needs to be called, FIXME
	while True:
		logger.debug('loop')
		board.redraw()		# this draw on pixmap

		# print addition information about game, like players, and filename
		gc = drawable.new_gc()
		color = gtk.gdk.Color(0,0,0)
		text = pango.Layout(pango_ctx)
		text.set_width(-1)

		text.set_text(game.get_metadata())
		x,y = board.get_header_offset()
		pixmap.draw_layout(gc, x, y , text, color)

		text.set_text(game.get_filename())
		x,y = board.get_footer_offset()
		pixmap.draw_layout(gc, x,y, text, color)	

		# finally draw the pixbuf
		pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, *board.get_size())
		pixbuf = pixbuf.get_from_drawable(pixmap, gtk.gdk.colormap_get_system(), 0, 0, 0, 0, -1, -1)
		scale_pixbuf = pixbuf.scale_simple(screenx, screeny, gtk.gdk.INTERP_BILINEAR)
		drawable.draw_pixbuf(None, scale_pixbuf, 0, 0, x_off, y_off)

		gtk.main_iteration()
		time.sleep(1)
		game.step()

if __name__ == '__main__':
	if os.getenv("GNOMEGO_DEBUG") != None:
		logging.basicConfig(level=logging.DEBUG)
	else:
		logging.basicConfig()

	main()
