Completed
Push — master ( 59c50d...1e8f66 )
by Davide
02:13
created

Calculator::calculateSumByDictionary()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 9.6667
cc 2
eloc 6
nc 2
nop 3
crap 2
1
<?php
2
3
namespace DavidePastore\CodiceFiscale;
4
5
/**
6
 * Codice Fiscale calculator.
7
 * @author davidepastore
8
 *
9
 */
10
class Calculator
11
{
12
    
13
    private $subject;
14
    private $omocodiaLevel = 0;
15
    
16
    /**
17
     * Array of available vowels.
18
     */
19
    private $vowels = array('A', 'E', 'I', 'O', 'U');
20
    
21
    /**
22
     * Array of all available months.
23
     */
24
    private $months = array(
25
        '1' => 'A',
26
        '2' => 'B',
27
        '3' => 'C',
28
        '4' => 'D',
29
        '5' => 'E',
30
        '6' => 'H',
31
        '7' => 'L',
32
        '8' => 'M',
33
        '9' => 'P',
34
        '10' => 'R',
35
        '11' => 'S',
36
        '12' => 'T'
37
    );
38
    
39
    /**
40
     * Array of all avaialable odd characters.
41
     */
42
    private $odd = array(
43
		'0' => 1, 
44
		'1' => 0, 
45
		'2' => 5, 
46
		'3' => 7, 
47
		'4' => 9, 
48
		'5' => 13, 
49
		'6' => 15, 
50
		'7' => 17, 
51
		'8' => 19, 
52
		'9' => 21, 
53
		'A' => 1,
54
		'B' => 0,
55
		'C' => 5,
56
		'D' => 7,
57
		'E' => 9,
58
		'F' => 13,
59
		'G' => 15,
60
		'H' => 17,
61
		'I' => 19,
62
		'J' => 21,
63
		'K' => 2,
64
		'L' => 4,
65
		'M' => 18,
66
		'N' => 20,
67
		'O' => 11,
68
		'P' => 3,
69
		'Q' => 6,
70
		'R' => 8,
71
		'S' => 12,
72
		'T' => 14,
73
		'U' => 16,
74
		'V' => 10,
75
		'W' => 22,
76
		'X' => 25,
77
		'Y' => 24,
78
		'Z' => 23
79
	);
80
	
81
    /**
82
     * Array of all avaialable even characters.
83
     */
84
	private $even = array(
85
		'0' => 0, 
86
		'1' => 1, 
87
		'2' => 2, 
88
		'3' => 3, 
89
		'4' => 4, 
90
		'5' => 5, 
91
		'6' => 6, 
92
		'7' => 7, 
93
		'8' => 8, 
94
		'9' => 9, 
95
		'A' => 0,
96
		'B' => 1,
97
		'C' => 2,
98
		'D' => 3,
99
		'E' => 4,
100
		'F' => 5,
101
		'G' => 6,
102
		'H' => 7,
103
		'I' => 8,
104
		'J' => 9,
105
		'K' => 10,
106
		'L' => 11,
107
		'M' => 12,
108
		'N' => 13,
109
		'O' => 14,
110
		'P' => 15,
111
		'Q' => 16,
112
		'R' => 17,
113
		'S' => 18,
114
		'T' => 19,
115
		'U' => 20,
116
		'V' => 21,
117
		'W' => 22,
118
		'X' => 23,
119
		'Y' => 24,
120
		'Z' => 25
121
	);
122
    
123
    /**
124
     * Array of all avaialable omocodia characters.
125
     */
126
	private $omocodiaCodes = array(
127
		'0' => 'L',
128
		'1' => 'M',
129
        '2' => 'N',
130
        '3' => 'P',
131
        '4' => 'Q',
132
        '5' => 'R',
133
        '6' => 'S',
134
        '7' => 'T',
135
        '8' => 'U',
136
        '9' => 'V'
137
	);
138
	
139
	/**
140
	 * Create a Codice Fiscale instance.
141
	 * @param Subject $subject The subject that will have the codice fiscale.
142
     * @param $properties An array with additional properties.
143
	 */
144 17
	public function __construct(Subject $subject, $properties = array()){
145 17
        $this->subject = $subject;
146
        
147 17
        if (array_key_exists('omocodiaLevel', $properties)) {
148 15
            $this->omocodiaLevel = $properties['omocodiaLevel'];
149 15
        }
150 17
	}
151
    
152
    /**
153
     * Calculate the code fiscale.
154
     * @returns Returns the complete codice fiscale.
155
     */
156 17
    public function calculate(){
157 17
        $temporaryCodiceFiscale = $this->calculateSurname() . $this->calculateName() .
158 17
               $this->calculateBirthDateAndGender() . $this->calculateBelfioreCode();
159 17
        $temporaryCodiceFiscale = $this->calculateOmocodia($temporaryCodiceFiscale);
160 17
        return $temporaryCodiceFiscale . $this->calculateCheckDigit($temporaryCodiceFiscale);
161
    }
162
    
163
    /**
164
     * Calculate all possibilities for the code fiscale.
165
     * @returns Returns the complete codice fiscale.
166
     */
167 3
    public function calculateAllPossibilities(){
168 3
        $allPossibilities = array();
169 3
        for($i = 0; $i < 8; $i++){
170 3
            $this->omocodiaLevel = $i;
171 3
            $allPossibilities[] = $this->calculate();
172 3
        }
173 3
        return $allPossibilities;
174
    }
175
    
176
    
177
    /**
178
     * Calculate the surname part of the codice fiscale.
179
     * @returns Returns the surname part of the codice fiscale.
180
     */
181 17
    private function calculateSurname(){
182 17
        $consonants = str_replace($this->vowels, '', $this->subject->getSurname());
183 17 View Code Duplication
        if(strlen($consonants) > 2){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184 14
            $result = substr($consonants, 0, 3);
185 14
        } else {
186 3
            $vowels = str_replace(str_split($consonants), '', $this->subject->getSurname());
187 3
			$result = substr($consonants . $vowels . 'XXX', 0, 3);
188
        }
189 17
        return $result;
190
    }
191
    
192
    /**
193
     * Calculate the name part of the codice fiscale.
194
     * @returns Returns the name part of the codice fiscale.
195
     */
196 17
    private function calculateName(){
197 17
        $consonants = str_replace($this->vowels, '', $this->subject->getName());
198 17
        if(strlen($consonants) > 3){
199 5
            $result = $consonants[0] . $consonants[2] . $consonants[3];
200 17 View Code Duplication
        } else if(strlen($consonants) == 3){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
            $result = join($consonants);
202
        } else{
203 12
            $vowels = str_replace(str_split($consonants), '', $this->subject->getName());
204 12
			$result = substr($consonants . $vowels . 'XXX', 0, 3);
205
        }
206 17
        return $result;
207
    }
208
    
209
    /**
210
     * Calculate the birth date and the gender.
211
     * @returns Returns the birth date and gender part of the codice fiscale.
212
     */
213 17
    private function calculateBirthDateAndGender(){
214 17
        $year = $this->subject->getBirthDate()->format('y');
215 17
        $month = $this->months[$this->subject->getBirthDate()->format('n')];
216 17
        $day = $this->subject->getBirthDate()->format('d');
217 17
        if($this->subject->getGender() == "F"){
218 1
            $day += 40;
219 1
        }
220 17
        return $year . $month . $day;
221
    }
222
    
223
    /**
224
     * Calculate the Belfiore code.
225
     * @returns Returns the Belfiore code.
226
     */
227 17
    private function calculateBelfioreCode(){
228 17
        return $this->subject->getBelfioreCode();
229
    }
230
    
231
    /**
232
     * Calculate the check digit.
233
     * @param $temporaryCodiceFiscale The first part of the codice fiscale.
234
     * @returns Returns the check digit part of the codice fiscale.
235
     */
236 17
    private function calculateCheckDigit($temporaryCodiceFiscale){
237 17
        $sumEven = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->even, 1);
238 17
        $sumOdd = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->odd, 0);
