#!/usr/bin/env python2.7
from GRAViTy.MutualInformationCalculator import MutualInformationCalculator
from GRAViTy.Utilities.str2bool import str2bool
from GRAViTy.Utilities.CheckInput import check_FILEPATH, check_POSINTEGER
import optparse, os

import textwrap
class IndentedHelpFormatterWithNL(optparse.IndentedHelpFormatter):
	def format_description(self, description):
		if not description: return ""
		desc_width = self.width - self.current_indent
		indent = " "*self.current_indent
		# the above is still the same
		bits = description.split('\n')
		formatted_bits = [
			textwrap.fill(bit,
				desc_width,
				initial_indent=indent,
				subsequent_indent=indent)
			for bit in bits]
		result = "\n".join(formatted_bits) + "\n"
		return result
	
	def format_option(self, option):
		# The help for each option consists of two parts:
		#	 * the opt strings and metavars
		#	 eg. ("-x", or "-fFILENAME, --file=FILENAME")
		#	 * the user-supplied help string
		#	 eg. ("turn on expert mode", "read data from FILENAME")
		#
		# If possible, we write both of these on the same line:
		#	 -x		turn on expert mode
		#
		# But if the opt string list is too long, we put the help
		# string on a second line, indented to the same column it would
		# start in if it fit on the first line.
		#	 -fFILENAME, --file=FILENAME
		#			 read data from FILENAME
		result = []
		opts = self.option_strings[option]
		opt_width = self.help_position - self.current_indent - 2
		if len(opts) > opt_width:
			opts = "%*s%s\n" % (self.current_indent, "", opts)
			indent_first = self.help_position
		else: # start help on same line as opts
			opts = "%*s%-*s	" % (self.current_indent, "", opt_width, opts)
			indent_first = 0
		result.append(opts)
		if option.help:
			help_text = self.expand_default(option)
			# Everything is the same up through here
			help_lines = []
			for para in help_text.split("\n"):
				help_lines.extend(textwrap.wrap(para, self.help_width))
			# Everything is the same after here
			result.append("%*s%s\n" % (
				indent_first, "", help_lines[0]))
			result.extend(["%*s%s\n" % (self.help_position, "", line)
				for line in help_lines[1:]])
		elif opts[-1] != "\n":
			result.append("\n")
		return "".join(result)

def main():
	parser = optparse.OptionParser(	usage = "usage: %prog [options]",
					version = "%prog 1.1.0",
					formatter = IndentedHelpFormatterWithNL())
	
	parser.add_option(	'--ShelveDir',
				dest	= "ShelveDir",
				help	= "Full path to the shelve directory, storing GRAViTy outputs.",
				metavar	= "DIRECTORYPATH",
				type	= "string",
	)
	parser.add_option(	'--IncludeIncompleteGenomes',
				dest	= "IncludeIncompleteGenomes",
				default	= False,
				help	= "Include incomplete virus genomes in the mutual information calculation if True. [default: %default]",
				metavar	= "BOOLEAN",
				type	= "choice",
				choices	= ["True", "False",],
	)
	
	VirusGroupingForMICalGroup = optparse.OptionGroup(	parser		= parser,
								title		= "Virus grouping for mutual information calculation options",
								description	= "GRAViTy can calculate mutual information between (various schemes of) taxonomic groupings and values of PPHMM scores to determine which PPHMMs are highly (or weakly) correlated with the virus taxonomic scheme(s).")
	VirusGroupingForMICalGroup.add_option(	'--VirusGroupingSchemesFile',
						dest	= "VirusGroupingFile",
						default	= None,
						help	= "Fill path to the virus grouping scheme file. [default: %default] "
							  "The file contains column(s) of arbitrary taxonomic grouping scheme(s) that users want to investigate. The file may look something like: \n\n"
							  "Scheme 1\tScheme 2\t...\n"
							  "A\tX\t...\n"
							  "A\tX\t...\n"
							  "B\tX\t...\n"
							  "B\tX\t...\n"
							  "C\tY\t...\n"
							  "C\tY\t...\n"
							  "...\t...\t...\n\n"
							  "If 'None', the taxonomic grouping as specified in 'Taxonomic grouping' column in the VMR will be used. "
							  "Note that the file must contain headers.",
						metavar	= "FILEPATH",
						type	= "string",
						action	= "callback",
						callback= check_FILEPATH,
	)
	parser.add_option_group(VirusGroupingForMICalGroup)
	
	SamplingGroup = optparse.OptionGroup(	parser		= parser,
						title		= "Virus sampling options",
						description	= "")
	SamplingGroup.add_option(	'--N_Sampling',
					dest = "N_Sampling",
					default = 10,
					help = "The number of mutual information scores sample size. [default: %default]",
					metavar = "NUMBER",
					type = "int",
					action = "callback",
					callback = check_POSINTEGER,
	)
	SamplingGroup.add_option(	'--SamplingStrategy',
					dest = "SamplingStrategy",
					default = "balance_with_repeat",
					help = "Virus sampling scheme. [default: %default]",
					metavar = "SCHEME",
					type = "choice",
					choices = [None, "balance_without_repeat", "balance_with_repeat"],
	)
	SamplingGroup.add_option(	'--SampleSizePerGroup',
					dest = "SampleSizePerGroup",
					default = 10,
					help = "If 'SamplingStrategy' != None, this option specifies the number of viruses to be sampled per taxonomic group [default: %default]",
					metavar = "NUMBER",
					type = "int",
					action = "callback",
					callback = check_POSINTEGER,
	)
	parser.add_option_group(SamplingGroup)
	
	options, arguments = parser.parse_args()
	
	print "Input for MutualInformationCalculator:"
	print "="*100
	print "Main input"
	print "-"*50
	print "ShelveDir: %s"%options.ShelveDir
	print "IncludeIncompleteGenomes: %s"%options.IncludeIncompleteGenomes
	
	print "\n"
	print "Virus grouping for mutual information calculation options"
	print "-"*50
	print "VirusGroupingFile: %s"%options.VirusGroupingFile
	
	print "\n"
	print "Virus sampling options"
	print "-"*50
	print "N_Sampling: %s"%options.N_Sampling
	print "SamplingStrategy: %s"%options.SamplingStrategy
	print "SampleSizePerGroup: %s"%options.SampleSizePerGroup
	print "="*100
	
	MutualInformationCalculator (
		ShelveDir = options.ShelveDir,
		IncludeIncompleteGenomes = str2bool(options.IncludeIncompleteGenomes),
		VirusGroupingFile = options.VirusGroupingFile,

		N_Sampling = options.N_Sampling,
		SamplingStrategy = options.SamplingStrategy,
		SampleSizePerGroup = options.SampleSizePerGroup,
		)

if __name__ == '__main__':
	main()

