import QCumber
import datetime
import numpy as np
import getpass
import csv
from helper import *
import re
from os.path import basename, splitext, join, exists, dirname, isdir
from os import uname, listdir, remove
import configparser
import shutil
from collections import OrderedDict
import base64

default_parameter = configparser.ConfigParser()
default_parameter.read(join(dirname(__file__), "parameter.txt"))

def get_tool_path(name, section="PATH"):
	config = configparser.ConfigParser()
	config.read(join(dirname(__file__), "config.txt"))
	path_dict = config[section]
	return path_dict[name]

class Pipeline:
	'''Get all tool versions '''
	def __init__(self):

		self.name = "Quality Control"
		self.version = QCumber.__version__
		self.user = getpass.getuser()
		self.python_version = toLatex(sys.version)
		self.fastqc_version = toLatex(subprocess.check_output(join(get_tool_path("fastqc"), "fastqc") + " --version", shell = True, stderr=subprocess.PIPE).decode("utf-8"))

		try:
			self.trimmo_version = subprocess.check_output(join(get_tool_path("trimmomatic"), "TrimmomaticSE") + " -version", shell=True, stderr=subprocess.PIPE).decode("utf-8")
		except:
			try:
				from debpackageinfo import get_upstream_version
				self.trimmo_version = get_upstream_version("trimmomatic")
				#self.trimmo_version = re.search("Trimmomatic-(?P<version>\d.\d+)",get_tool_path("trimmomatic")).group("version")
			except:
				self.trimmo_version = "< 0.32"
		bowtie_v = subprocess.check_output(join(get_tool_path("bowtie2"), "bowtie2") + " --version", shell=True).decode("utf-8")
		self.bowtie_version = re.match(".*\)", toLatex(bowtie_v, True)).group()
		self.kraken_version =toLatex(subprocess.check_output( join(get_tool_path('kraken'), "kraken") + " --version", shell = True).decode("utf-8"))

		system = uname()
		self.system = toLatex(system.sysname)
		self.server = toLatex(system.nodename)
		self.release = toLatex(system.release)
		self.operating_version = toLatex(system.version)
		self.machine = toLatex(system.machine)


class Sample(object):
	"""Sample with reference to ReadSets, MappingRes, KrakenResr"""

	def __init__(self, name, path, reference, threads, techn):
		global mainResultsPath
		global num_threads
		global technology
		num_threads = threads
		mainResultsPath = path
		technology = techn

		self.start = datetime.datetime.strftime(datetime.datetime.now(),"%d.%m.%Y, %H:%M:%S")
		self.stop = None

		self.name = name
		self.technology = techn
		self.threads = threads
		self.phred = "phred33"
		self.readSets = []

		self.mainResultsPath = path
		self.mappingRes = None
		self.krakenRes = None
		self.reference = reference
	def get_all_qc_plots(self):
		qc_dict = OrderedDict([("setname", self.name),("raw",[]), ("trimmed",[])])
		for rs in self.readSets:
			qc_dict["raw"].append(rs.r1.qcRes.plots)
			qc_dict["trimmed"].append(rs.trimRes.readset.r1.qcRes.plots)
			if (rs.r2 is not None):
				qc_dict["raw"].append(rs.r2.qcRes.plots)
				qc_dict["trimmed"].append(rs.trimRes.readset.r2.qcRes.plots)
		return qc_dict

	def total_reads(self):
		total = 0
		for rs in self.readSets:
			total += rs.numberOfReads
		return total

	def pTrimmed(self):
		perc = []
		for rs in self.readSets:
			if rs.trimRes:
				perc.append(rs.trimRes.pTrimmed)
		if len(perc) == 0 :
			return 0
		return round(np.mean(perc), 2)
	def nTrimmed(self):
		total = 0
		for rs in self.readSets:
			if rs.trimRes:
				total += rs.trimRes.nTrimmed
		return total

	def add_readSet(self, readSet):
		self.readSets.append(readSet)
		return self

	def run_Kraken(self, db, trimmed):
		r1, r2 = self.get_all_reads(trimmed)
		self.krakenRes = KrakenResult(r1,r2,db, self.name)
		return self

	def run_Bowtie2(self, bowtie_index, save_mapping, trimmed ):
		r1, r2 = self.get_all_reads(trimmed)
		self.mappingRes = MappingResult(self.reference, r1, r2, bowtie_index)
		self.mappingRes = self.mappingRes.run_bowtie(save_mapping)
		return self.mappingRes

	def get_all_reads(self, trimmed = True):
		if trimmed:
			r1 = " ".join([x.trimRes.readset.r1.filename for x in self.readSets])#join_reads([x.trimRes.readset.r1.filename for x in self.readSets], self.mainResultsPath, self.name + "_R1")
			r2 = " ".join([x.trimRes.readset.r2.filename for x in self.readSets if x.trimRes.readset.r2 is not None])#join_reads([x.trimRes.readset.r2.filename for x in self.readSets if x.trimRes.readset.r2 is not None], self.mainResultsPath, self.name + "_R2")
		else:
			r1 = " ".join([x.r1.filename for x in self.readSets])#join_reads([x.r1.filename for x in self.readSets], self.mainResultsPath, self.name + "_R1")
			r2 = " ".join([x.r2.filename for x in self.readSets if x.r2 is not None]) #join_reads([x.r2.filename for x in self.readSets if x.r2 is not None], self.mainResultsPath, self.name + "_R2")  #readnames = {'r1' : r1}
		return r1,r2

	def get_mean_trimRes(self):
		try:
			return round(np.mean([x.trimRes.shorter_fragments_percentage for x in self.readSets]),2)
		except:
			return None

