'''togl_setup.py

Compiles and installs Togl.

We create a sub-class of the standard build_ext command,
named build_togl, which is responsible for compiling the
Tk Togl widget.  Our sub-class of install then takes care
of installing the resulting .dll/.so into the Python
installation against which we have compiled.

The setup process uses the headers from a source
distribution of tcl (from the tcl project on sourceforge)
and the .lib files from the Python Tkinter directory.
'''

# created 2000/08/01, Rene Liebscher <R.Liebscher@gmx.de>

import sys,os,string, os.path
import distutils.command.install
import distutils.command.build_ext
from distutils.dep_util import newer_group

# this is also a simple test if we need to build Togl
# without Tkinter it is not neccessary
try:
	import Tkinter
	tk = Tkinter.Tk()
	if tk.getvar('tk_version') < '8.1' or tk.getvar('tcl_version') < '8.1':
		Togl = 'Togl-1.5'
		togl_version_decimal = '1.5.0'
	else:
		Togl = 'Togl-1.6'
		togl_version_decimal = '1.6.0'
##	if tk.getvar( 'tk_version' ) >= '8.4':
##		raise ImportError( """Preventing (doomed) attempts to build togl with Tk 8.4""" )
	# if the Togl sources are not included then don't build
	if not os.path.exists(os.path.join('src', Togl)):
		tk = None
except ImportError:
	tk = None
	Togl = None
	togl_version_decimal = ''
if Togl:
	print 'Togl to be built:', Togl
else:
	print 'Togl not to be built change config/%s.cfg to enable'%(sys.platform,)

class build_togl( distutils.command.build_ext.build_ext):
	"""Build the togl.dll/togl.so shared library for Tk/Tkinter

	The build_togl extension is a pretty minimal sub-class
	of build_ext.  It has a two extra options for specifying
	the tk-source and tcl-source directories which will be
	used for adding new directories to the include path for
	the command.

	The command also makes sure that the Python Tkinter .lib
	files are in the command's lib
	"""
	user_options = distutils.command.build_ext.build_ext.user_options + [
		('tk-source=', None,
		"The Tk source directory (e.g. the tk8.4.5 directory from a source distribution)"),
		('tcl-source=', None,
		"The Tcl source directory  (e.g. the tcl8.4.5 directory from a source distribution)"),
	]
	def build_extensions(self):
		"""Do the actual creation of the togl shared library"""
		if tk is not None and self.distribution.BUILD_TOGL:
			self.togl_build(
				self.distribution.togl_libs,
			)
	def initialize_options (self):
		"""Do normal initialisation and initialise our own options"""
		distutils.command.build_ext.build_ext.initialize_options( self )
		self.tk_source = None
		self.tcl_source = None
	def finalize_options (self):
		"""Finalise the options for building, we add Togl-specific includes/libs"""
		distutils.command.build_ext.build_ext.finalize_options( self )
		if not Togl:
			return
		tkDirs = ['generic', 'xlib' ]
		tclDirs = [ 'generic', 'win', ] #'include', ]
		newIncludes = [
			os.path.join( 'src', Togl ),
			os.path.join(tk.getvar('tk_library'), '..', '..', 'include'),
		]
		if not (self.tk_source or self.tcl_source):
			tk_version = tk.getvar( 'tk_version' )
			self.warn(
				"""Neither --tk-source nor --tcl-source specified for build_togl

    Unless your Tk and Tcl source-distribution headers and libraries are
    already on the system search path the building of Togl will likely
    fail.  To remedy the situation, download the Tk and Tcl sources from:

        https://sourceforge.net/project/showfiles.php?group_id=10894

    for version %(tk_version)s and unpack them into some directory
    somewhere.  Then specify:

        setup.py build_togl --tk-source=/path/to/source --tcl-source=/path/to/source

    on the command line for building PyOpenGL.""" % locals())

		if self.tk_source:
			if not self.tcl_source:
				tkDirs = tkDirs + tclDirs
			for fragment in tkDirs:
				directory = os.path.join( self.tk_source, fragment )
				if os.path.isdir( directory ):
					newIncludes.append( directory )
				else:
					self.warn(
						"""Warning, build_togl tk_source/%s (%s) doesn't exist, Togl build will likely fail!"""%(
							fragment, directory,
					))
		if self.tcl_source:
			if not self.tk_source:
				tclDirs = tkDirs + tclDirs
			for fragment in tclDirs:
				directory = os.path.join( self.tcl_source, fragment )
				if os.path.isdir( directory ):
					newIncludes.append( directory )
				else:
					self.warn(
						"""Warning, build_togl tcl_source/%s (%s) doesn't exist, Togl build will likely fail!"""%(
							fragment, directory,
					))
		self.include_dirs.extend( newIncludes )
		self.library_dirs.append( os.path.normpath(os.path.join(tk.getvar('tk_library'), '..')) )

		extra_compile_args = []

		if sys.platform == 'win32':
			# VC++ 6.0 needs this, why togl doesn't use _WIN32?
			extra_compile_args.append('-DWIN32=1')
			
			self.libraries.append('tcl' + string.replace(tk.getvar('tcl_version'), '.', ''))
			self.libraries.append('tk' + string.replace(tk.getvar('tk_version'), '.', ''))
			if Togl == 'Togl-1.6':
				self.libraries.append('tclstub' + string.replace(tk.getvar('tcl_version'), '.', ''))
				self.libraries.append('tkstub' + string.replace(tk.getvar('tk_version'), '.', ''))
		else:
			self.include_dirs.append(os.path.normpath(os.path.join(tk.getvar('tcl_library'), '..', '..', 'include')))
			
			self.library_dirs.append(os.path.normpath(os.path.join(tk.getvar('tcl_library'), '..')))
			
			self.libraries.append('tcl' + tk.getvar('tcl_version'))
			self.libraries.append('tk' + tk.getvar('tk_version'))

		# hardcoded Debian include/lib paths
		self.library_dirs.append('/usr/lib')
		self.include_dirs.append('/usr/include/tcl8.4')
		self.library_dirs.append('/usr/X11R6/lib')

		if os.environ.has_key('CFLAGS'):
			extra_compile_args.extend(string.split(os.environ['CFLAGS']))

		# these should really be coming from the setup, shouldn't they?
		self.extra_compile_args = extra_compile_args


	def togl_build(self, libs):
		"""Core functionality of the togl_build command"""
		# we subclass build_ext because need an initialized
		# compiler object from build_ext, but we also need a pointer
		# to the build command instance
		build = self.get_finalized_command ('build')
		
		libs = libs + []
		
		extra_link_args = [] # ['-s']
		# Name for the shared lib: (distutils will change it to Togl.{so|dll})
		output_name = 'Togl'
		# where to put the built shared object (only for build process)
		output_dir = Togl + '-tk' + tk.getvar('tk_version')
		export_symbols = ['Togl_Init']
		sources = [os.path.join('src',Togl,'togl.c')]
		
		runtime_library_dirs = None


		# rest of this function was inspired by build_ext.py , build_extensions() 
		
		if not self.inplace:
			output_dir = os.path.join (build.build_base, output_dir)

		# what is the name of the resulting file
		output_filename = self.compiler.shared_object_filename(
				basename=output_name,
				output_dir=output_dir)

		if not (self.force or newer_group(sources, output_filename, 'newer')):
			self.announce ('skipping "%s" (up-to-date)' % output_name)  
		else:
			self.announce ('building "%s"' % output_name)

			# compile source files        
			objects = self.compiler.compile (sources,
								output_dir=self.build_temp,
								macros=[],
								include_dirs=self.include_dirs,
								debug=self.debug,
								extra_postargs=self.extra_compile_args)

			# link all together
			self.compiler.link_shared_object (
					objects, 
					output_filename,
					'', # <= output_dir
					libraries=libs,
					library_dirs=self.library_dirs,
					runtime_library_dirs=runtime_library_dirs,
					extra_postargs=extra_link_args,
					export_symbols=export_symbols, 
					debug=self.debug,
					build_temp=self.build_temp)


