import sys
from snpgpu import *

############################
#START of MAIN Program Flow#
############################

#Check if correct number of cl args are entered
if ( len( sys.argv ) < 4 ) :
	print '\n Program usage:\n'+sys.argv[ 0 ] + ' confVec spikTransMat rules-in-reg-exp\n'

#if correct, proceed
else :
	confVecFile = sys.argv[ 1 ]
	spikTransMatFile = sys.argv[ 2 ]
#	rulesFile = sys.argv[ 3 ]
	ruleRegExpFile = sys.argv[ 3 ]

#####
#{1}#	Input Ck (C0 initially), spiking transition matrix, rules
#####	
	confVec = importVec( confVecFile )
	#spikVec = importVec( sys.argv[ 2 ] )
	spikTransMat  = importVec( spikTransMatFile )
#	rules = importVec( rulesFile )
	ruleregexp = importRule( ruleRegExpFile )

	#first, determine number of neurons
	print ' ruleregexp', ruleregexp
	neurNum = len( ruleregexp )

	#preliminary prints
	print '\n' + '*'*50 + 'SNP system simulation run STARTS here' + '*'*50 + '\n'
	print '\nSpiking transition Matrix: '
	#printMatrix( spikTransMat )
	print '\nSpiking transition Matrix in row-major order (converted into a square matrix):\n', spikTransMat[ 2: ]
	#print '\nRules of the form a^n/a^m -> a or a^n ->a loaded:\n', rules
	print '\nInitial configuration vector:\n', confVec, '\nor in dash delimited format:', concatConfVec( confVec, neurNum )


#####
#{2}#	proceed to determining spikVec from loaded rules + confVec, then invoke CUDA C code
#####	works for rules of type 3) only for now

	print '\nNumber of neurons for the SN P system is %d ' % ( neurNum )
	
	#generate list of list of form [ [spike/s, rule1 criterion1, rule1 criterion2, ...], ... ]
	spikRuleList = genSpikRuleList( confVec, neurNum )
	print 'genSpikRuleList(): spikeRuleList =',spikRuleList
	
	#function to print neurons + rules criterion and total order
	#prNeurons( spikRuleList )
	#print '\n'

	#generate a list of spikes + rules they are applicable to, in order
	#e.g. C0 = 2 1 1, r = 2 2 $ 1 $ 1 2
	#output should be : [['2', 1, 2], ['1', 1], ['1', 1, 0]]  
	tmpList = genPotentialSpikrule( spikRuleList, ruleregexp )
	print 'genPotentialSpikrule(): tmpList = ', tmpList
	
	# generate all possible + valid 10 strings PER neuron
	# if tmp = [ '01', '10 ], tmp2 = [ '1' ], returns tmp = [ tmp, tmp2 ] to get tmp = [ [ '01', '10 ], [ '1' ] ]
	tmpList = genNeurSpikVecStr( tmpList, neurNum )
	print 'genNeurSpikVecStr(): tmpList = ', tmpList

	#pair up sub-lists in tmpList to generate a single list of all possible + valid 10 strings
	allValidSpikVec = genNeurPairs( tmpList )
	print 'genNeurPairs(): allValidSpikVec =', allValidSpikVec

	#create total (not global) list of all generated Ck + Sk to prevent loops in the computation tree +extra file creation
	allGenCk = [ ]
	allGenSk = [ ]	
	allGenCkFile = "allGenCkFile.txt"
	#create allGenCkFile file w/o writing anything into it for now
	totalCkFile = open( allGenCkFile, 'w' )
	totalCkFile.close( )

	# string concatenation of the configVec, Ck-1, from configVec = [ '2', '2', '1', '0', '0', ...]
	# to configVec = 211 <type 'str'>
	print 'len of confVec + confVec', len( confVec ), confVec
	Ck_1_str = concatConfVec( confVec, neurNum ) 
	#write into total list of Cks
	allGenCk = addTotalCk( allGenCk, Ck_1_str, allGenCkFile )


	#write all valid spiking vectors onto each of their own files e.g. given 10110, create file s_10110 and write 10110 in it
	createSpikVecFiles( spikTransMat, allValidSpikVec )

	#print confVec
	print ' spikTransMat len ', len( spikTransMat )
	sqrMatWidth = int( math.sqrt( len( spikTransMat ) ) ) #input matrix is 'manually squared' for now, AND multiple of 2!
	tileWidth = 2 #default TILE_WIDTH value for now...

#####
#{3}#	using all generated valid spiking vector files, 'feed' the files to the CUDA C kernel to evaluate (1)
#####	

	#write all valid config vectors onto each of their own files e.g. given 211, create file c_211 and write 211 in it
	createConfVecFiles( spikTransMat, allGenCk )
	
	#use PyCUDA to evaluate equation (1) in parallel
	genCks( allValidSpikVec, sqrMatWidth, tileWidth, concatConfVec( confVec, neurNum ),  spikTransMatFile )

	#add all Cks generated from C0
	for spikVec in allValidSpikVec[ 0 ] :
	#build filename string for the the Ck to be loaded from file
		strn = 'c_' +  concatConfVec( confVec, neurNum ) + '_' + spikVec
		#import/load Cks generated by Ck-1 from files
		C_k_vec = importVec( strn )
		C_k = concatConfVec( C_k_vec, neurNum )
		#add the generated Ck-1 to the total list of generated Cks
		addTotalCk( allGenCk, C_k, allGenCkFile )

	print ' allGenCk =', allGenCk
	print ' End of C0 \n**\n**\n**'

