#!/usr/bin/env python

import sys, os
import time
from argparse import ArgumentParser

from findCPcore import Facade
from findCPcore import FacadeUtils

TASK_SPREADSHEET       = "TASK_SPREADSHEET"
TASK_SENSIBILITY       = "TASK_SENSIBILITY"
TASK_SAVE_WITHOUT_DEM  = "TASK_SAVE_WITHOUT_DEM"
TASK_SAVE_WITH_FVA     = "TASK_SAVE_WITH_FVA"
TASK_SAVE_WITH_FVA_DEM = "TASK_SAVE_WITH_FVA_DEM"

def verbose_f(text, args1=False, args2=False):
	if args1:
		print(text)

def run(task, model_path, output_path, verbose, objective=None):
	try:
		if task == TASK_SPREADSHEET:
			print("Task: Save results spreadsheet")
			facade = Facade()
			error = facade.generate_spreadsheet(False, model_path, verbose_f, args1=verbose, args2=None, output_path=None, objective=objective)
			if error == "":	
				(result_ok, text) = facade.save_spreadsheet(False, output_path, verbose_f)
				if result_ok:
					print("File succesfully saved at: " + text)
				else:
					print("Error, something went wrong: " + text)
			else:
				print("Error, something went wrong: " + error)
			print("")

		elif task == TASK_SENSIBILITY:
			print("Task: Save growth dependent chokepoints spreadsheet")
			facade = Facade()
			error = facade.generate_sensibility_spreadsheet(False, model_path, verbose_f, args1=verbose, args2=None, output_path=None, objective=objective)
			if error == "":	
				(result_ok, text) = facade.save_spreadsheet(False, output_path, verbose_f)
				if result_ok:
					print("File succesfully saved at: " + text)
				else:
					print("Error, something went wrong: " + text)
			else:
				print("Error, something went wrong: " + error)
			print("")

		elif task == TASK_SAVE_WITHOUT_DEM:
			print("Task: save model without dead end metabolites")
			facade = Facade()
			facade.find_and_remove_dem(False, output_path, verbose_f, model_path, args1=verbose, args2=None)
			(result_ok, text) = facade.save_model(output_path, False, verbose_f)
			if result_ok:
				print("File succesfully saved at: " + text)
			else:
				print("Error, something went wrong: " + text)
			print("")

		elif task == TASK_SAVE_WITH_FVA:
			print("Task: save model refined with Flux Variability Analysis")
			facade = Facade()
			error = facade.run_fva(False, output_path, verbose_f, model_path, args1=verbose, args2=None, objective=objective)
			if error != "":
				print("Error, something went wrong: " + error)
			else:
				(result_ok, text) = facade.save_model(output_path, False, verbose_f)
				if result_ok:
					print("File succesfully saved at: " + text)
				else:
					print("Error, something went wrong: " + text)
			print("")

		elif task == TASK_SAVE_WITH_FVA_DEM:
			print("Task: save model refined with Flux Variability Analysis without dead end metabolites")
			facade = Facade()
			error = facade.run_fva_remove_dem(False, output_path, verbose_f, model_path, args1=verbose, args2=None, objective=objective)
			if error != "":
				print("Error, something went wrong: " + error)
			else:
				(result_ok, text) = facade.save_model(output_path, False, verbose_f)
				if result_ok:
					print("File succesfully saved at: " + text)
				else:
					print("Error, something went wrong: " + text)
			print("")

	except Exception as error:
		print("Error: Something went wrong:")
		print(str(error))
		#raise error


def read_input():
	input_file = ""
	output = ""
	verbose = False
	parser = ArgumentParser(description="")

	parser.add_argument("-v", "--verbose",  
				help="Print feedback while running.", 
				action="store_true")
	parser.add_argument("-i", 
				dest="inputfile", required=True,
				metavar="<input file>",
				help="Input metabolic model. Allowed file formats: .xml .json .yml")
	parser.add_argument("-o", 
				dest = "outputfile",
				metavar = "<output file>",
				help = "Output spreadsheet file with results. Allowed file formats: .xls .xlsx .ods")
	parser.add_argument("-cp", 
				dest = "cp",
				metavar = "<output file>",
				help = "Output spreadsheet file with growth dependent chokepoints. Allowed file formats: .xls .xlsx .ods")
	parser.add_argument("-swD", 
				dest = "modelwodem",
				metavar = "<output file>",
				help = "Save output model without Dead End Metabolites. Allowed file formats: .xml .json .yml")
	parser.add_argument("-sF", 
				dest = "modelfva",
				metavar = "<output file>",
				help = "Save output model with reactions bounds updated with Flux Variability Analysis. Allowed file formats: .xml .json .yml")
	parser.add_argument("-swDF", 
				dest = "modelfvawodem",
				metavar = "<output file>",
				help = "Save output model with reactions bounds updated with Flux Variability Analysis and without Dead End Metabolites. Allowed file formats: .xml .json .yml")
	parser.add_argument("-objective", 
				dest = "objective",
				metavar = "<reaction id>",
				help = "Reaction id to be used as objective function with Flux Balance Analysis")

	args          = parser.parse_args()

	input_file    = args.inputfile
	output        = args.outputfile
	cp            = args.cp
	modelwodem    = args.modelwodem
	modelfva      = args.modelfva
	modelfvawodem = args.modelfvawodem
	objective     = args.objective

	return (input_file, output, cp, modelwodem, modelfva, modelfvawodem, args.verbose, objective)


