#!/usr/bin/env python

# Copyright 2013-2014 Ajabu Tex
#
# This file is part of TrY.
#
# TrY 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.
#
# TrY 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 TrY.  If not, see <http://www.gnu.org/licenses/>.

import sys
from datetime import datetime
import argparse
import os
import subprocess

prog_name = 'TrY'
prog_cmd = 'try'
prog_version = '4.0'
prog_author = 'Ajabu Tex'
prog_revisiondate = 'Jan 2, 2014'
prog_releasedate = '2014'
prog_license = prog_name + ' ' + prog_version + '\n' + \
    'Copyright 2013-' + prog_releasedate + ' ' + prog_author + '\n' + \
    'There is NO warranty.  Redistribution of this software is\n' + \
    'covered by the terms of both the ' + prog_name + ' copyright and\n' + \
    'the GNU General Public License.\n' + \
    'For more information about these matters, see the file\n' + \
    'named COPYING and the ' + prog_name + ' source.\n' + \
    'Author of ' + prog_name + ': ' + prog_author + '.'

def append_to_logfile(a_file_name, a_string_line):
    if a_string_line.startswith('This is ' + prog_name + \
    ' ver. ' + prog_version + ' revision ' + prog_revisiondate):
        openmode = 'w'
    else:
        openmode = 'a'
    now = datetime.now()
    time_string = now.strftime("%d %b %Y %H:%M:%S.%f")
    log_string = time_string + ' ' + a_string_line
    logfile_name = a_file_name + '.trylog'
    logfile = open(logfile_name, openmode)
    logfile.write(log_string + '\n')
    logfile.close

def notify(text, args):
    if args.log:
        append_to_logfile(args.filename, text)
    if args.verbose:
        print (text)

def get_args():
    parser = argparse.ArgumentParser(
        prog=prog_cmd,
        usage='%(prog)s [options] filename',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description='''\
            ''' + prog_name + '''
            TeX automation tool''',
        epilog='(C) 2013-' + prog_releasedate + ' ' + prog_author)
    parser.add_argument('-l', '--log',
        action='store_true',
        help='generate a log output')
    parser.add_argument('-s' ,'--safe',
        action='store_true',
        help='print the list of commands prior to execute them')
    parser.add_argument('-v', '--verbose',
        action='store_true',
        help='print the command output')
    parser.add_argument('-V', '--version',
        action='version',
    version=prog_license)
    parser.add_argument('filename', nargs='?', default='')
    args = parser.parse_args()
    if args.filename == '':
        parser.print_help()
    return args

def get_commentchar_from(str_list):
    result = '%'
    for str_line in str_list:
        if '$trycommentchar=' in str_line:
            str_line = str_line.rpartition('$trycommentchar=')[2]
            str_line = str_line.rsplit('$')[0]
            result = str_line
    return result

def get_trystatement_list_from(str_list, args, flag):
    file_name = args.filename
    result = []
    for str_line in str_list:
        if str_line.startswith(flag):
            if '$0' in str_line:
                str_line = str_line.replace('$0', file_name)
            str_line = str_line.strip()
            str_line = str_line.partition(flag)[2]
            notify('Found command ' + str_line, args)
            result.append(str_line)
    return result

def get_trystatements_from(args):
    file_name = args.filename
    notify('Looking for ' + prog_name + ' commands in ' + file_name, args)
    f = open(file_name, 'r')
    str_lines = f.readlines()
    f.close()
    comment_char = get_commentchar_from(str_lines)
    notify('Comment char used: ' + comment_char, args)
    try_statement_flag = comment_char + '$ '
    result = get_trystatement_list_from(str_lines,
        args, try_statement_flag)
    return result

def execution_confirmed_of(str_lst):
    prompt = 'These are the commands that will be processed:\n'
    for str_line in str_lst:
        prompt += str_line + '\n'
    prompt += '\n\nDo you want to continue? [Yes/No]\n'
    answer = raw_input(prompt)
    result = answer in ['Y', 'y', 'Yes', 'yes']
    return result

def execute_statements(try_statements, args):
    if len(try_statements) == 0:
        notify('No commands found.', args)
        sys.exit()
    else:
        for statement in try_statements:
            notify('Executing instruction: ' + statement, args)
            exit_status = subprocess.call([statement],
                stdout=subprocess.PIPE, shell=True)
            if exit_status != 0:
                notify(prog_name + ': error at system level. \n' + \
                    'Execution aborted with exit status ' + \
                    str(exit_status) + '\n', args)
                sys.exit(exit_status)
            else:
                notify('SUCCESS', args)

if __name__ == "__main__":
    args = get_args()
    if not args.filename =='':
        notify('This is ' + prog_name + ' ver. ' + prog_version + \
            ' revision ' + prog_revisiondate + '\n', args)
        try_statements = get_trystatements_from(args)
        if len(try_statements) == 0:
            notify('No commands found in ' + args.filename + '.', args)
            sys.exit('Nothing to execute.')
        else:
            if args.safe:
                if execution_confirmed_of(try_statements):
                    execute_statements(try_statements, args)
                else:
                    notify('Execution stopped by the user.', args)
                    sys.exit('Execution aborted.')
            else:
                execute_statements(try_statements, args)