'''
    SASSIE: Copyright (C) 2011 Joseph E. Curtis, Ph.D. 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''
import os,sys,string,locale,time
import numpy
import sassie.sasmol.sasmol as sasmol

#       CENTER
#
#	12/17/2004	--	adapted from trehalose project for gag modeling :	jc
#	12/20/2004	--	align N-terminal of CA in 1L6N and 1E6J		:	jc
#	10/16/2005	--	generic align structures 			:	jc
#	11/02/2005	--	generic center					:	jc
#	01/01/2011	--	added SASMOL 					:	jc
#LC      1         2         3         4         5         6         7
#LC4567890123456789012345678901234567890123456789012345678901234567890123456789
#                                                                      *      **
'''
        CENTER is the module that centers molecules from a dcd/pdb file
	to the coordinates (0.0,0.0,0.0).

        This module is called from Center Frames from the main
        GUI through the graphical_center.py script.

'''

def print_failure(message,txtOutput):

	txtOutput.put("\n\n>>>> RUN FAILURE <<<<\n")
	txtOutput.put(">>>> RUN FAILURE <<<<\n")
	txtOutput.put(">>>> RUN FAILURE <<<<\n\n")
	txtOutput.put(message)

	return

def unpack_variables(variables):

	runname=variables['runname'][0]
	infile=variables['infile'][0]
	refpdb=variables['refpdb'][0]
	ofile=variables['ofile'][0]
	path=variables['path'][0]

	return runname,infile,refpdb,ofile,path

def write_frame_to_file(m1,nf,frame,cenpath,ofile,outtype,dcdoutfile,intype):

	if(outtype == 'dcd'):
		if(intype == 'dcd'):
			m1.write_dcd_step(dcdoutfile,0,frame)
		elif(intype == 'pdb'):
			m1.write_dcd_step(dcdoutfile,frame,frame)
	elif(outtype == 'pdb'):
		if(nf == 1):
			m1.write_pdb(cenpath+ofile,0,'w')
		elif(nf > 1 and intype == 'dcd'):
			m1.write_pdb(cenpath+ofile,0,'a')
		elif(nf > 1 and intype == 'pdb'):
			m1.write_pdb(cenpath+ofile,frame,'a')
	return
	
def check_output_type(ofile):

	if(ofile[-3:] == 'dcd'):
		print ' output file will be a DCD file'
		outtype = 'dcd'
	elif(ofile[-3:] == 'pdb'):
		print ' output file will be a PDB file'
		outtype = 'pdb'
	else:
		outtype = 'dcd'
		message='output filename '+ofile+' needs to end in either ".pdb" (1 frame) or ".dcd" (1 or more frames)\n'
		message+=' :  writing output file as a '+ofile+'.dcd\n'
		print '\n\n',message,'\n\n'
		ofile = ofile +'.dcd'
	
	return outtype,ofile

def center(variables,txtOutput):

        '''
        CENTER is the module that centers molecules from a dcd/pdb file
	  to the coordinates (0.0,0.0,0.0).
        

        INPUT:  variable descriptions:

		runname:			project name
            infile:			filename of dcd input file
		refpdb:			reference pdb file
		path:				input/output filepath
	 
        OUTPUT:

            files stored in runname/center directory

            ofile:                  output filename
            ofile*.minmax:          text file with min & max dimensions

        '''

	runname,infile,refpdb,ofile,path=unpack_variables(variables)
        
	cenpath=runname+'/center/'
	direxist=os.path.exists(cenpath)
	if(direxist==0):
		os.system('mkdir -p '+cenpath)

	print 'runname = ',runname

	minmaxfile=ofile+'.minmax'
	mmfile=open(cenpath+minmaxfile,'w')
	ttxt=time.ctime()

	st=''.join(['=' for x in xrange(60)])

	txtOutput.put("\n%s \n" %(st))
	txtOutput.put("DATA FROM RUN: %s \n\n" %(ttxt))

	m1=sasmol.SasMol(0)

	try:
		if(infile[-3:] == 'dcd'):
			m1.read_pdb(path+refpdb)
			dcdfile = m1.open_dcd_read(path+infile)
			nf = dcdfile[2]
			intype = 'dcd'
		elif(infile[-3:] =='pdb'):
			m1.read_pdb(path+infile)
			nf = m1.number_of_frames()
			intype = 'pdb'

	except:
		message='input filename is a PDB or DCD file but it must end with ".pdb" or ".dcd" '
		message+=' :  stopping here'
		print_failure(message,txtOutput)
	
	minx=[] ; miny=[] ; minz=[]
	maxx=[] ; maxy=[] ; maxz=[]

	outtype,ofile = check_output_type(ofile)

	dcdoutfile = 'None'	
	if(outtype == 'dcd'):
		dcdoutfile = m1.open_dcd_write(cenpath+ofile)
 	
	txtOutput.put("Total number of frames = %d\n\n" % (nf))

	
	for i in range(nf):

		if(intype == 'dcd'):
			m1.read_dcd_step(dcdfile,i)
			m1.center(0)
			minmax=m1.calcminmax_frame(0)
		elif(intype == 'pdb'):
			m1.center(i)
			minmax=m1.calcminmax_frame(i)
		
		write_frame_to_file(m1,nf,i+1,cenpath,ofile,outtype,dcdoutfile,intype)

		minx.append(minmax[0][0]) ; miny.append(minmax[0][1]) ; minz.append(minmax[0][2])
		maxx.append(minmax[1][0]) ; maxy.append(minmax[1][1]) ; maxz.append(minmax[1][2])

		if(((i+1)%(float(nf)/10.0)==0 or (nf<10))):
			fraction_done = (float(i+1)/float(nf))
			progress_string='\nCOMPLETED '+str(i+1)+' of '+str(nf)+' : '+str(fraction_done*100.0)+' % done'
			print('%s\n' % progress_string)
			report_string='STATUS\t'+str(fraction_done)
         		txtOutput.put(report_string)

	if(intype == 'dcd'):
		m1.close_dcd_read(dcdfile[0])
	if(outtype == 'dcd'):
		m1.close_dcd_write(dcdoutfile)

	min_x = numpy.min(minx) ; min_y = numpy.min(miny) ; min_z = numpy.min(minz)
	max_x = numpy.max(maxx) ; max_y = numpy.max(maxy) ; max_z = numpy.max(maxz)

	mmfile.write("%s\n" % ("#min_x,min_y,min_z,max_x,max_y,max_z"))
	mmfile.write("%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n" % (min_x,min_y,min_z,max_x,max_y,max_z))
	mmfile.close()
	
 	txtOutput.put("Min/Max data written to : %s\n\n" % ('./'+cenpath+minmaxfile))
	txtOutput.put("minimum x = %lf\t maximum x = %lf -> range: %lf Angstroms\n" % (min_x,max_x,(max_x-min_x)))
	txtOutput.put("minimum y = %lf\t maximum y = %lf -> range: %lf Angstroms\n" % (min_y,max_y,(max_y-min_y)))
	txtOutput.put("minimum z = %lf\t maximum z = %lf -> range: %lf Angstroms\n\n" % (min_z,max_z,(max_z-min_z)))

	print '\nCentered coordinate data (nf=%i) were written to %s\n' % (nf,'./'+cenpath+ofile)
	txtOutput.put("\nCentered coordinate data (nf=%i) were written to %s\n\n" % (nf,'./'+cenpath+ofile))
	txtOutput.put("\n%s \n" %(st))
	time.sleep(0.5)

	print 'CENTER IS DONE'
	return() 