239 17
        return chr(($sumOdd + $sumEven) % 26 + 65);
240
    }
241
    
242
    /**
243
     * Calculate the sum by the given dictionary for the given temporary codice fiscale.
244
     * @param $temporaryCodiceFiscale The temporary codice fiscale.
245
     * @param $dictionaryArray The dictionary array.
246
     * @param $i The start index value.
247
     * @returns Returns the sum by the given dictionary for the given temporary codice fiscale.
248
     *
249
     */
250 17
    private function calculateSumByDictionary($temporaryCodiceFiscale, $dictionaryArray, $i){
251 17
        $sum = 0;
252 17
        for (; $i < 15; $i = $i + 2)
253
		{
254 17
			$k = $temporaryCodiceFiscale{$i};
255 17
			$sum = $sum + $dictionaryArray[$k];
256 17
		}
257 17
        return $sum;
258
    }
259
    
260
    /**
261
     * Calculate the omocodia case (additional translation).
262
     * @param $temporaryCodiceFiscale The first part of the codice fiscale.
263
     * @returns Returns the new codice fiscale.
264
     */
265 17
    private function calculateOmocodia($temporaryCodiceFiscale){
266 17
        if($this->omocodiaLevel > 0){
267 7
            $omocodiaLevelApplied = 0;
268 7
            for($i = strlen($temporaryCodiceFiscale) - 1; $i > 0; $i--){
269 7
                $k = $temporaryCodiceFiscale{$i};
270 7
                if($omocodiaLevelApplied < $this->omocodiaLevel && is_numeric($k)){
271 7
                    $newChar = $this->omocodiaCodes[$k];
272 7
                    $temporaryCodiceFiscale{$i} = $newChar;
273 7
                    $omocodiaLevelApplied++;
274 7
                }
275 7
            }
276 7
        }
277 17
        return $temporaryCodiceFiscale;
278
    }
279
}
280