#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
datconv is a script intended to perform configurable comversion of file with data in one format to file with data in another format.

Script should be run using Python 2.7 interpretter.
It also required installation of external modules: lxml, PyYAML.
For more information see README.rst file distributed in source ball.

Both input and output files can be text or binary files.
However it is assumed that input files and output files have following structure:
--- Some Header ---
Record 1
Record 2
....
Record N
--- Some Footer ---
There may be different types of records (i.e. every record has string characteristic called record type).
Each record may contain different number and kind of data (have different internal structure) even among records of the same type.

Program has modular architecture with following swichable compoments:
Reader - major obligatory component responsible for:
         reading input data (i.e. every reader class assumes certain input file format)
         driving entire data conversion process (i.e. main processing loop in implemented in this class)
         determine internal representation of header, records and footer (this strongly depands on reader and kind of input format).
Filter - optional compoment that is able to:
         filter data (i.e. do not pass certain records further - i.e. to writer for placing in output)
         change data (i.e. change on the fly contents of certain records)
         produce data (i.e. cause that certain records, maybe slightly modified, are being sent multiply times to writer)
         break conversion process (i.e. caused that conversion stop on certain record).
Writer - obligatory component responsible for:
         writing data to output file.
Logger - all messages intended to be presented to user are being send (except few very initial error messages) to 
         Logger classes from Python standard library 'logging'.
         This script can use all comfiguration power of logging thru 'logging' package.

Except datconv script itself this package contain following modules/packages:
datconv.py - module that allows user to call datconv from other Python program (as Datconv class)
readers - package that contain Reader classes for different commonly used data file formats.
filters - package that contain some generic Filter clsaaes possible to use with different readers.
writers - package that contain Writrer classes for different commonly used data file formats.
For more detailed description of Reader, Filter, Writer interfaces see code and pydoc descriptions in _skeleton.py modules in readers, filters and writers standard packages.
For more detailed description of concrete modules and classes provided with this package see their pydoc descriptions (refer Python documentation for information how to see it in Web Browser (e.g. pydoc -g works on Linux)).

This datconv.py script has following call syntax:
datconv yaml_file [--key1:val [--key2:val ...]] [arg1 [arg2 ...]]
where:
yaml_file - is obligatory path to file in YAML formet in which above described compoments are set up.
            See file conf_template.yaml in this folder for more detailed desctiption of this file.
--key1:val - any number of arguments thta add new settings or overwrite settings from yaml_file.
             It works this way: let say that in yaml_file we have:
             Writer:
                Module: writers.pdxml
                CArg: 
                    pretty:   true
             by invoking option --Writer:CArg:pretty:false we overwrite 'pretty' option of Writer.
             Note that in YAML file we have to have space after : that end the key, while in command line there are no spaces.
arg1 - any number of arguments (that do not begin with --).
       Those arguments will replace $1, $2, ... markers in yaml_file according to their position in command line:
       i.e. $1 will be replaced by first argument that do not begin with --, etc.
This datconv.py script returns to shell 0 on sucess or 1 on error.
"""

# Standard Python Libs
import sys, traceback

# Libs installed using pip
import yaml

# Datconv generic modules
from datconv import Datconv, Logger


############################################################################
if __name__ == "__main__":
    try:
        ####################################################################
        ## Command line arguments
        script_name = sys.argv[0]
        if len(sys.argv) < 2:
            sys.stderr.writelines(
"""ERROR: Wrong command arguments - too few parameters:
Usage: %s yaml_file [--key1:val [--key2:val ...]] [arg1 [arg2 ...]]
""" % script_name)
            sys.exit(1)
            
        arg_keys = list()
        arg_num = 1
        conf_name = sys.argv[1]
        conf_text = open(conf_name).read()
        for i in range(2,len(sys.argv)):
            if sys.argv[i].startswith('--'):
                kv = sys.argv[i][2:].split(':')
                if len(kv) < 2:
                    sys.stderr.writelines(
"""ERROR: Wrong command arguments - argument: %s should have the form: --key:val
Where key is collon-separated compoud key, eg. Writer:CArg:pretty
""" % sys.argv[i])
                    sys.exit(1)
                arg_keys.append(kv)
            else:
                conf_text = conf_text.replace('$' + str(arg_num), sys.argv[i])
                arg_num = arg_num + 1
        conf = yaml.load(conf_text)
        for kv in arg_keys:
            arg_key = yaml.load('key: ' + kv[-1])
            ac = conf
            for key in kv[:-2]:
                if key not in ac:
                    ac[key] = dict()
                ac = ac[key]
            ac[kv[-2]] = arg_key['key']

        ####################################################################
        ## Run process
        pd = Datconv()
        pd.Run(conf)
    
    except SystemExit:
        pass
    except KeyboardInterrupt:
        Logger.info('Process broken on user request (Ctrl-C pressed)')
        pass
    except:
        sys.stderr.write('Exception was thrown during %s execusion\n' % script_name)
        if Logger:
            sys.stderr.write('Look at configured Logger for more details\n')
            Logger.exception('Exception was thrown during %s execusion' % script_name)
        else:
            traceback.print_exc()
        sys.exit(1)


########################################################################
from datconv.version import *
__author__  = datconv_author
__status__  = datconv_status
__version__ = datconv_version
__date__    = datconv_date
