-
Notifications
You must be signed in to change notification settings - Fork 116
/
CardTypeRegister.swift
105 lines (84 loc) · 4.24 KB
/
CardTypeRegister.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//
// CardTypeRegister.swift
// Caishen
//
// Created by Daniel Vancura on 2/17/16.
// Copyright © 2016 Prolific Interactive. All rights reserved.
//
import UIKit
/// A `CardTypeRegister` is used to maintain the range of accepted card types. You can provide different card type registers for different CardTextField's and customize the range of accepted card types individually.
public class CardTypeRegister {
/**
The default card type register, shared among all CardTextFields.
*/
public static let sharedCardTypeRegister = CardTypeRegister(registeredCardTypes: CardTypeRegister.defaultCardTypes)
/// An array of all registered card types. You can edit this array with `registerCardType`, `unregisterCardType` or `setRegisteredCardTypes`.
public private(set) var registeredCardTypes: [CardType]
/**
Creates a new `CardTypeRegister` that accepts no card types.
*/
public init() {
registeredCardTypes = []
}
/**
Creates a new `CardTypeRegister` with the given sequence of card types.
- parameter registeredCardTypes: Any sequence of `CardType` that should be accepted by `self`.
*/
public convenience init<T: Sequence>(registeredCardTypes: T) where T.Iterator.Element == CardType {
self.init()
setRegisteredCardTypes(registeredCardTypes)
}
/// An array with the default card types provided by Caishen.
public static let defaultCardTypes: [CardType] = [
AmericanExpress(),
ChinaUnionPay(),
DinersClub(),
Discover(),
JCB(),
MasterCard(),
Visa()
]
/**
Adds the provided card type to the array of registered card types.
- parameter cardType: The card type that should be contained in this card type register.
*/
public func register(cardType: CardType) {
if registeredCardTypes.contains(where: { $0.isEqual(to: cardType) }) {
return
}
registeredCardTypes.append(cardType)
}
/**
Removes the provided card type from the array of registered card types.
- parameter cardType: The card type that should be removed from this card type register.
*/
public func unregister(cardType: CardType) {
registeredCardTypes = registeredCardTypes.filter { !$0.isEqual(to: cardType) }
}
/**
Replaces the range of registered card types.
- parameter cardTypes: The new range of card types contained in this card type register.
*/
public func setRegisteredCardTypes<T: Sequence>(_ cardTypes: T) where T.Iterator.Element == CardType {
registeredCardTypes = [CardType]()
registeredCardTypes.append(contentsOf: cardTypes)
}
/**
Retreives a card type for a specific card number by parsing the Issuer Identification Numbers in the registered card types and matching them with the provided card number.
- important: When creating custom card types, you should make sure, that there are no conflicts in the Issuer Identification Numbers you provide. For example, using [309] to detect a Diners Club card and using [3096] to detect a JCB card will not cause issues as IINs are parsed with the highest numbers first, i.e. the numbers that provide the most context possible, which will return a JCB card in this case. However, no two card types should provide the exact same number (like [309] to detect both a Diners Club card and a JCB card)!
- parameter number: The card number whose CardType should be determined
- returns: An instance of UnknownCardType, if no card type matches the Issuer Identification Number of the provided card number or any other card type that matches the card number.
*/
public func cardType(for number: Number) -> CardType {
for i in (0...min(number.length, 6)).reversed() {
if let substring = number.rawValue[0,i], let substringAsNumber = Int(substring) {
if let firstMatchingCardType = registeredCardTypes.filter({
$0.identifyingDigits.contains(substringAsNumber)
}).first {
return firstMatchingCardType
}
}
}
return UnknownCardType()
}
}