# Copyright 2006 Andrey Golovizin
#
# This file is part of pybtex.
#
# pybtex is free software; you can redistribute it and/or modify
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# pybtex 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 rdiff-backup; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA

"""pybtex' core datatypes
"""

import re
import utils
from richtext import Phrase, Symbol

class FormattedEntry:
    """Formatted bibliography entry. Consists of
    - key (which is used for sorting);
    - label (which appears in the resulting bibliography)
    - text (usually RichText)
    """
    def __init__(self, key, text, label=None):
        self.key = key
        self.text = text
        self.label = label

class Entry:
    """Bibliography entry. Important members are:
    - authors (a list of Person objects)
    - editors (like authors, but contains editors)
    - fields (all other information)
    """
    valid_roles = ['author', 'editor'] 
    def __init__(self, type_, fields = None):
        self.type = type_
        if fields == None:
            fields = {}
        self.fields = fields
        self.has_key = self.fields.has_key
        self.authors = []
        self.editors = []

    def __getattr__(self, name):
        try:
            return self.fields[name]
        except KeyError:
            return ""

    def add_person(self, person, role):
        """Add an author or an editor.
        """
        #if not isinstance(person, Person):
        #    person = Person(person)
        list = getattr(self, '%ss' % role)
        list.append(person)
                

class Person:
    """Represents a person (usually human).
    """
    style1_re = re.compile('^(.+),\s*(.+)$')
    style2_re = re.compile('^(.+),\s*(.+),\s*(.+)$')
    def __init__(self, string="", first="", middle="", prelast="", last="", lineage=""):
        self._first = []
        self._middle = []
        self._prelast = []
        self._last = []
        self._lineage = []
        string = string.strip()
        if string:
            self.parse_string(string)
        self._first.extend(first.split())
        self._middle.extend(middle.split())
        self._prelast.extend(prelast.split())
        self._last.extend(last.split())
        self._lineage.extend(lineage.split())

    def parse_string(self, s):
        """Extract various parts of the name from a string.
        Supported formats are:
         - von Last, First
         - von Last, Jr, First
         - First von Last
        (see BibTeX manual for explanation)
        """
        def process_von_last(s):
            for part in s.split():
                if part.islower():
                    self._prelast.append(part)
                else:
                    self._last.append(part)
        match1 = self.style1_re.match(s)
        match2 = self.style2_re.match(s)
        if match2: # von Last, Jr, First
            parts = match2.groups()
            process_von_last(parts[0])
            self._lineage.extend(parts[1].split())
            self._first.extend(parts[2].split())
        elif match1: # von Last, First
            parts = match1.groups()
            process_von_last(parts[0])
            self._first.extend(parts[1].split())
        else: # First von Last
            parts = reversed(s.split())
            self._last.append(parts.next())
            for part in parts:
                if part.islower():
                    self._prelast.insert(0, part)
                else:
                    self._first.insert(0, part)

    def get_part_as_text(self, type):
        names = getattr(self, '_' + type)
        return ' '.join(names)

    def get_part(self, type, abbr=False):
        names = getattr(self, '_' + type)
        if abbr:
            names = [utils.abbreviate(name) for name in names]
        p = Phrase(sep=Symbol('nbsp'))
        p.extend(names)
        return p
    def first(self, abbr=False):
        return self.get_part('first', abbr)
    def middle(self, abbr=False):
        return self.get_part('middle', abbr)
    def prelast(self, abbr=False):
        return self.get_part('prelast', abbr)
    def last(self, abbr=False):
        return self.get_part('last', abbr)
    def lineage(self, abbr=False):
        return self.get_part('lineage', abbr)

@@ -2992,32 +2992,222 @@
 on)%0A        %22%22%22%0A
+        def process_first_middle(s):%0A            try:%0A                self._first.append(s%5B0%5D)%0A                self._middle.extend(s%5B1:%5D)%0A            except IndexError:%0A                pass%0A
         def proc
@@ -3219,24 +3219,24 @@
 on_last(s):%0A
-
             
@@ -3667,34 +3667,36 @@
         
-self._first.extend
+process_first_middle
 (parts%5B2
@@ -3832,34 +3832,36 @@
         
-self._first.extend
+process_first_middle
 (parts%5B1
@@ -3982,24 +3982,54 @@
 rts.next())%0A
+            first_middle = %5B%5D%0A
             
@@ -4178,34 +4178,82 @@
     
-self._first.insert(0, part
+first_middle.append(0, part)%0A            process_first_middle(first_middle
 )%0A%0A 

split a list of names into first and middle (almost) correctly