PTL.cpp


// Test program for Eli Tilevich which was originally coded in two versions for
// for comparison between Data Object Library and Pattern Template Library.

#include <stdio.h>
#include <string.h>
#include "manymany.h"
#include <mgr.h>

class School;
class Student;
class Takes;
class Class;

// School encapsulates your problem
class School : public CollectionParent<School,Student>,
               public CollectionParent<School,Class> {
public:
    School(){}
    char *getName(int i,char *buf);
};

class Student : public CollectionChild<School,Student>,
                public ManyToManySource<Student,Takes,Class> {
    char *sName;
public:
    Student(char *name){
        if(name)sName=new char[strlen(name)+1]; else sName=NULL;
        if(sName)strcpy(sName,name);
    }
    ~Student(){if(sName)delete[] sName;}
    char *getName(){return sName;}
};

class Class : public CollectionChild<School,Class>,
                public ManyToManyTarget<Student,Takes,Class> {
    char *cName;
public:
    Class(char *name){
        if(name)cName=new char[strlen(name)+1]; else cName=NULL;
        if(cName)strcpy(cName,name);
    }
    ~Class(){if(cName)delete[] cName;}
    char *getName(){return cName;}
};

class Takes : public ManyToManyRelation<Student,Takes,Class> {
    int mark;
    int absentDays;
public:
    int addAbsent(int d){absentDays+=d; return absentDays;} // for d=0 reports
    int getMark(){return mark;}
    void setMark(int m){mark=m;}
};


// ----------- data organization --------------
ManyToMany<Student,Takes,Class> scRelation;
Collection<School,Student> students;
Collection<School,Class> classes;
// --------------------------------------------

// pick up names including spaces, if i>0 skip the first word
char* School::getName(int i,char *buf){
    char *p;
    for(p=buf; *p!='\n'; p++)continue;
    *p='\0'; // mark the end of the name
    if(i==0)return buf;
    for(p=buf; *p!='\0' && *p!=' '; p++)continue;
    if(*p=='\0')return p;
    for( ;*p==' ' && *p!='\0'; p++);
    return p;
}

#define BSIZE 80
char buff[BSIZE];
char* fileName="eli.dat";

// compared to DOL, the main is shorter, because PTL does not store data to disk
int main(int argc,char **argv) {
    School *school; Student *sp; Takes *tp; Class *cp;
    char *name,cc;
    CollectionIterator<School,Student> sit;
    CollectionIterator<School,Class> cit;
    ManyToManySourceIterator<Student,Takes,Class> sourceIter;

    school=new School;
    for(;;){
        printf("type your name (STOP to stop the program):\n");
        fgets(buff,BSIZE,stdin);
        name=school->getName(0,buff);
        if(!strcmp(name,"STOP"))break;
        
        ITERATE(sit,school,sp){ // search for 'your name'
            if(!strcmp(name,sp->getName()))break;
        }
        if(sp){
            printf("registered in:");
            ITERATE(sourceIter,sp,tp){ // walk through all Takes's of sp
                cp=scRelation.target(tp);
                printf("(%s)",cp->getName());
            }
            printf("\n");
        }
        else {
            printf("new student=%s\n",name);
            sp=new Student(name);
            students.addTail(school,sp);
        }
        for(;;){
            printf("menu(A className,D className,R=remove student,E=exit):\n");
            fgets(buff,BSIZE,stdin);
            sscanf(buff,"%c",&cc);
            name=school->getName(1,buff);
            if(cc=='A'){
                // first check that this student isn't already registered there
                ITERATE(sourceIter,sp,tp){ // walk through all Takes's of sp
                    cp=scRelation.target(tp);
                    if(!strcmp(name,cp->getName()))break;
                }
                if(tp){ printf("... you are already registered\n"); continue;}

                // find the class
                ITERATE(cit,school,cp){ // search for the given class
                    if(!strcmp(name,cp->getName()))break;
                }
                if(!cp){
                    printf("... new class\n");
                    cp=new Class(name);
                    classes.addTail(school,cp);
                }
                tp=new Takes; // many-to-many involves 3 object types!!
                scRelation.add(sp,tp,cp);
            }
            else if(cc=='D'){
                ITERATE(sourceIter,sp,tp){ // walk through all Takes's of sp
                    cp=scRelation.target(tp);
                    if(!strcmp(name,cp->getName()))break;
                }
                if(!tp){
                    printf(" you are not registered for this class\n");
                    continue;
                }
                scRelation.remove(tp); // disconnect tp
                delete tp;
            }
            else if(cc=='R'){
                // delete all class links of this student
                ITERATE(sourceIter,sp,tp){ // walk through all Takes's of sp
                    scRelation.remove(tp); // disconnect tp
                    delete tp;          // yes, this is allowed within the loop!
                }
                students.remove(school,sp);
                break;
            }
            else if(cc=='E')break;
            else printf("unknown command=%c\n",cc);
        }
    }
    return(0);
}