module LectureDB;

(****
* The core object of the Eclass application is a Lecture, which is modeled as a series of slides. 
* Slides are comprised of HTML and EclassML tag blocks with start and end indexes within the 
* XHTML source file for the Lecture. The Lecture is also represented internally as three different 
* pools of tag blocks for the purposes of filtering. They are the SourcePool (complete source), 
* OutlineVisibles (Outline version) and SlideVisibles (Slide version). The UserWorkSpace object
* ties together objects from various modules making them easily accesible to File and Edit operations.
*)


from View import PublicLayer, PrivateLayer;
from roster_specs import RosterDB; 
from QandA_specs import QuestionLogDB;
from Tools import PostItLog;
from StudentVersion import Notepad;
from file import File;

export CurrentSlide, EclassML, EndIndex, EndPosition, GlobalSlideSetup, LastClicked, Lecture, 
MaxSize, NumberOfSlides, OutlineVisibles, PreviousState, Scrollable, Source, Slide, SlideNumber, 
SlideName, SequenceBlock, SequenceItemBlock, SlideBreak, Size, SourcePool, SlideVisibles, StartIndex, 
SlideData, SlideSetup, UserWorkSpace, HTML, TitleBlock, ParagraphBlock, LineBreak, IndentBlock, 
Heading1Block, Heading2Block, Heading3Block, Heading4Block, Heading5Block, Heading6Block, 
UnorderedListBlock, OrderedListBlock, DefinitionListBlock, ListItemBlock, EmphasisBlock, ItalicsBlock, 
UnderlineBlock, ImageBlock, EclassML, SlideTitle, HideBlock, ReplaceBlock, SubstitutionBlock, SelectBlock,
StartIndex, EndIndex, StartTag, EndTag, StartPosition, EndPosition;


object Lectures is LectureFileName*;


object LectureFileName is string;


object RequiresSaving is boolean
  	description: (* The Source file requires saving whenever XHTML tags are inserted or text is
  			added or deleted in the Outline window. *);
end RequiresSaving;


object Source is 
	components: text:string and file:File and requires_saving:RequiresSaving;
	description: (* The Source is a long character string containing the entire XHTML source for 
			the Lecture. It contains all the tag blocks that make up the SourcePool but it 
			must be saved as a separate file from the Lecture so the instructor can edit it 
			manually. *);
end Source;


object Lecture is
     components:  slides:Slide* and myCurrentPosition:CurrentSlide and clsCurrentPosition:CurrentSlide 
     		  and total:NumberOfSlides and and source:Source and sourcePool:SourcePool and 
     		  outlineVisibles:OutlineVisibles and slideVisibles:SlideVisibles and
     		  setup:GlobalSlideSetup;
     description: (* The object lecture is composed of Slide objects and a slide marker for individual 
     		     students called myCurrentPosition and another marker for the class set by the 
     		     instructor called clsCurrentPosition and an integer storing the total number of 
     		     slides in this lecture. It also contains the XHTML source for the Lecture and
     		     the three tag block pools which represent what tag blocks are visible in the
     		     Source file, Outline window and Slides window. *);
end Lecture;


object CurrentSlide is integer;
object NumberOfSlides is integer;


object Slide is
     components: data:SlideData and number:SlideNumber and name:SlideName;
     description: (* Each slide consists of its own data, number, and title. *);
end Slide;


object SlideNumber is integer;
object SlideName is string;
object SlideDefaultName is string;


