#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""This module can run standalone, within the native project directory, or with
mrv available in the python path. It can be imported in order to provide common 
functionality"""
import sys
import os

__docformat__ = "restructuredtext"

#{ Initialization

def prepare_project_syspath():
	"""Make sure the project's root package is in the python path, and manipulate 
	sys.path if required in order to assure that.
	
	:return: tuple(root, info) tuple of imported root module/package and the projects
		info package.
	:raise ImportError: If project's root package could not be found in this interpreter"""
	# try to figure out our actual root package, resort to a hardcoded choice
	ospd = os.path.dirname
	ospj = os.path.join
	default_package = 'mrv'
	env_mrv_info_dir = 'MRV_INFO_DIR'
	root_package = default_package
	
	# HANDLE PRE-EXISTING INFO MODULES
	##################################
	# search for existing info module which is already in the path
	# if it exists, store it for later - we prefer the one we find ourselves
	# from the current directory.
	# Additionally, we remove all other parent modules with an info file, as 
	# they would interfere with our own attempt
	existing_info_parent_module = None
	for path in sys.path[:]:
		for ext in (".py", ".pyc", ".pyo"):
			if os.path.isfile(ospj(path, "info" + ext)):
				if existing_info_parent_module is None:
					existing_info_parent_module = path
				else:
					print >> sys.stderr, "WARNING: Found additional module info in python path:", path
				# END handle first info parent module
				try:
					sys.path.remove(path)
				except ValueError:
					pass 
				# END ignore if the same path is included multiple times
			# END if file exists
		# END for each extension
	# END for each sys path
	
	# HANDLE EXPLICIT OVERRIDES
	###########################
	# this allows the user to explicitly specify directories in which to search 
	# for the info module. It will take precedence over anything we do
	info_override = False
	if env_mrv_info_dir in os.environ:
		val = os.environ[env_mrv_info_dir]
		info_dirs = val.split(os.pathsep)
		
		
		for path in info_dirs:
			sys.path.append(path)
			
			try:
				try:
					import info
					root_package = info.root_package
					info_override = True
					# add the one which allows to import the root package with the name we now have
					sys.path.append(ospd(os.path.abspath(path)))
					break
				except ImportError:
					print >> sys.stderr, "WARNING: Although %s was explicitly set, no info module could be found in one of %s (CWD=%s)" % (env_mrv_info_dir, val, os.getcwd())
				#END exception handling
			finally:
				# remove all previously added info-dir paths
				sys.path.remove(path)
			#END handle sys.path cleanup
		# END for each extra path
	#END handle extra include paths
	

	# TRY TO FIND INFO MODULE
	#########################
	# try to import the root info
	# We search upwards,  take our file if required, which somewhat
	# limits the choice to our own package unless someone has overwritten the 
	# __file__ before executing us.
	if not info_override:
		found_search_path = False
		for search_path in (ospd(os.path.realpath(__file__)), os.getcwd()):
			while True:
				sys.path.append(search_path)
				try:
					import info
					root_package = info.root_package
				except (ImportError, AttributeError):
					sys.path.pop()
				else:
					# we have one - one above it should be the project include path
					sys.path.pop()
					sys.path.append(ospd(search_path))
					found_search_path = True
					break
				# END get root package
				
				new_path = os.path.split(search_path)[0]
				if new_path == search_path:
					break
				search_path = new_path
			# END endless loop
			if found_search_path:
				break
			#END break if we have found something
		# END for each possible search-base
	#END additional search if nothing else was found
	
	# if we didn't find anything use the existing info parent path
	if not info_override and root_package == default_package and existing_info_parent_module:
		sys.path.append(ospd(existing_info_parent_module))
	# END handle path

	# IMPORT ROOT PACKAGE
	#####################
	# This should work if we have found the info module beforehand
	root = None
	try:
		root = __import__(root_package)
		info = __import__("%s.info" % root_package, globals(), locals(), [''])
	except ImportError, e:
		if root_package != default_package:
			raise AssertionError("Couldn't import root package of %r with error: %s" % (root_package, str(e)))
		# END assertion 
		
		# manipulate the import path - first we may be within the mrv structurure
		# or alternatively within /usr/bin/, that is outside of the structure.
		# In the latter case we can't do anything though, and in fact we 
		# should be natively installed.
		# default candidate assumes we are mrv/bin/
		sys.path.append(ospd(ospd(ospd(os.path.realpath(os.path.abspath(__file__))))))
		
		try:
			root = __import__(root_package)
			info = __import__("%s.info" % root_package, globals(), locals(), [''])
		except ImportError, e:
			last_path = sys.path.pop()
			raise ImportError("Failed to import %s as it could not be found in your syspath, tried it at %r, error was : %s" % (root_package, last_path, str(e)))
		# END exception handling
			
	# END import exception handling
	
	# HANDLE PYTHONPATH
	###################
	# At this point, we either imported mrv or we imported the root package 
	# of a derived project.
	# As mrv is just like a shell script, it adjust the environment in order to 
	# allow subprograms to run with an environment that allows them to import 
	# what they need right away.
	# If code that follows in a subprocess is from mrv, the import mrv statement 
	# would fail as only the project root package would work by default, and will 
	# adjust the sys.path to allow direct mrv imports.
	# To allow all code to run, we put both paths to the PYTHONPATH, so it will be 
	# inherited by subprocessess
	import mrv.cmd.base as cmdbase
	envppath = "PYTHONPATH"
	def add_package_to_env(p):
		cmdbase.update_env_path(os.environ, envppath, ospd(ospd(os.path.abspath(p.__file__))), append=False)
	# END utility
	
	# this should be available here
	try:
		import mrv
	except ImportError:
		raise ImportError("Parent package %r needs to add mrv to the system path" % root)
	#END handle mrv import
	
	add_package_to_env(root)
	if root.__name__ != default_package:
		import mrv
		add_package_to_env(mrv)
	# END add mrv specificallys
	
	# keep the root-info around in the mrv pacakge, allowing mrv tools to 
	# access the extra root info, instead of its own
	mrv.pinfo = info
	
	return root, info
	

def mrvmain(args, args_modifier=lambda a, v, m, i: a):
	"""Prepare the path and redirect the call to the actual library module"""
	root, info = prepare_project_syspath()
	try:
		import mrv.cmd.startup as startup
	except ImportError:
		raise EnvironmentError("Failed to import mrv as the root package did not initialize the python import path correctly")
	# END final exception handling
	startup.mrv(args, info, args_modifier)
	
#} END initialization


if __name__ == "__main__":
	# ignore first arg which is the executable
	mrvmain(sys.argv[1:])
# END initialization
