#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#==============================================================================
# Copyright (C) 2011 by Loïc Grobol
#
# This file is part of CTESLO.
# 
#    CTESLO 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.
# 
#    CTESLO 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 CTESLO.  If not, see <http://www.gnu.org/licenses/>.
#==============================================================================

"""Text data files column-wise handling utilities.

Created on 24 mai 2011
@author: Loïc Grobol <loic.grobol@gmail.com>

This module is essentially an executable script to apply
flib.columns_handling functions easily in a command
line interface.

It provides three commands (aka argparse subparsers),
each for a specific task
    - select -- is for selecting and ordering the columns
of a data file.
    - insert -- is for merging two data files.
    - check -- is for checking the consistency of the
columns of a data file.

> columns -i source -o result --column-delimiter "\t" select -s 1 0 2 4

> columns -i source -o result --column-delimiter "\t"
insert -t source 2-s 1 0 2 4 -n 2 3 4 5

> columns -i source -o result --column-delimiter "\t"
check -l log --repair_stream repaired --number 5

see --help for more details.
"""

import argparse
import sys

# Ugly hack to allow absolute import from the root folder
# whatever its name is. Please forgive the heresy.
if __name__ == "__main__" and __package__ is None:
    from sys import path
    from os.path import dirname as dir
    path.append(dir(dir(path[0])))

import libcteslo.dflib.columns_handling as dfch

def main(argv=sys.argv[1:]):
    """Main function."""


#==============================================================================
# Common arguments
#==============================================================================
    parent = argparse.ArgumentParser(add_help=False)
    parent.add_argument(
            "--in-stream", "-i", type=argparse.FileType('r'), default=sys.stdin,
            help="Data file where the selection occurs. (default: stdin).")
    parent.add_argument(
            "--out-stream", "-o", type=argparse.FileType('w'), default=sys.stdout,
            help="File where the modified datas will be written. (default: stdout).")

    parent.add_argument(
            "--column-delimiter", default=dfch.DEFAULT_DELIMITER,
            help="The column delimiter used in the data files. (default: %(default)s)")

#==============================================================================
# Main parser
#==============================================================================
    parser = argparse.ArgumentParser(
            parents=[parent],
            description="Column handling utilities for text data files")

#==============================================================================
# Subparsers (commands)
#==============================================================================
    subparsers = parser.add_subparsers(help="sub-commands")
    parser_select = subparsers.add_parser(
                        "select",
                        parents=[parent],
                        description="Select and order columns of a single file.")
    parser_merge = subparsers.add_parser(
                        "insert",
                        parents=[parent],
                        description="Insert the selected columns of a file\
                        at the selected columns of another")
    parser_check = subparsers.add_parser(
                        "check",
                        parents=[parent],
                        description="""Check the number-of-columns-wise
                        consistency of a data file.""")


#==============================================================================
# select command defaults and arguments    
#==============================================================================
    parser_select.set_defaults(
            func=dfch.stream_select,
            selected=(("in_stream", "stream_in"),
                      ("out_stream", "stream_out"),
                      ("order", "order"),
                      ("column_delimiter", "column_delimiter")))
    parser_select.add_argument(
            "--order", "-s", type=int, nargs="+",
            help="The columns to be selected in the desired order")

#==============================================================================
# merge command defaults and arguments
#==============================================================================
    parser_merge.add_argument(
            "--select-order", "-s", type=int, nargs="+",
            default=None,
            help="The columns to be selected in the desired order")

    parser_merge.add_argument(
            "--insert-order", "-n", type=int, nargs="+",
            default= -1,
            help="The insertion positions")
    parser_merge.add_argument(
            "--to_stream", "-t", type=argparse.FileType('r'),
            help="Data file where the insertion occurs.")
    parser_merge.add_argument(
            "--strict", action="store_true", default=False,
            help="Enable strict blank line consistency check.")

    parser_merge.set_defaults(
            func=dfch.stream_insert,
            selected=(("in_stream", "stream_in_from"),
                      ("out_stream", "stream_out"),
                      ("to_stream", "stream_in_to"),
                      ("insert_order", "order_to"),
                      ("select_order", "order_from"),
                      ("strict", "strict"),
                      ("column_delimiter", "column_delimiter")))

#==============================================================================
# check command defaults and arguments
#==============================================================================
    parser_check.add_argument(
            "--log-stream", "-l", type=argparse.FileType('w'),
            default=sys.stderr,
            help="Log file for errors found. Default stderr.")
    parser_check.add_argument(
            "--repair_stream", type=argparse.FileType('w'),
            default=None, help="Output stream for repairing. (default: None)")
    parser_check.add_argument(
            "--number", type=int, nargs="?",
           help="""Number of columns supposed to be in the data file.
           (default: first line's number of columns).""")
    parser_check.set_defaults(
           func=dfch.check_stream_consistency,
           selected=(("in_stream", "stream_in"),
                     ("log_stream", "stream_log"),
                     ("repair_stream", "stream_repair"),
                     ("column_delimiter", "column_delimiter"),
                     ("number", "column_number")))

#==============================================================================
# parsing and running
#==============================================================================
    args = vars(parser.parse_args(argv))
    if args["in_stream"].isatty():
        parser.print_help()
    else:
        func = args["func"]
        pass_args = {argument: args[keyword] for (keyword, argument) in args["selected"] if args[keyword]}
        try:
            func(**pass_args)
        except Exception as E:
            #print(E)
            raise(E)

if __name__ == "__main__":
    sys.exit(main())
