Passed
Push — master ( 1e8a0f...55b2d7 )
by Alec
04:01
created

AllocationCalculator   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 71
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 71
ccs 38
cts 38
cp 1
rs 10
c 0
b 0
f 0
wmc 13

2 Methods

Rating   Name   Duplication   Size   Complexity  
C compute() 0 49 12
A __construct() 0 5 1
1
<?php
2
/**
3
 * User: alec
4
 * Date: 27.11.18
5
 * Time: 13:33
6
 */
7
8
namespace AlecRabbit\Money;
9
10
11
use AlecRabbit\Money\Contracts\CalculatorInterface;
12
13
class AllocationCalculator
14
{
15
    /** @var string */
16
    protected $amount;
17
18
    /** @var Currency */
19
    protected $currency;
20
21
    /** @var CalculatorInterface */
22
    protected $calculator;
23
24
    /**
25
     * AllocationCalculator constructor.
26
     * @param Money $param
27
     */
28 37
    public function __construct(Money $param)
29
    {
30 37
        $this->amount = $param->getAmount();
31 37
        $this->currency = $param->getCurrency();
32 37
        $this->calculator = CalculatorFactory::getCalculator();
33 37
    }
34
35 37
    public function compute(array $ratios, ?int $precision): array
36
    {
37 37
        $precision = $precision ?? 2;
38 37
        if (0 === $allocations = \count($ratios)) {
39 1
            throw new \InvalidArgumentException('Cannot allocate to none, ratios cannot be an empty array.');
40
        }
41 36
        if (0 >= $total = array_sum($ratios)) {
42 1
            throw new \InvalidArgumentException('Sum of ratios must be greater than zero.');
43
        }
44
45 35
        $remainder = $amount = $this->amount;
46 35
        $results = [];
47
48 35
        foreach ($ratios as $ratio) {
49 35
            if ($ratio < 0) {
50 1
                throw new \InvalidArgumentException('Ratio must be zero or positive.');
51
            }
52
53 35
            $share = $this->calculator->share($amount, $ratio, $total, $precision);
54 35
            $results[] = $share;
55 35
            $remainder = $this->calculator->subtract($remainder, $share);
56
        }
57 34
        switch ($this->calculator->compare($remainder, '0')) {
58
            case -1:
59 13
                for ($i = $allocations - 1; $i >= 0; $i--) {
60 13
                    if (!$ratios[$i]) {
61 1
                        continue;
62
                    }
63 13
                    $results[$i] = $this->calculator->add($results[$i], $remainder);
64 13
                    break;
65
                }
66 13
                break;
67 21
            case 1:
68 7
                for ($i = 0; $i < $allocations; $i++) {
69 7
                    if (!$ratios[$i]) {
70 1
                        continue;
71
                    }
72 7
                    $results[$i] = $this->calculator->add($results[$i], $remainder);
73 7
                    break;
74
                }
75 7
                break;
76
            default:
77 14
                break;
78
        }
79 34
        $computed = [];
80 34
        foreach ($results as $result) {
81 34
            $computed[] = new Money($result, $this->currency);
82
        }
83 34
        return $computed;
84
    }
85
}