# 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 3 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, see <http://www.gnu.org/licenses/>.

"""Manage an address book.

ATTRIBUTES

path                    The path to the address book.

CLASSES

ABError                 AB error.
AddressBook             Store contacts.
Contact                 Store contact information.
ContactDoesNotExistError
                        The contact is not in the address book.
ContactExistsError      The contact is already in the address book.

"""

import os

__author__ = 'Delvian Valentine <djdvalentine@gmail.com>'
__version__ = '0.3'

path = os.path.join(os.environ['HOME'], '.ab')


class ABError(Exception):

    """AB error."""

    pass


class AddressBook(dict):

    """Store contacts.

    METHODS

    add                 Add a contact to the address book.
    edit                Edit a contact in the address book.
    remove              Remove a contact from the address book.
    search              Search the address book.

    """

    def add(self, contact):
        """Add a contact to the address book.

        Raise a ContactExistsError if a contact with the same name is already in
        the address book.

        ARGUMENTS

        contact         The contact.

        """
        if contact.name not in self:
            self[contact.name] = contact
        else:
            raise ContactExistsError(contact.name)

    def edit(self, contact):
        """Edit a contact in the address book.

        Raise a ContactDoesNotExistError if the contact is not in the address
        book.

        ARGUMENTS

        contact         The contact.

        """
        if contact.name in self:
            self[contact.name] = contact
        else:
            raise ContactDoesNotExistError(contact.name)

    def remove(self, name):
        """Remove a contact from the address book.

        Raise a ContactDoesNotExistError if the contact is not in the address
        book.

        ARGUMENTS

        name            The name of the contact.

        """
        if name in self:
            del self[name]
        else:
            raise ContactDoesNotExistError(name)

    def search(self, args):
        """Search the address book.

        Return a list of names of contacts that contain the arguments.

        ARGUMENTS

        args            The items to search for.

        """
        return [name for name in self if args in self[name]]


class Contact:

    """Store contact information.

    ATTRIBUTES

    email               The email address of the contact.
    name                The name of the contact.

    METHODS

    __cmp__             Compare a contact.
    __contains__        Search the contact.
    __init__            Create a new contact.
    __str__             Return the contact information.

    """

    def __init__(self, name, email):
        """Create a new contact.

        ARGUMENTS

        name            The name of the contact.
        email           The email address of the contact.

        """
        self.name = name
        self.email = email

    def __cmp__(self, other):
        """Compare a contact.

        Return a negative integer if self < other, zero if self == other or a
        positive integer if self > other.

        ARGUMENTS

        other           The contact to compare.

        """
        if self.name == other.name:
            return cmp(self.email, other.email)
        else:
            return cmp(self.name, other.name)

    def __contains__(self, items):
        """Search the contact.

        Return True if the contact contains the items or False if it does not.

        ARGUMENTS

        items           The items to search for.

        """
        for item in items:
            if item not in self.name and item not in self.email:
                return False
        return True

    def __str__(self):
        """Return the contact information."""
        return '%s: %s' % (self.name, self.email)


class ContactDoesNotExistError(ABError):

    """The contact is not in the address book.

    METHODS

    __init__            Create a new error.

    """

    def __init__(self, name):
        """Create a new error.

        ARGUMENTS

        name            The name of the contact.

        """
        ABError.__init__(self, '%s is not in your address book' % name)


class ContactExistsError(ABError):

    """The contact is already in the address book.

    METHODS

    __init__            Create a new error.

    """

    def __init__(self, name):
        """Create a new error.

        ARGUMENTS

        name            The name of the contact.

        """
        ABError.__init__(self, '%s is already in your address book' % name)


# (c) 2010 Delvian Valentine <djdvalentine@gmail.com>
