#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006  Donald N. Allingham
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

"""
Support classes to simplify GEDCOM importing
"""

import re
import gen.lib

NAME_RE    = re.compile(r"/?([^/]*)(/([^/]*)(/([^/]*))?)?")
SURNAME_RE = re.compile(r"/([^/]*)/([^/]*)")

#-------------------------------------------------------------------------
#
# CurrentState
#
#-------------------------------------------------------------------------
class CurrentState(object):
    """
    Keep track of the current state variables.
    """
    def __init__(self, person=None, level=0, event=None, event_ref=None):
        """
        Initialize the object.
        """
        self.name_cnt = 0
        self.person = person
        self.level = level
        self.event = event
        self.event_ref = event_ref
        self.source_ref = None

    def __getattr__(self, name):
        """
        Return the value associated with the specified attribute.
        """
        return self.__dict__.get(name)

    def __setattr__(self, name, value):
        """
        Set the value associated with the specified attribute.
        """
        self.__dict__[name] = value

#-------------------------------------------------------------------------
#
# PlaceParser
#
#-------------------------------------------------------------------------
class PlaceParser(object):
    """
    Provide the ability to parse GEDCOM FORM statements for places, and
    the parse the line of text, mapping the text components to Location
    values based of the FORM statement.
    """

    __field_map = {
	'addr'          : gen.lib.Location.set_street,
	'subdivision'   : gen.lib.Location.set_street,
	'addr1'         : gen.lib.Location.set_street,
	'adr1'          : gen.lib.Location.set_street,
	'city'          : gen.lib.Location.set_city,
	'town'          : gen.lib.Location.set_city,
	'village'       : gen.lib.Location.set_city,
	'county'        : gen.lib.Location.set_county,
	'country'       : gen.lib.Location.set_country,
	'state'         : gen.lib.Location.set_state,
	'state/province': gen.lib.Location.set_state,
	'region'        : gen.lib.Location.set_state,
	'province'      : gen.lib.Location.set_state,
	'area code'     : gen.lib.Location.set_postal_code,
	}

    def __init__(self, line=None):
        self.parse_function = []

        if line:
            self.parse_form(line)

    def parse_form(self, line):
        """
        Parses the GEDCOM PLAC.FORM into a list of function
        pointers (if possible). It does this my mapping the text strings
        (separated by commas) to the corresponding gen.lib.Location
        method via the __field_map variable
        """
        for item in line.data.split(','):
            item = item.lower().strip()
            fcn = self.__field_map.get(item, lambda x, y: None)
            self.parse_function.append(fcn)

    def load_place(self, place, text):
        """
        Takes the text string representing a place, splits it into
        its subcomponents (comma separated), and calls the approriate
        function based of its position, depending on the parsed value
        from the FORM statement.
        """
        items = [item.strip() for item in text.split(',')]
        if len(items) != len(self.parse_function):
            return
        loc = place.get_main_location()
        index = 0
        for item in items:
            self.parse_function[index](loc, item)
            index += 1

#-------------------------------------------------------------------------
#
# IdFinder
#
#-------------------------------------------------------------------------
class IdFinder(object):
    """
    Provide method of finding the next available ID.
    """
    def __init__(self, keys, prefix):
        """
        Initialize the object.
        """
        self.ids = set(keys)
        self.index = 0
        self.prefix = prefix

    def find_next(self):
        """
        Return the next available GRAMPS' ID for a Event object based
        off the person ID prefix.

        @return: Returns the next available index
        @rtype: str
        """
        index = self.prefix % self.index
        while str(index) in self.ids:
            self.index += 1
            index = self.prefix % self.index
        self.ids.add(index)
        self.index += 1
        return index

#-------------------------------------------------------------------------
#
# IdMapper
#
#-------------------------------------------------------------------------
class IdMapper(object):

    def __init__(self, trans, find_next, translate):
        self.translate = translate
        self.trans = trans
        self.find_next = find_next
        self.swap = {}
    
    def __getitem__(self, gid):
        if self.translate:
            return self.get_translate(gid)
        else:
            return self.no_translate(gid)
    
    def clean(self, gid):
        temp = gid.strip()
        if len(temp) > 1 and temp[0] == '@' and temp[-1] == '@':
            temp = temp[1:-1]
        return temp

    def no_translate(self, gid):
        return self.clean(gid)
        
    def get_translate(self, gid):
        gid = self.clean(gid)
        if gid in self.swap:
            return self.swap[gid]
        else:
            if self.trans.get(str(gid)):
                new_val = self.find_next()
            else:
                new_val = gid
        self.swap[gid] = new_val
        return new_val

#------------------------------------------------------------------------
#
# Support functions
#
#------------------------------------------------------------------------
def parse_name_personal(text):
    """
    Parses a GEDCOM NAME value into an Name structure
    """
    name = gen.lib.Name()

    match = SURNAME_RE.match(text)
    if match:
        names = match.groups()
        name.set_first_name(names[1].strip())
        name.set_surname(names[0].strip())
    else:
        try:
            names = NAME_RE.match(text).groups()
            name.set_first_name(names[0].strip())
            name.set_surname(names[2].strip())
            name.set_suffix(names[4].strip())
        except:
            name.set_first_name(text.strip())
    return name

def extract_id(value):
    """
    Extracts a value to use for the GRAMPS ID value from the GEDCOM
    reference token. The value should be in the form of @XYZ@, and the
    returned value will be XYZ
    """
    return value.strip()[1:-1]
