/**
 * Copyright 2017 University of Victoria
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
package com.rigiresearch.examgen.model;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;

/**
 * A written examination.
 * @author Miguel Jimenez (miguel@uvic.ca)
 * @date 2017-08-20
 * @version $Id$
 * @since 0.0.1
 */
@Accessors(fluent = true)
@Getter
@RequiredArgsConstructor
public final class Examination {

    /**
     * Parameters regarding this exam.
     * Parameters related to the course can be removed if course is modeled as
     * a separate entity.
     * @author Miguel Jimenez (miguel@uvic.ca)
     * @date 2017-08-21
     * @version $Id$
     * @since 0.0.1
     */
    public enum Parameter {
        /**
         * The course to which this exam belongs.
         */
        COURSE,

        /**
         * The course identifier.
         */
        COURSE_REFERENCE_NUMBER,

        /**
         * The expected date in which this exam takes place.
         */
        DATE,

        /**
         * The course instructors.
         */
        INSTRUCTORS,

        /**
         * The specific course sections (a list), if any.
         */
        SECTIONS,

        /**
         * The corresponding term.
         */
        TERM,

        /**
         * The time allocated to this exam.
         */
        TIME_LIMIT,

        /**
         * This exam's title.
         */
        TITLE,
    }

    /**
     * Parameters composing the document header. Values are expected.
     */
    private final Map<Parameter, Object> parameters;

    /**
     * Optional instructions.
     */
    private TextSegment instructions = new TextSegment.Simple("");

    /**
     * This exam's set of questions.
     */
    private final List<Question> questions;

    /**
     * Instantiates an exam setting the instructions field.
     * @param parameters parameters composing the document header
     * @param instructions optional exam instructions
     * @param questions this exam's set of questions
     */
    public Examination(final Map<Parameter, Object> parameters,
        final TextSegment instructions,
        final List<Question> questions) {
        this(parameters, questions);
        this.instructions = instructions;
    }

    /**
     * Scramble this exam.
     * @param seed the seed for the random number generator
     * @return a scrambled version of this exam
     */
    public Examination scrambled(final long seed) {
        final List<Question> scrambledQuestions = this.questions.stream()
            .map(question -> question.scrambled(seed))
            .collect(Collectors.toList());
        Collections.shuffle(
            scrambledQuestions,
            new Random(seed)
        );
        return new Examination(
            this.parameters,
            this.instructions,
            scrambledQuestions
        );
    }

}

@@ -1178,27 +1178,81 @@
 va.util.
-Collections
+ArrayList;%0Aimport java.util.Collections;%0Aimport java.util.HashMap
 ;%0Aimport
@@ -4128,10 +4128,1290 @@
 %0A    %7D%0A%0A
+    public List%3CExamination%3E variants(final long seed,%0A        final int questionsLimit) throws Exception %7B%0A        final List%3CExamination%3E quizzes = new ArrayList%3C%3E();%0A        @SuppressWarnings(%22unchecked%22)%0A        final List%3CString%3E sections =%0A            (List%3CString%3E) this.parameters.get(Parameter.SECTIONS);%0A        long _seed = seed;%0A        for (int i = 0; i %3C sections.size(); i++) %7B%0A            parameters.put(Parameter.SECTIONS, sections.get(i));%0A            quizzes.add(%0A                new Examination(%0A                    new HashMap%3C%3E(parameters),%0A                    this.randomisedQuestions(_seed, questionsLimit)%0A                ).scrambled(_seed)%0A            );%0A            // Use consecutive to randomize results & still control the output%0A            _seed++;%0A        %7D%0A        return quizzes;%0A    %7D%0A%0A    private List%3CQuestion%3E randomisedQuestions(final long seed,%0A        final int questionsLimit) throws Exception %7B%0A        if (this.questions.size() %3C questionsLimit)%0A            throw new IllegalArgumentException(%22questions limit %3E questions%22);%0A        final List%3CQuestion%3E copy = new ArrayList%3C%3E(this.questions);%0A        Collections.shuffle(%0A            copy,%0A            new Random(seed)%0A        );%0A        return copy.subList(0, questionsLimit);%0A    %7D%0A
 %7D%0A

Add methods to generate exam variants based on sections