"""
sLaTeX support for Rubber.
"""

from os import unlink
from os.path import exists, getmtime, join

import rubber
from rubber import _, msg, Depend, DependLeaf

def run(doc, env, base):
	msg.progress(_("running slatex on %s") % doc.src_base)
	if env.execute(["slatex", "-n", base], {}):
		msg.error(_("Error executing slatex"))
		return 1
			
	doc.must_compile = 1
	return 0

def slatex_needed(target, srcs):
	if not exists(target):
		msg.log(_("File %s does not exist") % target, pkg="slatex")
		return 1
	for src in srcs:
		if getmtime(target) < getmtime(src):
			msg.log(_("File %s older than %s") % (target, src), pkg="slatex")
			return 1
	return 0

class RubberDep (Depend):
	# Base is the slatex module
	# Target is the autogenerated file (i.e. .Z# + doc.src_base + ".tex")
	# Sources is a list of sources on which this file depends
	def __init__ (self, mod, target, srcs):
		self.mod = mod
		self.doc = mod.doc
		self.env = mod.doc.env
		self.target = target
		self.srcs = srcs
		
		sources = {}
		for src in srcs:
			sources[src] = DependLeaf(self.env, src)
		Depend.__init__(self, self.env,
			prods=[target],
			sources=sources)
		
		self.urvater = join(self.doc.src_path, self.doc.src_base + ".tex")

	def run(self):
		# We may have been out of date before any dependency was run,
		# but by this point we may be up to date since slatex builds
		# all the files at once.  Otherwise we'll run once per out of
		# date generated file.
		if slatex_needed(self.target, self.srcs):
			run(self.doc, self.env, self.urvater)

class Module (rubber.rules.latex.Module):
	def __init__ (self, doc, dict):
		self.base = doc.src_base
		self.base_file = join(doc.src_path, doc.src_base + ".tex")
		self.final = join(doc.env.path[0], doc.env.final.prods[0])
		self.count = 0
		self.doc = doc
		self.env = doc.env
		self.file_deps = {}
		self.path = doc.src_path
		self.preamble = False

		def add_scheme_file(dict, others=[]):
			filename = ".Z" + str(self.count) + self.base + ".tex"
			path = join(self.path, filename)
			deps = [dict["pos"]["file"]]
			if others:
				deps.extend(others)
			self.doc.sources[path] = RubberDep(self, path, deps)
			msg.log(_("Marking %s as dependent on %s") % (path, deps), pkg = "slatex")
			self.count += 1

		scheme_macros = ["scheme", "schemeresult"]

		scheme_envs = ["schemedisplay",
			       "schemeresponse",
			       "schemebox",
			       "schemeresponsebox"]

		preamble_macros = ["setspecialsymbol",
				   "setkeyword",
				   "defschememathescape"]

		def add_preamble_hook(name):
			def h_preamb(dict):
				if not self.preamble and slatex_needed(self.final, [self.base_file]):
					run(self.doc, self.env, self.base_file)
					self.preamble = True
			doc.add_hook(name, h_preamb)

		def add_macro_hook(name):
			def h_macro(dict):
				add_scheme_file(dict)
			doc.add_hook(name, h_macro)

		def add_env_hook(name):
			beg_env = "begin{%s}" % name
			end_env = "end{%s}" % name
			def begin_env_hook(dict):
				def end_env_hook(dict, self=doc, hooks=doc.hooks):
					self.hooks = hooks
					self.update_seq()
				doc.hooks = { end_env : end_env_hook }
				# \scheme, \schemeresult allowed in these.
				for macro in scheme_macros:
					add_macro_hook(macro)
				doc.update_seq()
				add_scheme_file(dict)
			doc.add_hook(beg_env, begin_env_hook)

		for macro in preamble_macros:
			add_preamble_hook(macro)
		for macro in scheme_macros:
			add_macro_hook(macro)
		for environ in scheme_envs:
			add_env_hook(environ)

		# handled specially so that we get dependence on the
		# file being included as well.
		def h_schemeinput(dict):
			arg_path = join(self.path, dict["arg"])
			add_scheme_file(dict, others=[arg_path])

		doc.add_hook("schemeinput", h_schemeinput)

		# schemeregions should generate one file for the entire
		# thing, so we shouldn't allow the separate scheme
		# hooks like above.
		def h_schemeregion(dict, end = "end{schemeregion}"):
			def end_env_hook(dict, self=doc, hooks=doc.hooks):
				self.hooks = hooks
				self.update_seq()
			doc.hooks = doc.hooks.copy()
			doc.hooks[end] = end_env_hook
			for macro in scheme_macros:
				if macro in doc.hooks:
					del doc.hooks[macro]
			for env in scheme_envs:
				if ("begin{%s}" % env) in doc.hooks:
					del doc.hooks["begin{%s}" % env]
			doc.update_seq()
			add_scheme_file(dict)

		doc.add_hook("begin{schemeregion}", h_schemeregion)

