#!/usr/bin/env python
#\if DOXYGEN_IGNORE ############################################################
#                                                                              #
#   Copyright (C) 2016 by John Spitzak                                         #
#                                                                              #
#   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, write to the                              #
#   Free Software Foundation, Inc.,                                            #
#   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.                  #
#                                                                              #
#\endif ########################################################################
#################################################################################
#\defgroup difxcorrelatorreport correlatorReport
#
#\brief Create a "correlator report" for an R4.
#
#  Usage:  <b><code>correlatorReport [options]</code></b>
#
#  This application produces a "correlator report" for an R4 after correlation
#  and HOPS analysis have been accomplished by other means.  It requires several
#  types of data to be in predictable places, including:
#  <ol>
#  <li><b>The .vex file</b> that was used in correlation, updated with any clock
#      delays and delay rates, as well as anything else applicable.  You can
#      specify the .vex file using the "-vex" command line argument.  If you do
#      not specify a .vex file, the application will try to locate by searching (in order)
#      for "r###.vex", "R###.vex", and "###.vex" both in the directory that contains
#      the HOPS results (see below) and in the directory where you are running
#      <i>correlationReport</i>, where "###" is the experiment number.
#
#  <h3>Command Line Arguments</h3>
#
#  <table border="0" cellspacing="25">
#  <tr><td><pre><b>-h, --help</b></pre>                   <td>Print help information and quit.
#  <tr><td><pre><b>-v, --vex <i>PATH</i></b></pre>        <td>Show available DiFX versions.
#  </table>
#
################################################################################
program = 'correlatorReport'
version = '0.1'
author  = 'John Spitzak'
verdate = '20160809'

import sys
import datetime
import DiFXVex
import StationCodes

#===============================================================================
#  MAIN
#===============================================================================
experimentNumber = None
vexFilePath = None
hopsDataDirectory = None
argumentProblem = False
salutation = "autogenerated by correlatorReport"
nominalStationNote = "Ok."
correlator = "WACO"
correlationTime = None
fourfitControlFile = None
try:
	i = 1
	while i < len( sys.argv ):
		#  Check against legal command line arguments.  There are no other arguments
		#  to this application.
		if sys.argv[i] in [ "-h", "--help" ]:
			print '\n%s ver %s  %s  %s' % (program, version, author, verdate)
			print "Produces a \"correlator report\" for a specified experiment."
			print "Usage: %s [options] [<experiment number>]" % ( sys.argv[0] )
			print ""
			print "Options can include:"
			print ""
			print "   --author NAME"
			print "   -a NAME    Use NAME as the \"author\" of this report.  The author"
			print "              appears at the end of the report.  The default author"
			print "              is \"autogenerated by correlatorReport\"."
			print ""
			print "   --correlator NAME"
			print "   -C NAME    Use NAME as the \"correlator\" in this report.  The correlator"
			print "              appears in the header and another location.  \"WACO\" by default."
			print ""
			print "   --correlationTime STR"
			print "   -c STR     Use STR as the \"correlation time\" in this report.  The correlation"
			print "              time appears only as a string in the header.  By default a string will"
			print "              be formed out of the date this application is run."
			print ""
			print "   -cf PATH   Specify the path to the fourfit control file.  If not"
			print "              specified a file of the form \"cf_####\" (where #### is the experiment"
			print "              number) will be search for in the HOPS results directory."
			print ""
			print "   --dir PATH"
			print "   -d PATH    Specify the directory containing HOPS results.  If not"
			print "              specified a directory name matching the specified experiment"
			print "              number will be used.  Failing that, the current directory"
			print "              will be assumed."
			print ""
			print "   --help"
			print "   -h         Print this help information and quit."
			print ""
			print "   --vex PATH"
			print "   -v PATH    Specify the full path to the .vex file.  "
			print ""
			exit( 0 )
		elif sys.argv[i] in [ "-a", "--author" ]:
			salutation = sys.argv[i+1]
			i = i + 1
		elif sys.argv[i] in [ "-C", "--correlator" ]:
			correlator = sys.argv[i+1]
			i = i + 1
		elif sys.argv[i] in [ "-c", "--correlationTime" ]:
			correlationTime = sys.argv[i+1]
			i = i + 1
		elif sys.argv[i] in [ "-cf" ]:
			fourfitControlFile = sys.argv[i+1]
			i = i + 1
		elif sys.argv[i] in [ "-v", "--vex" ]:
			vexFilePath = sys.argv[i+1]
			i = i + 1
		else:
			experimentNumber = sys.argv[i]
		i = i + 1