class install(distutils.command.install.install):

	togl_outfiles = None

	def run(self):
		distutils.command.install.install.run(self)
		# togl_install can read instance variables of install_lib
		# it has to return the filenames of all installed files
		if tk is not None and self.distribution.BUILD_TOGL:
			self.togl_outfiles = togl_install(self) 


	def get_outputs(self):
		if self.togl_outfiles is None:
			if tk is not None and self.distribution.BUILD_TOGL:
				self.togl_outfiles = togl_install(self,dry_run=1)
			else:
				self.togl_outfiles = []
		return distutils.command.install.install.get_outputs(self) + self.togl_outfiles              



def replace_lib(include_dirs, path):
	components = [path]
	rep = 0
	while 1:
		head, tail = os.path.split(components[0])
		if tail:
			if tail == 'lib':
				rep = 1
				components[0] = 'include'
			else:
				components[0] = tail
			components.insert(0, head)
		else:
			break
	if rep:
		include_dirs.append(apply(os.path.join, components))


# build togl

	# building togl shared library

# togl_build    


from distutils.util import change_root
# install togl
#
# It is possibly to do this all in the build step, but then
# it is not included in a RPM distribution.
#

pkgIndex_tcl = r"""if {![package vsatisfies [package provide Tcl] 8]} {return}
package ifneeded Togl %(togl_version)s \
    [list load [file join $dir %(togl)s] Togl]"""

def togl_install(self,dry_run=0): # a simple function, not a class !!!

	outfiles = [] # we have to return all files we have installed
	
	# get path to Tk directory
	togl_dir = os.path.normpath(os.path.join(self.install_lib,'OpenGL','Tk', \
				sys.platform + '-tk' + tk.getvar('tk_version')))
	self.mkpath(togl_dir)       
	# how are the built files called, and 
	# which names should have the installed files
	if sys.platform == 'win32':
		togl = 'Togl.dll'
	else:
		togl = 'Togl.so'
	togl_src = os.path.join(self.build_base,
				Togl + '-tk' + tk.getvar('tk_version'), togl)
	togl_dst = os.path.join(togl_dir,togl)
	# copy togl in tk directory
	if not dry_run:
		from types import TupleType
		out = self.copy_file(togl_src, togl_dst)
		if type(out) is TupleType:
			out = out[0] 
	else:
		out = togl_dst
	outfiles.append(out)

	# make package index for tcl/tk
	indexFile = os.path.join( togl_dir, 'pkgIndex.tcl' )
	if not dry_run: 
		# only if real install
		self.announce( 'creating pkgIndex.tcl in %(togl_dir)s for %(togl)s'%locals())
		file = open( indexFile, 'w')
		togl_version = togl_version_decimal
		file.write( pkgIndex_tcl % locals())
		file.close()
	outfiles.append(indexFile)

	return outfiles
