import shutil
import subprocess
import tempfile

from flask import make_response

from steady_cell_phenotype._util import *


def compute_fixed_points(knockout_model, variables, continuous):
    """ Run the fixed-point finding computation """

    # check to make sure that we have macaulay installed
    macaulay_executable = shutil.which('M2')
    if macaulay_executable is None:
        return make_response(error_report("Macaulay2 was not found on the server; we cannot do as you ask."))

    # we are set to do the computation
    with tempfile.TemporaryDirectory() as tmp_dir_name:
        with open(tmp_dir_name + '/model.txt', 'w') as model_file:
            model_file.write(knockout_model)
            model_file.write('\n')

        # convert the model to polynomials
        non_continuous_vars = [variable for variable in variables if not continuous[variable]]
        if len(non_continuous_vars) > 0:
            continuity_params = ['-c', '-comit'] + [variable for variable in variables if not continuous[variable]]
        else:
            continuity_params = ['-c']

        convert_to_poly_process = \
            subprocess.run([get_resource_path('scp_converter.py'), '-n',
                            '-i', tmp_dir_name + '/model.txt',
                            '-o', tmp_dir_name + '/model-polys.txt'] + continuity_params,
                           capture_output=True)

        if convert_to_poly_process.returncode != 0:
            return make_response(error_report(
                'Error running converter!\n{}\n{}'.format(html_encode(convert_to_poly_process.stdout),
                                                          html_encode(convert_to_poly_process.stderr))))

        template_contents = get_text_resource('find_steady_states.m2-template')
        with open(tmp_dir_name + '/find_steady_states.m2', 'w') as macaulay_script:
            macaulay_script.write(template_contents.format(
                polynomial_file=tmp_dir_name + '/model-polys.txt',
                output_file=tmp_dir_name + '/results.txt'))

        # TODO: put a limit on the amount of time this can run
        find_steady_states_process = \
            subprocess.run([macaulay_executable,
                            '--script',
                            tmp_dir_name + '/find_steady_states.m2'],
                           capture_output=True)
        if find_steady_states_process.returncode != 0:
            with open(tmp_dir_name + '/model-polys.txt', 'r') as poly_file:
                return make_response(error_report(
                    'Error running Macaulay!\n<br>\n{}\n<br>\n{}\n<br>\n{}'.format(
                        html_encode(find_steady_states_process.stdout),
                        html_encode(find_steady_states_process.stderr),
                        html_encode(poly_file.read()))))

        def process_line(line):
            line = line.strip()
            if len(line) < 2:  # should at least have {}
                return None
            elif line[0] != '{' or line[-1] != '}':
                raise RuntimeError("Malformed response from Macaulay")

            line = line[1:-1]  # strip the {}'s
            try:
                results = map(int, line.split(','))
            except ValueError:
                raise RuntimeError("Malformed response from Macaulay")

            # make sure they are in 0,1,2
            results = map(lambda n: (n + 3) % 3, results)

            return tuple(results)

        try:
            with open(tmp_dir_name + '/results.txt', 'r') as file:
                fixed_points = [process_line(line) for line in file]
        except (IOError, RuntimeError):
            return make_response(error_report('Malformed response from Macaulay!'))

    # respond with the results-of-computation page
    return make_response(
        render_template('compute-fixed-points.html', variables=variables, fixed_points=fixed_points))
