object QuestionDatabase
	components: Question*;
	operations: Add, Modify, Delete, Import, Export;
	description: 
	(* A question database is an object that contains zero or more records *);
end QuestionDatabase;

object Question
	components: cl:ClassName, l:Length, k:Keywords, w:Week, qs:QuestionString, au:Author, dlu:DateLastUsed, d:Difficulty, an:Answer, dbn:DBNumber;
	description:
	(* A Question has all the generic elements included in a question *);
end Question;

object Answer
description: (* This object encapsulates the True/False, MatchingAnswer, Multiple Choice, Short Answer, Long Answer, Code objects *);
end Answer;

object TrueFalse extends Answer = boolean
description: (* This object contains a boolean that indicates whether the question is true or false *);
end TrueFalse;

object MutliChoice extends Answer
	components: AnswerList, CorrectAnswer;
	description: (* This object contains a list of strings and the correct choice*);
end MultiChoice; 
AnswerList = string*;
CorrectAnswer= string;

object MatchingAnswer extends Answer
	components:AnswerList, CorrectAnswerList;
	description: (* This object contains a list of strings and a list of correct choices *);
end MatchingAnswer;
CorrectAnswerList = string*;

object ShortAnswer extends Answer = string
description: (* This object contains a string of a short answer *);
end ShortAnswer;

object LongAnswer extends Answer = string*
description: (* This object contains strings for the answer and keywords *);
end LongAnswer;

object code extends Answer = string*
description: (* This object contains strings for the answer, stdout, and script output *);
end code;


object IsCorrect = boolean
description: (* This object says whether a question is correct *);
end IsCorrect;

object IsGraded = boolean
description: (* This object tells whether a test is graded *);
end IsGraded;

object ClassName = string
description: (* This object says what class the question is for *);
end ClassName;

object Length = integer
description: (* This object says how long the question should take *);
end Length;

object Keywords = string
description: (* This object contains the keywords related to the question *);
end Keywords;

object Week = integer
description: (* This object says what week the question should be used in *);
end Week;

object QuestionString = string
description: (* This object contains the question string *);
end QuestionString;

object Author = string
description: (* Contains the author computer *);
end AUthor;

object DateLastUsed = integer
description: (* Says when the question was last used *);
end DateLastUsed;

object Difficulty = string
description: (* Tells the difficulty of the problem *);
end Difficulty;

object DBNumber = integer
description: (* Tells what number the question is in the database *);
end DBNumber;

object Points = integer
description: (* Says how many points the question is worth *);
end Points;

object Number = integer
description: (* Tells what number the question is *);
end Number;

object FileName = string
description: (* Says what the file name is *);
end FileName;

object SearchString 
	components:cl:ClassName, l:Length, k:Keywords, w:Week, qs:QuestionString, au:Author, dlu:DateLastUsed, d:Difficulty, an:Answer;
	description: (* This object is used to search for questions *);
end SearchString;

operation Add
	description: (* Adds a question to the question database *);
	inputs: qdb:QuestionDatabase, q:Question;
	outputs: qdb':QuestionDatabase;
	precondition: (q.cl)!=nil and (q.l)!=nil and (q.k)!=nil and (q.w)!=nil and (q.qs)!=nil and (q.au)!=nil and (q.d)!=nil and (q.an)!= nil and (q.dlu)!=nil 
		      and (not ( exists (q' in qdb)q'.qs = q.qs));
	postcondition: forall (q':Question)
		       (q' in qdb;) iff((q' = q) or (q' in qdb));
end;

operation Modify
	description: (* Modfies a question in the question database *);
	inputs: qdb:QuestionDatabase,old_q:Question, new_q:Question;
	outputs: qdb':QuestionDatabase;
	precondition:(old_q != new_q)
			and
		     (old_q in qdb)
			and
		     (not (exists (new_q' in qdb) new_q'.qs = new_q.qs));
	postcondition:forall (q':Question)
			     (q' in qdb') iff(((q' = new_q) or (q' in qdb)) and (q' != old_q));  
end;

operation Delete
	description: (* Removes a question from the question database *);
	inputs: qdb:QuestionDatabase, q:Question;
	outputs: qdb':QuestionDatabase;
	precondition: q in qdb;
	postcondition:(forall (q':Question)
		      (q' in qdb') iff((q' != q) and (q' in qdb))); 
end;

operation Import
	description: (* Imports a question database into the existing database *);
	inputs: qdb:QuestionDatabase, fn:FileName;
	outputs: qdb':QuestionDatabase;
	precondition: qdb != nil and fn != nil;
	postcondition: qdb' != nil;
end;

operation Export
	description: (* Exports the question database to a file *);
	inputs: qdb:QuestionDatabase, fn:FileName;
	outputs: qdb':QuestionDatabase;
	precondition: qdb != nil and fn != nil;
	postcondition: qdb' != nil;
end;

operation Search
	description: (* Searches for questions that match a field the user specifies *); 
	inputs: qdb:QuestionDatabase, ss:SearchString;
	outputs: qdb':QuestionDatabase;
	precondition: (ss!= nil);
	postcondition: (qdb' != nil)iff
	forall (q:Question)
	(ss.cl = q.cl) or (ss.l = q.l) or (ss.k = q.k) or (ss.w = q.w) or (ss.qs = q.qs) or (ss.au = q.au) or (ss.an = q.an) or (ss.dlu = q.dlu) ; 
end;