class ReadSet:
	''' Readset contains of r1 and r2'''
	def __init__(self, r1 ,r2=None):

		self.r2 = None
		if type(r1) is str:
			self.r1 = FastQFile(r1) # FastQFile
			if r2 is not None:
				self.r2 = FastQFile(r2) # FastQFile
		else:
			self.r1 = r1
			if r2 is not None:
				self.r2 = r2
		self.numberOfReads = 0
		self.numberofTrimmedReads = 0
		self.trimRes = None
		self.paired = True
		if len( basename(self.r1.filename).split("_")[:-3]) > 4:
			self.setname = "_".join(basename(self.r1.filename).split("_")[:-3])
		else:
			self.setname = basename(self.r1.filename)
		if(r2 is None):
			self.paired = False

	def run_FastQC(self, output):
		self.r1 = self.r1.run_FastQC(output)
		self.numberOfReads += self.r1.qcRes.total_reads
		if(self.r2 is not None):
			self.r2 = self.r2.run_FastQC(output)
			self.numberOfReads += self.r1.qcRes.total_reads
		return self

	def run_Trimmomatic(self, adapter, palindrome, minlen, trimOption, betterTrimming,gz):
		self.trimRes = TrimResult(self, adapter, palindrome, minlen, trimOption, betterTrimming,gz )
		return self

	def get_all_qc(self):
		qc_results = [ (self.r1.qcRes, self.trimRes.readset.r1.qcRes) ]
		if (self.r2 is not None):
			qc_results.append((self.r2.qcRes, self.trimRes.readset.r2.qcRes) )
		return qc_results

	def get_all_qc_dict(self):
		qc_dict = OrderedDict({"raw": [], "trimmed": []})
		qc_dict["raw"] = [[x.__dict__ for x in self.r1.qcRes.results_for_report()]]
		if self.trimRes:
			qc_dict["trimmed"] = [[x.__dict__ for x in self.trimRes.readset.r1.qcRes.results_for_report()]]
		if (self.r2 is not None):
			qc_dict["raw"].append([x.__dict__ for x in self.r2.qcRes.results_for_report()])
			if self.trimRes:
				qc_dict["trimmed"].append([x.__dict__ for x in self.trimRes.readset.r2.qcRes.results_for_report()])
		return qc_dict


