#!/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("")