#####
#{4}#	From {3}, exhaustively repeat steps {1} to {3} on all generated Ck/c_xxxx except C0
#####
	#print isVecZero( [ '0', '0', '0', '0','0','1','0','0' ] )
	#Ck = confVec
	print ' initial total Ck list is allGenCk =', allGenCk
	#exhaustively loop through total Ck list/list of all the generated Ck except C0

	allGenCkFilePtr = open( allGenCkFile, 'rb' )
#	Ck = allGenCkFilePtr.readline( )	
	Ck = allGenCkFilePtr.readline( )	
	strlen = len( Ck.replace( '-', '') )
	CkCnt = 0
	while  ( Ck != '' ) and not ( isConfVecNeg( Ck ) ) :
#	while ( Ck != '') & ( CkCnt != 20 ) :
		print 'Current spikVec:', spikVec, ' and Ck:', Ck
		#for Cks whose string length exceeds the number of neurons e.g. neurons = 3 Ck = 2110 (2,1,10)
		Ck = Ck.replace( '\n', '' )

		#no more spikes to be used by the P system
		if isConfVecZero( Ck ) : #works
			print '\tZero Ck/spikes. Stop.'
			print '\n' + '*'*50 + 'SNP system simulation run ENDS here' + '*'*50 + '\n'
			allGenCkFilePtr.close( )
			break
		else :
			#write all valid config vectors onto each of their own files e.g. given 211, create file c_211 and write 211 in it
			#print ' allGenCk ', allGenCk
			createConfVecFiles( spikTransMat, allGenCk )

			#build filename string for the Ck to be loaded from file
			strn = 'c_' +  Ck
			#import/load Cks generated by Ck-1 from files
			C_k_vec = importVec( strn )
			C_k = concatConfVec( C_k_vec, neurNum )

			#generate list of list of form [ [spike/s, rule1 criterion1, rule1 criterion2, ...], ... ]
			spikRuleList = genSpikRuleList( C_k_vec, neurNum )
			#print '\tList of lists w/ spike + rule criterion, spikRuleList = ', spikRuleList, ' for Ck = ', C_k

			#generate a list of spikes + rules they are applicable to, in order
			#e.g. C0 = 2 1 1, r = 2 2 $ 1 $ 1 2
			#output should be : [['2', 1, 2], ['1', 1], ['1', 1, 0]]  
			tmpList = genPotentialSpikrule( spikRuleList, ruleregexp )
			#print '\tAfter generating list of spikes+rules, tmpList = ', tmpList

			# generate all possible + valid 10 strings PER neuron
			# if tmp = [ '01', '10 ], tmp2 = [ '1' ], returns tmp = [ tmp, tmp2 ] to get tmp = [ [ '01', '10 ], [ '1' ] ]
			tmpList = genNeurSpikVecStr( tmpList, neurNum )
			#print '\tAfter generating all valid+possible spik vecs, tmpList =', tmpList

			#pair up sub-lists in tmpList to generate a single list of all possible + valid 10 strings
			allValidSpikVec = genNeurPairs( tmpList )
			print '\tAll valid 10 strings i.e. spiking vectors are in allValidSpikVec =', allValidSpikVec

			#write all valid spiking vectors onto each of their own files e.g. given 10110, create file s_10110 and write 10110 in it
			createSpikVecFiles( spikTransMat, allValidSpikVec )

			#print confVec
			sqrMatWidth = int( math.sqrt( len( spikTransMat ) ) )

			#write all valid config vectors onto each of their own files e.g. given 211, create file c_211 and write 211 in it
			#print ' All currently generated config vectors/Cks are allGenCk = ', allGenCk
			createConfVecFiles( spikTransMat, allGenCk )

			#print 'allValidSpikVec, sqrMatWidth, Ck, spikTransMatFile ' , allValidSpikVec, sqrMatWidth, Ck, spikTransMatFile
			genCks( allValidSpikVec, sqrMatWidth, tileWidth, Ck, spikTransMatFile)

			#add all Cks generated from C0
			for spikVec in allValidSpikVec[ 0 ] :
			#build filename string for the the Ck to be loaded from file
				strn = 'c_' +  Ck + '_' + spikVec
				#import/load Cks generated by Ck-1 from files
				C_k_vec = importVec( strn )
				C_k = concatConfVec( C_k_vec, neurNum )
				#print '\t\tLoaded file ', strn, ' and concatenated its contents into to C_k ', C_k
				#add the generated Ck-1 to the total list of generated Cks
				addTotalCk( allGenCk, C_k, allGenCkFile )

			print '\t\tGenerated from Sk-1 = ', spikVec, 'and Ck-1 =', Ck, 'is Ck = ', C_k
			addTotalCk( allGenCk, C_k, allGenCkFile )

			print '\tAll generated Cks are allGenCk =', allGenCk	
			print '\n**\n**\n**'		

			#go read the next Ck in the file allGenCkFile = "allGenCkFile.txt"	
			Ck = allGenCkFilePtr.readline( )		
			CkCnt += 1
	print '\nNo more Cks to use (infinite loop/s otherwise). Stop.\n' + '\n' + '*'*50 + 'SNP system simulation run ENDS here' + '*'*50 + '\n'
##########################
#END of MAIN Program Flow#
##########################
