#!/usr/bin/env python
#############################################################################
# Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999
# All Rights Reserved.
#
# The software contained on this media is the property of the DSTC Pty
# Ltd.  Use of this software is strictly in accordance with the
# license agreement in the accompanying LICENSE.HTML file.  If your
# distribution of this software does not contain a LICENSE.HTML file
# then you have no rights to use this software in any manner and
# should contact DSTC at the address below to determine an appropriate
# licensing arrangement.
# 
#      DSTC Pty Ltd
#      Level 7, GP South
#      Staff House Road
#      University of Queensland
#      St Lucia, 4072
#      Australia
#      Tel: +61 7 3365 4310
#      Fax: +61 7 3365 4311
#      Email: enquiries@dstc.edu.au
# 
# This software is being provided "AS IS" without warranty of any
# kind.  In no event shall DSTC Pty Ltd be liable for damage of any
# kind arising out of or in connection with the use or performance of
# this software.
#
# Project:      Fnorb
# File:         $Source: /projects/fnorb/Fnorb-1.1/compiler/RCS/IDLCompiler.py,v $
# Version:      @(#)$RCSfile: IDLCompiler.py,v $ $Revision: 1.7 $
#
#############################################################################
""" The back-end of an IDL compiler for Fnorb! """


# Standard/built-in modules.
import os

# Fnorb modules.
from Fnorb.orb import CORBA

# Compiler modules.
import SkelGenerator, StubGenerator


class Context:
    """ Context specifying the locations of generated files and packages. """

    def __init__(self, directory, package, globals):
        """ Constructor.

        'directory' is the directory in which to put all of the files and
	            packages generated by the compiler.

        'package'   is the name of the package under 'directory' in which to
	            put all of the packages generated by the compiler (this
		    parameter must be an instance of the 'Util.PackageName'
		    class).

        'globals'   is the base name of the sub-packages under 'package' in
	            which to put the stubs and skeletons generated for global
		    scope IDL definitions.

        """
        self._directory = directory
        self._package = package
	self._globals = globals

	return

    def create_package_path(self, package):
	""" Create the full pathname of the specified package. """

	# Create a valid filename relative to the context's target directory.
	return os.path.join(self._directory, package.join('/'))

    def create_import_statement(self, package):
	""" Create a statement to import the specified package.

	N.B This method will work for both PackageName instances AND
        --- stringified package names!

	"""
	if len(self._package) == 0:
	    statement = 'import %s' % package

	else:
	    statement = 'from %s import %s' % (self._package, package)

	return statement
	
    #########################################################################
    # Accessors.
    #########################################################################

    def directory(self):
	return self._directory

    def package(self):
	return self._package

    def globals(self):
	return self._globals


class IDLCompiler:
    """ The back-end of an IDL compiler for Fnorb! """

    def compile(self, context, ifr_objects):
	""" Generate code for a list of IR objects.

	'context'     is the compilation context giving the directory and 
                      package names in which to put the files and packages
                      generated by the compiler.
    
        'ifr_objects' is a list containing the object references of the IFR
                      objects that we want to generate Python code for.

        """
	# Create the stub and skeleton code generators to do the work!
	stub_gen = StubGenerator.StubGenerator()
	skel_gen = SkelGenerator.SkelGenerator()

	# If there are global scope definitions that are not modules then we
	# create Python stub and skeleton packages to put them in.
	if self.__have_global_defs(ifr_objects):
	    globals     = context.globals()
	    global_stub = stub_gen._create_package(context, globals)
	    global_skel = skel_gen._create_package(context, globals + '_skel')

	    # Generate Python for each IFR object.
	    for ifr_object in ifr_objects:
		stub_gen.generate(context, global_stub, ifr_object, 0)
		skel_gen.generate(context, global_skel, ifr_object, 0)

	    # End of the packages.
	    stub_gen._end_package(global_stub, 0)
	    skel_gen._end_package(global_skel, 0)

	    global_stub.close()
	    global_skel.close()

	# Otherwise, there is at least some semblance of order, and there are
	# no global scope definitions other than modules ;^)
	else:
	    # Generate Python for each IFR object.
	    for ifr_object in ifr_objects:
		stub_gen.generate(context, None, ifr_object, 0)
		skel_gen.generate(context, None, ifr_object, 0)

	return

    #########################################################################
    # Internal interface.
    #########################################################################

    def __have_global_defs(self, ifr_objects):
	""" Are any of the IFR objects NOT module definitions? """

	for ifr_object in ifr_objects:
	    if ifr_object._get_def_kind() != CORBA.dk_Module:
		return 1

	return 0

#############################################################################
