# coding: utf8
# Debian Contributors data mining on emails
#
# Copyright (C) 2013--2014  Enrico Zini <enrico@debian.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from ..types import Identifier
from .utils.mine import Aggregate
from .utils.email import get_mailbox
from .. import scanner
import email.utils
import datetime
import time

__all__ = ["MailFrom"]

class MailFrom(scanner.Scanner):
    """
    Scan email address from From: headers in mailboxes

    Example::

        contribution: developer
        method: mailfrom
        folders: /home/debian/lists/debian-devel-announce/*
        url: http://www.example.com/{email}
    """
    folders = scanner.GlobField(blank=False, help_text="""
                             mail folders to scan. You can give one or more,
                             and even use shell-style globbing. Mailbox,
                             mailbox.gz and Maildir folders are supported.
                             """)
    whitelist = scanner.EmailsField(help_text="""
                             if present, only emails from this list will be
                             considered as contributors.
                             """)
    blacklist = scanner.EmailsField(help_text="""
                             if present, emails from this list will not be
                             considered as contributors.
                             """)
    url = scanner.CharField(help_text="""
                            template used to build URLs to link to people's contributions.
                            ``{email}`` will be replaced with the email address
                            """)

    def scan(self):
        # Build a filter function from whitelist and blacklist
        whitelist = frozenset(self.whitelist)
        blacklist = frozenset(self.blacklist)
        if whitelist and blacklist:
            filter_func = lambda x: x in whitelist and x not in blacklist
        elif whitelist:
            filter_func = lambda x: x in whitelist
        elif blacklist:
            filter_func = lambda x: x not in blacklist
        else:
            filter_func = lambda x: True

        contribs = Aggregate()
        desc_by_email = {}
        for pathname in self.folders:
            folder = get_mailbox(pathname)
            try:
                for msg in folder:
                    # Extract From address
                    addr = msg.get("From", None)
                    if addr is None: continue
                    name, addr = email.utils.parseaddr(addr)
                    if not filter_func(addr): continue
                    if name:
                        desc_by_email[addr] = name

                    # Extract date
                    date = msg.get("Date", None)
                    if date is None: continue
                    date = email.utils.parsedate(date)
                    if date is None: continue
                    ts = time.mktime(date)

                    contribs.add(addr, ts)
            finally:
                folder.close()

        for addr, (begin, end) in contribs.iteritems():
            ident = Identifier("email", addr, desc_by_email.get(addr, None))
            begin = datetime.date.fromtimestamp(begin)
            end = datetime.date.fromtimestamp(end)
            if self.url:
                yield ident, begin, end, self.url.format(email=addr)
            else:
                yield ident, begin, end, None
