(****
*
*The following section provides specifications for the 'Q&A' tool.
*
*)

module QandA;

from Roster import RosterDB;
export QuestionLogDB;

object QuestionLogDB is 
	components: pairs:QuestionAnswerPair*;
	operations: AddPair;
	description: (*
		This database is comprised of QuestionLog objects that contain 
		both a question and an answer.  The Question Log is made into an
		HTML file that has the questions and their corresponding answers.  
		There is no RemovePair because the database should not need to have
		any questions removed.
	*); 
end QuestionLogDB;

object QuestionAnswerPair is 
	components: Question and Answer;
	description: (*
		This is the object that holds the question and answer.
	*);
end QuestionLog;

object Question is
	components: content:QuestionContent and id:QuestionID and name:UserName;
	description: (*
		This is the base question object. Content is a string. Synch'ed with 
		answer by ID.  The user name of the person who created the question
		will also be attached to the question.
	*);
end Question;

object QuestionContent is string;

object QuestionID is integer;

object UserName is
	components: StudentRecord.login;
	description: (*
		This user name is extrapolated from RosterDB, which was imported
		from the Roster module.
	)*;
end UserName;

object Answer is
	components: content:AnswerContent and id:AnswerID and date:AnswerDate;
	description: (*
		This is the base answer object. Same components as Question, but
		date is also tracked for tracking in log.
	*);
end Answer;

object AnswerContent is string;

object AnswerDate is string;

object AnswerID is integer;

object QuestionQueue is
	components: quesitons:Question*;
	description: (*
		This queue holds the questions until an answer is either given, 
		or the question is skipped.
	*);
end QuestionQueue;

operation AddPair is
	inputs: logdb:QuestionLogDB and pair:QuestionAnswerPair;
	outputs: logdb':QuestionLogDB;
	preconditions: 
		(* The pair doesn't already exist in the log.*)
		not (exists (pair':QuestionAnswerPair in logdb) 
			pair'.answer.id = pair.answer.id);
	postconditions:
		(*
		 * A QuestionAnswerPair is in the output db if and only if it is 
		 * the new pair to be added or it is in the input db.
		 *)
		forall (pair':QuestionAnswerPair)
			(pair' in logdb') iff ((pair' = pair) or (pair' in logdb));
	description: (*
		Adds the QuestionAnswerPair to the question log db after an 
		question is paired up with an answer in AnsweringQuestion.  
		Until an answer is given to the question, or it is skipped
		the question is a floating object waiting for something to be 
		done to it.
	*);
end AddPair;

operation AnsweringQuestion is
	inputs: queue:QuestionQueue and answer:Answer;
	outputs: pair:QuestionAnswerPair and queue':QuestionQueue;
	preconditions: 
		(* There is actually an answer, and there is a question in the
		 * queue with a matching ID number to the answer.
		 *)
		answer.content != nil

		and

		exists (question:Question in queue)
			question.id = answer.id;
	postconditions:
		(* For all questions in the output queue they are only there if
		 * they were they before and they were not the question that 
		 * matched up with the answer.
		 *)
		forall (question:Question)
			(question in queue') iff ((question in queue) and 
			(question.id != answer.id));
	description: (*
		When an answer is given, a search is done on the question queue 
		until the answer.id and a question.id match.  This is then created
		into a pair.  This question is then removed from the queue.
	*);
end AnsweringQuestion;

operation AddToQueue is
	inputs: queue:QuestionQueue and question:Question;
	outputs: queue':QuestionQueue;
	preconditions:
		(* The question isn't already in the queue and the question
		 * isn't blank.
		 *)
		question.content != nil 

		and 

		not (exists (question':Question in queue) question'.id = question.id);
	postconditions:
		question in queue';	
	description: (*
		This operation adds a newly created question to the queue until
		it can be answered.
	*);
end AddToQueue;
		
operation RemoveFromQueue is
	inputs: queue:QuestionQueue and question:Question;
	outputs: queue':QuestionQueue;
	preconditions:
		(* The queue must have something to remove from it.*)
		queue != nil;
	postconditions:
		(*
		 * Questions in output queue had to have been in the input queue 
		 * and not the input question.
		 *)
		forall (question':Question)
			(question' in queue') iff ((quesiton' in queue) and 
			(question' != question));
	description: (*
		This operation removes questions from the queue.
	*);
end RemoveFromQueue;

end QandA;