1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetNonAvailablePool.php';
5/**
6 * @author		Björn Heyser <bheyser@databay.de>
7 * @version		$Id$
8 *
9 * @package		Modules/Test
10 */
11class ilTestRandomQuestionSetSourcePoolDefinitionList implements Iterator
12{
13    /**
14     * global $ilDB object instance
15     *
16     * @var ilDBInterface
17     */
18    protected $db = null;
19
20    /**
21     * object instance of current test
22     *
23     * @var ilObjTest
24     */
25    protected $testOBJ = null;
26
27    /**
28     * @var ilTestRandomQuestionSetSourcePoolDefinition[]
29     */
30    private $sourcePoolDefinitions = array();
31
32    /**
33     * @var ilTestRandomQuestionSetSourcePoolDefinitionFactory
34     */
35    private $sourcePoolDefinitionFactory = null;
36
37    /**
38     * @var array
39     */
40    protected $lostPools = array();
41
42    /**
43     * @var array
44     */
45    protected $trashedPools = array();
46
47    /**
48     * Constructor
49     *
50     * @param ilDBInterface $db
51     * @param ilObjTest $testOBJ
52     */
53    public function __construct(ilDBInterface $db, ilObjTest $testOBJ, ilTestRandomQuestionSetSourcePoolDefinitionFactory $sourcePoolDefinitionFactory)
54    {
55        $this->db = $db;
56        $this->testOBJ = $testOBJ;
57        $this->sourcePoolDefinitionFactory = $sourcePoolDefinitionFactory;
58    }
59
60    public function addDefinition(ilTestRandomQuestionSetSourcePoolDefinition $sourcePoolDefinition)
61    {
62        $this->sourcePoolDefinitions[ $sourcePoolDefinition->getId() ] = $sourcePoolDefinition;
63    }
64
65    protected function addLostPool(ilTestRandomQuestionSetNonAvailablePool $lostPool)
66    {
67        $this->lostPools[$lostPool->getId()] = $lostPool;
68    }
69
70    public function isLostPool($poolId)
71    {
72        return isset($this->lostPools[$poolId]);
73    }
74
75    public function hasLostPool()
76    {
77        return (bool) count($this->lostPools);
78    }
79
80    public function getLostPools()
81    {
82        return $this->lostPools;
83    }
84
85    public function getLostPool($poolId)
86    {
87        if ($this->isLostPool($poolId)) {
88            return $this->lostPools[$poolId];
89        }
90
91        return null;
92    }
93
94    public function isTrashedPool($poolId)
95    {
96        return isset($this->trashedPools[$poolId]);
97    }
98
99    public function hasTrashedPool()
100    {
101        return (bool) count($this->trashedPools);
102    }
103
104    /**
105     * @return array
106     */
107    public function getTrashedPools()
108    {
109        return $this->trashedPools;
110    }
111
112    /**
113     * @param array $trashedPools
114     */
115    public function setTrashedPools($trashedPools)
116    {
117        $this->trashedPools = $trashedPools;
118    }
119
120    // hey: fixRandomTestBuildable - provide single definitions, quantities distribution likes to deal with objects
121
122    public function hasDefinition($sourcePoolDefinitionId)
123    {
124        return $this->getDefinition($sourcePoolDefinitionId) !== null;
125    }
126
127    public function getDefinition($sourcePoolDefinitionId)
128    {
129        if (isset($this->sourcePoolDefinitions[$sourcePoolDefinitionId])) {
130            return $this->sourcePoolDefinitions[$sourcePoolDefinitionId];
131        }
132
133        return null;
134    }
135
136    public function getDefinitionBySourcePoolId($sourcePoolId)
137    {
138        foreach ($this as $definition) {
139            if ($definition->getPoolId() != $sourcePoolId) {
140                continue;
141            }
142
143            return $definition;
144        }
145
146        throw new InvalidArgumentException('invalid source pool id given');
147    }
148
149    public function getDefinitionIds()
150    {
151        return array_keys($this->sourcePoolDefinitions);
152    }
153
154    public function getDefinitionCount()
155    {
156        return count($this->sourcePoolDefinitions);
157    }
158    // hey.
159
160    public function loadDefinitions()
161    {
162        $query = "
163			SELECT tst_rnd_quest_set_qpls.*, odat.obj_id pool_id, tree.child
164			FROM tst_rnd_quest_set_qpls
165			LEFT JOIN object_data odat
166			ON odat.obj_id = pool_fi
167			LEFT JOIN object_reference oref
168			ON oref.obj_id = pool_fi
169			LEFT JOIN tree
170			ON tree = %s
171			AND child = oref.ref_id
172			WHERE test_fi = %s
173			ORDER BY sequence_pos ASC
174		";
175
176        $res = $this->db->queryF($query, array('integer', 'integer'), array(1, $this->testOBJ->getTestId()));
177
178        $handledDefinitions = array();
179        $trashedPools = array();
180
181        while ($row = $this->db->fetchAssoc($res)) {
182            $sourcePoolDefinition = $this->sourcePoolDefinitionFactory->getEmptySourcePoolDefinition();
183            $sourcePoolDefinition->initFromArray($row);
184
185            if (!isset($handledDefinitions[$sourcePoolDefinition->getId()])) {
186                $this->addDefinition($sourcePoolDefinition);
187                $handledDefinitions[$sourcePoolDefinition->getId()] = $sourcePoolDefinition->getId();
188
189                $trashedPool = new ilTestRandomQuestionSetNonAvailablePool();
190                $trashedPool->assignDbRow($row);
191
192                $trashedPool->setUnavailabilityStatus(
193                    ilTestRandomQuestionSetNonAvailablePool::UNAVAILABILITY_STATUS_TRASHED
194                );
195
196                $trashedPools[$trashedPool->getId()] = $trashedPool;
197            }
198
199            if (!$this->isLostPool($row['pool_id'])) {
200                if (!$row['pool_id']) {
201                    $lostPool = new ilTestRandomQuestionSetNonAvailablePool();
202                    $lostPool->assignDbRow($row);
203
204                    $lostPool->setUnavailabilityStatus(
205                        ilTestRandomQuestionSetNonAvailablePool::UNAVAILABILITY_STATUS_LOST
206                    );
207
208                    $this->addLostPool($lostPool);
209
210                    if (isset($trashedPools[$lostPool->getId()])) {
211                        unset($trashedPools[$lostPool->getId()]);
212                    }
213                }
214            }
215
216            if ($row['child']) {
217                unset($trashedPools[$row['pool_id']]);
218            }
219        }
220
221        $this->setTrashedPools($trashedPools);
222    }
223
224    public function saveDefinitions()
225    {
226        foreach ($this as $sourcePoolDefinition) {
227            /** @var ilTestRandomQuestionSetSourcePoolDefinition $definition */
228            $sourcePoolDefinition->saveToDb();
229        }
230    }
231
232    public function cloneDefinitionsForTestId($testId)
233    {
234        $definitionIdMap = array();
235
236        foreach ($this as $definition) {
237            /** @var ilTestRandomQuestionSetSourcePoolDefinition $definition */
238
239            $originalId = $definition->getId();
240            $definition->cloneToDbForTestId($testId);
241            $cloneId = $definition->getId();
242
243            $definitionIdMap[$originalId] = $cloneId;
244        }
245
246        return $definitionIdMap;
247    }
248
249    public function deleteDefinitions()
250    {
251        $query = "DELETE FROM tst_rnd_quest_set_qpls WHERE test_fi = %s";
252        $this->db->manipulateF($query, array('integer'), array($this->testOBJ->getTestId()));
253    }
254
255    public function reindexPositions()
256    {
257        $positionIndex = array();
258
259        foreach ($this as $definition) {
260            /** @var ilTestRandomQuestionSetSourcePoolDefinition $definition */
261            $positionIndex[ $definition->getId() ] = $definition->getSequencePosition();
262        }
263
264        asort($positionIndex);
265
266        $i = 1;
267
268        foreach ($positionIndex as $definitionId => $definitionPosition) {
269            $positionIndex[$definitionId] = $i++;
270        }
271
272        foreach ($this as $definition) {
273            $definition->setSequencePosition($positionIndex[$definition->getId()]);
274        }
275    }
276
277    public function getNextPosition()
278    {
279        return (count($this->sourcePoolDefinitions) + 1);
280    }
281
282    public function getInvolvedSourcePoolIds()
283    {
284        $involvedSourcePoolIds = array();
285
286        foreach ($this as $definition) {
287            /** @var ilTestRandomQuestionSetSourcePoolDefinition $definition */
288            $involvedSourcePoolIds[ $definition->getPoolId() ] = $definition->getPoolId();
289        }
290
291        return array_values($involvedSourcePoolIds);
292    }
293
294    public function getQuestionAmount()
295    {
296        $questionAmount = 0;
297
298        foreach ($this as $definition) {
299            /** @var ilTestRandomQuestionSetSourcePoolDefinition $definition */
300            $questionAmount += $definition->getQuestionAmount();
301        }
302
303        return $questionAmount;
304    }
305
306    /**
307     * @return bool
308     */
309    public function savedDefinitionsExist()
310    {
311        $query = "SELECT COUNT(*) cnt FROM tst_rnd_quest_set_qpls WHERE test_fi = %s";
312        $res = $this->db->queryF($query, array('integer'), array($this->testOBJ->getTestId()));
313
314        $row = $this->db->fetchAssoc($res);
315
316        return $row['cnt'] > 0;
317    }
318
319    public function hasTaxonomyFilters()
320    {
321        foreach ($this as $definition) {
322            /** @var ilTestRandomQuestionSetSourcePoolDefinition $definition */
323            // fau: taxFilter/typeFilter - new check for existing taxonomy filter
324            if (count($definition->getMappedTaxonomyFilter())) {
325                return true;
326            }
327            #if( $definition->getMappedFilterTaxId() && $definition->getMappedFilterTaxNodeId() )
328            #{
329            #	return true;
330            #}
331            // fau.
332        }
333
334        return false;
335    }
336
337    // fau: taxFilter/typeFilter - check for existing type filters
338    public function hasTypeFilters()
339    {
340        foreach ($this as $definition) {
341            if (count($definition->getTypeFilter())) {
342                return true;
343            }
344        }
345        return false;
346    }
347    // fau.
348
349    public function areAllUsedPoolsAvailable()
350    {
351        if ($this->hasLostPool()) {
352            return false;
353        }
354
355        if ($this->hasTrashedPool()) {
356            return false;
357        }
358
359        return true;
360    }
361
362    /**
363     * @return ilTestRandomQuestionSetSourcePoolDefinition
364     */
365    public function rewind()
366    {
367        return reset($this->sourcePoolDefinitions);
368    }
369
370    /**
371     * @return ilTestRandomQuestionSetSourcePoolDefinition
372     */
373    public function current()
374    {
375        return current($this->sourcePoolDefinitions);
376    }
377
378    /**
379     * @return integer
380     */
381    public function key()
382    {
383        return key($this->sourcePoolDefinitions);
384    }
385
386    /**
387     * @return ilTestRandomQuestionSetSourcePoolDefinition
388     */
389    public function next()
390    {
391        return next($this->sourcePoolDefinitions);
392    }
393
394    /**
395     * @return boolean
396     */
397    public function valid()
398    {
399        return key($this->sourcePoolDefinitions) !== null;
400    }
401
402    public function getNonAvailablePools()
403    {
404        //echo get_class($this->getTrashedPools()[0]);
405        return array_merge($this->getTrashedPools(), $this->getLostPools());
406    }
407}
408