
# script.py
# Runs a selection script

# Copyright (c) 2005 by Matthias Urlichs <smurf@smurf.noris.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of Version 2 of the GNU General Public License as
# published by the Free Software Foundation. See the file COPYING.txt
# or (on Debian systems) /usr/share/common-licenses/GPL-2 for details.

"""\
The Script class encapsulates the interpreter for the keymap selection
script generated by FileReporter.

The .run method will either return the keymap's name, or an error
exception will be raised.

"""

class FoundMap(Exception):
	"""Pseudo-exception, raised when the script terminates with a unique keyboard map"""
	pass
class UnknownLine(Exception):
	"""The script file contains a line that's not parseable"""
	pass
class BadFile(Exception):
	"""The script file isn't well-formed"""
	pass

class Script(object):
	"""Run this script with that query. Return the result."""

	def __init__(self,file,query):
		self.file = file
		self.in_step = -1
		self.query = query

	def get_step(self,nr):
		"""Return the data for step NR."""
		for f in self.file:
			f = f.strip()
			if f == "" or f.startswith("#"):
				continue
			if f.startswith("STEP"):
				f = f[4:]
				f = int(f.strip())
				if self.in_step == nr: # done
					self.in_step = f
					return
				self.in_step = f
			elif self.in_step == nr:
				yield f

		# ran off the end of the file?
		if nr != self.in_step:
			raise BadFile

	def run_step(self,step):
		"""Run a singe step.
		   Returns the next step's number, or raise an exception."""
		what = None
		syms = []
		keys = {}

		# First, collect the data
		for line in self.get_step(step):
			if line.startswith("PRESS") and what in (None,"press"):
				what="press"
				syms.append(line[5:].strip())
			elif line.startswith("CODE") and what in (None,"press"):
				what="press"
				code,goal = line[4:].strip().split()
				keys[int(code)] = int(goal)
			elif line.startswith("MAP") and what in (None,):
				raise FoundMap(line[3:].strip())
			elif line.startswith("FIND") and what in (None,):
				what="find1"
				find = line[4:].strip()
			elif line.startswith("YES") and what in ("find1",):
				what="find2"
				dest_yes = int(line[3:].strip())
			elif line.startswith("NO") and what in ("find2",):
				what="find3"
				dest_no = int(line[4:].strip())
			else:
				raise UnknownLine(line.strip())

		# Second, decide what to do
		if what == "press" and syms and keys:
			while True:
				code = self.query.press(syms)
				if code in keys:
					return keys[code]
				self.query.message("Unexpected key code: <%d>" % code)
		elif what == "find3":
			if self.query.ask(find):
				return dest_yes
			else:
				return dest_no

		else:
			raise BadFile
		
	def run(self):
		"""Run this script, starting with step 0."""
		step=0
		while True:
			try:
				step = self.run_step(step)
			except FoundMap,exc:
				return exc.args[0]
		
