#! /usr/bin/python
# -*- coding: utf-8 -*-
# $Id$
from __future__ import with_statement
"""
Copyright (C) 2007, 2008 by Martin Thorsen Ranang

This file is part of InTeX.

InTeX 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.

InTeX 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 InTeX.  If not, see <http://www.gnu.org/licenses/>.
"""
__version__ = "@VERSION@"
__author__ = "Martin Thorsen Ranang <[email protected]>"

from contextlib import nested
from itertools import count, imap

import logging
import optparse
import os
import re
import sys

from intex.config import INTEX_DEFAULT_INDEX, INTEX_INPUT_EXT, INTEX_OUTPUT_EXT

from intex.index import Index

def parse_command_line(command_line_options, usage):
   """Parse the command line according to the possible
   COMMAND_LINE_OPTIONS.
   """
   license_notice = """
Copyright (C) 2007, 2008 by Martin Thorsen Ranang
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Martin Thorsen Ranang."""
   parser = optparse.OptionParser(usage=usage,
                                  version='%%prog %s %s' % (__version__,
                                                            license_notice))
   for option, description in command_line_options:
       parser.add_option(*option, **description)

   # Parse the command line.
   return parser.parse_args()


def resolve_auxiliary_and_args(args):
   """Resolve the name of the current LaTeX auxiliary file (.aux)
   based on the supplied arguments and the current working directory.
   """
   aux_re = re.compile('^.*\.aux$', re.IGNORECASE)
   auxiliary = [arg for arg in args
                if aux_re.match(arg) and os.path.exists(arg)]
   args = [arg for arg in args if arg not in auxiliary]

   attempts = count(-2)

   while attempts.next():
       if len(auxiliary) > 1:
           logging.error('Please explicitly specify the ' \
                         'LaTeX auxiliary (.aux) file to use.')
           sys.exit(1)

       elif not auxiliary:
           auxiliary = ['%s.aux' % (arg) for arg in args
                        if os.path.exists('%s.aux' % (arg))]
           args = [arg for arg in args if '%s.aux' % (arg) not in auxiliary]

       else:
           auxiliary = auxiliary[0]
           break

   return auxiliary, args


def main():
   """Module mainline (for standalone execution).
   """
   command_line_options = [
       (['-D', '--debug'],
        {'dest': 'debug',
         'default': False,
         'action': 'store_true',
         'help': 'whether or not to output debug information'}),
       (['-V', '--verbose'],
        {'dest': 'verbose',
         'default': False,
         'action': 'store_true',
         'help': 'whether or not to output verbose information'}),
       (['-I', '--only-build-index'],
        {'dest': 'only_build_index',
         'default': False,
         'action': 'store_true',
         'help': 'only build the internal model of the index'}),
       (['-O', '--ito-file'],
        {'dest': 'ito_filename',
         'default': None,
         'metavar': 'FILE',
         'help': 'output the new internal InTeX information to FILE ' \
         '(default: %default)'}),
       (['-o', '--index-file'],
        {'dest': 'index_filename',
         'default': None,
         'metavar': 'FILE',
         'help': 'output the new indexing information to FILE ' \
         '(default: %default)'}),
       (['-a', '--acrodef-output'],
        {'dest': 'acrodef_output',
         'default': None,
         'metavar': 'FILE',
         'help': 'output acronym definitions to FILE ' \
         '(default: %default)'}),
       (['-p', '--persondef-output'],
        {'dest': 'persondef_output',
         'default': None,
         'metavar': 'FILE',
         'help': 'output (person) name definitions to FILE ' \
         '(default: %default)'}),
       ]

   # Parse the command line options.
   options, args = parse_command_line(command_line_options,
                                      usage='%prog [options] ' \
                                      '<index> [index ...]',)

   # Sort out the name for the basic log.
   logging.root.name = os.path.basename(__file__)

   log_level = None

   if options.verbose:
       log_level = logging.INFO
   if options.debug:
       log_level = logging.DEBUG

   # Configure the logging module.
   logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s',
                       level=log_level)

   auxiliary, args = resolve_auxiliary_and_args(args)
   if not auxiliary:
       logging.warning('No LaTeX auxiliary file specified; exiting.')
       sys.exit(1)

   if options.index_filename is None:
       logging.warning('No output index file specified; exiting.')
       sys.exit(1)

   if len(args) == 0:
       suffix_re = re.compile('^.*\.%s$' % (INTEX_INPUT_EXT))

       filenames = [filename
                    for filename in os.listdir(os.getcwd())
                    if suffix_re.match(filename)]
   else:
       filenames = args

   # If no ITO file was explicitly stated, deduce the implied name.
   if options.ito_filename is None:
       options.ito_filename = (os.path.splitext(auxiliary)[0] \
                               + os.path.extsep + 'ito')

   for filename in filenames:
       if not os.path.exists(filename):
           logging.error('Input file "%s" not found', filename)
           sys.exit(1)

   if options.verbose:
       logging.info('Will use "%s" as (main) LaTeX auxiliary file', auxiliary)
       logging.info('Will use InTeX input files: %s',
                    ', '.join(imap('"%s"'.__mod__, filenames)))

   # Instatiate one Index object per file specified on the command
   # line.
   logging.info('Generating index...')
   indices = [Index.from_file(filename) for filename in filenames]

   # Generate all reference indices.
   for index in indices:
       index.generate_reference_index()

   logging.info('... done (index generated).')

   if options.debug:
       for index in indices:
           logging.debug('\n%s', index)

   if options.only_build_index:
       return

   with nested(open(options.ito_filename, 'w'),
               open(options.index_filename, 'w')) \
       as (internal_file, index_file):
       not_found = index.interpret_auxiliary(auxiliary, internal_file,
                                             index_file)

   for reference, page in not_found:
       logging.warn('On page %s, reference to "%s" was not found '
                    'in the index.', page, reference)

if __name__ == "__main__":
   main()