#!/usr/bin/env python
"""
This script provides the command-line interface (CLI) to the PyReshaper

This script is used to generate Specifier object files ("specfiles") that
can then be run directly from the command-line with the corresponding
"runs2sspec" tool.

Copyright 2017, University Corporation for Atmospheric Research
See the LICENSE.rst file for details
"""

# Builtin Modules
import optparse
import glob
import cPickle as pickle

# Package Modules
from pyreshaper import specification


#==============================================================================
# Command-Line Interface
#==============================================================================
def cli(argv=None):
    desc = """Create a PyReshaper Specifier object from command-line
              options and write the Specifier to a named file."""

    parser = optparse.OptionParser(prog='s2smake', description=desc)
    parser.add_option('-1', '--meta1d', default=False, action='store_true',
                      help=("Treat all 1D time-variant variables as metadata "
                            "variables"))
    parser.add_option('-b', '--backend', default='netCDF4', type='string',
                      help=("I/O backend to be used when reading or writing "
                            "from NetCDF files ('Nio' or 'netCDF4')"))
    parser.add_option('-c', '--compression_level', type='int', default=1,
                      help=('NetCDF compression level, when using the '
                            'netcdf4 format. [Default: 1]'))
    parser.add_option('-f', '--netcdf_format', default='netcdf4', type="string",
                      help=('NetCDF file format to be used for all output '
                            'files. [Default: "netcdf4"]'))
    parser.add_option('-m', '--metadata', action='append', default=[],
                      help=('Names of a variable to be included in all '
                            'output files.  There may be more than one '
                            '--metadata (-m) option given, and each one is '
                            'appended to a list.  [Default: []]'))
    parser.add_option('--metafile', default=None, type="string",
                      help=('The name of a time-slice input file from which '
                            'metadata variable names will be read.  [Default: None]'))
    parser.add_option('-o', '--specfile', default='input.s2s', type="string",
                      help=('The name of the Pickled Specifier (specfile) '
                            'to be output [Default: "input.spec"]'))
    parser.add_option('-p', '--output_prefix', default='tseries.', type='string',
                      help=('String prefix for all output files.  The output '
                            'file will be named according to the rule: '
                            'output_prefix + variable_name + output_suffix '
                            '[Default: "tseries."]'))
    parser.add_option('-s', '--output_suffix', default='.nc', type='string',
                      help=('String suffix for all output files.  The output '
                            'file will be named according to the rule: '
                            'output_prefix + variable_name + output_suffix '
                            '[Default: ".nc"]'))
    parser.add_option('--time_series', action='append', default=None,
                      help=('Names of variables to be given their own output file. '
                            'There may be more than one --time_series option given, and '
                            'each name will be appended to a list.  If the --time_series '
                            'option is not used, then all time-variant variables that '
                            'are not labelled as metadata will be given their own '
                            'output file. [Default: None]'))
    opts, args = parser.parse_args(argv)

    # Check that input files are given
    if len(args) == 0:
        raise ValueError("No input files given.")

    # Check range of compression levels
    if opts.compression_level < 0 or opts.compression_level > 9:
        raise ValueError(("Unacceptable compression level of "
                          "{0}".format(opts.compression_level)))

    # Check for valid format types
    if opts.netcdf_format not in ['netcdf', 'netcdf4', 'netcdf4c']:
        raise ValueError(("Unacceptable NetCDF format "
                          "{0}".format(opts.netcdf_format)))

    # Check the I/O backend name
    if opts.backend not in ['Nio', 'netCDF4']:
        raise ValueError(("Unacceptable NetCDF backend name "
                          "{0}".format(opts.backend)))

    return opts, args

#==============================================================================
# Main Script Function
#==============================================================================


def main(argv=None):
    opts, args = cli(argv)

    # Create the input object for the Reshaper
    spec = specification.create_specifier()

    # Generate the input file list from (potentially) globs/wildcards
    full_input_file_list = []
    for infile in args:
        full_input_file_list.extend(glob.glob(infile))

    # Add input to the specifier
    spec.input_file_list = full_input_file_list
    spec.io_backend = opts.backend
    spec.compression_level = opts.compression_level
    spec.netcdf_format = opts.netcdf_format
    spec.output_file_prefix = opts.output_prefix
    spec.output_file_suffix = opts.output_suffix
    spec.time_series = opts.time_series
    spec.time_variant_metadata = opts.metadata
    spec.metadata_filename = opts.metafile
    spec.assume_1d_time_variant_metadata = opts.meta1d

    # Validate before saving
    spec.validate()

    # Write the specfile
    spec.write(opts.specfile)


#==============================================================================
# Command-line Operation
#==============================================================================
if __name__ == '__main__':
    main()
