# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012  Andrey Golovizin
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""parse LaTeX aux file
"""

from __future__ import with_statement

import re

from pybtex.exceptions import PybtexError
import pybtex.io


class AuxDataError(PybtexError):
    def __init__(self, message, context):
        super(AuxDataError, self).__init__(message, context.filename)
        self.context = context
    
    def get_context(self):
        marker = '^' * len(self.context.line)
        return self.context.line + '\n' + marker

    def __unicode__(self):
        base_message = super(AuxDataError, self).__unicode__()
        return u'{message} in line {lineno}'.format(
            message=base_message,
            lineno=self.context.lineno,
        )


class AuxDataContext(object):
    lineno = None
    line = None
    filename = None

    def __init__(self, filename):
        self.filename = filename


class AuxData(object):
    command_re = re.compile(r'\\(citation|bibdata|bibstyle|@input){(.*)}')
    context = None
    style = None
    data = None
    citations = None

    def __init__(self, encoding):
        self.encoding = encoding
        self.citations = []

    def handle_citation(self, keys):
        for key in keys.split(','):
            if not key in self.citations:
                self.citations.append(key)

    def handle_bibstyle(self, style):
        if self.style is not None:
            raise AuxDataError(r'illegal, another \bibstyle command', self.context)
        self.style = style

    def handle_bibdata(self, bibdata):
        if self.data is not None:
            raise AuxDataError(r'illegal, another \bibdata command', self.context)
        self.data = bibdata.split(',')

    def handle_input(self, filename):
        self.parse_file(filename)

    def handle(self, command, value):
        action = getattr(self, 'handle_%s' % command.lstrip('@'))
        action(value)

    def parse_file(self, filename):
        previous_context = self.context
        self.context = AuxDataContext(filename)

        with pybtex.io.open_unicode(filename, encoding=self.encoding) as aux_file:
            for lineno, line in enumerate(aux_file):
                self.context.lineno = lineno + 1
                self.context.line = line.strip()
                match = self.command_re.match(line)
                if match:
                    command, value = match.groups()
                    self.handle(command, value)
        self.context = previous_context


def parse_file(filename, encoding):
    """Parse a file and return an AuxData object."""

    data = AuxData(encoding)
    data.parse_file(filename)
    if data.data is None:
        raise AuxDataError(r'found no \bibdata command in %s' % filename)
    if data.style is None:
        raise AuxDataError(r'found no \bibstyle command in %s' % filename)
    return data

@@ -1207,16 +1207,33 @@
 ort re%0A%0A
+import pybtex.io%0A
 from pyb
@@ -1266,32 +1266,54 @@
 exError%0A
-import pybtex.io
+from pybtex.errors import report_error
 %0A%0A%0Aclass
@@ -2499,37 +2499,44 @@
 e:%0A            r
-aise 
+eport_error(
 AuxDataError(r'i
@@ -2576,33 +2576,52 @@
 ', self.context)
-%0A
+)%0A        else:%0A    
         self.sty
@@ -2710,37 +2710,44 @@
 e:%0A            r
-aise 
+eport_error(
 AuxDataError(r'i
@@ -2794,17 +2794,36 @@
 context)
-%0A
+)%0A        else:%0A    
         

Use pybtex.errors.report_error() for handling .aux parse errors.