def __check_model_file(path):
	if path[-4:] != ".xml" and path[-5:] != ".json" and path[-4:] != ".yml":
		return False
	else:
		return True

def __check_spread_file(path):
	if path[-4:] != ".xls" and path[-4:] != ".ods" and path[-5:] != ".xlsx":
		return False
	else:
		return True

def validate_input_model(input_file):
	if not __check_model_file(input_file):
		print("Model file must be either .xml .json .yml")
		print("run findCPcli -h for further information.")
		exit(1)
		
# Method for validating the output file path for operation that generate a new model
def validate_output_model(list_of_output_path):
	for output_path in list_of_output_path:
		# if the output path is not None, 
		# 	the task will be performed and the file needs validation
		# else if the output path is None, 
		# 	the task has not been selected and the file is not checked
		if output_path is not None and not __check_model_file(output_path):
			print("Output model file must be either .xml .json .yml")
			print("run findCPcli -h for further information.")
			exit(1)

# Method for validating the output file path for operation that generate a new spreadsheet file
def validate_output_spread(list_of_output_path):
	for output_path in list_of_output_path:
		# if the output path is not None, 
		# 	the task will be performed and the file needs validation
		# else if the output path is None, 
		# 	task has not been selected and the file is not checked
		if output_path is not None and not __check_spread_file(output_path):
			print("Output file must be .xls .xlsx or .ods")
			exit(1)

# Check that at least one operation has been selected
def validate_operation_selected(list_of_possible_operations):
	operation_selected = False
	for operation in list_of_possible_operations:
		if operation is not None:
			operation_selected = True

	if not operation_selected:
		print("Please select at least one operation to perform: ")
		print("[-o <output file>] [-cp <output file>] [-swD <output file>] " \
			+ "[-sF <output file>] [-swDF <output file>]")
		print("run findCPcli -h for further information.")
		exit(1)

#
#	Main cli workflow
#	 Input is read, validated and each task executed independently
#
def main():

	# Read input
	(input_file, output, cp, modelwodem, modelfva, modelfvawodem, verbose, objective) \
		= read_input()

	# Note that the following save the outputh path of each operation
	# If the variable is None, no operation that operation has not been selected
	NEW_MODEL_OPERATIONS = [modelwodem, modelfva, modelfvawodem] # Tasks that generate new models
	NEW_SPREADSHEET_OPS  = [output, cp] # Tasks that generate spreadsheet files

	# Check input file formats and task
	validate_input_model(input_file)
	validate_output_model(NEW_MODEL_OPERATIONS)
	validate_output_spread(NEW_SPREADSHEET_OPS)
	validate_operation_selected(NEW_MODEL_OPERATIONS + NEW_SPREADSHEET_OPS)

	# Run task
	if output is not None:
		task     = TASK_SPREADSHEET
		out_path = output
		run(task, input_file, out_path, verbose, objective)

	if cp is not None:
		task     = TASK_SENSIBILITY
		out_path = cp
		run(task, input_file, out_path, verbose, objective)

	if modelwodem is not None:
		task     = TASK_SAVE_WITHOUT_DEM
		out_path = modelwodem
		run(task, input_file, out_path, verbose, objective)

	if modelfva is not None:
		task     = TASK_SAVE_WITH_FVA
		out_path = modelfva
		run(task, input_file, out_path, verbose, objective)

	if modelfvawodem is not None:
		task     = TASK_SAVE_WITH_FVA_DEM
		out_path =  modelfvawodem
		run(task, input_file, out_path, verbose, objective)


if __name__ == "__main__":
	main()



