# w.c.s. - web application for online forms
# Copyright (C) 2005-2010  Entr'ouvert
#
# 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, see <http://www.gnu.org/licenses/>.

import re

from django.utils.six.moves.urllib import parse as urllib

from . import errors, misc
from . import get_cfg, get_logger
from .form import StringWidget, PasswordWidget
from wcs.wscalls import call_webservice


class MobytSMS(object):
    """This class allows to send a SMS using Mobyt provider"""
    parameters = [
         (StringWidget, 'sender', N_('Sender (number or name)')),
         (StringWidget, 'mobyt_username', N_('Username')),
         (PasswordWidget, 'mobyt_password', N_('Password')),
    ]

    def __init__(self):
        sms_cfg = get_cfg('sms', {})
        self.user = sms_cfg.get('mobyt_username', '')
        self.password = sms_cfg.get('mobyt_password', '')

    def send(self, sender, destinations, text, quality='l'):
        """ Send a sms using Mobyt provider"""
        rcpt = ""
        for dest in destinations:
            rcpt += "%s," % dest
        rcpt = rcpt[:len(rcpt) - 1]
        params = urllib.urlencode({
            'user': self.user,
            'pass': self.password,
            'rcpt': rcpt,
            'data': text,
            'sender': sender,
            'qty': quality
            })
        try:
            r = misc.urlopen("http://multilevel.mobyt.fr/sms/batch.php", params)
        except misc.ConnectionError as e:
            raise errors.SMSError("failed to POST to mobyt.fr (%s)" % e)
        answer = r.read()
        r.close()
        if answer[:2] == "KO":
            raise errors.SMSError(answer[3:])

    def get_credit(self, type):
        params = urllib.urlencode({
            'user': self.user,
            'pass': self.password,
            'type': type
            })
        try:
            r = misc.urlopen("http://multilevel.mobyt.fr/sms/credit.php", params)
        except misc.ConnectionError as e:
            raise errors.SMSError("failed to POST to mobyt.fr (%s)" % e)
        answer = r.read()
        r.close()
        if answer[:2] == "KO":
            raise errors.SMSError(answer[3:])
        else:
            return answer[3:]

    def get_sms_left(self, type="standard"):
        """
        type (mobyt provider): standard, lowcost or top
        """
        if type == "standard":
            return self.get_credit("l")
        elif type == "lowcost":
            return self.get_credit("ll")
        elif type == "top":
            return self.get_credit("n")
        else:
            raise errors.SMSError("%s is invalid type for provider Mobyt" % type)

    def get_money_left(self):
        """ return money left in euros """
        return self.get_credit("credit")


class OxydSMS(object):
    """This class allows to send a SMS using Oxyd provider"""
    parameters = [
         (StringWidget, 'oxyd_username', N_('Username')),
         (PasswordWidget, 'oxyd_password', N_('Password')),
         (StringWidget, 'oxyd_default_country_code', N_('Default Country Code')),
    ]

    def __init__(self):
        sms_cfg = get_cfg('sms', {})
        self.user = sms_cfg.get('oxyd_username', '')
        self.password = sms_cfg.get('oxyd_password', '')
        self.default_country_code = sms_cfg.get('oxyd_default_country_code')
        if not self.default_country_code:
            self.default_country_code = '33' # arbitrary

    def send(self, sender, destinations, text, quality=None):
        """Send a SMS using Oxyd provider"""
        # unfortunately it lacks a batch API...
        for dest in destinations:
            # oxyd needs the number prefixed by the country code, this is
            # really unfortunate.
            number = ''.join(re.findall(r'\d', dest))
            if dest.startswith('+'):
                pass # it already is fully qualified
            elif number.startswith('00'):
                # assumes 00 is international access code, remove it
                number = number[2:]
            elif number.startswith('0'):
                # local prefix, remove 0 and add default country code
                number = self.default_country_code + number[1:]
            params = urllib.urlencode({
                'id': self.user,
                'pass': self.password,
                'num': number,
                'sms': text,
                'flash': '0'
                })
            try:
                r = misc.urlopen('http://sms.oxyd.fr/send.php', params)
            except misc.ConnectionError as e:
                # XXX: add proper handling of errors
                raise errors.SMSError("failed to POST to oxyd.fr (%s)" % e)
            r.close()

    def get_sms_left(self, type='standard'):
        raise NotImplementedError

    def get_money_left(self):
        raise NotImplementedError


class ChoositSMS(object):
    """This class allows to send a SMS using the Choosit provider

    http://sms.choosit.com/documentation_technique.html
    """
    parameters = [
         (StringWidget, 'choosit_key', N_('Key')),
         (StringWidget, 'choosit_default_country_code', N_('Default Country Code')),
    ]

    def __init__(self):
        sms_cfg = get_cfg('sms', {})
        self.key = sms_cfg.get('choosit_key', '')
        self.default_country_code = sms_cfg.get('choosit_default_country_code')
        if not self.default_country_code:
            self.default_country_code = '33' # arbitrary

    def send(self, sender, destinations, text, quality=None):
        """Send a SMS using the Choosit provider"""
        # unfortunately it lacks a batch API...
        for dest in destinations:
            # choosit needs the number prefixed by the country code, this is
            # really unfortunate.
            number = ''.join(re.findall(r'\d', dest))
            if dest.startswith('+'):
                pass # it already is fully qualified
            elif number.startswith('00'):
                # assumes 00 is international access code, remove it
                number = number[2:]
            elif number.startswith('0'):
                # local prefix, remove 0 and add default country code
                number = self.default_country_code + number[1:]
            params = urllib.urlencode({
                'key': self.key,
                'recipient': number,
                'content': text[:160],
                })
            try:
                r = misc.urlopen('http://sms.choosit.com/webservice', params)
            except misc.ConnectionError as e:
                # XXX: add proper handling of errors
                raise errors.SMSError("failed to POST to choosit.com (%s)" % e)
            r.close()

    def get_sms_left(self, type='standard'):
        raise NotImplementedError

    def get_money_left(self):
        raise NotImplementedError

class PasserelleSMS(object):
    """This class allows to send a SMS using Passerelle
    """
    parameters = [
         (StringWidget, 'sender', N_('Sender (number or name)')),
         (StringWidget, 'passerelle_url', N_('URL')),
    ]

    TIMEOUT = 10

    def __init__(self):
        sms_cfg = get_cfg('sms', {})
        self.sender = sms_cfg.get('sender', '')
        self.url = sms_cfg.get('passerelle_url', '')

    def send(self, sender, destinations, text, quality=None):
        """Send a SMS using the Choosit provider"""
        sender = sender or self.sender
        payload = {
              'from': sender,
              'message': text,
              'to': destinations,
        }

        response, status, data = call_webservice(self.url, method='POST',
                                                 post_data=payload)
        get_logger().debug('sms %r sent using passerelle to %r, result: %r',
                text, destinations, data)

    def get_sms_left(self, type='standard'):
        raise NotImplementedError

    def get_money_left(self):
        raise NotImplementedError

class SMS(object):
    providers = {
        'mobyt': (N_('Mobyt provider'), MobytSMS),
        'oxyd': (N_('Oxyd provider'), OxydSMS),
        'choosit': (N_('Choosit provider'), ChoositSMS),
        'passerelle': (N_('Passerelle provider'), PasserelleSMS),
    }

    @classmethod
    def get_sms_class(cls, provider_id):
        if not provider_id:
            sms_cfg = get_cfg('sms', {})
            provider_id = sms_cfg.get('mode', '')
        if provider_id in cls.providers:
            return cls.providers.get(provider_id)[1]()
        else:
            return None
