(*
 * Module Authoring defines the operations needed to perform Authoring
 * within a Lesson in CSTutor.
 *
*)

module Authoring;

    from LessonDB import Lesson, InfoNode, Node, NodeProperties,
      LessonProperties, CodeSegment, LinkPath, NavLink, Color, Red, Green,
      Blue, NodeItem, Region, FontStyle, Image, QuizNode, NextNode, PrevNode,
      NodeTitle, LessonTitle, NodeSummary, Author, DateMade, Text,
      CodeTextArea, StraightLine, CurveLine, Rectangle, Oval, Question,
      ScoreTable, URL;
    from File import File, FileName;

operation AddInfoNode is
    inputs: lesson:Lesson;
    outputs: node:InfoNode, lesson':Lesson;
    description: (*
        Adding a node to an empty lesson requires only the lesson you are
        working on.  A new empty node is returned to you. This is the
        first thing an instructor must do when creating a lesson.
    *);
    precondition: (* no nodes in the lesson. *)

                  (lesson.node_count = 0);

   postcondition: (* the lesson contains the new node, node_count = 1 *)

                  (node in lesson'.info_node) and (lesson.node_count = 1);
end AddInfoNode;

-- if nodes exsist in the lesson
operation AddInfoNode is
    inputs: old_node:InfoNode, lesson:Lesson;
    outputs: new_node:Node;
    description: (* Adding an info_node to the current lesson requires a
        InfoNode and the Lesson it will be contained in.  A new Lesson is
        returned that contains the new InfoNode as the last node in the
        lesson.
    *);
    precondition: (* The max number of nodes has not been exceeded *)
		
		(lesson.node_count < (lesson.node_limit-1));
    
	postcondition: (* The node is the last in the lesson, the lesson
        gets the last node being worked on in the editor added to the
        lesson.
    *)

	    (lesson.node_count = lesson.node_count + 1)
		
		and 
		
		(new_node = nil)
		
		and 
		
		(* updates links *)
		(new_node in lesson.info_node);
end AddInfoNode;

operation AddQuizNode is
  inputs: quiz_node:Node, lesson:Lesson;
  outputs: new_node:QuizNode;
  description: (* Adding an quiz_node to the current lesson requires a
      QuizNode and the Lesson it will be contained in.  A new Lesson is
      returned that contains the new QuizNode as the last node in the
      lesson.
  *);

  precondition: (* The max number of nodes has not been exceeded *)

      (lesson.node_count < (lesson.node_limit-1));

  postcondition: (* The node is the last in the lesson, the lesson is 100%
      intact and unchanged except for the addition of the quiz_node.
  *)
	  
	  (lesson.node_count = lesson.node_count + 1) 
	  
	  and 
	  
	  (new_node = nil)

	  and 
	  
	  (* updates links *)
	  (new_node in lesson.quiz_node);
end AddQuizNode;

operation DeleteNode is
  inputs: node:Node, lesson:Lesson;
  outputs: lesson':Lesson, node':Node;
  description: (* Deleting any node requires the node and the lesson. The
      lesson is returned without the selected node.
  *);

  preconditions: (* a node is in the current lesson *)
		
	  (exists(node in lesson.info_node) node = nil)
	  
	  or
	  
	  (exists(node in lesson.quiz_node) node = nil);
      
  postconditions: (*  The remaining nodes in the lesson fall linearly into place.
      The lesson is 100% intact and unchanged except for the removal of the
      quiz_node. *)
	  
	  (lesson.node_count = lesson.node_count - 1)
	  
	  and

	  (* update links *)
	  (node'.prev_node = node.prev_node)

	  and

	  (node'.nxt_node = node.nxt_node)

	  and
	  
      (lesson' = lesson);
end DeleteNode;

operation EditNodeProperties is
    inputs: node:Node, old_properties:NodeProperties, new_properties:NodeProperties;
    outputs: node':Node;
    
    precondition: (* make sure the fields being edit are not empty *)

		(old_properties.title != nil) 
		
		and 
		
		(old_properties.summary != nil)
		
		and 
		
		(new_properties.title != nil) 
		
		and 
		
		(new_properties.summary != nil);
    
	postcondition: (* The pertinent data edited by the author: title, summary
        and position are contained in the Node, and this update is reflected in
        the Lesson.
    *)
	
		(old_properties = new_properties) 
		
		and 
		
		(node' = node);

    description: (* Editing the NodeProperties requires the Node you are
        editing information on, its Lesson and its pertinent subdata.  A new
        Lesson is returned that contains the new nodes data.
    *);		
end EditNodeProperties;

-- End of Node Functions


-- Lesson Functions
operation EditLessonProperties is
    inputs: lesson:Lesson, old_properties:LessonProperties, new_properties:LessonProperties;
    outputs: lesson':Lesson;

    precondition: (* make sure the fields are not empty *)

		(lesson != nil) 
		
		and 
		
		(old_properties.author != nil) 
		
		and 
		
		(old_properties.made != nil)
		
		and 
		
		(old_properties.title != nil) 
		
		and 
		
		(new_properties.author != nil) 
		
		and
		
		(new_properties.made != nil) 
		
		and 
		
		(new_properties.title != nil);

    postcondition: (* The pertinent data edited by the author are contained in
        the Lesson, and this update is reflected in the Lesson.
    *)
	    (old_properties = new_properties) 
		
		and 
		
		(lesson' = lesson);

    description: (* Editing the LessonProperties requires the Lesson you are
        editing and its pertinent subdata.  A new Lesson is returned that
        contains the new lesson properties.
    *);
end EditLessonProperties;


-- NodeTool Functions
operation addText is
  inputs: node:Node, text:Text;
  outputs: node':Node;
  description: (* Adding Text to a node requires the Lesson, the node you are
      editing and all the data need for the Text to be in the node. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
  preconditions: (*  the maximum number of items in a node has not been reached *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end addText;

operation editText is
  inputs: node:Node, text:Text;
  outputs: node':Node;
  description: (* Adding Text to a node requires the Lesson, the node you are
      editing and all the data need for the Text to be in the node. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
  preconditions: (*  the maximum number of items in a node has not been reached *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end editText;

operation editFont is
  inputs: node:Node, text:Text;
  outputs: node':Node;
  description: (* Adding Text to a node requires the Lesson, the node you are
      editing and all the data need for the Text to be in the node. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
  preconditions: (*  the maximum number of items in a node has not been reached *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end editFont;

operation addCodeSegment is
  inputs: node:Node, code_object:CodeSegment;
  outputs: node':Node;
  description: (* Adding a codeseg to a node requires the Lesson, the node you are
      editing and all the data need for the codeseg to be in the node. A new node
      is returned to the user with the codeseg object, the lesson is also updated.
  *);
  preconditions: (* the maximum number of items in a node has not been reached *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end addCodeSegment;

operation editCode is
  inputs: node:Node, text:CodeTextArea;
  outputs: node':Node;
  description: (* editing code to a node requires the Lesson, the node you are
      editing and all the data needed for the code to be in the node. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
  preconditions: (*  the maximum number of items in a node has not been reached *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end editCode;

-- NavLink type 1: URL given
operation addNavLink is
  inputs: node:Node, url:URL;
  outputs: node':Node, navlink:NavLink;
  description: (* Adding a url navlink to a node requires the Lesson, the node you are
      editing and all the data need for the url to be in the node. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
  preconditions: (* the maximum number of items in a node has not been reached *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end addNavLink;

-- this operation is here from the Enter URL window...that operation has be modeled.
-- and get lesson path for a node not in the lesson also has to be modeled, this
-- action is done using a view of the Lesson Explorer.
operation GetURL(url:string)->URL;
operation GetLessonPath(path:string)->string;

operation addNavLink is
  inputs: node:Node, lessonPath:LinkPath, title:LessonTitle;
  outputs: node':Node, navlink:NavLink;
  description: (*
      Adding a navlink button requires information of the linkpath and
      the lessons title (to be placed on top of the button.
  *);
  preconditions: (*
      the maximum number of nodes has not been reached. CSTutor does not
      check that lessons exist after a navlink is inserted. if they don't
      exist an error is thrown.
  *);
  postconditions: (*
      The navlink object is in the node and selected.
  *);
end addNavLink;              

operation InsertImage is
  inputs: node:Node, lesson:Lesson, image:Image;
  outputs: node':Node;
  
  preconditions: (* the maximum number of items in a node has not been reached and
                    the image is supported by CSTutor *)

		(node.item_count < ( node.item_limit-1 )) and canRead(image);

  postconditions: (* The node you were working on is updated to reflect the
					 changes the author has done. The image. *)

		(node' in lesson.info_node) and (lesson.node_count = lesson.node_count + 1);

  description: (* Adding an image to a node requires the Lesson, the node you are
      editing and the file of the image to be in the node. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
end InsertImage;

operation addStraightLine is
  inputs: node:Node, line:StraightLine;
  outputs: node':Node;
  description: (* adding a line *);
  preconditions: (* The max number of items in a node has not been exceeded or met. *)

	(node.item_count < (node.item_limit - 1));

  postconditions: (* The selected items' bounding box appears. *)

	(node.item_count = node.item_count + 1) and (node' = node);
end addStraightLine;

operation addCurveLine is
  inputs: node: Node, line:CurveLine, lesson:Lesson;
  outputs: node':InfoNode;
  description: (* adding a curveline.  *);
  preconditions: (* The max number of items in a node has not been exceeded or met. *)

	(node.item_count < (node.item_count - 1));
  
  postconditions: (* The selected item appears in node *)

	(node.item_count = node.item_count + 1) 

	and 

	(node'.item_count = node.item_count)
	
	and
	
	(node' in lesson.info_node);
end addCurveLine;

operation addRectangle is
  inputs: node:Node, rectangle:Rectangle;
  outputs: node':Node;
  description: (* adding a rectangle outline *);
  preconditions: (* the max number of items in a node has not been exceeded or met. *);
  postconditions: (* the rectangle is in the node, it is update and so is the lesson. *);
end addRectangle;

operation addOval is
  inputs: node:Node, oval:Oval;
  outputs: node':Node;
  description: (* adds a oval outline. *);
  pre: (* the max number of items in a node has not been exceeded or met. *);
  post: (* the rectangle is in the node, it is update and so is the lesson. *);
end addOval;

-- Support Functions

-- For all items except Image, and Text.
operation modifyColor is
  inputs: color:Color;
  outputs: color': Color;
  description: (* Changing the color requires the current color and Item being edited, then that item
      is returned with the new color.
  *);
  preconditions: (* the item has an editable color. *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. Also the lesson is updated to reflect these changes.
  *);
end ChooseNewColor;

operation getRGB(red:Red, blue:Blue, green:Green)->Color;
(* this is the color function when a user views the color wheel and click on the
   mouse, they get a color composed of a rgb. *)

operation SelectItem is
  inputs: item: NodeItem, node:Node;
  outputs: is_selected':boolean;
  description: (* selecting an item.  *);
  preconditions: (* There are items in the Node. *);
  postconditions: (* The selected items' bounding box appears. *);
end SelectItem;

-- support functions for Select/Move/Resize tool.
operation MoveItem is
  inputs: item: NodeItem, node:Node;
  outputs: region':Region, node':Node;
  description: (* moving an item  *);
  preconditions: (* There is at least one item in the node and it is selected. *);
  postconditions: (* the items region (x1, y1, x2, y2) values are changed. 'area' is unchanged. *);
end MoveItem;

operation ResizeItem is
  inputs: item:NodeItem, region:Region, node:Node;
  outputs: region':Region, node':Node;
  description: (* Resizing an Item.  *);
  preconditions: (* An item is selected. *);
  postconditions: (* The item (x1, y1) position stay the same, it's area variable is changed. *);
end ResizeItem;

operation changeFontStyle is
  inputs: text:string, begin_index:integer, end_index:integer,
          old_style:FontStyle, new_style:FontStyle;
  outputs: text':string, old_style':FontStyle;
  description: (* changing the font style *);
  preconditions: (* The text field is selected *);
  postconditions: (* The selected text field will show the desired changes *);
end changeFontStyle;  

operation changeFontType is
  inputs: text:string, begin_index:integer, end_index:integer,
          old_style:FontStyle, new_style:FontStyle;
  outputs: text':string, old_style':FontStyle;
  description: (* changing the font type *);
  preconditions: (* The text field is selected *);
  postconditions: (* The selected text field will show the desired changes *);
end changeFontType;

operation changeFontSize is
  inputs: text:string, begin_index:integer, end_index:integer,
          old_style:FontStyle, new_style:FontStyle;
  outputs: text':string, old_style':FontStyle;
  description: (* changing the font size *);
  preconditions: (* The text field is selected *);
  postconditions: (* The selected text field will show the desired changes *);
end changeFontSize;

operation addBackground is
  inputs: node:Node, color:Color, image:Image;
  outputs: node':Node;
  preconditions: (* a node is opened *);
  postconditions: (* The node you were working on is updated to reflect the
      changes the author has done. *);
  description: (* Adding a background to a node requires the Lesson, the node you are
      editing and the file of the image to be in the node or a color. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
end addBackground;

-- QuizNode Funtions
operation AddQuestion is
  inputs: node:QuizNode, question:Question, lesson:Lesson;
  outputs: node':QuizNode;
  preconditions: (* a node is opened and is a quiz node *)

	node in lesson.quiz_node;

  postconditions: (* The node you were working on is updated to reflect the
					 changes the author has done. *)

	(node' = node);

  description: (* Adding a question in a node requires the node you are
      editing. A new node is returned to the user with the updates, 
	  node is also updated.
  *);
end AddQuestion;

operation RemoveQuestion is
  inputs: node:QuizNode, lesson:Lesson;
  outputs: node':QuizNode;
  preconditions: (* a node is opened and is a quiz node *)

	node in lesson.quiz_node;

  postconditions: (* The node you were working on is updated to reflect the
					 changes the author has done. *)
	
	(node.question = nil)
	
	and
	
	(node' = node);

  description: (* Removing a question in a node requires the node you are
      editing.  A new node is returned to the user with the updates.
  *);
end RemoveQuestion;

operation addScoreTable is
  inputs: node:QuizNode, lesson:Lesson;
  outputs: node':QuizNode;
  preconditions: (* a node is opened and is a quiz node *)

	node in lesson.quiz_node;

  postconditions: (* The node you were working on is updated to reflect the
					 changes the author has done. *)

	(node'.table = node.table);

  description: (* Adding a background to a node requires the Lesson, the node you are
      editing and the file of the image to be in the node or a color. A new node
      is returned to the user with the updates, the lesson is also updated.
  *);
end addScoreTable;

-- auxillury functions used by CSTutor behind the scenes.

function canRead(image:Image)->boolean = (

        -- checking the type of file.
        -- where '.name' is a component of the obj File in File.rsl
        -- that is the filename of the file, checking the last chars.
	(image.name = ".jpg") or (image.name = ".gif");

)
end;

end Authoring;