object SlideData is
     components: startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and 
     		 endPos:EndPosition and maxPos:EndPosition and size:Size and slideSetup:SlideSetup;
     description: (* Each slide can contain data in the form of HTML or EclassML. A slide's data is 
     		     part of a long master string of characters containing the entire XHTML source for 
     		     the Lecture. StartIndex and endIndex are indexes within that string denoting where 
     		     a slide's XHTML data begins and ends. A slide's data must also be represented 
     		     graphically in the Slides window. For the purposes of this model the graphical 
     		     representation of the Lecture within the Slides window is treated as one giant
     		     mapped display or scrolling grid with a fixed number of columns and a fixed
     		     row height. This simplification makes it easy to deal with screen geography 
     		     inside the slides window. StartPos and endPos are indexes within the display map 
     		     denoting where a slide's graphical representation begins and ends. Size can be 
     		     derived by subtracting startPos from endPos. maxPos is the highest endPos a 
     		     slide can handle. It is equivalent to startPos plus the slideSetup's maxSize. *);
end SlideData;


object StartIndex is integer;
object EndIndex is integer;
object StartPosition is integer;
object EndPosition is integer;
object Size is integer;


object UserWorkSpace is
     components: lect:Lecture and private:PrivateLayer and public:PublicLayer and prev_state:PreviousState 
     		 and clipboard:Clipboard and selection:Selection and context:SelectionContext and 
     		 postIts:PostItLog or roster:RosterDB or qanda:QuestionLogDB or notePad:Notepad;
     description: (* Every users workspace contains the Lecture, PublicLayer, PrivateLayer, PreviousState, 
                     Clipboard, Selection and SelectionContext. Additionally, instructors get the QandA 
                     and Roster and students get their own NotePad. *);
end UserWorkSpace;


object PreviousState is
     components: PrivateLayer or PublicLayer;
     description: (* PreviousState is the snapshot of the space that the user last worked 
                     on. It could be the private layer or the public layer. *);
end PreviousState;


object HTML is
	components: titleBlocks:TitleBlock* or pBlocks:ParagraphBlock* or lineBreaks:LineBreak* 
		    or bqBlocks:IndentBlock* or h1Blocks:Heading1Block* or h2Blocks:Heading2Block* 
		    or h3Blocks:Heading3Block* or h4Blocks:Heading4Block* or h5Blocks:Heading5Block* 
		    or h6Blocks:Heading6Block* or ulBlocks:UnorderedListBlock* 
		    or olBlocks:OrderedListBlock* or dlBlocks:DefinitionListBlock* 
		    or liBlocks:ListItemBlock* or emBlocks:EmphasisBlock* or iBlocks:ItalicsBlock* 
		    or aBlocks:UnderlineBlock* or imgBlocks:ImageBlock*;
	description: (* The pool of blocks in the source within W3C compliant HTML tags. Only the 
			most commonly used HTML tag blocks are specified. There are many more. Refer 
			to W3C for details. *);
end HTML;


object EclassML is
	components: slideBreaks:SlideBreak* or slideTitles:SlideTitle* 
		    or seqBlocks:SequenceBlock* or siBlocks:SequenceItemBlock* 
		    or hideBlocks:HideBlock* or repBlocks:ReplaceBlock* 
		    or subsBlocks:SubstitutionBlock* or selectBlocks:SelectBlock*;
	description: (* The pool of blocks in the source within EclassML tags. *);
end EclassML;


object StartTag is string and startIndex:StartIndex and endIndex:EndIndex;
object EndTag is string and startIndex:StartIndex and endIndex:EndIndex;
(* Tags do not have position information since they do not appear in the Slides window. *)


object TitleBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex;
	description: (* A TitleBlock is anything within HTML title tags. TitleBlocks have no size or 
			positioning information because titles normally appear on the title bar of the 
			browser window rather than in the document itself. *);
end TitleBlock;


object ParagraphBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A ParagraphBlock is anything within HTML paragraph tags. *);
end ParagraphBlock;


object LineBreak is
	components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A LineBreak corresponds to a single HTML break tag, hence no endTag. *);
end LineBreak;


object IndentBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An IndentBlock is anything within HTML block quote tags. *);
end IndentBlock;


object Heading1Block is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A Heading1Block is anything within HTML h1 tags. *);
end Heading1Block;


object Heading2Block is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A Heading1Block is anything within HTML h2 tags. *);
end Heading2Block;


object Heading3Block is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A Heading1Block is anything within HTML h3 tags. *);
end Heading3Block;


object Heading4Block is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A Heading1Block is anything within HTML h4 tags. *);
end Heading4Block;


object Heading5Block is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A Heading1Block is anything within HTML h5 tags. *);
end Heading5Block;


object Heading6Block is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A Heading1Block is anything within HTML h6 tags. *);
end Heading6Block;


object UnorderedListBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An UnorderedListBlock is anything within HTML unordered list tags. *);
end UnorderedListBlock;


object OrderedListBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An OrderedListBlock is anything within HTML ordered list tags. *);
end OrderedListBlock;


object DefinitionListBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An DefinitionListBlock is anything within HTML definition list tags. *);
end DefinitionListBlock;


object ListItemBlock is
	components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* Since line items do not employ endTags, a ListItemBlock can be anything between
			and HTML list item start tag and the next list item start tag. In the case of 
			the last item in a list, the next list item tag is replaced by the closing 
			unordered, ordered or definition list endTag. *);
end ListItemBlock;


object EmphasisBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An EmphasisBlock is anything within HTML emphasis tags. *);
end EmphasisBlock;


object ItalicsBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An ItalicsBlock is anything within HTML italics tags. *);
end ItalicsBlock;


object UnderlineBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An UnderlineBlock is anything within HTML 'a' tags which are normally used for 
			hypertext links. The default is not to link to anything so the 'a' tags are used 
			solely for underlining unless the instructor edits the starTag manually. *);
end UnderlineBlock;


object ImageBlock is
	components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* An ImageBlock is an HTML image tag which contains a 'src' attribute pointing
			to the location of the image file. Other attributes such as width, height and
			alignment can also be specified within the image tag. *);
end ImageBlock;


object SlideTitle is  
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex;
	description: (* SlideTitle is the EclassML representation of Slide.name. SlideTitles have no
			size or positioning information becuase they do not appear in the Slides window. 
			They only appear in the Outline windown as headers for each Slide. *);
end SlideTitle;


object SlideBreak is 
	components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* A SlideBreak corresponds to a single EclassML slidebreak tag, hence no EndTag. *);
end Slidebreak;


object SequenceBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and numberingType:NumberingType 
		    and expanded:Expanded and collapsed:Collapsed and size:Size;
	description: (* SequenceTags are similar to the Ordered List tags in HTML. They are 
			used to define lecture content hierarchically. Eclass uses these 
			hierarchical sequence structures to display lecture content in outline 
			format and to implement expand and collapse. The NumberingType corresponds 
			to HTML's numbering conventions for ordered list types (ie. arabic numbers, 
			upper case alphabetial, lower case roman numerals, etc). *);
end SequenceBlock;


object NumberingType is string;
object Expanded is boolean;
object Collapsed is boolean;


object SequenceItemBlock is
	components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size 
		    and lastClicked:LastClicked; 
	description: (* SequenceItems are just like LineItems in HTML ordered lists. Notice the EndTag
			is omitted. *);
end SequenceItemBlock;


object LastClicked is boolean;


object SelectBlock is
	components: startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and 
		    endPos:EndPosition and size:Size;
	description: (* SelectBlocks are all the HTML and EclassML that is not within HideBlocks hence 
			the omission of start and endTags. Characters within SelectBlocks appear as 
			regular text in the Outline and Slides windows. *);
end SelectBlock;


object HideBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* HideBlocks appear highlighted in yellow within the Outline window. Hideblocks do 
			not appear in the Slides window. In theory, the size and positioning fields 
			aren't necessary since HideBlocks never appear in the Slides window but this
			information is kept in case the hide tags are removed. *);
end HideBlock;


object ReplaceBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* ReplaceBlocks appear highlighted in blue within the Outline window. ReplaceBlocks 
			do not appear in the Slides window but their corresponding SubstitutionBlocks do. 
			In theory, the size and positioning fields aren't necessary since ReplaceBlocks 
			never appear in the Slides window but this information is kept in case the replace 
			tags are removed.*);
end ReplaceBlock;
	

object SubstitutionBlock is
	components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex 
		    and startPos:StartPosition and endPos:EndPosition and size:Size;
	description: (* SubstitutionBlocks appear highlighted in green within the Outline window. 
			They appear in the Slides window in place of their corresponding ReplaceBlocks. *);
end SubstitutionBlock;


object Scope is integer*;


