Τρίτη, 26 Σεπτεμβρίου 2017

Class in a class in M2000


We have one class, with two lists, a list of students and a list of history. We have one class as factory for making students groups of data/code (objects in M2000). We can add students, we can get a student and alter credits and put back again, we can move a student to another list, we can rename student (adding a title perhaps).
There are three modes for students. A simple object with name$, id$ and credits, where name$ and id$ are readonly properties, and credits is a field, a public field. In students inventory we put


font "Tahoma"
Form 60, 32
Print $(4),   ' so now we get proportional printing
Bold False ' so now we get no bold font on screen
\\ Class is a factory function for groups
\\ a Class in a Module has global scope (until Module erased)
\\ a Class in a Class (a group defintion) is member of group as own factory
\\ groups holded by one pointer everytime. We can pass by reference (a weak type, not a pointer)
\\ but we can set a pointer to other variable.
\\ for setting pointer we have special objects, like Arrays, Inventories, Stacks, which use pointers only
\\ Here we use Inventories as pointer holders, which map to keys (here the id of student).
\\ Groups can be copied, and can be merged to other groups.
\\ Properties are Groups with set and value. or set, or value part. So a readonly Property has only value.
\\ For each property there is a private field, for name$ is [name]$, so we can write from inside code in group.

Class Student {
            property name$ {Value}
            property Id$ {Value}
            \\ just a value
            Credits=0
            Class:
            \\  String and String, or String and Group
            \\ if "", "" then give an empry student
            Module Student (name$) {
                  If match("G") then {
                        Read it
                        if trim$(name$)="" then {
                              .[name]$<=it.name$
                        } else .[name]$<=name$
                        .Credits<=it.Credits
                        .[id]$<=it.id$
                       
                  } else {
                        Read check$
                         If trim$(check$) ="" then {
                              If trim$(name$) ="" then break
                              Error "No ID found"
                         }
                        .[id]$<=check$
                        If trim$(name$) ="" then Error "No name found"
                        .[name]$<=name$
                  }
                 
            }
      }
Class Students {
      Private:
      \\ inventory Queue can take same keys, but in a search through exist() function get the last one
      Inventory Queue historyStudents
      Inventory iStudents
      Class Stamp {
            TimeStamp=Now+Today
            Status$
      Class:
            Module Stamp (.Status$) {}
      }
      Class Subclass {
      \\ hide private here
      \\ using \\
      \\ and unhide list ! in ExportById()
      Private:
            \\ this is a pointer to Inventory (a list/map type in M2000)
            \\ first time we get an empty Inventory
            \\ but in constructor we get a reference to other Inventory.
            inventory connectTo
      Public:
            Module PutBack {
            \\ here Student("",This) clear This from connectTo and Module PutBack
            Return .connectTo, .id$:=Student("", This)
        }
      Class:
      \\ Class part used once. so Class Subclass return a group with two members:
      \\ a private reference to an inventory and a module  PutBack
      \\ this class added to an existing group, with id$
      \\ also need to exist a Student Class.
            Module Subclass (.connectTo) {}
      }
      Function DispStamp$ (x) {
           =str$(x, "yyyy|mm|dd|hhnnss|")
      }      
      Public:
      Module InfromHistory (id$, status$) {
             If exist(.iStudents, id$) then {
                       simple_student=eval(.iStudents)
                       simple_student=.Stamp(status$)
                       Append .historyStudents, id$:=simple_student
             }
      }
      Module RenameStudent (id$, newName$){
            If Trim$(newName$)="" Then Error "Please place a name"
            If exist(.iStudents, id$) then {
                  simple_student=Student(newName$, eval(.iStudents))
                  Return .iStudents, id$:=simple_student
                  \\  not needed here:    Sort Ascending .iStudents as number
                  \\ merge a stamp part
                  simple_student=.Stamp("Rename")
                  Append .historyStudents, id$:=simple_student
            } else Error "Id not exist"
      }
      Module AddStudentByName (name$, id$) {
            If exist(.iStudents, id$) then {
                  Error "Id exist"
            } else {
                  simple_student=Student(name$, id$)
                  PutTimeToclass=simple_student
                  PutTimeToClass=.Stamp("Included")
                  Append .historyStudents, id$:=PutTimeToClass
                  Append .iStudents, id$:=simple_student
                  Sort Ascending .iStudents as number
            }
      }
      Function GetById (id$) {
            If exist(.iStudents, id$) Then {
                  \\ we get a copy
                  M=Eval(.iStudents)
                  M=.Subclass(.iStudents)
                  =M
            } Else Error "Id not exist"
             \\ List : k=Key$
      }
      Function ExportById (id$) {
            If exist(.iStudents, id$) Then {
                  toExport=Eval(.iStudents)
                  Delete .iStudents, id$
                  Sort Ascending .iStudents as number
                  PutTimeToclass= toExport
                  PutTimeToclass=.Stamp("Excluded")
                  Append .historyStudents, id$:=PutTimeToClass
                  =toExport
            }  Else Error "Id not exist"
      }
      Module AddStudent (student){
            If exist(.iStudents, student.id$) Then {
                  Error "Student exist"
            } Else {
                  PutTimeToclass=student
                  PutTimeToclass=.Stamp("Included")
                  Append .historyStudents, student.id$:=PutTimeToClass
                  Append .iStudents, student.id$:=student
                  Sort Ascending .iStudents as number
            }
      }
      Property friendlyname$ {Value}
      Module Students (.[friendlyname]$){}
      Module PrintData {
            Italic : Pen 12 {Print "List of "; .friendlyname$ } : Italic
            M=Each(.iStudents)
            While M {
                  For .iStudents(M^!) {
                        Print .name$, .id$, .credits
                  }
            }
      }
      Module DisplayHistory {
            Bold : Print "History of "; .friendlyname$ : Bold
            M=Each(.historyStudents)
            If len(.historyStudents)>0 then {
                 Pen 11 { Print Part  "TimeStamp", "Status", "Name", "Id", "Credits"}
                 Print Under
            }
            While M {
                  For .historyStudents(M^!) {
                        Print This.DispStamp$(.TimeStamp) , .status$, .name$, .id$, .credits
                  }
            }      
      }
}

students=Students("Students")
graduateStudents=Students("Graduate Students")
students.AddStudentByName "George","11217"
students.AddStudentByName "Bilis","11417"
\\ M is a copy of original student
M=students.getById("11217")
\\ name$ is a property. All properties are public. We can define If a property return value, or take value, or do either.
Pen 15 {Print "Pick One Student: 11217: ";M.name$, "credits: ";M.credits}
\\ credits is not a property, but a field, and we have access because it is public
M.credits+=100
\\ we can putback because we have a reference to inventory (not to students)
M.PutBack
students.InfromHistory M.Id$, "Add 100"
graduateStudents.AddStudentByName "Mark","11317"
students.PrintData
graduateStudents.PrintData
Pen 15 {Print "Now student George Graduate"}
graduateStudents.AddStudent students.ExportById("11217")
students.PrintData
graduateStudents.PrintData
graduateStudents.DisplayHistory
Pen 15 {Print "Now student George has a phD"}
graduateStudents.RenameStudent  "11217" , "Dr George"
graduateStudents.PrintData
graduateStudents.DisplayHistory
students.DisplayHistory