1<?php
2
3declare(strict_types=1);
4
5use ILIAS\KioskMode\ControlBuilder;
6use ILIAS\KioskMode\LocatorBuilder;
7use ILIAS\KioskMode\TOCBuilder;
8use ILIAS\KioskMode\URLBuilder;
9
10use ILIAS\UI\Factory;
11
12/**
13 * Class LSControlBuilder
14 */
15class LSControlBuilder implements ControlBuilder
16{
17    const CMD_START_OBJECT = 'start_legacy_obj';
18    const CMD_CHECK_CURRENT_ITEM_LP = 'ccilp';
19
20    /**
21     * @var Component|null
22     */
23    protected $exit_control;
24
25    /**
26     * @var Component|null
27     */
28    protected $previous_control;
29
30    /**
31     * @var Component|null
32     */
33    protected $next_control;
34
35    /**
36     * @var Component|null
37     */
38    protected $done_control;
39
40    /**
41     * @var Component[]
42     */
43    protected $controls = [];
44
45    /**
46     * @var Component[]
47     */
48    protected $toggles = [];
49
50    /**
51     * @var Component[]
52     */
53    protected $mode_controls = [];
54
55    /**
56     * @var TOCBuilder|null
57     */
58    protected $toc;
59
60    /**
61     * @var LocatorBuilder|null
62     */
63    protected $loc;
64
65    /**
66     * @var Factory
67     */
68    protected $ui_factory;
69
70    /**
71     * @var URLBuilder
72     */
73    protected $url_builder;
74
75    /**
76     * @var Component|null
77     */
78    protected $start;
79
80    /**
81     * @var string | null
82     */
83    protected $additional_js;
84
85    /**
86     * @var LSGlobalSettings
87     */
88    protected $global_settings;
89
90    public function __construct(
91        Factory $ui_factory,
92        LSURLBuilder $url_builder,
93        ilLanguage $language,
94        LSGlobalSettings $global_settings
95    ) {
96        $this->ui_factory = $ui_factory;
97        $this->url_builder = $url_builder;
98        $this->lng = $language;
99        $this->global_settings = $global_settings;
100    }
101
102    public function getExitControl()
103    {
104        return $this->exit_control;
105    }
106
107    public function getPreviousControl()
108    {
109        return $this->previous_control;
110    }
111
112    public function getNextControl()
113    {
114        return $this->next_control;
115    }
116
117    public function getDoneControl()
118    {
119        return $this->done_control;
120    }
121
122    public function getToggles()
123    {
124        return $this->toggles;
125    }
126
127    public function getModeControls()
128    {
129        return $this->mode_controls;
130    }
131
132    public function getControls() : array
133    {
134        return $this->controls;
135    }
136
137    public function getLocator()
138    {
139        return $this->loc;
140    }
141
142    public function getToc()
143    {
144        return $this->toc;
145    }
146
147    /**
148     * @inheritdoc
149     */
150    public function exit(string $command) : ControlBuilder
151    {
152        if ($this->exit_control) {
153            throw new \LogicException("Only one exit-control per view...", 1);
154        }
155        $cmd = $this->url_builder->getHref($command);
156
157        $label = 'lso_player_suspend';
158        if ($command === ilLSPlayer::LSO_CMD_FINISH) {
159            $label = 'lso_player_finish';
160        }
161
162        $exit_button = $this->ui_factory->button()->bulky(
163            $this->ui_factory->symbol()->glyph()->close(),
164            $this->lng->txt($label),
165            $cmd
166        );
167
168        $this->exit_control = $exit_button;
169        return $this;
170    }
171
172    /**
173     * @inheritdoc
174     */
175    public function next(string $command, int $parameter = null) : ControlBuilder
176    {
177        if ($this->next_control) {
178            throw new \LogicException("Only one next-control per view...", 1);
179        }
180        $label = $this->lng->txt('lso_player_next');
181        $cmd = $this->url_builder->getHref($command, $parameter);
182        $btn = $this->ui_factory->button()->standard($label, $cmd);
183        if ($command === '') {
184            $btn = $btn->withUnavailableAction();
185        }
186        $this->next_control = $btn;
187        return $this;
188    }
189
190    /**
191     * @inheritdoc
192     */
193    public function previous(string $command, int $parameter = null) : ControlBuilder
194    {
195        if ($this->previous_control) {
196            throw new \LogicException("Only one previous-control per view...", 1);
197        }
198        $label = $this->lng->txt('lso_player_previous');
199        $cmd = $this->url_builder->getHref($command, $parameter);
200        $btn = $this->ui_factory->button()->standard($label, $cmd);
201        if ($command === '') {
202            $btn = $btn->withUnavailableAction();
203        }
204        $this->previous_control = $btn;
205        return $this;
206    }
207
208    /**
209     * @inheritdoc
210     */
211    public function done(string $command, int $parameter = null) : ControlBuilder
212    {
213        if ($this->done_control) {
214            throw new \LogicException("Only one done-control per view...", 1);
215        }
216        $label = $this->lng->txt('lso_player_done');
217        $cmd = $this->url_builder->getHref($command, $parameter);
218        $btn = $this->ui_factory->button()->primary($label, $cmd);
219        $this->done_control = $btn;
220        return $this;
221    }
222
223    /**
224     * @inheritdoc
225     */
226    public function generic(string $label, string $command, int $parameter = null) : ControlBuilder
227    {
228        $cmd = $this->url_builder->getHref($command, $parameter);
229        $this->controls[] = $this->ui_factory->button()->standard($label, $cmd);
230        return $this;
231    }
232
233    /**
234     * A toggle can be used to switch some behaviour in the view on or of.
235     */
236    public function toggle(string $label, string $on_command, string $off_command) : ControlBuilder
237    {
238        throw new \Exception("NYI: Toggles", 1);
239
240        $cmd_on = $this->url_builder->getHref($on_command, 0);
241        $cmd_off = $this->url_builder->getHref($off_command, 0);
242        //build toggle and add to $this->toggles
243        //return $this;
244    }
245
246    /**
247     * @inheritdoc
248     */
249    public function mode(string $command, array $labels) : ControlBuilder
250    {
251        $actions = [];
252        foreach ($labels as $parameter => $label) {
253            $actions[$label] = $this->url_builder->getHref($command, $parameter);
254        }
255        $this->mode_controls[] = $this->ui_factory->viewControl()->mode($actions, '');
256        return $this;
257    }
258
259    /**
260     * @inheritdoc
261     */
262    public function locator(string $command) : LocatorBuilder
263    {
264        if ($this->loc) {
265            throw new \LogicException("Only one locator per view...", 1);
266        }
267        $this->loc = new LSLocatorBuilder($command, $this);
268        return $this->loc;
269    }
270
271    /**
272     * @inheritdoc
273     */
274    public function tableOfContent(
275        string $label,
276        string $command,
277        int $parameter = null,
278        $state = null
279    ) : TOCBuilder {
280        if ($this->toc) {
281            throw new \LogicException("Only one ToC per view...", 1);
282        }
283        $this->toc = new LSTOCBuilder($this, $command, $label, $parameter, $state);
284        return $this->toc;
285    }
286
287    /**
288     * Add a "start"-button as primary.
289     * This is NOT regular behavior, but a special feature for the LegacyView
290     * of LearningSequence's sub-objects that do not implement a KioskModeView.
291     *
292     * The start-control is exclusively used to open an ILIAS-Object in a new windwow/tab.
293     */
294    public function start(string $label, string $url, int $parameter = null) : ControlBuilder
295    {
296        if ($this->start) {
297            throw new \LogicException("Only one start-control per view...", 1);
298        }
299        $this_cmd = $this->url_builder->getHref(self::CMD_START_OBJECT, $parameter);
300        $lp_cmd = str_replace(
301            '&cmd=view&',
302            '&cmd=' . self::CMD_CHECK_CURRENT_ITEM_LP . '&',
303            $this_cmd
304        );
305
306        $this->setListenerJS($lp_cmd, $this_cmd);
307        $this->start = $this->ui_factory->button()
308            ->primary($label, '')
309            ->withOnLoadCode(function ($id) use ($url) {
310                $interval = $this->global_settings->getPollingIntervalMilliseconds();
311                return "$('#{$id}').on('click', function(ev) {
312					var il_ls_win = window.open('$url');
313					window._lso_current_item_lp = -1;
314					window.setInterval(lso_checkLPOfObject, $interval);
315				})";
316            });
317
318        return $this;
319    }
320
321    public function getStartControl()
322    {
323        return $this->start;
324    }
325
326    public function getAdditionalJS() : string
327    {
328        return $this->additional_js;
329    }
330
331    protected function setListenerJS(
332        string $check_lp_url,
333        string $on_lp_change_url
334    ) {
335        $this->additional_js =
336<<<JS
337function lso_checkLPOfObject()
338{
339    if(! il.UICore.isPageVisible()) {
340        return;
341    }
342
343	$.ajax({
344		url: "$check_lp_url",
345	}).done(function(data) {
346		if(window._lso_current_item_lp === -1) {
347			window._lso_current_item_lp = data;
348		}
349		if (window._lso_current_item_lp !== data) {
350			location.replace('$on_lp_change_url');
351		}
352	});
353}
354JS;
355    }
356}
357