Completed
Push — master ( 47ea5c...7bab12 )
by Julien
03:03
created

CreateDirectEliminationTree::printBrackets()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 35
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 15
nc 4
nop 0
1
<?php
2
3
namespace Xoco70\KendoTournaments\TreeGen;
4
5
use Xoco70\KendoTournaments\Models\Competitor;
6
use Xoco70\KendoTournaments\Models\Team;
7
8
class CreateDirectEliminationTree
9
{
10
    public $firstRoundName;
11
    public $groupsByRound;
12
    public $hasPrelimimary;
13
    public $brackets = [];
14
    public $championship;
15
    public $numFighters;
16
    public $noRounds;
17
    public $playerWrapperHeight = 30;
18
    public $matchWrapperWidth = 150;
19
    public $roundSpacing = 40;
20
    public $matchSpacing = 42;
21
    public $borderWidth = 3;
22
23
    public function __construct($groupsByRound, $championship, $hasPreliminary)
24
    {
25
        $this->championship = $championship;
26
        $this->groupsByRound = $groupsByRound;
27
        $this->hasPreliminary = $hasPreliminary;
0 ignored issues
show
Bug introduced by
The property hasPreliminary does not seem to exist. Did you mean hasPrelimimary?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
28
29
        $this->firstRoundName = $groupsByRound->first()->map(function ($item) use ($championship) {
30
            $fighters = $item->getFightersWithBye();
31
            $fighter1 = $fighters->get(0);
32
            $fighter2 = $fighters->get(1);
33
            return [$fighter1, $fighter2];
34
        })->flatten()->all();
35
    }
36
37
    public function build()
38
    {
39
40
        $fighters = $this->firstRoundName;
41
        $this->numFighters = count($fighters);
42
43
44
        //Calculate the size of the first full round - for example if you have 5 fighters, then the first full round will consist of 4 fighters
45
        $this->noRounds = log($this->numFighters, 2);
46
        $roundNumber = 1;
47
48
        //Group 2 fighters into a match
49
        $matches = array_chunk($fighters, 2);
50
51
        //If there's already a match in the match array, then that means the next round is round 2, so increase the round number
52
        if (count($this->brackets)) {
53
            $roundNumber++;
54
        }
55
        $countMatches = count($matches);
56
        //Create the first full round of fighters, some may be blank if waiting on the results of a previous round
57
        for ($i = 0; $i < $countMatches; $i++) {
58
            $this->brackets[$roundNumber][$i + 1] = $matches[$i];
59
        }
60
61
        //Create the result of the empty rows for this tournament
62
        $this->assignFightersToBracket($roundNumber, $this->hasPreliminary);
0 ignored issues
show
Bug introduced by
The property hasPreliminary does not seem to exist. Did you mean hasPrelimimary?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
63
        $this->assignPositions();
64
65
    }
66
67
    private function assignPositions()
68
    {
69
70
        //Variables required for figuring outing the height of the vertical connectors
71
72
        $spaceFactor = 0.5;
73
        $playerHeightFactor = 1;
74
75
        foreach ($this->brackets as $roundNumber => &$round) {
76
77
            foreach ($round as $matchNumber => &$match) {
78
79
                //Give teams a nicer index
80
81
                $match['playerA'] = $match[0];
82
                $match['playerB'] = $match[1];
83
84
                unset($match[0]);
85
                unset($match[1]);
86
87
                //Figure out the bracket positions
88
89
                $match['matchWrapperTop'] = (((2 * $matchNumber) - 1) * (pow(2, ($roundNumber) - 1)) - 1) * (($this->matchSpacing / 2) + $this->playerWrapperHeight);
90
                $match['matchWrapperLeft'] = ($roundNumber - 1) * ($this->matchWrapperWidth + $this->roundSpacing - 1);
91
                $match['vConnectorLeft'] = floor($match['matchWrapperLeft'] + $this->matchWrapperWidth + ($this->roundSpacing / 2) - ($this->borderWidth / 2));
92
                $match['vConnectorHeight'] = ($spaceFactor * $this->matchSpacing) + ($playerHeightFactor * $this->playerWrapperHeight) + $this->borderWidth;
93
                $match['vConnectorTop'] = $match['hConnectorTop'] = $match['matchWrapperTop'] + $this->playerWrapperHeight;
94
                $match['hConnectorLeft'] = ($match['vConnectorLeft'] - ($this->roundSpacing / 2)) + 2;
95
                $match['hConnector2Left'] = $match['matchWrapperLeft'] + $this->matchWrapperWidth + ($this->roundSpacing / 2);
96
97
                //Adjust the positions depending on the match number
98
99
                if (!($matchNumber % 2)) {
100
                    $match['hConnector2Top'] = $match['vConnectorTop'] -= ($match['vConnectorHeight'] - $this->borderWidth);
101
                } else {
102
                    $match['hConnector2Top'] = $match['vConnectorTop'] + ($match['vConnectorHeight'] - $this->borderWidth);
103
                }
104
105
            }
106
107
            //Update the spacing variables
108
109
            $spaceFactor *= 2;
110
            $playerHeightFactor *= 2;
111
112
        }
113
114
    }
115
116
    /**
117
     * Print Round Titles
118
     */
119
    public function printRoundTitles()
120
    {
121
122
        if ($this->numFighters == 2) {
123
124
            $roundTitles = array('Final');
125
126
        } elseif ($this->numFighters <= 4) {
127
128
            $roundTitles = array('Semi-Finals', 'Final');
129
130
        } elseif ($this->numFighters <= 8) {
131
132
            $roundTitles = array('Quarter-Finals', 'Semi-Finals', 'Final');
133
134
        } else {
135
136
            $roundTitles = array('Quarter-Finals', 'Semi-Finals', 'Final');
137
            $noRounds = ceil(log($this->numFighters, 2));
138
            $noTeamsInFirstRound = pow(2, ceil(log($this->numFighters) / log(2)));
139
            $tempRounds = array();
140
141
            //The minus 3 is to ignore the final, semi final and quarter final rounds
142
143
            for ($i = 0; $i < $noRounds - 3; $i++) {
144
                $tempRounds[] = 'Last ' . $noTeamsInFirstRound;
145
                $noTeamsInFirstRound /= 2;
146
            }
147
148
            $roundTitles = array_merge($tempRounds, $roundTitles);
149
150
        }
151
152
        echo '<div id="round-titles-wrapper">';
153
154
        foreach ($roundTitles as $key => $roundTitle) {
155
156
            $left = $key * ($this->matchWrapperWidth + $this->roundSpacing - 1);
157
158
            echo '<div class="round-title" style="left: ' . $left . 'px;">' . $roundTitle . '</div>';
159
160
        }
161
162
        echo '</div>';
163
164
    }
165
166
    /**
167
     * @param $selected
168
     * @return string
169
     */
170
    public function getPlayerList($selected)
171
    {
172
173
        $html = '<select>
174
                <option' . ($selected == '' ? ' selected' : '') . '></option>';
175
176
        foreach ($this->championship->fighters as $fighter) {
177
            $html = $this->addOptionToSelect($selected, $fighter, $html);
178
        }
179
180
        $html .= '</select>';
181
182
        return $html;
183
184
    }
185
186
    public function getNewFighter()
187
    {
188
        if ($this->championship->category->isTeam()) {
189
            return new Team;
190
        }
191
        return new Competitor;
192
    }
193
194
    /**
195
     * @param $numRound
196
     */
197
    private function assignFightersToBracket($numRound, $hasPreliminary)
198
    {
199
        //TODO When Preliminary, we get a problem : Round 2 to 2, or get rounNumber = 1, and fails
200
        for ($roundNumber = $numRound; $roundNumber <= $this->noRounds; $roundNumber++) {
201
            $groupsByRound = $this->groupsByRound->get($roundNumber + $hasPreliminary);
202
            for ($matchNumber = 1; $matchNumber <= ($this->numFighters / pow(2, $roundNumber)); $matchNumber++) {
203
                $fight = $groupsByRound[$matchNumber - 1]->fights[0];
204
205
                if ($this->championship->category->isTeam()) {
206
                    $fighter1 = $fight->team1;
207
                    $fighter2 = $fight->team2;
208
209
                } else {
210
                    $fighter1 = $fight->competitor1;
211
                    $fighter2 = $fight->competitor2;
212
                }
213
                $this->brackets[$roundNumber][$matchNumber] = [$fighter1, $fighter2];
214
            }
215
        }
216
    }
217
218
    /**
219
     * @param $selected
220
     * @param $fighter
221
     * @param $html
222
     * @return string
223
     */
224
    private function addOptionToSelect($selected, $fighter, $html): string
225
    {
226
        if ($fighter != null) {
227
            $select = $selected != null && $selected->id == $fighter->id ? ' selected' : '';
228
            $html .= '<option' . $select
229
                . ' value='
230
                . ($fighter->id ?? '')
231
                . '>'
232
                . $fighter->name
233
                . '</option>';
234
235
        }
236
        return $html;
237
    }
238
}
239