from buildutils import *
import subprocess

Import('env','build','install')
localenv = env.Clone()

localenv.Append(CPPPATH=['#ext/gtest/include', '#include'],
                LIBPATH='#build/lib',
                LIBS=['gtest'] + localenv['cantera_libs'])

localenv['ENV']['PYTHONPATH'] = Dir('#interfaces/python').abspath
localenv['ENV']['CANTERA_DATA'] = Dir('#data/inputs').abspath

# Needed for Intel runtime libraries when compiling with ICC
if 'LD_LIBRARY_PATH' in os.environ:
    localenv['ENV']['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']

def testRunner(target, source, env):
    """SCons Action to run a compiled test program"""
    program = source[0]
    passedFile = target[0]
    workDir = Dir('#test/work').abspath

    del testResults.tests[passedFile.name]
    if not os.path.isdir(workDir):
        os.mkdir(workDir)
    code = subprocess.call([program.abspath], env=env['ENV'], cwd=workDir)
    if not code:
        # Test was successful
        open(passedFile.path, 'w').write(time.asctime()+'\n')
        testResults.passed[passedFile.name] = program
    else:
        testResults.failed[passedFile.name] = program


def addTestProgram(subdir, progName):
    """
    Compile a test program and create a targets for running
    and resetting the test.
    """
    program = localenv.Program(pjoin(subdir, progName),
                               mglob(localenv, subdir, 'cpp'))
    passedFile = File(pjoin(str(program[0].dir), '%s.passed' % program[0].name))
    testResults.tests[passedFile.name] = program
    run_program = localenv.Command(passedFile, program, testRunner)
    Alias('test', run_program)
    Alias('test-%s' % progName, run_program)
    env['testNames'].append(progName)
    if os.path.exists(passedFile.abspath):
        Alias('test-reset', localenv.Command('reset-%s%s' % (subdir, progName),
                                             [], [Delete(passedFile.abspath)]))


def addTestScript(subdir, script, interpreter, dependencies):
    """
    Create targets for running and resetting a test script.
    """
    def scriptRunner(target, source, env):
        """Scons Action to run a test script using the specified interpreter"""
        workDir = Dir('#test/work').abspath
        passedFile = target[0]
        del testResults.tests[passedFile.name]
        if not os.path.isdir(workDir):
            os.mkdir(workDir)

        code = subprocess.call([interpreter, source[0].abspath],
                               env=env['ENV'],
                               cwd=workDir)
        if not code:
            # Test was successful
            open(target[0].path, 'w').write(time.asctime()+'\n')
            testResults.passed[passedFile.name] = True
        else:
            testResults.failed[passedFile.name] = True


    testenv = localenv.Clone()
    passedFile = File(pjoin(subdir, '%s.passed' % (script)))
    testResults.tests[passedFile.name] = True
    run_program = testenv.Command(passedFile, pjoin(subdir, script), scriptRunner)
    for dep in dependencies:
        if isinstance(dep, str):
            dep = File(pjoin(subdir, dep))
        testenv.Depends(run_program, dep)
    Alias('test', run_program)
    if os.path.exists(passedFile.abspath):
        Alias('test-reset', testenv.Command('reset-%s%s' % (subdir, script),
                                            [], [Delete(passedFile.abspath)]))

    return run_program


def addMatlabTest(script, dependencies=None):
    def matlabRunner(target, source, env):
        passedFile = target[0]
        del testResults.tests[passedFile.name]
        workDir = Dir('#test/work').abspath
        if not os.path.isdir(workDir):
            os.mkdir(workDir)
        outfile = pjoin(workDir, 'matlab-results.txt')
        runCommand = "%s('%s'); exit" % (source[0].name[:-2], outfile)
        if os.name == 'nt':
            matlabOptions = ['-nojvm','-nosplash','-wait']
        else:
            matlabOptions = ['-nojvm','-nodisplay']
        if os.path.exists(outfile):
            os.remove(outfile)

        environ = dict(os.environ)
        environ.update(env['ENV'])
        code = subprocess.call([pjoin(env['matlab_path'], 'bin', 'matlab')] +
                               matlabOptions + ['-r', runCommand],
                               env=environ, cwd=Dir('#test/matlab').abspath)
        results = open(outfile).read()
        print '-------- Matlab test results --------'
        print results
        print '------ end Matlab test results ------'
        if 'FAILED' in results:
            testResults.failed[passedFile.name] = True
        else:
            testResults.passed[passedFile.name] = True
            open(target[0].path, 'w').write(time.asctime()+'\n')

    testenv = localenv.Clone()
    passedFile = File(pjoin('matlab', '%s.passed' % (script)))
    testResults.tests[passedFile.name] = True
    run_program = testenv.Command(passedFile, pjoin('matlab', script), matlabRunner)

    dependencies = (dependencies or []) + localenv['matlab_extension']
    for dep in dependencies:
        if isinstance(dep, str):
            dep = File(pjoin('matlab', dep))
        testenv.Depends(run_program, dep)

    Alias('test', run_program)
    if os.path.exists(passedFile.abspath):
        Alias('test-reset', testenv.Command('reset-%s%s' % ('matlab', script),
                                            [], [Delete(passedFile.abspath)]))

    return run_program

# Instantiate tests
addTestProgram('thermo', 'thermo')
addTestProgram('kinetics', 'kinetics')

if localenv['python_package'] == 'full':
    pyTest= addTestScript('python', 'runTests.py',
                          interpreter=sys.executable,
                          dependencies=['testSolution.py', 'testReactors.py',
                                        localenv['python_module']])
    localenv.Alias('test-python', pyTest)
    env['testNames'].append('python')

if localenv['matlab_toolbox'] == 'y':
    matlabTest = addMatlabTest('runCanteraTests.m',
                               dependencies=mglob(localenv, 'matlab', 'm'))
    localenv.Alias('test-matlab', matlabTest)
    env['testNames'].append('matlab')
