package testtool.teacher_app.question_view;

import java.lang.*;
import java.util.*;

import testtool.component.question.Question;

/**
 * A QuestionBank consists of a collection of questions created by the user.
 * The QuestionBank provides options to manage a single question
 * as well as to manage the collection of questions shown.
 */
public abstract class QuestionBank {
   /**
    * The collection of questions created by the user and
    * stored in the database.
    */
   private Collection<Question> questions;

   /**
    * A collection of questions viewable by the user.
    * The user can view all available questions by
    * clicking on the “Question” button from the Start menu.
    * The QuestionBank may not show all available questions
    * in the case of an advanced manual test generation.
    */
   private Collection<Question> shownQuestions;

 /**
     * Add the given Question to the given QuestionBank.  The ID of the given
     * question must not be the same as a question already in the QuestionBank.
     * The ID component is required.
     */
    /*@
      requires
        //
        // There is no question in the input QuestionBank with the same id as the
        // question to be added.
        //
        (! (\exists Question q_other ;
                questions.contains(q_other) ;
                    (q_other.getID()) == (q.getID())));

        //    &&

        //
        // The id of the given question is not empty.
        //
        //(q.id != null);

      ensures
        //
        // A question is in the output data if and only if it is the new
        // question to be added or it is in the input data.
        //
        (\forall Question q_other ;
            (questions.contains(q_other)) <==>
                q_other.equals(q) || \old(questions).contains(q_other));
     @*/
    abstract void add(Question q);
   
   /**
    * Delete the given question from the given QuestionBank.  The given question
    * must already be in the input QuestionBank.  Typically the user runs the Find
    * Question by ID operation prior to Delete to locate an existing question to delete.
    */
   /*@
      requires
         (* //
         // The question being deleted must exist in the Question Bank.
         //
         // (questions.contains(q));
         *);
  
      ensures
         (* //The question is removed from the Question Bank.
         //
         (\forall Question q_other ;
            questions.contains(q_other) <==>
                !q_other.equals(q) && \old(questions).contains(q_other));
         *);
     
     @*/ 
   public abstract void delete(Question q);

    /**
     * Change the given old Question to the given new question.  The old and
     * new questions must not be the same.  The old question must already be in
     * the input db.  The new question must meet the same conditions as for the
     * input to the Add Question operation.  Typically the user runs the Find Question
     * by ID operation prior to Change to locate an existing question to be changed.
     *
     * If the question ID is changed, then change all occurrences of the
     * old id in the group db to the new id.
     */
    /*@
      requires
        //
        // The old and new questions are not the same.
        //
        // !old_q.equals(new_q);

        // &&   

        //
        // The old question is in this.questions.
        // 
        // questions.contains(old_q);

        //    &&

        //
        // There is no question in the input QuestionBank with the same ID as the
        // new question to be added.
        //
        (! (\exists Question q_other ;
                questions.contains(q_other) ;
                    (q_other.getID()) == (new_q.getID())));

        //    &&

        //
        // The id of the new question is not empty.
        //
        //(new_q.ID != null);

      ensures
        //
        // A question is in the output data if and only if it is the new
        // question to be added or it is in the input data, and it is not the old
        // question.
        //
        (\forall Question q_other ;
            questions.contains(q_other) <==>
                q_other.equals(new_q) ||
                    (\old(questions).contains(q_other) &&
                        !q_other.equals(old_q)));
        //    &&

        //
        // If new ID is different than old ID, then all occurrences of old ID
        // in the QuestionBank are replaced by new ID.
        //
        // !old_q.ID.equals(new_q.ID) ==>
        //    old_q.ID.equals(new_q.ID);
      @*/
    abstract void edit(Question old_q, Question new_q);

   /**
     * Preview the given question from the given QuestionBank.  The given question
     * must already be in the input QuestionBank.  Typically the user runs the Find
     * Question by ID operation prior to Preview to locate an existing question to preview.
     */
     /*@
      requires
        //
        // The given question is in this.questions.
        //
        questions.contains(q);
      @*/
    abstract void preview(Question q);

    /**
     * Find a question by unique id.
     */
    /*@
      ensures
        //
        // If there is a question with the given ID in the input data, then the
        // output question is equal to that question, otherwise the output question
        // is null.
        //
        (\exists Question q_found ; questions.contains(q_found) ;
                q_found.getID() == (ID) && q_found.equals(\result));

        //    ||

        // !(\exists Question q_found ; questions.contains(q_found) ;
        //        q_found.id.equals(ID)) && \result == null;

     @*/
    abstract Question filterById(int ID);

   /**
    * Sorts questions per column based on flags.
    */
   /*@
     requires
       //
       // Active flags.
       //
       // ((AUTHOR || TYPE || POINTS || TIME || DIFFICULTY 
       //    || HAS_IMAGE || MODIFIED || LAST_USED) == true);
      (* *);
      ensures
        //
        // The question columns to be sorted accordingly by the 
        // active flags.
         (* *);
     @*/
   public abstract void sort(SortFlag flag);

   /** 
    * The QuestionFilter class contains a collection of data fields
    * that can be filled and applied by the professor in order
    * to omit seeing certain questions in the QuestionBank.
    */
   private abstract class QuestionFilter {
      /**
       * The collection of authors that created questions in the Question
       * Bank.
       */
      private List<String> authors;
      /**
       * The collection of all question types in the Question Bank.
       */
      private List<Question.QuestionType> types;
      /**
       * A collection of the keywords used to describe individual
       * questions in the Question Bank.
       */
      private List<String> keywords;
      /**
       * The minimum point value of questions to show in the 
       * Question Bank.
       */
      private int minPoint;
      /**
       * The maximum point value of questions to show in the
       * Question Bank.
       */
      private int maxPoint;
      /**
       * The minimum time value of questions to show in the
       * Question Bank.
       */
      private int minTime;
      /**
       * The maximum time value of questions to show in the 
       * Question Bank.
       */
      private int maxTime;

      /**
       * The mimimum difficulty value of questions to show
       * in the Question Bank.
       */
      private int minDifficulty;
      /**
       * The maximum difficulty value of questions to show
       * in the Question Bank.
       */
      private int maxDifficulty;
      /**
       * The Calendar that was last used by the professor.
       */
      private Calendar lastUsed;
   }
   
/**
 * The flags used to sort the Question Bank columns.
 */
   private enum SortFlag {
      AUTHOR, TYPE, POINTS, TIME, DIFFICULTY, HAS_IMAGE, MODIFIED, LAST_USED
   }
}