# # ## ### ##### ######## ############# ######################
## Validation of IBAN numbers.
#
# # ## ### ##### ######## ############# ######################

# The code below implements the interface of a snit validation type,
# making it directly usable with snit's -type option in option
# specifications.

# References:
# http://en.wikipedia.org/wiki/International_Bank_Account_Number
# http://www.swift.com/dsp/resources/documents/IBAN_Registry.pdf
# 	IBAN REGISTRY, this registry provides detailed information about all ISO 13616-compliant national IBAN formats


# # ## ### ##### ######## ############# ######################
## Requisites

package require Tcl 8.5
package require snit
package require valtype::common

# # ## ### ##### ######## ############# ######################
## Implementation

namespace eval ::valtype::iban {
    namespace import ::valtype::common::*
}

snit::type ::valtype::iban {
    #-------------------------------------------------------------------
    # Type Methods

    typemethod validate {value} {

	array set iban_len "AL 28 AD 24 AT 20 BH 22 BE 16 BA 20 BG 22 CR 21 HR 21 CY 28 CZ 24 DK 18 FO 18 GL 18 DO 28 EE 20 FI 18\
                        FR 27 GF 27 GP 27 MQ 27 RE 27 PF 27 TF 27 YT 27 NC 27 PM 27 WF 27 GE 22 DE 22 GI 23 GR 27 HU 28\
                        IS 26 IE 22 IL 23 IT 27 KZ 20 KW 30 LV 21 LB 28 LI 21 LT 20 LU 20 MK 19 MT 31 MR 27 MU 30 MC 27\
                        ME 22 NL 18 NO 15 PL 28 PT 25 RO 24 SM 27 SA 24 RS 22 SK 24 SI 19 ES 24 SE 24 CH 21 TN 24 TR 26\
                        AE 23 GB 22"

	set country [string range $value 0 1]

	if {![info exists iban_len($country)]} {
		badprefix IBAN "" "IBAN number, unknown country code"
	}
	if {[string length $value] != $iban_len($country)} {
		badlength IBAN $iban_len($country) "IBAN number"
	}

	set number "[string toupper [string range $value 4 end][string range $value 0 3]]"

	set number [string map {A 10 B 11 C 12 D 13 E 14 F 15 G 16 H 17 I 18 J 19 K 20 L 21 M 22 N \
                	23 O 24 P 25 Q 26 R 27 S 28 T 29 U 30 V 31 W 32 X 33 Y 34 Z 35} $number]

	set number [string trimleft $number 0]
	if {![expr {$number%97}] == 1} {
		badcheck IBAN "IBAN number"
	}

	return $value

    }

    #-------------------------------------------------------------------
    # Constructor

    # None needed; no options

    #-------------------------------------------------------------------
    # Public Methods

    method validate {value} {
        $type validate $value
    }
}

# # ## ### ##### ######## ############# ######################
## Ready

package provide valtype::iban 1
