##############################################################################
#
# Copyright (c) 2002-2005 Nexedi SARL and Contributors. All Rights Reserved.
#               Jean-Paul Smets-Solanes <jp@nexedi.com>
#               Kevin Deldycke <kevin@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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.
#
##############################################################################

from AccessControl import ClassSecurityInfo

from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5Type.Document.Folder import Folder
from Products.ERP5.Document.Coordinate import Coordinate

import string


class BankAccount(Folder, Coordinate):
    """
      A bank account number holds a collection of numbers and codes
        (ex. SWIFT, RIB, etc.) which may be used to identify a bank account.

      A Bank Account is owned by a Person or an Organisation. A Bank Account
        contain Agents with Agent Privileges used by the owner to delegate the
        management of the bank account to trusted third-party Persons.

      BankAccount inherits from Base and from the mix-in Coordinate.
    """

    meta_type = 'ERP5 BankAccount'
    portal_type = 'BankAccount'
    add_permission = Permissions.AddPortalContent
    isPortalContent = 1
    isRADContent = 1

    # Declarative security
    security = ClassSecurityInfo()
    security.declareObjectProtected(Permissions.View)

    # Declarative properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.SimpleItem
                      , PropertySheet.Task
                      , PropertySheet.Resource
                      , PropertySheet.BankAccount
                      )

    # Declarative interfaces
    __implements__ = ( Interface.Coordinate )


    security.declareProtected(Permissions.View, 'getIbanTextFormat')
    def getIbanTextFormat(self):
        """
          Returns the standard IBAN text format
        """
        iban = self.getIban()
        l = 4
        s = "IBAN"
        for i in range((len(iban) / l) + 1):
          s += ' ' + iban[i*l : (i+1)*l]
        return s.strip()


    security.declareProtected(Permissions.View, 'getIbanTextFormat')
    def getIban(self):
        """
          The International Bank Account Number of this bank account.
          IBAN is an international standard for identifying bank accounts worldwide.
        """
        key          = self.getIbanKey()
        country_code = self.getBankCountryCode()
        bban         = self.getBban()
        if key          == None: key          = ''
        if country_code == None: country_code = ''
        if bban         == None: bban         = ''
        return (country_code + key + bban).upper().strip()


    security.declareProtected(Permissions.View, 'getIbanKey')
    def getIbanKey(self):
        """
          The IBAN key ensure the integry of the IBAN code.
          It's calculated with the ISO 7064 method (known as "97-10 modulo").
        """
        # Construct the alpha to number translation table
        table = {}
        for i in range(26):
          table[chr(65+i)] = str(10+i)
        # Calcul the key
        country_code = self.getBankCountryCode() + '00'
        s = self.getBban() + country_code
        n = ''
        for c in s:
          if c.isalpha():
            n += table[c.upper()]
          if c.isdigit():
            n += c
        key = str(98 - (int(n) % 97))
        return key.zfill(2)


    security.declareProtected(Permissions.View, 'getBban')
    def getBban(self):
        """
          The Basic Bank Account Number (BBAN) is the last part of the IBAN.
          Usualy it correspond to the national bank account number.
        """
        bank   = self.getBankCode()
        branch = self.getBranch()
        ban    = self.getBankAccountNumber()
        key    = self.getBbanKey()
        if bank   == None: bank   = ''
        if branch == None: branch = ''
        if ban    == None: ban    = ''
        if key    == None: key    = ''
        return (bank + branch + ban + key).upper().strip()


    security.declareProtected(Permissions.View, 'getBbanTextFormat')
    def getBbanTextFormat(self, sep=' '):
        """
          Returns a BBAN text format
        """
        bank   = self.getBankCode()
        branch = self.getBranch()
        ban    = self.getBankAccountNumber()
        key    = self.getBbanKey()
        if bank   == None: bank   = ''
        if branch == None: branch = ''
        if ban    == None: ban    = ''
        if key    == None: key    = ''
        return sep.join([bank, branch, ban, key]).upper().strip()


    security.declareProtected(Permissions.View, 'getBbanKey')
    def getBbanKey(self):
        """
          The BBAN key ensure the integry of the BBAN code.
          This is the french BBAN key algorithm.
        """
        def transcode(string):
          letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
          digit  = '12345678912345678923456789'
          for i in range(len(letter)):
            string = string.replace(letter[i], digit[i])
          return int(string)

        bank   = self.getBankCode()
        branch = self.getBranch()
        ban    = self.getBankAccountNumber()
        if bank   == None: bank   = ''
        if branch == None: branch = ''
        if ban    == None: ban    = ''
        if len(bank + branch + ban) == 0:
          return ''

        bank   += ('0' * (5 - len(bank)))
        branch += ('0' * (5 - len(branch)))

        s = (bank + branch + ban).upper()
        key = str(97 - ((transcode(s) * 100) % 97))
        return key.zfill(2)