import logging
import os
import subprocess
from plugins import BaseAssembler
from yapsy.IPlugin import IPlugin

class MegahitAssembler(BaseAssembler, IPlugin):
    def run(self):
        """
        Prepare command
        Launch command
        Yield result

        A megahit command looks like this:

        ./megahit -m 500000000000 --cpu-only -l 300 -o megahit-test-2015-01-23-2 \
            --input-cmd "zcat SRS150404/*.fastq.gz" \
            --k-min 21 --k-max 99 --k-step 10 \
            --min-count 2 \
            --num-cpu-threads 32 \
        | tee Log

        The --k-* parameters can be ommited. --min-count is valued at 2 by default too.

        """

        command = []
        command += [self.executable, "--cpu-only"]
        command += ['--num-cpu-threads', self.process_threads_allowed]
        command += ['-l', '512']
        command += ['-m', str(self.get_system_memory())]
        command += ['--input-cmd']

        # quotes are not required because the argument will be passed to arast_popen,
        # which will pass it to subprocess.Popen
        command += ["cat " + " ".join(self.data.readfiles) + ""]

        # TODO self.Name does not exist although the key Name is defined
        # in the configuration file.
        command += ['-o', os.path.join(self.outpath, "megahit")]

        logging.warning("megahit plugin =>")
        logging.warning(" ".join(command))
        logging.warning(command)

        self.arast_popen(command)

        contigs = os.path.join(self.outpath, 'megahit', 'final.contigs.fa')

        return {'contigs': contigs}

    def get_system_memory(self):
        # TODO: This could us psutil instead

        with open('/proc/meminfo') as my_file:
            for line in my_file:
                tokens = line.split()
                if len(tokens) == 3:
                    [entry, value, units] = tokens

        # The metahit vendor recommends using 90% to 95% of the memory available.
                    if entry == "MemTotal:":
                        return int(int(value) * 1024 * 0.90)

        # If the amount is unknown, return 4 GiB.
        return 4 * 1024 * 1024 * 1024

@@ -103,16 +103,39 @@
  IPlugin
+%0Aimport multiprocessing
 %0A%0Aclass 
@@ -865,24 +865,25 @@
  '512'%5D%0A
+%0A
         
 command 
@@ -878,54 +878,384 @@
     
+# The metahit vendor re
 comm
-and += %5B'-m', str(self.get_system_memory()
+ends using 90%25 to 95%25 of the memory available.%0A        system_memory = self.get_system_memory()%0A        process_threads_allowed = int(self.process_threads_allowed)%0A        total_threads = self.get_total_thread_count()%0A%0A        available_memory = system_memory / total_threads * process_threads_allowed%0A%0A        command += %5B'-m', str(available_memory
 )%5D%0A 
@@ -1666,16 +1666,54 @@
 hit%22)%5D%0A%0A
+        print(%5B%22command%22%5D + command)%0A%0A
         
@@ -1975,16 +1975,102 @@
 ntigs%7D%0A%0A
+    # TODO: this should be moved elsewhere%0A    # because other classes may need this.%0A
     def 
@@ -2351,90 +2351,8 @@
 ns%0A%0A
-        # The metahit vendor recommends using 90%25 to 95%25 of the memory available.%0A
     
@@ -2423,20 +2423,16 @@
  return 
-int(
 int(valu
@@ -2444,16 +2444,8 @@
 1024
- * 0.90)
 %0A%0A  
@@ -2522,16 +2522,98 @@
 4 * 1024 * 1024%0A
+%0A    def get_total_thread_count(self):%0A        return multiprocessing.cpu_count()%0A

normalize memory limit using the total thread count