import os
import tempfile
import shutil
import pyfastaq
from pymummer import syscall

class Error (Exception): pass


class Runner:
    '''Handy reference for all the arguments needed for nucmer, delta-filter, show-coords, show-snps'''
    def __init__(
      self,
      ref,
      query,
      outfile,
      min_id=None,
      min_length=None,
      breaklen=None,
      coords_header=True,
      diagdiff=None,
      diagfactor=None,
      maxgap=None,
      maxmatch=False,
      mincluster=None,
      simplify=True,
      show_snps=False,
      snps_header=True,
      verbose=False,
      promer=False,
      show_snps_C=True,
   ):
        self.qry = query
        self.ref = ref
        self.outfile = outfile
        self.min_id = min_id
        self.min_length = min_length
        self.breaklen = breaklen
        self.diagdiff = diagdiff
        self.diagfactor = diagfactor
        self.coords_header = coords_header
        self.maxgap = maxgap
        self.maxmatch = maxmatch
        self.mincluster = mincluster
        self.simplify = simplify
        self.show_snps = show_snps
        self.snps_header = snps_header
        self.verbose = verbose
        self.use_promer = promer
        self.show_snps_C = show_snps_C


    def _nucmer_command(self, ref, qry, outprefix):
        '''Construct the nucmer command'''
        if self.use_promer:
            command = 'promer'
        else:
            command = 'nucmer'

        command += ' -p ' + outprefix

        if self.breaklen is not None:
            command += ' -b ' + str(self.breaklen)

        if self.diagdiff is not None and not self.use_promer:
            command += ' -D ' + str(self.diagdiff)

        if self.diagfactor:
            command += ' -d ' + str(self.diagfactor)

        if self.maxgap:
            command += ' -g ' + str(self.maxgap)

        if self.maxmatch:
            command += ' --maxmatch'

        if self.mincluster is not None:
            command += ' -c ' + str(self.mincluster)

        if not self.simplify and not self.use_promer:
        	command += ' --nosimplify'

        return command + ' ' + ref + ' ' + qry


    def _delta_filter_command(self, infile, outfile):
        '''Construct delta-filter command'''
        command = 'delta-filter'

        if self.min_id is not None:
            command += ' -i ' + str(self.min_id)

        if self.min_length is not None:
            command += ' -l ' + str(self.min_length)

        return command + ' ' + infile + ' > ' + outfile


    def _show_coords_command(self, infile, outfile):
        '''Construct show-coords command'''
        command = 'show-coords -dTlro'

        if not self.coords_header:
            command += ' -H'

        return command + ' ' + infile + ' > ' + outfile


    def _show_snps_command(self, infile, outfile):
        command = 'show-snps -T' + ('C' if self.show_snps_C else '') + 'lr'

        if not self.snps_header:
            command += ' -H'

        return command + ' ' + infile + ' > ' + outfile


    def _write_script(self, script_name, ref, qry, outfile):
        '''Write commands into a bash script'''
        f = pyfastaq.utils.open_file_write(script_name)
        print(self._nucmer_command(ref, qry, 'p'), file=f)
        print(self._delta_filter_command('p.delta', 'p.delta.filter'), file=f)
        print(self._show_coords_command('p.delta.filter', outfile), file=f)
        if self.show_snps:
            print(self._show_snps_command('p.delta.filter', outfile + '.snps'), file=f)
        pyfastaq.utils.close(f)


    def run(self):
        '''
        Change to a temp directory
        Run bash script containing commands
        Place results in specified output file
        Clean up temp directory
        '''
        qry = os.path.abspath(self.qry)
        ref = os.path.abspath(self.ref)
        outfile = os.path.abspath(self.outfile)
        tmpdir = tempfile.mkdtemp(prefix='tmp.run_nucmer.', dir=os.getcwd())
        original_dir = os.getcwd()
        os.chdir(tmpdir)
        script = 'run_nucmer.sh'
        self._write_script(script, ref, qry, outfile)
        syscall.run('bash ' + script, verbose=self.verbose)
        os.chdir(original_dir)
        shutil.rmtree(tmpdir)

