(********
 *
 * This file defines operation and objects for viewing schedules
 *
 *******)

module View;
  
  from Sched import Schedule, ClassAssignment, section, Time;

  from CourseDB import Department, CourseName, CourseNumber, CourseRecord, SCUs;

  from RoomDB import BuildingName, RoomNumber, RoomRecord;

  from Teacher import Name, TeacherRecord, Teacher_info;

  from Ws import Workspace, StatusWindow, StatusMessage;

  export View, CatalogView, TableView, WeekView;

  object View
    components: tv:TableView or cv:CatalogView or wv:WeekView;
    description: (*
      The current View in the workspace, either of the three views.
    *);
  end View;

  object TableView
    components: tr:TableRow*;
    description: (*
      A TableView is the current Schedule displayed in table form
    *);
  end TableVew;

  object TableRow
    components: d:Department, cnum:CourseNumber, s:section,  cnam:CourseName, 
		t:Time, bnum:BuildingName, rnum:RoomNumber, n:Name, 
		rmcflt:boolean, tchrcflt:boolean;
    description: (*
      a row in the table view, with all the columns, and booleans to represent 
      a conflict and color change.
    *);
  end TableRow;

  object CatalogView
    components: DepartmentDescriptor*;
    description: (*
      A CatalogView shows the Schedule formated like the class Schedule.
      It is a collection of DepartmentDescriptors.
    *);
  end CatalogView;

  object DepartmentDescriptor
    components: dn:DepartmentName, cdf:CourseDescriptionFull*;
    description: (*
      A Department it has a DepartmentName which is the name of the department,
      and a collection of Course Descriptions.
    *);
  end DepartmentDescriptor;

  object DepartmentName
    components: string;
    description: (*
      The name of the department
    *);
  end DepartmentName;

  object CourseDescriptionFull
    components: ct:CourseTitle, sd:SectionDescription*;
    description: (*
      A CourseDescriptionFull describes a course in the schedule, with ALL its 
      sections.  It is a CourseTitle and a list of all the sections for that 
      course.
    *);
  end CourseDescriptionFull;

  object CourseDescriptionShort
    components: ct:CourseTitle, sd:SectionDescription;
    description: (*
      A CourseDescriptionShort describe ONE section of a course in the 
      schedule. It is a CourseTitle and SectionDescription.
    *);
  end CourseDescriptionShort;

  object CourseTitle
    components: d:Department, cnum:CourseNumber, cnam:CourseName, scu:SCUs;
    description: (*
      A CourseTitle is the displayed titled of a course, it has the short name
      of the department, i.e. CSC for Computer Science, folowed by a - and the 
      CourseNumber, the full CourseName, and lastly the number of SCUs in 
      parenthesis.
    *);
  end CourseTitle;

  object SectionDescription
    components: s:section, t:Time, bnam:BuildingName, rnum:RoomNumber, 
                n:Name;
    description: (*
      A section description describes a section of a course.  Sections of a 
      course with combined lecture and lab sections get 2 SectionDescriptions 
      one for the lecture and one for the lab.
    *);
  end SectionDescription;

  object WeekView
    components: dv:DayView*;
    description: (*
      A WeekView is a view of the Subset of the Schedule displayed in a table
      with of days and hours and entrys in the table for courses. It has a 
      DayView for every day this department might schedule a course.
    *);
  end WeakView;

  object DayView
    components: hv:HourView*;
    description: (*
      A DayView has a bunch of HourViews, one for each hour this schedules 
      department might schedule a course.
    *);
  end DayView;

  object HourView
    components: cds:CourseDescriptionShort*, t:Time;
    description: (*
      A single entry in the WeekView table.  It contains one or more 
      CourseDescriptionShorts for every ClassAssignment with a Time 
      corresponding to this HourView's Time which is its day and hour. 
    *);
  end HourView;

  operation GetTableView
    inputs: ws:Workspace;
    outputs: ws':Workspace;
    precondition: ;
    postcondition:

      (ws'.stat = ws.stat) and (ws'.sch = ws.sch) and 

      forall(ca:ClassAssignment)
	( ca in ws.sch.ca )
        iff
          ( exists(tr in ws'.v.tv.tr)
              ( (tr.d = ca.cr.dept) and (tr.cnum = ca.cr.cnum) and
	  	(tr.cnam = tr.cnam) and (tr.t = ca.t) and (tr.s = ca.s) and 
		(tr.bnum = ca.rr.rn) and (tr.n = ca.tr.ti.n) ) )

      and 

      forall(i:integer | i>0 and i<(#ws'.v.tv.tr))
  	IsBefore(ws'.v.tv.tr[i],ws'.v.tv.tr[i+1])

      and

      forall(tr in ws'.v.tv)
	( tr.rmcflt = exists(ca in ws'.sch.ca) ( ConflictRm(tr, ca) )
	  and
  	  tr.tchrcflt = exists(ca in ws'.sch.ca) ( ConflictTchr(tr, ca) ) );

    description: (*
      Returns a TableView with every course in the Schedule listed properly.
    *);
  end GetTableView;

  operation GetCatalogView
    inputs: sch:Schedule;
    outputs: cv:CatalogView;
    precondition: ;
    postcondition: 

      (* if its in the schedule its listed by its Department, and vice versa *)
      forall(ca:ClassAssignment)
	( ca in sch.ca )

	iff
	  exists(dd in cv)
	    dd.dn = ca.cr.dept and
	    exists(cdf in dd.cdf)
	      AccurateCT(cdf.ct, ca) and
	      exists(sd in cdf.sd)
		 AccurateSD(sd, ca);

    description: (*
      Returns a CatalogView that display the Schedule like the course catalog.
      Works in any app, so can't interact with the Workspace itself.
    *);
  end GetCatalogView;

  operation GetWeekView
    inputs: ws:Workspace, vf:ViewFilter;
    outputs: ws':Workspace;
    precondition: ;
    postcondition: 

      (ws'.stat = ws.stat) and (ws'.sch = ws.sch) and 

      (* if it should be *there* it is, if its *there* it should be *)
      forall(ca:ClassAssignment)
        ( (ca in ws.sch.ca) and (ca.tr in vf.teachers) and 
             (ca.rr in vf.rooms) and (ca.cr in vf.courses) )
        iff
          exists(dv in ws'.v.wv)
            exists (hv in dv)
              exists(cds in hv.cds) (
                AccurateCT(cds.ct, ca) and AccurateSD(cds.sd, ca) and 
                (hv.t = cds.sd.t)
              );

    description: (*
      Returns a WeekView object that displays the Schedule as filtered by the
      ViewFilter object.  It only shows classes that are in vf.Classes, that 
      are taught by the Teachers in vf.Teachers and in rooms in vf.Rooms.
    *);
  end GetWeekView;

  object ViewFilter
    components: teachers:TeacherRecord*, rooms:RoomRecord*, 
		courses:CourseRecord*;
    description: (*
      The object for defining limited views of a Schedule
    *);
  end ViewFilter;

  function IsBefore(one:TableRow, two:TableRow) = 
    ( if(one.d = two.d) then
        if(one.cnum = two.cnum) then
          one.s < two.s
        else
          one.cnum < two.cnum
      else
        one.cnam < two.cnam
    );

  function ConflictRm(tr:TableRow, ca:ClassAssignment) = 
    ( (ca.t = tr.t) and (ca.rr.bn = tr.bnum) and (ca.rr.rn = tr.rnum) and
      not ( (ca.cr.dept = tr.d) and (ca.cr.cnum = tr.cnum) and (ca.s = tr.s)));

  function ConflictTchr(tr:TableRow, ca:ClassAssignment) = 
    ( (ca.t = tr.t) and (ca.tr.ti.n = tr.n) and
      not ( (ca.cr.dept = tr.d) and (ca.cr.cnum = tr.cnum) and (ca.s = tr.s)));

  function AccurateCT(ct:CourseTitle, ca:ClassAssignment)=
    (ct.d = ca.cr.dept) and (ct.cnum = ca.cr.cnum) and 
    (ct.cnam = ca.cr.cname) and (ct.scu = ca.cr.scu);

  function AccurateSD(sd:SectionDescription, ca:ClassAssignment)=
    (sd.t = ca.t) and (sd.bnam = ca.rr.bn) 
    and (sd.rnum = ca.rr.rn) and 
    (sd.n = ca.tr.ti.n) and (sd.s = ca.s);

end View;