#!/usr/bin/env python3

'''
*+
*  Name:
*     tilecutout

*  Purpose:
*     Create a single NDF holding a region from the JSA tile collection.

*  Language:
*     python (2.7 or 3.*)

*  Description:
*     This script identifies the JSA tiles that overlap the specified
*     region, extract the overlaps from these tiles, and join them
*     together into a single NDF covering the specified region.
*
*     The environment variable JSA_TILE_DIR should be defined prior to
*     using this command, and should hold the path to the directory in
*     which the NDFs containing the accumulated co-added data for each
*     tile are stored. Tiles for a specified instrument will be stored
*     within a sub-directory of this directory (see parameter INSTRUMENT).
*     If JSA_TILE_DIR is undefined, the current directory is used.

*  Usage:
*     tilecutout region out instrument [retain] [msg_filter] [ilevel] [glevel] [logfile]

*  ADAM Parameters:
*     GLEVEL = LITERAL (Read)
*        Controls the level of information to write to a text log file.
*        Allowed values are as for "ILEVEL". The log file to create is
*        specified via parameter "LOGFILE. In adition, the glevel value
*        can be changed by assigning a new integer value (one of
*        starutil.NONE, starutil.CRITICAL, starutil.PROGRESS,
*        starutil.ATASK or starutil.DEBUG) to the module variable
*        starutil.glevel. ["ATASK"]
*     ILEVEL = LITERAL (Read)
*        Controls the level of information displayed on the screen by the
*        script. It can take any of the following values (note, these values
*        are purposefully different to the SUN/104 values to avoid confusion
*        in their effects):
*
*        - "NONE": No screen output is created
*
*        - "CRITICAL": Only critical messages are displayed such as warnings.
*
*        - "PROGRESS": Extra messages indicating script progress are also
*        displayed.
*
*        - "ATASK": Extra messages are also displayed describing each atask
*        invocation. Lines starting with ">>>" indicate the command name
*        and parameter values, and subsequent lines hold the screen output
*        generated by the command.
*
*        - "DEBUG": Extra messages are also displayed containing unspecified
*        debugging information. In addition scatter plots showing how each Q
*        and U image compares to the mean Q and U image are displayed at this
*        ILEVEL.
*
*        In adition, the glevel value can be changed by assigning a new
*        integer value (one of starutil.NONE, starutil.CRITICAL,
*        starutil.PROGRESS, starutil.ATASK or starutil.DEBUG) to the module
*        variable starutil.glevel. ["PROGRESS"]
*     REGION = LITERAL (Read)
*        Defines the region to be extracted from the JSA tile collection.
*        It can be either the path to an NDF, or a text file holding an AST
*        Region.
*     INSTRUMENT = LITERAL (Read)
*        Indicates the JCMT instrument for which data is required. The
*        following instrument names are recognised (unambiguous abbreviations
*        may be supplied): "SCUBA-2(450)", "SCUBA-2(850)", "ACSIS", "DAS".
*        NDFs containing co-added data for the selected
*        instrument reside within a corresponding sub-directory of the
*        directory specified by environment variable JSA_TILE_DIR. These
*        sub-directories are called "scuba2-450", "scuba2-850", "acsis",
*        and "das".
*     LOGFILE = LITERAL (Read)
*        The name of the log file to create if GLEVEL is not NONE. The
*        default is "<command>.log", where <command> is the name of the
*        executing script (minus any trailing ".py" suffix), and will be
*        created in the current directory. Any file with the same name is
*        over-written. The script can change the logfile if necessary by
*        assign the new log file path to the module variable
*        "starutil.logfile". Any old log file will be closed befopre the
*        new one is opened. []
*     MSG_FILTER = LITERAL (Read)
*        Controls the default level of information reported by Starlink
*        atasks invoked within the executing script. This default can be
*        over-ridden by including a value for the msg_filter parameter
*        within the command string passed to the "invoke" function. The
*        accepted values are the list defined in SUN/104 ("None", "Quiet",
*        "Normal", "Verbose", etc). ["Normal"]
*     OUT = NDF (Read)
*        The name of the output NDF.
*     RETAIN = _LOGICAL (Read)
*        Should the temporary directory containing the intermediate files
*        created by this script be retained? If not, it will be deleted
*        before the script exits. If retained, a message will be
*        displayed at the end specifying the path to the directory. [FALSE]

*  Copyright:
*     Copyright (C) 2013 Science & Technology Facilities Council.
*     All Rights Reserved.

*  Licence:
*     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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA
*     02110-1301, USA.

*  Authors:
*     DSB: David S. Berry (JAC, Hawaii)
*     {enter_new_authors_here}

*  History:
*     16-JUL-2013 (DSB):
*        Original version

*-
'''

import os
import shutil
import starutil
from starutil import invoke
from starutil import NDG
from starutil import Parameter
from starutil import ParSys
from starutil import msg_out

#  Assume for the moment that we will not be retaining temporary files.
retain = 0

