#!/usr/bin/python3
"""
Compile and run the primes.mixal sample program using mixvm and mixguile.
"""

import os
import subprocess
import sys
import tempfile


MIXASM = os.environ.get('TEST_MIXASM_PROG', 'mixasm')
MIXVM = os.environ.get('TEST_MIXVM_PROG', 'mixvm')
MIXGUILE = os.environ.get('TEST_MIXGUILE_PROG', 'mixguile')

SRCDIR = os.environ.get('TEST_SRCDIR', '.')
SRCFILE = f'{SRCDIR}/samples/primes.mixal'

ENC = 'us-ascii'


def test_primes() -> None:
    """ Primes sample program test: compile, run, check. """
    print('')
    if not os.path.isfile(SRCFILE):
        sys.exit(f'Not a file: "{SRCFILE}"; set TEST_SRCDIR?')

    with tempfile.TemporaryDirectory() as tmpdir:
        print(f'Using temporary directory {tmpdir}')

        os.mkdir(f'{tmpdir}/home')
        mix_env = dict(os.environ)
        mix_env.update({'HOME': f'{tmpdir}/home'})

        def examine_output(fname: str) -> None:
            """ Examine the primes output file. """
            print(f'Examining {fname}')
            with open(fname, mode='r', encoding=ENC) as printer_file:
                line = printer_file.readline()
                assert line.rstrip() == 'FIRST FIVE HUNDRED PRIMES'

                found = {
                    '0002': False,
                    '0004': False,
                    '0239': False,
                    '0048': False,
                }
                print(f'Looking for {" ".join(sorted(found.keys()))}')
                for line in printer_file.readlines():
                    words = set(line.split())
                    for num in found:
                        if num in words:
                            assert not found[num]
                            found[num] = True

                print(f'Result: {found}')
                assert found == {
                    '0002': True,
                    '0004': False,
                    '0239': True,
                    '0048': False,
                }

        def run_program(program: str, subdir: str, commands: str) -> None:
            """ Create a subdir and input and output files, run a program. """
            program_dir = f'{tmpdir}/{subdir}'
            os.mkdir(program_dir)
            infname = f'{program_dir}/in.txt'
            with open(infname, mode='w+', encoding=ENC) as infile:
                print(commands, file=infile)
                infile.flush()
                infile.seek(0)
                print(f'Created {infname}')
                subprocess.check_call(['cat', '--', infname])

                outfname = f'{program_dir}/out.txt'
                with open(outfname, mode='w', encoding=ENC) as outfile:
                    print(f'Invoking {program} in {infname} out {outfname}')
                    subprocess.check_call(
                        [program], shell=False, env=mix_env,
                        stdin=infile, stdout=outfile)
                print(f'Got {program} output:')
                subprocess.check_call(['cat', '--', outfname])

            assert sorted(os.listdir(f'{program_dir}')) == [
                'in.txt', 'out.txt',
                'printer.dev',
            ]
            assert os.path.isfile(f'{program_dir}/printer.dev')
            examine_output(f'{program_dir}/printer.dev')

        program_base = f'{tmpdir}/primes'
        program_full = f'{program_base}.mix'
        print(f'Running {MIXASM} on {SRCFILE} to create {program_full}')
        subprocess.check_call([MIXASM, '-o', program_base, '--', SRCFILE])
        print(f'Checking for {program_full}')
        assert sorted(os.listdir(tmpdir)) == ['home', 'primes.mix']
        assert os.path.isfile(program_full)

        run_program(
            MIXVM, 'mixvm',
            f'''load {program_base}
sddir {tmpdir}/mixvm
run''')

        assert sorted(os.listdir(tmpdir)) == [
            'home',
            'mixvm',
            'primes.mix',
        ]

        run_program(
            MIXGUILE, 'mixguile',
            f'''(mix-load "{program_base}")
(mix-sddir "{tmpdir}/mixguile")
(mix-run)''')

        assert sorted(os.listdir(tmpdir)) == [
            'home',
            'mixguile', 'mixvm',
            'primes.mix',
        ]