except RuntimeError:
	argumentProblem = True
	
#  Is there an experiment number?  This is required...
if experimentNumber == None:
	argumentProblem = True
	
#  If the directory containing HOPS results has not been specified, create it using
#  the experiment number.
if not argumentProblem and hopsDataDirectory == None:
	hopsDataDirectory = experimentNumber
	
#  See if the HOPS results directory actually exists.
	
#  The .vex file path is either specified by the user directly or is looked for in
#  a number of "typical" places.
if not argumentProblem and vexFilePath == None:
	#  The first of these that works, we keep!
	try:
		vex1 = hopsDataDirectory + "/r" + experimentNumber + ".vex"
		dummyVex = open( vex1 )
		dummyVex.close()
		vexFilePath = vex1
	except IOError:
		try:
			vex2 = hopsDataDirectory + "/R" + experimentNumber + ".vex"
			dummyVex = open( vex2 )
			dummyVex.close()
			vexFilePath = vex2
		except IOError:
			try:
				vex3 = "r" + experimentNumber + ".vex"
				dummyVex = open( vex3 )
				dummyVex.close()
				vexFilePath = vex3
			except IOError:
				try:
					vex4 = "R" + experimentNumber + ".vex"
					dummyVex = open( vex4 )
					dummyVex.close()
					vexFilePath = vex4
				except IOError:
					print "Unable to find vex file, tried (in order) \"" + vex1 + "\", \"" + vex2 + "\", \"" + vex3 + "\" and \"" + vex4 + "\""
					argumentProblem = True

if argumentProblem:
	print "Exiting due to errors..."
	print "Usage: %s [options] [<experiment number>]" % ( sys.argv[0] )
	exit( 0 )
	
vex = DiFXVex.Parser( open( vexFilePath ).read() )
translator = StationCodes.Translator()

#-------------------------------------------------------------------------------
#  Output
#-------------------------------------------------------------------------------

#  The HEADER section contains a bunch of hard-coded stuff.  We figure times from the .vex
#  file.
print "+HEADER"
#  The correlator is hard-coded to "WACO".  If you don't like that, use "-correlator".
print "CORRE    " + correlator
#  Data base is formed out of the start date of observations.
print "DATABASE " + vex.startTime().strftime( "%y" ) + vex.startTime().strftime( "%b" ).upper() + vex.startTime().strftime( "%d" ) + "XE"
#  Session name is the experiment number preceded by an "R".
print "SESSNAME R" + experimentNumber
#  Observation time is the start and end day of the observations
print "OBSTIME  " + str( vex.startTime().strftime( "%Y/%m/%d" ) ) + " " + str( vex.endTime().strftime( "%Y/%m/%d" ) )
#  UT start is the nearest half hour from the observations.  Not certain this is
#  right.
theHour = vex.startTime().strftime( "%H" )
theMin = int( vex.startTime().strftime( "%M" ) )
if theMin > 0 and theMin < 15:
	print "UTSTART  " + theHour + "00"
elif theMin < 45:
	print "UTSTART  " + theHour + "30"
else:
	newHour = int( theHour ) + 1
	if newHour < 9:
		print "UTSTART  0" + str( newHour ) + "00"
	elif newHour == 24:
		print "UTSTART  0000"  #  hopefully this doesn't happen!
	else:
		print "UTSTART  " + str( newHour ) + "00"
#  Duration is also from the observations - to the nearest hour.
print "DURATION " + str( int( 0.5 + ( vex.endTime() - vex.startTime() ).total_seconds() / 3600 ) )
#  Days of the year of the start and end of observations.
print "DOY      " + str( vex.startTime().strftime( "%j" ) ) + "/" + str( vex.endTime().strftime( "%j" ) )
#  Correlation time is whenever you run this application (use "-correlationTime"
#  to change that).
if correlationTime == None:
	correlationTime = datetime.date.today().strftime( "%Y/%m/%d" )
print "CORRTIME " + correlationTime + " " + correlationTime
#  This stuff is standard output - copied from former reports.
print "CORRPASS 1"
print "EXPORT   Done."
print ""  #  end of HEADER