#  A function to clean up before exiting. Delete all temporary NDFs etc,
#  unless the script's RETAIN parameter indicates that they are to be
#  retained. Also delete the script's temporary ADAM directory.
def cleanup():
   global retain
   ParSys.cleanup()
   if retain:
      msg_out( "Retaining temporary files in {0}".format(NDG.tempdir))
   else:
      NDG.cleanup()


#  Catch any exception so that we can always clean up, even if control-C
#  is pressed.
try:

#  Declare the script parameters. Their positions in this list define
#  their expected position on the script command line. They can also be
#  specified by keyword on the command line. No validation of default
#  values or values supplied on the command line is performed until the
#  parameter value is first accessed within the script, at which time the
#  user is prompted for a value if necessary. The parameters "MSG_FILTER",
#  "ILEVEL", "GLEVEL" and "LOGFILE" are added automatically by the ParSys
#  constructor.
   params = []

   params.append(starutil.Par0S( "REGION", "The required region (an NDF or "
                                 "AST Region)"))

   params.append(starutil.ParNDG("OUT", "The output NDF", default=None,
                                  exists=False, minsize=0, maxsize=1 ))

   params.append(starutil.ParChoice("INSTRUMENT",
                                    ["SCUBA-2(450)", "SCUBA-2(850)", "ACSIS",
                                    "DAS"],
                                    "The JCMT instrument", "SCUBA-2(850)"))

   params.append(starutil.Par0L("RETAIN", "Retain temporary files?", False,
                                 noprompt=True))

#  Initialise the parameters to hold any values supplied on the command
#  line.
   parsys = ParSys( params )

#  It's a good idea to get parameter values early if possible, in case
#  the user goes off for a coffee whilst the script is running and does not
#  see a later parameter propmpt or error...
   region = parsys["REGION"].value
   outdata = parsys["OUT"].value
   instrument = starutil.shell_quote( parsys["INSTRUMENT"].value )
   retain = parsys["RETAIN"].value

#  Report what we will be doing...
   msg_out( "Creating a cut-out for {0} data".format(instrument) )

   tiledir = os.getenv( 'JSA_TILE_DIR' )
   if tiledir:
      msg_out( "Tiles will be read from {0}".format(tiledir) )
   else:
      msg_out( "Environment variable JSA_TILE_DIR is not set!" )
      msg_out( "Tiles will be read from the current directory ({0})".format(os.getcwd()) )

#  Create an empty list to hold the NDFs for the tiles holding the
#  required data.
   tilendf = []
   itilelist = []

#  Identify the tiles that overlap the specified region, and loop round
#  them.
   invoke("$SMURF_DIR/jsatilelist in={0} instrument={1}".format(region,instrument) )
   for itile in starutil.get_task_par( "tiles", "jsatilelist" ):

#  Get information about the tile, including the 2D spatial pixel index
#  bounds of its overlap with the required Region.
      invoke("$SMURF_DIR/jsatileinfo itile={0} instrument={1} "
             "target={2}".format(itile,instrument,region) )

#  Skip this tile if it does not exist (i.e. is empty).
      if starutil.get_task_par( "exists", "jsatileinfo" ):

#  Get the 2D spatial pixel index bounds of the part of the master tile that
#  overlaps the required region.
         tlbnd = starutil.get_task_par( "tlbnd", "jsatileinfo" )
         tubnd = starutil.get_task_par( "tubnd", "jsatileinfo" )

#  Get the path to the tile's master NDF.
         tndf = starutil.get_task_par( "tilendf", "jsatileinfo" )

#  Add on the section specifier for the overlap region.
         sec = "{0}({1}:{2},{3}:{4},)".format(tndf,tlbnd[0],tubnd[0],tlbnd[1],tubnd[1])

#  Check the overlap contains some good values. */
         invoke( "$KAPPA_DIR/stats ndf={0}".format(starutil.shell_quote(sec)) )
         if starutil.get_task_par( "numgood", "stats" ) > 0:

#  If so, append the section to the list of NDFs to be included in the output.
            tilendf.append( sec )
            itilelist.append( itile )

#  Raise an exception if no data is available for the tiles overlap
   msg_out( " " )
   if len( tilendf ) == 0:
      raise starutil.StarUtilError( "No JSA {0} data is available "
                          "for the requested region.".format(instrument) )

#  Otherwise, paste the sections together to form the output NDF.
   else:
      tiles = NDG( tilendf )
      invoke( "$KAPPA_DIR/paste in={0} out={1}".format(tiles,outdata) )
      msg_out( "Created output NDF {0} from tiles {1}".format(outdata,itilelist) )

#  Remove temporary files.
   cleanup()

#  If an StarUtilError of any kind occurred, display the message but hide the
#  python traceback. To see the trace back, uncomment "raise" instead.
except starutil.StarUtilError as err:
#  raise
   print( err )
   cleanup()

# This is to trap control-C etc, so that we can clean up temp files.
except:
   cleanup()
   raise

