# CAT Python Executable
# Version 1.3
# pythonflow.exe <option> <input.txt> <output.csv>
# requires module load.py 
# Methods:
# -b // nx.betweenness_centrality
# -d // nx.betweenness_centrality_subset
# -c // nx.current_flow_betweenness_centrality
# -e // nx.current_flow_betweenness_centrality_subset
# -f // nx.page_rank
# Inputs
# -x // [required for options -d and -e] input file for sources, format is textfile with single column of node ids
# -y // [required for options -d and -e] input file for targets, format is textfile with single column of node ids
# -a // [required for options -b, -c, and -f] probability value: proportion of nodes sampled (k/n) for betweenness, error tolerance (epsilon) for current flow, alpha (1 - probability of random move) for pagerank 
# arg1 // input file for graph, format is a tab-delimited textfile with three columns: from_node,to_node,edge_weight
# arg2 // output file, format is a csv with two columns: node, value

import sys, load, locale, fileinput
from csv import writer as csvwriter
from optparse import OptionParser
import numpy as np
from scipy import sparse
from scipy.sparse import linalg
from scipy.sparse.csgraph import _validation
import networkx as nx
import xml.etree.ElementTree
import xml.etree.cElementTree
locale.setlocale(locale.LC_ALL, '') 
tmp = locale.localeconv()['decimal_point']

if __name__ == "__main__":
        parser = OptionParser("usage: %prog [options] arg1 arg2")
        parser.add_option("-b", dest="bc", action="store_true", help="nx.betweenness_centrality")
	parser.add_option("-c", dest="cc", action="store_true", help="nx.current_flow_betweenness_centrality")
	parser.add_option("-d", dest="bcs", action="store_true", help="nx.betweenness_centrality_subset")
	parser.add_option("-e", dest="ccs", action="store_true", help="nx.current_flow_betweenness_centrality_subset")
	parser.add_option("-f", dest="pr", action="store_true", help="nx.pagerank")
	parser.add_option("-x", action="store", type="string", dest="sourcefile", help="subset source nodes file")
	parser.add_option("-y", action="store", type="string", dest="targetfile", help="subset target nodes file")
	parser.add_option("-a", action="store", type="string", dest="alpha", help="probability value")
					
        (options, args) = parser.parse_args()
        
        if options.alpha:
        	alpha = float(options.alpha.replace(",", "."))
      
        
    	if tmp in [',']:
		for line in fileinput.FileInput(args[0],inplace=1):
		   line = line.replace(",",".")
		   print line,		

    	if len(args) != 2:
        	parser.error("Please specify and input and output file")
	
	if options.bc:
		if not options.alpha:
			print "No probability (sampling proportion) value entered, using exact algorithm"
			F=nx.read_weighted_edgelist(args[0],delimiter=" ")
			G=nx.connected_component_subgraphs(F)[0]
			output=nx.betweenness_centrality(G,weight='weight',k=None)
		elif options.alpha:
			F=nx.read_weighted_edgelist(args[0],delimiter=" ")
			G=nx.connected_component_subgraphs(F)[0]
			if alpha==1:
				print "Using exact algorithm"
				output=nx.betweenness_centrality(G,weight='weight',k=None)		
			elif alpha!=1:
				samplesize=int(nx.number_of_nodes(G)*alpha)
				output=nx.betweenness_centrality(G,weight='weight',k=samplesize)
		
	elif options.cc:
		if not options.alpha:
			print "No probability (error tolerance) value entered, using exact algorithm"
			F=nx.read_weighted_edgelist(args[0],delimiter=" ")
			G=nx.connected_component_subgraphs(F)[0]
			output=nx.current_flow_betweenness_centrality(G,normalized=True,solver='lu')
		elif options.alpha:
			F=nx.read_weighted_edgelist(args[0],delimiter=" ")
			G=nx.connected_component_subgraphs(F)[0]
			if alpha==0:
				print "Using exact algorithm"
				try:
					output=nx.current_flow_betweenness_centrality(G,normalized=True,solver='lu')
				except MemoryError:
				     print '\nCAT ran out of memory. This function is memory-intensive.\nPlease try again on a system with more available RAM or see manual for information on alternative functions with lower memory requirements.\n'
			elif alpha!=0:
				try:
					output=nx.approximate_current_flow_betweenness_centrality(G,normalized=True,epsilon=alpha,solver='lu')
				except nx.NetworkXError:
					print "Error tolerance set too low, will use exact algorithm"
					output=nx.current_flow_betweenness_centrality(G,normalized=True)
	elif options.pr:
		if not options.alpha:
		    	print "Pagerank requires an probability (alpha) value"
			parser.print_help()
			exit(-1)
		elif options.alpha:
			G=nx.read_weighted_edgelist(args[0],delimiter=" ",create_using=nx.DiGraph())
			output=nx.pagerank(G, alpha=alpha, max_iter=1000000, tol=1e-08, nstart=None)
		
	elif options.bcs:
		if not options.sourcefile:
	    		print "Subset centrality requires source and target files"
			parser.print_help()
			exit(-1)
		elif options.sourcefile:
			if not options.targetfile:
			    	print "Subset centrality requires source and target files"
				parser.print_help()
				exit(-1)
			elif options.targetfile:
				s=load.lines(options.sourcefile,strip='right')
				t=load.lines(options.targetfile,strip='right')
				G=nx.read_weighted_edgelist(args[0],delimiter=" ")
				output=nx.betweenness_centrality_subset(G,sources=s,targets=t,normalized=False,weight='weight')
		
	elif options.ccs:
		if not options.sourcefile:
		    	print "Subset centrality requires source and target files"
			parser.print_help()
			exit(-1)
		elif options.sourcefile:
			if not options.targetfile:
				print "Subset centrality requires source and target files"
				parser.print_help()
				exit(-1)
			elif options.targetfile:
				try:
					s=load.lines(options.sourcefile,strip='right')
					t=load.lines(options.targetfile,strip='right')
					G=nx.read_weighted_edgelist(args[0],delimiter=" ")
					output=nx.current_flow_betweenness_centrality_subset(G,sources=s,targets=t,normalized=False)
				except MemoryError:
				     print '\nCAT ran out of memory. This function is memory-intensive.\nPlease try again on a system with more available RAM or see manual for information on alternative functions with lower memory requirements.\n'
		
	olist = list(output.items())		
	ofile  = open(args[1], "wb")
	ofile.write('HEX_ID\tVALUE\n')
 	writer = csvwriter(ofile, delimiter='\t')
	writer.writerows(olist)
	ofile.close()
	
	if tmp in [',']:
		for line in fileinput.FileInput(args[1],inplace=1):
			line = line.replace(".",",")
		   	print line,