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

AllocationCalculator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
}