# This macro will initialize the current cmake session for Python. The
# macro starts by looking for the Python interpreter of correct
# version. When a Python interepreter of the correct version has been
# located the macro will continue to set variables, load other cmake
# modules and generate scripts to be used in the remaining part of the
# cmake process. 
#
# Variables which will be set:
# ----------------------------
#
# PYTHON_INSTALL_PREFIX: All python packages will be located in
#        ${GLOBAL_PREFIX}/${PYTHON_INSTALL_PREFIX} - this applies both
#        when searching for dependencies and when installing.
#
# CTEST_PYTHONPATH: Normal ':' separated path variables which is
#        passed to the test runner. Should contain the PYTHONPATH to
#        all third party packages which are not in the default search
#        path. The CTEST_PYTHONPATH variable will be updated by the
#        python_package( ) function when searching for third party
#        packages.
#
#
# New functions/macros which will be available:
# ---------------------------------------------
#
# add_python_package( ): This function will copy python source files
#        to the build directory, 'compile' them and set up installation.
#
#
# add_python_test( ): Set up a test based on invoking a Python test
#        class with a small python executable front end.
#
# find_python_package( ): Will search for a python package.
#
#
# New scripts generated:
# ----------------------
#
#
# cmake_pyc: Small script which will run in-place Python compilation
#        of a directory tree recursively.
#
# cmake_pyc_file: Small script which will compile one python file.
#
# ctest_run_python: Small script which will invoke one Python test class.
#
# All the generated scripts will be located in ${PROJECT_BINARY_DIR}/bin.
#
#
# Downstream projects should use this as:
#
# include( init_python )
# init_python( 2.7 )
# ...

macro(init_python target_version)

   FIND_PACKAGE(PythonInterp)
   if (NOT DEFINED PYTHON_EXECUTABLE)
      message(WARNING "Python interpreter not found - Python wrappers not enabled")
      set( BUILD_PYTHON OFF PARENT_SCOPE )
      return()
   endif()

   if (PYTHON_VERSION_MAJOR EQUAL 3)
      message(WARNING "libecl is not PYTHON 3 compatible. Python wrappers are enabled, but will fail horribly.")
   elseif (NOT "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" STREQUAL "${target_version}")
      message(WARNING "Need Python version ${target_version}, found version: ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} - Python wrappers not enabled")
      set( BUILD_PYTHON OFF PARENT_SCOPE )
      return()
   endif()

   if (EXISTS "/etc/debian_version")
      set( PYTHON_PACKAGE_PATH "dist-packages")
   else()
      set( PYTHON_PACKAGE_PATH "site-packages")
   endif()

   set(PYTHON_INSTALL_PREFIX  "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/${PYTHON_PACKAGE_PATH}"  CACHE STRING "Subdirectory to install Python modules in")
   set(CTEST_PYTHONPATH ${PROJECT_BINARY_DIR}/${PYTHON_INSTALL_PREFIX})
   configure_python_env( )
   include(add_python_test)
   include(find_python_package) 
   include(add_python_package)
endmacro()



# The function configure_python_env( ) will generate three small
# Python scripts which will be located in ${PROJECT_BINARY_DIR}/bin
# and will be used when 'compiling' and testing Python code. The
# function will be called from the init_python() macro.

function( configure_python_env )

FILE(WRITE "${PROJECT_BINARY_DIR}/bin/ctest_run_python"
"import sys
import os
from unittest import TextTestRunner


def runTestCase(tests, verbosity=0):
    test_result = TextTestRunner(verbosity=verbosity).run(tests)

    if len(test_result.errors) or len(test_result.failures):
        test_result.printErrors()
        sys.exit(1)


# This will update both the internal sys.path load order and the
# environment variable PYTHONPATH with the following list:
#
#      cwd:CTEST_PYTHONPATH:PYTHONPATH

def update_path():
     path_list = [os.getcwd()]

     if 'CTEST_PYTHONPATH' in os.environ:
        ctest_pythonpath = os.environ['CTEST_PYTHONPATH']
        for path in ctest_pythonpath.split(':'):
            path_list.append( path )
   
     for path in reversed(path_list):
         sys.path.insert(0 , path)     

     if 'PYTHONPATH' in os.environ:
        pythonpath = os.environ['PYTHONPATH']
        for path in pythonpath.split(':'):
            path_list.append( path )

     os.environ['PYTHONPATH'] = ':'.join( path_list )


    
if __name__ == '__main__':
    update_path( )
    from ecl.util.test import ErtTestRunner
    for test_class in sys.argv[1:]:
        tests = ErtTestRunner.getTestsFromTestClass(test_class)
        
        # Set verbosity to 2 to see which test method in a class that fails.
        runTestCase(tests, verbosity=0)
")    

#-----------------------------------------------------------------

FILE(WRITE "${PROJECT_BINARY_DIR}/bin/cmake_pyc"
"
import py_compile
import os
import os.path
import sys
import shutil


src_file = sys.argv[1]
target_file = sys.argv[2]

(target_path , tail) = os.path.split( target_file )
if not os.path.exists( target_path ):
   try:
      os.makedirs( target_path )
   except:
      # When running make with multiple processes there might be a
      # race to create this directory.
      pass

shutil.copyfile( src_file , target_file )
shutil.copystat( src_file , target_file )
try:
    py_compile.compile( target_file , doraise = True)
except Exception as error:
    sys.exit('py_compile(%s) failed:%s' % (target_file , error))
")

#-----------------------------------------------------------------

FILE(WRITE "${PROJECT_BINARY_DIR}/bin/cmake_pyc_file"
"
import py_compile
import os
import sys
import os.path

# Small 'python compiler' used in the build system for ert. 

for file in sys.argv[1:]:
    try:
        py_compile.compile( file , doraise = True )
    except Exception as error:
        sys.exit('py_compile(%s) failed:%s' % (file , error))
")
        


endfunction()
