# -*- coding: utf-8 -*-
#
# Copyright (C) 2006 Edgewall Software
# Copyright (C) 2006 Alec Thomas <alec@swapoff.org>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.com/license.html.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://projects.edgewall.com/trac/.
#
# Author: Alec Thomas <alec@swapoff.org>

import random

from trac.core import Component, TracError, implements
from trac.config import IntOption

from tracspamfilter.captcha import ICaptchaMethod
from tracspamfilter.api import N_, _, gettext


class ExpressionCaptcha(Component):
    """captcha in the form of a human readable numeric expression

    Initial implementation by sergeych@tancher.com.
    """

    implements(ICaptchaMethod)

    terms = IntOption('spam-filter', 'captcha_expression_terms', 3,
            """Number of terms in numeric CAPTCHA expression.""",
            doc_domain='tracspamfilter')

    ceiling = IntOption('spam-filter', 'captcha_expression_ceiling', 10,
            """Maximum value of individual terms in numeric CAPTCHA
            expression.""", doc_domain='tracspamfilter')

    operations = {'*': N_("multiplied by"), '-': N_("minus"),
                  '+': N_("plus")}

    numerals = (N_("zero"), N_("one"), N_("two"), N_("three"),
                N_("four"), N_("five"), N_("six"), N_("seven"),
                N_("eight"), N_("nine"), N_("ten"), N_("eleven"),
                N_("twelve"), N_("thirteen"), N_("fourteen"),
                N_("fifteen"), N_("sixteen"), N_("seventeen"),
                N_("eighteen"), N_("nineteen"))

    # TRANSLATOR: if compound numbers like in english are not
    # supported, simply add a "plus" command to the following
    # translations!
    tens = (N_("twenty"), N_("thirty"), N_("forty"), N_("fifty"),
            N_("sixty"), N_("seventy"), N_("eighty"), N_("ninety"))

    # ICaptchaMethod methods

    def generate_captcha(self, req):
        if self.ceiling > 100:
            raise TracError(
                _("Numeric captcha can not represent numbers > 100"))
        terms = [unicode(random.randrange(0, self.ceiling))
                 for i in xrange(self.terms)]
        operations = [random.choice(self.operations.keys())
                      for i in xrange(self.terms)]
        expression = sum(zip(terms, operations), ())[:-1]
        expression = eval(compile(' '.join(expression), 'captcha_eval', 'eval'))
        human = sum(zip([self._humanise(int(t)) for t in terms],
                        [gettext(self.operations[o]) for o in operations]),
                    ())[:-1]
        return expression, u' '.join(map(unicode, human))

    def verify_captcha(self, req):
        return False

    def is_usable(self, req):
        return True

    # Internal methods

    def _humanise(self, value):
        if value < 20:
            return gettext(self.numerals[value])
        english = gettext(self.tens[value / 10 - 2])
        if value % 10:
            english += u' ' + gettext(self.numerals[value % 10])
        return english