object SlideSetup is
	components: scope:Scope and margins:Margins and lineHeight:LineHeight and 
		    numberOfLines:NumberOfLines and maxSize:MaxSize and scrollable:Scrollable;
	description: (* Template values every slide must have. Scope is the list of slide numbers 
			the setup applies to. MaxSize represents the maximum amount of space available 
			for a nonscrollable slide. For the purposes of this model each slide is treated 
			as a mapped display or grid with a fixed number of rows and columns dependent 
			on the values of Margins and LineHeight. MaxSize is the total number of grid 
			units a slide can accomodate. This simplification does not take into account the 
			fact that certain character heights require more than one line height to display 
			correctly. It also assumes that images can be treated as blocks of grid units as 
			far as their location on a slide is concerned. *);
end SlideSetup;


object Margins is
	components: left:LeftMargin and right:RightMargin and top:TopMargin and bottom:BottomMargin;
	description: (* Margins measured in inches that determine where lecture content appears on 
			a slide. *);
end Margins;


object LeftMargin is integer;
object RightMargin is integer;
object TopMargin is integer;
object BottomMargin is integer;
object SlideWidth is integer;
object SlideHeight is integer;


object NumberOfLines is integer;
(* The user cannot enter anything in this field. It is calculated automatically by Eclass and provided 
   only for feedback. *) 


object LineHeight is integer;
(* Measured in typographical points. *)


object MaxSize is integer;
(* MaxSize does not apply to slides that are Scrollable. In the cases where a slide is scrollable the
   slide's endPoint can exceed actually exceed MaxSize which triggers the addition of a scrollbar on
   the right edge of the Slides window. *)


