#!python
# coding=utf-8
# -------------------------------------------------------------------------------
# Author: Alexandre Manhaes Savio <alexsavio@gmail.com>
# Grupo de Inteligencia Computational <www.ehu.es/ccwintco>
# Universidad del Pais Vasco UPV/EHU
#
# 2015, Alexandre Manhaes Savio
# Use this at your own risk!
# -------------------------------------------------------------------------------

import os
import json
import logging
import argparse
import math
import os.path as op

import sys
if sys.version_info >= (3, 0):
    from csv import DictReader
else:
    from docstamp.unicode_csv import UnicodeReader as DictReader

from  docstamp.file_utils    import get_extension
from  docstamp.template     import TextDocument
from  docstamp.model        import json_to_dict
from  docstamp.config       import LOGGING_LVL
from  docstamp.data_source  import Google_data


logging.basicConfig(level=LOGGING_LVL)
log = logging.getLogger(__name__)

ACCEPTED_DOCS = "Inkscape (.svg), PDFLatex (.tex), XeLatex (.tex)"


def get_items_from_csv(csv_filepath):
    # CSV to JSON
    # one JSON object for each item
    if not op.exists(csv_filepath):
        raise IOError('Could not find file {}.'.format(csv_filepath))

    log.debug('Reading CSV elements from {}.'.format(csv_filepath))

    items = {}
    with open(str(csv_filepath), 'r') as csvfile:

        reader = DictReader(csvfile)

        for idx, row in enumerate(reader):
            item = json_to_dict(json.dumps(row))
            if any([item[i] != '' for i in item]):
                items[idx] = item

        return items, reader.fieldnames


def verbose_switch(verbose=False):
    if verbose:
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO

    logging.getLogger().setLevel(log_level)


def create_argparser():
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    # parser.add_argument('-s', '--search', action='store',
    #                     dest='search',
    #                     help='''
    #                     Search condition string in the format: <field_name>=<field_partial_value>.
    #                     Look at --input argument help for the valid field_names.
    #                     Put as many of these as you need.
    #                     ''')
    parser.add_argument('-i', '--input', action='store', dest='input',
                        required=True,
                        help='''Path to the CSV file with the data elements to be used to fill the template.
                        This file must have the same fields as the template file.
                        ''')
    parser.add_argument('-t', '--template', action='store', dest='template',
                        required=True,
                        help='''Template file path. The extension of this file will be used to determine
                        what software to use to render the documents: ''' + ACCEPTED_DOCS)
    parser.add_argument('-f', '--file_name_fields', action='append',
                        dest='file_name_fields',
                        help='''The field or fields that will be used to name
                        the output files. Otherwise files will be numbered.''')
    parser.add_argument('-o', '--output', action='store', dest='output',
                        default='stamped',
                        help='Output folder path. Default stamped')
    parser.add_argument('-n', '--name', action='store', dest='basename',
                        help='''Output files prefix.
                        Default: Template file name.''')
    parser.add_argument('-d', '--type', choices=['pdf', 'png', 'svg'],
                        action='store', dest='file_type', default='pdf',
                        help='Output file type.')
    parser.add_argument('-c', '--command', choices=['', 'inkscape', 'pdflatex', 'xelatex'],
                        action='store', dest='command', default='',
                        help='The rendering command to be used in case file name extension is not specific.')
    parser.add_argument('--idx', action='append', dest='index', default=[],
                        help='''Index/es of the CSV file that you want to create
                        the document from.
                        Note that the samples numbers start from 0 and the empty
                        ones do not count.''')
    parser.add_argument('--dpi', type=int, action='store', dest='dpi',
                        default=150, help='Output file resolution')
    parser.add_argument('-g', '--google', action='store_true',
                        help='Fetch data from Google Drive')
    parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
                        default=False, help='Output debug logs.')
    return parser


if __name__ == '__main__':

    parser = create_argparser()

    try:
        args = parser.parse_args()
    except argparse.ArgumentError as exc:
        log.exception('Error parsing arguments.')
        parser.error(str(exc.message))
        exit(-1)

    if args.google:
        input_file = Google_data.getCSV()
    else:
        input_file = args.input

    if not op.exists(input_file):
        log.exception('Could not find file {}'.format(input_file))
        exit(-1)


    # get args
    output_dir       = args.output
    file_type        = args.file_type
    template         = args.template
    file_name_fields = args.file_name_fields
    index            = args.index
    dpi              = args.dpi
    basename         = args.basename
    command          = args.command
    verbose          = args.verbose



    # setup verbose mode
    verbose_switch(verbose)

    # init set of template contents
    items, fieldnames = get_items_from_csv(input_file)

    # check if got any item
    if len(items) == 0:
        print('Quiting because found 0 items.')
        exit(-1)

    if not len(file_name_fields):
        # set the number of zeros that the files will have
        n_zeros = math.floor(math.log10(len(items))) + 1
    else:
        # check that file_name_fields has all valid fields
        for field_name in file_name_fields:
            if field_name not in fieldnames:
                raise ValueError('Field name {} not found in input file '
                                 ' header.'.format(field_name))

    # filter the items if index
    if index:
        myitems = {int(idx): items[int(idx)] for idx in index}
        items   = myitems
        log.debug('Using the elements with index {} of the input file.'.format(index))

    # make output folder
    if not os.path.exists(output_dir):
        os.mkdir(output_dir)

    # create template document model
    log.debug('Creating the template object using the file {}.'.format(template))
    template_doc = TextDocument.from_template_file(template, command)

    # get file extension
    file_extension = get_extension(template)
    log.debug('Created an object of type {}.'.format(type(template_doc)))

    # let's stamp them!
    for idx in items:
        item = items[idx]

        if not len(file_name_fields):
            file_name = str(idx).zfill(n_zeros)
        else:
            field_values = []
            try:
                for field_name in file_name_fields:
                    field_values.append(item[field_name].replace(' ', ''))
            except:
                log.exception('Could not get field {} value from'
                              ' {}'.format(field_name, item))
                exit(-1)
            file_name = '_'.join(field_values)

        log.debug('Filling template {} with values of item {}.'.format(file_name, idx))
        try:
            template_doc.fill(item)
        except:
            log.exception('Error filling document for {}th item'.format(idx))
            continue

        # set output file path
        if basename is None:
            basename = op.basename(template).replace('.svg', '')

        file_name = basename + '_' + file_name
        file_path = os.path.join(output_dir, file_name + '.' + file_type)

        kwargs = {'file_type': file_type,
                  'dpi':       dpi}

        log.debug('Rendering file {}.'.format(file_path))
        try:
            template_doc.render(file_path, **kwargs)
        except:
            log.exception('Error creating {} for {}.'.format(file_path, item))
            exit(-1)