#  The SUMMARY data is produced by running BLAT
print "+SUMMARY\n"
print ""  #  end of SUMMARY

#  The CORRELATOR_NOTES section probably mostly applied to the hardware correlator.
#  Left empty in my experience.
print "+CORRELATOR_NOTES"
print ""  #  end of CORRELATOR_NOTES

#  This is the "STATION_NOTES" section that should be filled in by the user after
#  we create a template.  No real good way of automating this!
print "+STATION_NOTES\n"
stations = vex.stations()
#  Find the longest site name so we can line things up nicely
maxlen = 0
for station in stations:
	if len( vex.siteName( station ) ) > maxlen:
		maxlen = len( vex.siteName( station ) )
#  Print each site name along with its two- and one-letter codes.  We add a "nominal"
#  station note which is appropriate if all went well with the station (the nominal
#  note can be changed using the command line argument "-n").
for station in stations:
	newStr = vex.siteName( station )
	for i in range( maxlen - len( vex.siteName( station ) ) ):
		newStr = newStr + " "
	singleLetterCode = translator.singleLetter( station )
	if singleLetterCode == None:
		singleLetterCode = "UNKNOWN"
	newStr = newStr + " (" + station + "/" + singleLetterCode + "): " + nominalStationNote
	print newStr + "\n"
print ""  #  end of STATION_NOTES

#  DROP_CHANNELS section.  For this we parse the configuration file.
print "+DROP_CHANNELS"
print ""  #  end DROP_CHANNELS

#  MANUAL_PCAL section - also from the configuration file.  In hand-created reports
#  the antenna designations appear on the same line as "+MANUAL_PCAL" so we are
#  duplicating that (who knows if its really necessary).
print "+MANUAL_PCAL"
print ""  #  end MANUAL_PCAL

#  CHANNELS designations can be pulled out of the .vex file (I think).  Although for
#  the moment we are hard-coding this.
print "+CHANNELS"
print "XR1U = band|polarization|channel#|sideband"
print ""
print " XR1U/L  BBC01  8212.99"
print " XR2U    BBC02  8252.99"
print " XR3U    BBC03  8352.99"
print " XR4U    BBC04  8512.99"
print " XR5U    BBC05  8732.99"
print " XR6U    BBC06  8852.99"
print " XR7U    BBC07  8912.99"
print " XR8U/L  BBC08  8932.99"
print " SR1U    BBC09  2225.99"
print " SR2U    BBC10  2245.99"
print " SR3U    BBC11  2265.99"
print " SR4U    BBC12  2295.99"
print " SR5U    BBC13  2345.99"
print " SR6U    BBC14  2365.99"
print ""  #  end CHANNELS

#  CLOCKS come out of the .vex file
print "+CLOCKS"
print ""
print "Clocks: WACO"
print ""
print "Station          fmout-gps      Used      rate"
print "                  [usec]       [usec]   [sec/sec]"
print ""
print "Date: " + str( vex.startTime().strftime( "%Y/%m/%d" ) )
print ""  #  end CLOCKS

#  QCODES are generated by the BLAT application.  It needs access to the directory
#  containing the HOPS-reduced data.
print "+QCODES"
print ""
#  The "key" for Q codes stays the same.
print ""
print "QC = 0   Fringes not detected."
print "   = 1-9 Fringes detected, no error condition. Higher #, better quality."
print "   = B   Interpolation error in fourfit."
print "   = D   No data in one or more frequency channels."
print "   = E   Maximum fringe amplitude at edge of SBD, MBD, or rate window."
print "   = F   \"Fork\" problem in processing."
print "   = G   Fringe amp in a channel is <.5 times mean amp (only if SNR>20)."
print "   = H   Low Phase-cal amplitude in one or more channels."
print "   = N   No valid correlator data."
print " Tot     Total number of scans in schedule."
print " Minus   Scans in original schedule file for which correlation was not"
print "         attempted, usually because of known station problems."
print ""  #  end QCODES

#  SNR_RATIOS come from running BLAT.
print "+SNR_RATIOS"
print ""  # end SNR_RATIOS

#  The FOURFIT_CONTROL_FILE is read from the fourfitControlFile.  This can be
#  set with the "-cf" command line argument.
print "+FOURFIT_CONTROL_FILE"
print ""  # end FOURFIT_CONTROL_FILE

print "*" + salutation
print ""
print "+END"
print ""