object Scrollable is boolean;
(* Determines whether a slide 


object AllSlides is Scope;
(* Not as simple as might be imagined because existing slide setups must be preserved. AllSlides includes 
   SelectedSlides plus any new slides that are subsequently created. If the user really wants to apply the 
   setup to all the slides he/she must select them all first in the Outline window. *)


object ThisSlide is Scope;


object SelectedSlides is Scope;
(* SelectedSlides are all the slides in the Outline window that have been selected by shift clicking or
   CTRL-A. *)


object GlobalSlideSetup is SlideSetup;
(* Scope of GlobalSlideSetup is AllSlides which includes the current selection of slides plus any new 
   slides that are subsequently created.*)


object SourcePool is 
	components: hML:HTML and eML:EclassML;
	description: (* A pool of character string indexes and screen locations for all the HTML 
			and EclassML tagged blocks contained in the Lecture. *);
end SourcePool;


object SlideVisibles is  
	components: hML:HTML and eML:EclassML;
	description: (* A pool of character string indexes and screen locations for all the HTML 
			and EclassML tagged blocks that are visible in the Slides window. EclassML 
			Hide and Replace tag blocks never appear in the Slides window. *);
end SlideVisibles;


object OutlineVisibles is 
	components: hML:HTML and eML:EclassML;
	description: (* A pool of character string indexes and screen locations for all the HTML 
			and EclassML tagged blocks that are visible in the Outline window. *);
end OutlineVisibles;


operation ShowSlides is
	inputs: lect:Lecture, sourcePool:SourcePool, slideVisibles:SlideVisibles, 
		 outlineVisibles:OutlineVisibles, setup:GlobalSlideSetup;
	outputs: lect':Lecture, sourcePool':SourcePool, slideVisibles':SlideVisibles, 
		 outlineVisibles':OutlineVisibles;
	description: (* Illustrates how filtering and expand and collapse work within the Slides window. 
			Postconditions ensure that HideBlocks and ReplaceBlocks do not appear in the 
			Slides window. Postconditions also ensure that only expanded sequences are 
			visible in the Slides window. *);
			
	precondition: ;
	
	postcondition:
	(
		forall (slct in sourcePool.eML.selectBlocks)
			(slct in slideVisibles'.eML.selectBlocks)
		(* SelectBlocks appear in the Slides window. SelectBlocks are everything that is not
		   within EclassML hide tags. *)
		
				and
				
		forall (sub in sourcePool.eML.subsBlocks)
			(sub in slideVisibles'.eML.subsBlocks)
		(* SubstitutionBlocks appear in the Slides window. Substitution blocks are meant to
		   replace the ReplaceBlocks that appear in the Outline window. *)
				
				and
				
		forall (seq in sourcePool.eML.seqBlocks) 
		  ((seq in slideVisibles'.eML.seqBlocks) iff (seq.expanded = true))
		(* If SequenceBlock is still in slideVisibles and SequenceBlock is expanded then the 
		   SequenceBlock appears in the Slides window. *)
		   	
		   		and
		   
		forall (hb in sourcePool.eML.hideBlocks) 
			(not (hb in slideVisibles'.eML.hideBlocks))
		(* HideBlocks are filtered from the Slides window. *)
			 
			 	and
			 
		forall (rb in sourcePool.eML.repBlocks) 
			(not (rb in slideVisibles'.eML.repBlocks))
		(* ReplaceBlocks are filtered from the Slides window. *)
		
				and
				
		RecalcSlideBreaks(lect, sourcePool', slideVisibles', outlineVisibles', setup)
		(* If any SlideBreaks need to be adjusted they should be adjusted in the sourcePool,
		   and outlineVisibles as well as slideVisibles. *)
	);
end ShowSlides;


function DeleteSlides(lect:Lecture, startIndex:StartIndex, endIndex:EndIndex) =
	(forall (slide:Slide) 
	  ( (slide in lect.slides) iff ((slide.data.endIndex < startIndex) or 
	  				(slide.data.startIndex > endIndex)) )
		
		(* Slides whose data lies between the start and endIndex parameters are excluded
		   from lect.slides. *)
	  );
	  
	  
function Slidify(lect:Lecture, slideToExpand:Slide, sourcePool:SourcePool, slideVisibles:SlideVisibles, 
			outlineVisibles:OutlineVisibles, setup:SlideSetup) = 
	(
		exists (offset:integer)
		  (offset = (slideToExpand.data.endPos - slideToExpand.data.maxPos) 
		  		/ setup.maxSize)
		(* The offset in grid units is calculated by subtracting slideToExpand maxPos from 
		   slideToExpand endPos. This will not produce a negative value since endPos being
		   larger than maxPos is a precondition for this function. The difference between 
		   endPos and maxPos is then divided by setup.maxSize to get the number of slides to 
		   be inserted. *)
		   
		   	and
		  	
		forall (i:integer | (i > slideToExpand.number) and (i <= #(lect.slides)))
		  (lect.slides[i + offset] = lect.slides[i])
		(* All the existing slides after the slideToExpand need to be shifted over to make 
		   room for the new ones. The start and endPositions of all the tag blocks affected 
		   need to be increased by the difference between slideToExpand.endPos and 
		   slideToExpand.maxPos. *)
		   
		   	and
		   	
		forall (i:integer | (i > slideToExpand.number) and (i <= slideToExpand.number + offset))
		(
		  (* New Slides must be generated to fill the space left by shifting the existing
		     slides. Every new slide is maxSize by default so it's start and endPos can be
		     derived using simple arithmetic. *)
		        			
		  (* To derive each new Slide's start and endIndexes the tag block with the highest
		     endPos in the new Slide's data must be identified and its endIndex retrieved. A 
		     SlideBreak must then be inserted after that tag block. The endIndex of 
		     that SlideBreak becomes the endIndex of the new Slide. Adding one to that gives
		     us the startIndex of the next new Slide and so on. No new changes need to 
		     be made to new Slide's start and endPos each time a SlideBreak is added 
		     because SlideBreaks don't take up any space in the Slides window. *) 
		)
 
	); (* End Slidify. *)
	
	
function RecalcSlideBreaks(lect:Lecture, srcPool:SourcePool, slideVisibles:SlideVisibles, 
				outlineVisibles:OutlineVisibles, setup:GlobalSlideSetup) = true;
		(* Eclass uses data from SlideVisibles, GlobalSlideSetup and any individual 
		   SlideSetups to calculate where to place SlideBreaks. When a SlideBreak is moved 
		   or inserted the data for all the affected Slides needs to be updated along with 
		   the slides and currentSlide components of Lecture. Changes in the locations of 
		   prexisting SlideBreaks as well as the creation of any new SlideBreaks must also 
		   be reflected in the SourcePool, SlideVisibles and OutlineVisibles. *)
	  
	  
end LectureDB;