class FastQFile:
	def __init__(self, absFilename, concat_files = None):
		self.filename = absFilename
		self.qcRes = None
		#self.log = ""
		self.phred="phred33"
		self.concat_files = None

	def run_FastQC(self, outputDir):
		process = subprocess.Popen([join(get_tool_path('fastqc'), "fastqc") , self.filename , "-o" , outputDir, "-t", str(num_threads), "--extract"], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
		for line in iter(process.stderr.readline, b''):
			line = line.decode("utf-8")
			line = line.replace("\n", "")
			print(line, end="\r")
		for line in iter(process.stdout.readline, b''):
			line = line.decode("utf-8")
			if line.startswith("Approx"):
				print(line, end="\r")
			else:
				print(line, end="\r")
			pattern = re.match("Quality encoding detected as (?P<phred>\w+\d{2})", line)
			if pattern:
				self.phred = pattern.group("phred")
		process.communicate()
		self.qcRes = QCResult(join(outputDir, getFilenameWithoutExtension(basename(self.filename)) + "_fastqc"), join(mainResultsPath, "Report", "src"))
		return self
	def get_filename(self):
		return toLatex(basename(self.filename))
###########
## Result classes
###########

class QCResult:
	def __init__(self, resultsPath, summary_output):
		self.path = resultsPath
		self.results = self.get_results()
		#write summary csv for boxplots and assign total number of reads
		self.total_reads = write_fastqc_summary(resultsPath, summary_output)

	def get_results(self):
		summary_list = []
		no_plot=["Basic Statistics", "Overrepresented sequences"]
		with open(join(self.path, "summary.txt"), "r") as summary:
			reader = csv.reader(summary, delimiter = "\t")
			for row in reader:
				if (row[1] not in no_plot):
					try:
						plot = Plot(row[0], row[1], self.path)
						if exists(plot.file):
							summary_list.append(plot)
						else:
							print("No plot file ", plot.file, row[1])

							summary_list.append(Plot("NotExisting", row[1], "NotExisting"))
					except:
						print(row[1], "does not exist")
						summary_list.append(Plot("NotExisting", row[1], "NotExisting"))
		return summary_list

	def results_to_base64(self):
		converted_plot = []
		for plot in self.results:
			if not plot.file.startswith("NotExisting"):
				with open(plot.file, "rb") as imgfile:
					imgstring = base64.b64encode(imgfile.read())
					plot.file ='data:image/png;base64,' + imgstring.decode("utf-8")
					converted_plot.append(plot)
		return converted_plot

	def results_for_report(self):
		converted_plot = []
		for plot in self.results:
			if not plot.file.startswith("NotExisting"):
				plot.file =plot.file.replace(mainResultsPath, "..")
				converted_plot.append(plot)
		return converted_plot

class Plot:
	def __init__(self, value, name, resultsPath):
		self.color = self.get_color(value)
		self.name = name
		self.file = self.name_to_file(resultsPath)

	def get_color(self, value):
		if(value == "PASS"):
			return "green"
		elif(value =="FAIL"):
			return "red"
		#elif (value =="WARN"):
		#	return "orange"
		else:
			return "orange"#"grey"

	def name_to_file(self,resultsPath):
		if self.name in default_parameter["FastQC"].keys():
			return join(resultsPath, "Images", default_parameter["FastQC"][self.name])
		else:
			return ""


class TrimParameters:
	illuminaClip_seedMismatch = str(default_parameter["Trimmomatic"]["illuminaClip_seedMismatch"]) #"2" #specifies the maximum mismatch count which will still allow a full match to be performed
	illuminaClip_simpleClip = str(default_parameter["Trimmomatic"]["illuminaClip_simpleClip"]) # "10" #specifies how accurate the match between any adapter etc. sequence must be against a read
	leading = str(default_parameter["Trimmomatic"]["leading"]) #"3" # remove leading low quality below 3
	trailing = str(default_parameter["Trimmomatic"]["trailing"]) #"3" # remove trailing quality below 3
	adapter_path = get_tool_path('adapter')
	def __init__(self):
		#self.palindrome = palindrome
		self.extraTrimOptions = ""

	def make_callstring(self, adapter,palindrome, minlen, trimOption, betterTrimmingOption ):
		call = []
		if technology =="Illumina":
				call.append("ILLUMINACLIP:" + join(self.adapter_path, adapter+ ".fa") + ":" + self.illuminaClip_seedMismatch + ":" + str(palindrome) + ":" + self.illuminaClip_simpleClip)
		call.append(trimOption)
		call.append(betterTrimmingOption)
		call.append("MINLEN:" + str(minlen))
		return " ".join(call)


class TrimResult:
	def __init__(self,  readset, adapter, palindrome, minlen, trimOption, betterTrimming,gz):
		self.parameters = TrimParameters()
		self.readset = readset
		self.r1_paired = None
		self.r2_paired = None
		self.r1_unpaired = None
		self.r2_unpaired = None

		self.logs = ""

		#Results
		self.total=0
		self.shorter_fragments_percentage = 0
		self.input_number = 0
		self.nTrimmed = 0
		self.pTrimmed = 0
		self.adapter = adapter
		self.run(  palindrome, minlen, trimOption, betterTrimming, gz)

	def make_callstring(self, readset, palindrome,  minlen, trimOption, save = False, betterTrimmingOption ="", gz=True):
		if gz:
			extension= ".gz"
		else:
			extension =""
		if readset.paired:
			if save:
				self.r1_paired =join(mainResultsPath, "Trimmed", "r1_P_" + getFilenameWithoutExtension(readset.r1.filename,  getBase =  True) + ".fastq" + extension)
				self.r1_unpaired = join(mainResultsPath, "Trimmed", "r1_UP_" + getFilenameWithoutExtension(readset.r1.filename, getBase = True)+ ".fastq"+ extension)
				self.r2_paired =join(mainResultsPath, "Trimmed", "r2_P_" + getFilenameWithoutExtension(readset.r2.filename, getBase = True)+ ".fastq"+ extension)
				self.r2_unpaired =join(mainResultsPath, "Trimmed", "r2_UP_" + getFilenameWithoutExtension(readset.r2.filename, getBase = True)+ ".fastq"+ extension)
				output = " ".join([self.r1_paired, self.r1_unpaired, self.r2_paired, self.r2_unpaired])
			else:
				output = "/dev/null /dev/null /dev/null /dev/null"
			callProcess = [join(get_tool_path("trimmomatic"), "TrimmomaticPE "),
						   "-threads", str(num_threads),
						   "-" + readset.r1.phred,
						   readset.r1.filename,  # input 1
						   readset.r2.filename,  # input 2
						   output,
						   self.parameters.make_callstring(self.adapter,palindrome, minlen, trimOption, betterTrimmingOption)
						]
		else:
			callProcess = [join(get_tool_path("trimmomatic"),"TrimmomaticSE "),
						   "-threads", str(num_threads),
						   "-" + readset.r1.phred,
						   readset.r1.filename,  # input 1
						   join(mainResultsPath, "Trimmed", getFilenameWithoutExtension(readset.r1.filename, getBase = True)+ ".fastq"),#output
						   self.parameters.make_callstring(self.adapter,  palindrome, minlen, trimOption, betterTrimmingOption)
						  ]
			self.r1_unpaired = join(mainResultsPath, "Trimmed", getFilenameWithoutExtension(readset.r1.filename, getBase = True)+ ".fastq"+ extension)
		return callProcess

	def check_quality(self,readset, trim_perc):
		path = join(mainResultsPath, "Trimmed", "temp")
		if readset.paired:
			try:
				r1_name = join_reads([self.r1_paired, self.r1_unpaired], path, basename(readset.r1.filename))

				print("Run FastQC to optimize trimming.")
				process = subprocess.Popen( [join(get_tool_path('fastqc'), "fastqc"), r1_name,"--nogroup", "--extract", "-o", path,"--threads", str(num_threads)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
				process.communicate()
				trim_bool, headcrop, crop = optimize_trimming(join(path, getFilenameWithoutExtension(basename(r1_name)) + "_fastqc"), trim_perc)

				#if r1 was ok, go on and check r2
				print("Check 'per sequence base content' of R2.")

				r2_name = join_reads([self.r2_paired, self.r2_unpaired], path, basename(readset.r2.filename))
				process = subprocess.Popen(
					[join(get_tool_path('fastqc'), "fastqc"), r2_name,"--nogroup", "--extract", "-o",path, "--threads", str(num_threads)],
					stdout=subprocess.PIPE, stderr=subprocess.PIPE)
				process.communicate()
				r2_trim_bool, r2_headcrop, r2_crop = optimize_trimming(join(path, getFilenameWithoutExtension(basename(r2_name)) + "_fastqc"), trim_perc)

				return (trim_bool or r2_trim_bool), max(headcrop, r2_headcrop), min(crop, r2_crop)
			finally:
				shutil.rmtree(path)
		else:
			process = subprocess.Popen([join(get_tool_path('fastqc'), "fastqc"), self.r1_unpaired,"--nogroup", "--extract", "-o", path, "--threads", str(num_threads)],
									   stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			for line in iter(process.stdout.readline, b''):
				print(line, end='\r')
			process.communicate()
			trim_bool, headcrop, crop = optimize_trimming(join(path,getFilenameWithoutExtension(basename(self.r1_unpaired)) + "_fastqc"), trim_perc)

		return trim_bool, headcrop, crop

	def run(self,  palindrome, minlen, trimOption, betterTrimming, gz):
		# Report Trimmomatic Output
		# Run palindrome parameter which should be kept at last

		survived = {'30':0, '1000':0}

		call = self.make_callstring( self.readset, palindrome, minlen, trimOption, save=True, gz=gz)
		process = subprocess.Popen(" ".join(call), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
		survived1, total, nTrimmedReads, pTrimmedReads, log = trimmomatic_report(process,call[0], True)
		process.communicate()

		### Optimize trimming
		if betterTrimming !="":
			print("Improve trimming parameter")
			makedirs(join(mainResultsPath, "Trimmed","temp"), exist_ok=True)
			trim_bool, final_headcrop, final_crop = self.check_quality(self.readset, betterTrimming)

			if trim_bool:
				self.parameters.extraTrimOptions = "HEADCROP:"+str(final_headcrop) + " CROP:"+str(final_crop)
				call = self.make_callstring( self.readset, palindrome, minlen, trimOption, save=True, betterTrimmingOption = self.parameters.extraTrimOptions, gz=gz)
				process = subprocess.Popen(" ".join(call), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
				survived1, total, nTrimmedReads, pTrimmedReads, log = trimmomatic_report(process, call[0], True)
				process.communicate()
		if survived1==0:
			sys.exit("No reads remained after trimming. Check fastqc results before trimming in QCResults/Fastqc. Please rerun without -trimBetter or check -trimOptions and minlen again.")

		self.total = total
		self.nTrimmed = nTrimmedReads
		self.pTrimmed = pTrimmedReads
		self.logs += log

		############################

		survived[str(palindrome)] = survived1
		if self.readset.r2 is not None:
			if palindrome==30:
				palindrome=1000
			else:

				palindrome=30
			process = subprocess.Popen(" ".join(self.make_callstring( self.readset, palindrome, minlen, trimOption, save=False, betterTrimmingOption = self.parameters.extraTrimOptions, gz=gz)  ),
							stdout=subprocess.PIPE,
							stderr=subprocess.PIPE, shell=True)
			survived2, total,nTrimmedReads, pTrimmedReads, temp = trimmomatic_report(process, call[0],False)
			process.communicate()
			survived[str(palindrome)] = survived2
			self.shorter_fragments_percentage = round(survived["1000"] - survived["30"], 2)

		return self

	def run_FastQC(self,  tempdir):
		if self.readset.paired:
			#tempdir = tempfile.mkdtemp()
			r1_name = join_reads([self.r1_paired, self.r1_unpaired], tempdir, basename(self.readset.r1.filename))
			r2_name = join_reads([self.r2_paired, self.r2_unpaired], tempdir, basename(self.readset.r2.filename))
			try:
				self.readset = ReadSet( r1_name, r2_name)
				self.readset.run_FastQC(join(mainResultsPath, "Trimmed/FastQC"))
			except:
				print(sys.exc_info())
				sys.exit()
			finally:
				#remove(r1_name)
				#remove(r2_name)
				self.readset.r1.filename = " ".join([self.r1_paired, self.r1_unpaired])
				self.readset.r2.filename = " ".join([self.r2_paired, self.r2_unpaired])
		else:
			self.readset = ReadSet( self.r1_unpaired)
			self.readset.run_FastQC(join(mainResultsPath, "Trimmed"))
		return self


	def print_param(self, palindrome, minlen, trimOption):
		return self.parameters.make_callstring(self.adapter, palindrome, minlen, trimOption, self.parameters.extraTrimOptions)

class MappingParameter:
	def __init__(self, mapping):
		pass

class MappingResult:
	def __init__(self, reference, r1_name, r2_name, bowtie_index):
		self.numberOfAlignedReads = 0
		self.percentAlignedReads= 0
		self.index = self.build_index(reference, bowtie_index)
		self.log = ""
		self.r1_name = r1_name
		self.r2_name = r2_name

	def build_index(self, reference, index):
		index_name = join(index, getFilenameWithoutExtension(basename(reference)) +"_bt2")  # reference name "bowtie2 build index_name"
		if not isdir(index):
			return index
		if not exists(index_name + ".1.bt2"):
			process = subprocess.Popen([join(get_tool_path("bowtie2"),"bowtie2-build"),reference,  index_name ], stderr=subprocess.PIPE, stdout = subprocess.PIPE)

			for line in iter(process.stderr.readline, b''):
				line = line.decode("utf-8")
				print(line)
			process.communicate()
			print("Bowtie2-build. Done.")
		return index_name


	def run_bowtie(self, save_mapping):
		print("Run Bowtie2")
		call = [join(get_tool_path("bowtie2"), "bowtie2"), "-x", self.index, "--no-unal --threads ", str(num_threads)]

		#if self.r2_name is not None:
		#	call.extend(["-1", re.sub(r"(?<!\\)\s", ",", self.r1_name)])
		#	call.extend(['-2',re.sub(r"(?<!\\)\s",",",self.r2_name)])
		#else:
		#	call.extend(["-U", re.sub(r"(?<!\\)\s", ",", self.r1_name)])
		call.extend(["-U", re.sub(r"(?<!\\)\s", ",", self.r1_name + " " +  self.r2_name)])
		call.extend(["-S", save_mapping, "2>&1"])
		#print("Call  ", " ".join(call))
		process = subprocess.Popen(" ".join(call), stderr=subprocess.PIPE, stdout= subprocess.PIPE, shell=True)

		for line in iter(process.stdout.readline, b''):
			line = line.decode("utf-8")
			print(line)
			self.log += toLatex(line) + "\n"
			pattern1 = re.match(".* (?P<aligned_exact>\d+) \((?P<percent_aligned_exact>\d+.\d+)%\) aligned exactly 1 time", line)
			pattern2 = re.match(".* (?P<aligned_more_than_one>\d+) \((?P<percent_aligned_more_than_one>\d+.\d+)%\) aligned >1 times", line)
			if pattern1:
				self.numberOfAlignedReads += int(pattern1.group("aligned_exact"))
				self.percentAlignedReads += float(pattern1.group("percent_aligned_exact").replace(",","."))
			if pattern2:
				self.numberOfAlignedReads += int(pattern2.group("aligned_more_than_one"))
				self.percentAlignedReads += float(pattern2.group("percent_aligned_more_than_one"))
				self.percentAlignedReads = round(self.percentAlignedReads,2)

		for line in iter(process.stderr.readline, b''):
			line = line.decode("utf-8")
			self.log += "\\textcolor{red}{" + toLatex(line) + "}\n"
			print(line)
		process.communicate()
		print("Bowtie2 done.")
		return self


class KrakenResult:
	def __init__(self, r1,r2, db, name):
		self.name = name
		self.report_name = None
		self.report = ""
		self.pClassified = 0
		self.nClassified = 0
		self.log = ""
		self.run_kraken(r1,r2, db)

	def make_callstring(self, r1,r2, db):
		#input_type = ""
		#if fileext.endswith("")
		call = [join(get_tool_path('kraken') , "kraken") , "--db", db, r1]
		if r2 is not None:
			call.append( r2)# + " --paired")
		call.append("--preload")
		call.append("--threads " + str(num_threads))
		self.report_name = join(mainResultsPath, self.name + ".krakenreport")
		if exists(self.report_name):
			i = 2
			new_name = join(mainResultsPath, self.name + "_" +str(i) + ".krakenreport")
			while exists(new_name):
				i += 1
				new_name = join(mainResultsPath, self.name + "_" + str(i) + ".krakenreport")
			self.report_name=new_name

		call.append("--output " + self.report_name)
		return " ".join(call)

	def run_kraken(self, r1,r2, db):
		process = subprocess.Popen(self.make_callstring(r1,r2, db), shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
		self.log += "\\textcolor{gray}{Using Parameter " + " ".join(["\path{"+ x + "}" for x in self.make_callstring(r1,r2, db).split(" ")]) + "}\\\\"

		for line in iter(process.stderr.readline, b''):
			line = line.decode("utf-8")
			print(line)
			if not (line.startswith("Loading database") or re.search("Processed \d+", line)):
				self.log += toLatex(line) +"\n"
				pattern = re.match("\s+(?P<nClassified>\d+) sequences classified \((?P<pClassified>\d+.\d+)%\)", line)
				if pattern:
					self.nClassified = pattern.group("nClassified")
					self.pClassified = pattern.group("pClassified")

		for line in iter(process.stdout.readline, b''):
			line = line.decode("utf-8")
			print(line)
			if not ( re.search("Processed  \d+", line) or line.startswith("Loading database") ):
				self.output += line + "\n"
		process.communicate()

		print("Convert Kraken-Report..")
		self.convert_report(db)
		return self

	def convert_report(self, db):
		process = subprocess.check_output([join(get_tool_path('kraken') ,'kraken-report') , "--db", db, self.report_name])
		self.report = process.decode("utf-8")
		return self


