"Fossies" - the Fresh Open Source Software Archive

Member "fet-5.45.1/src/engine/rules.cpp" (21 Jun 2020, 698193 Bytes) of package /linux/privat/fet-5.45.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rules.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.45.0_vs_5.45.1.

    1 /*
    2 File rules.cpp
    3 */
    4 
    5 /***************************************************************************
    6                           rules.cpp  -  description
    7                              -------------------
    8     begin                : 2002
    9     copyright            : (C) 2002 by Lalescu Liviu
   10     email                : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
   11  ***************************************************************************/
   12 
   13 /***************************************************************************
   14  *                                                                         *
   15  *   This program is free software: you can redistribute it and/or modify  *
   16  *   it under the terms of the GNU Affero General Public License as        *
   17  *   published by the Free Software Foundation, either version 3 of the    *
   18  *   License, or (at your option) any later version.                       *
   19  *                                                                         *
   20  ***************************************************************************/
   21 
   22 #include "timetable_defs.h"
   23 #include "rules.h"
   24 
   25 #include <QDir>
   26 
   27 #include <algorithm>
   28 #include <iostream>
   29 using namespace std;
   30 
   31 #include <QTextStream>
   32 #include <QFile>
   33 #include <QFileInfo>
   34 
   35 #include <QDate>
   36 #include <QTime>
   37 #include <QLocale>
   38 
   39 #include <QString>
   40 
   41 #include <QXmlStreamReader>
   42 
   43 #include <QTranslator>
   44 
   45 #include <QtAlgorithms>
   46 #include <QtGlobal>
   47 
   48 #include <QSet>
   49 #include <QHash>
   50 
   51 #include <list>
   52 #include <iterator>
   53 
   54 //#include <QApplication>
   55 #ifndef FET_COMMAND_LINE
   56 #include <QProgressDialog>
   57 #endif
   58 
   59 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
   60 #include <QRegularExpression>
   61 #include <QRegularExpressionMatch>
   62 #else
   63 #include <QRegExp>
   64 #endif
   65 
   66 #include "messageboxes.h"
   67 
   68 #include "lockunlock.h"
   69 
   70 //static bool toSkipTime[MAX_TIME_CONSTRAINTS];
   71 //static bool toSkipSpace[MAX_SPACE_CONSTRAINTS];
   72 
   73 //extern QApplication* pqapplication;
   74 
   75 extern bool students_schedule_ready;
   76 extern bool rooms_schedule_ready;
   77 extern bool teachers_schedule_ready;
   78 
   79 FakeString::FakeString()
   80 {
   81 }
   82 
   83 void FakeString::operator=(const QString& other)
   84 {
   85     Q_UNUSED(other);
   86 }
   87 
   88 void FakeString::operator=(const char* str)
   89 {
   90     Q_UNUSED(str);
   91 }
   92 
   93 void FakeString::operator+=(const QString& other)
   94 {
   95     Q_UNUSED(other);
   96 }
   97 
   98 void FakeString::operator+=(const char* str)
   99 {
  100     Q_UNUSED(str);
  101 }
  102 
  103 
  104 void Rules::init() //initializes the rules (empty, but with default hours and days)
  105 {
  106     this->institutionName=tr("Default institution");
  107     this->comments=tr("Default comments");
  108 
  109     this->nDaysPerWeek=5;
  110     this->daysOfTheWeek[0] = tr("Monday");
  111     this->daysOfTheWeek[1] = tr("Tuesday");
  112     this->daysOfTheWeek[2] = tr("Wednesday");
  113     this->daysOfTheWeek[3] = tr("Thursday");
  114     this->daysOfTheWeek[4] = tr("Friday");
  115     
  116     //defaults
  117     this->nHoursPerDay=12;
  118     this->hoursOfTheDay[0]=tr("08:00", "Hour name");
  119     this->hoursOfTheDay[1]=tr("09:00", "Hour name");
  120     this->hoursOfTheDay[2]=tr("10:00", "Hour name");
  121     this->hoursOfTheDay[3]=tr("11:00", "Hour name");
  122     this->hoursOfTheDay[4]=tr("12:00", "Hour name");
  123     this->hoursOfTheDay[5]=tr("13:00", "Hour name");
  124     this->hoursOfTheDay[6]=tr("14:00", "Hour name");
  125     this->hoursOfTheDay[7]=tr("15:00", "Hour name");
  126     this->hoursOfTheDay[8]=tr("16:00", "Hour name");
  127     this->hoursOfTheDay[9]=tr("17:00", "Hour name");
  128     this->hoursOfTheDay[10]=tr("18:00", "Hour name");
  129     this->hoursOfTheDay[11]=tr("19:00", "Hour name");
  130     //this->hoursOfTheDay[12]=tr("20:00", "Hours name");
  131 
  132     permanentStudentsHash.clear();
  133     
  134     activitiesPointerHash.clear();
  135     bctSet.clear();
  136     btSet.clear();
  137     bcsSet.clear();
  138     apstHash.clear();
  139     aprHash.clear();
  140     mdbaHash.clear();
  141     tnatHash.clear();
  142     ssnatHash.clear();
  143     
  144     this->initialized=true;
  145 }
  146 
  147 bool Rules::computeInternalStructure(QWidget* parent)
  148 {
  149     //To fix a bug reported by Frans on forum, on 7 May 2010.
  150     //If user generates, then changes some activities (changes teachers of them), then tries to generate but FET cannot precompute in generate_pre.cpp,
  151     //then if user views the timetable, the timetable of a teacher contains activities of other teacher.
  152     //The bug appeared because it is possible to compute internal structure, so internal activities change the teacher, but the timetables remain the same,
  153     //with the same activities indexes.
  154     teachers_schedule_ready=false;
  155     students_schedule_ready=false;
  156     rooms_schedule_ready=false;
  157 
  158     //The order is important - firstly the teachers, subjects, activity tags and students.
  159     //After that, the buildings.
  160     //After that, the rooms.
  161     //After that, the activities.
  162     //After that, the time constraints.
  163     //After that, the space constraints.
  164 
  165     if(this->teachersList.size()>MAX_TEACHERS){
  166         RulesImpossible::warning(parent, tr("FET information"),
  167          tr("You have too many teachers. You need to increase the variable MAX_TEACHERS (which is currently %1).")
  168          .arg(MAX_TEACHERS));
  169         return false;
  170     }
  171     
  172     //kill augmented students sets
  173     QList<StudentsYear*> ayears;
  174     QList<StudentsGroup*> agroups;
  175     QList<StudentsSubgroup*> asubgroups;
  176     for(StudentsYear* year : qAsConst(augmentedYearsList)){
  177         if(!ayears.contains(year))
  178             ayears.append(year);
  179         for(StudentsGroup* group : qAsConst(year->groupsList)){
  180             if(!agroups.contains(group))
  181                 agroups.append(group);
  182             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
  183                 if(!asubgroups.contains(subgroup))
  184                     asubgroups.append(subgroup);
  185             }
  186         }
  187     }
  188     for(StudentsYear* year : qAsConst(ayears)){
  189         assert(year!=NULL);
  190         delete year;
  191     }
  192     for(StudentsGroup* group : qAsConst(agroups)){
  193         assert(group!=NULL);
  194         delete group;
  195     }
  196     for(StudentsSubgroup* subgroup : qAsConst(asubgroups)){
  197         assert(subgroup!=NULL);
  198         delete subgroup;
  199     }
  200     augmentedYearsList.clear();
  201     //////////////////
  202     
  203     //copy list of students sets into augmented list
  204     QHash<QString, StudentsSet*> augmentedHash;
  205     
  206     for(StudentsYear* y : qAsConst(yearsList)){
  207         StudentsYear* ay=new StudentsYear();
  208         ay->name=y->name;
  209         ay->numberOfStudents=y->numberOfStudents;
  210         ay->groupsList.clear();
  211         augmentedYearsList << ay;
  212         
  213         assert(!augmentedHash.contains(ay->name));
  214         augmentedHash.insert(ay->name, ay);
  215         
  216         for(StudentsGroup* g : qAsConst(y->groupsList)){
  217             if(augmentedHash.contains(g->name)){
  218                 StudentsSet* tmpg=augmentedHash.value(g->name);
  219                 assert(tmpg->type==STUDENTS_GROUP);
  220                 ay->groupsList<<((StudentsGroup*)tmpg);
  221             }
  222             else{
  223                 StudentsGroup* ag=new StudentsGroup();
  224                 ag->name=g->name;
  225                 ag->numberOfStudents=g->numberOfStudents;
  226                 ag->subgroupsList.clear();
  227                 ay->groupsList << ag;
  228                 
  229                 assert(!augmentedHash.contains(ag->name));
  230                 augmentedHash.insert(ag->name, ag);
  231             
  232                 for(StudentsSubgroup* s : qAsConst(g->subgroupsList)){
  233                     if(augmentedHash.contains(s->name)){
  234                         StudentsSet* tmps=augmentedHash.value(s->name);
  235                         assert(tmps->type==STUDENTS_SUBGROUP);
  236                         ag->subgroupsList<<((StudentsSubgroup*)tmps);
  237                     }
  238                     else{
  239                         StudentsSubgroup* as=new StudentsSubgroup();
  240                         as->name=s->name;
  241                         as->numberOfStudents=s->numberOfStudents;
  242                         ag->subgroupsList << as;
  243                         
  244                         assert(!augmentedHash.contains(as->name));
  245                         augmentedHash.insert(as->name, as);
  246                     }
  247                 }
  248             }
  249         }
  250     }
  251 
  252     /////////
  253     for(int i=0; i<this->augmentedYearsList.size(); i++){
  254         StudentsYear* sty=this->augmentedYearsList[i];
  255 
  256         //if this year has no groups, insert something to simulate the whole year
  257         if(sty->groupsList.count()==0){
  258             StudentsGroup* tmpGroup = new StudentsGroup();
  259             tmpGroup->name = sty->name+" "+tr("Automatic Group", "Please keep the translation short. It is used when a year contains no groups and an automatic group "
  260              "is added in the year, in the timetable (when viewing the students timetable from FET and also in the html timetables for students groups or subgroups)"
  261              ". In the empty year there will be added a group with name = yearName+a space character+your translation of 'Automatic Group'.");
  262             tmpGroup->numberOfStudents = sty->numberOfStudents;
  263             sty->groupsList << tmpGroup;
  264         }
  265         
  266         for(int j=0; j<sty->groupsList.size(); j++){
  267             StudentsGroup* stg=sty->groupsList[j];
  268 
  269             //if this group has no subgroups, insert something to simulate the whole group
  270             if(stg->subgroupsList.size()==0){
  271                 StudentsSubgroup* tmpSubgroup = new StudentsSubgroup();
  272                 tmpSubgroup->name = stg->name+" "+tr("Automatic Subgroup", "Please keep the translation short. It is used when a group contains no subgroups and an automatic subgroup "
  273                  "is added in the group, in the timetable (when viewing the students timetable from FET and also in the html timetables for students subgroups)"
  274                  ". In the empty group there will be added a subgroup with name = groupName+a space character+your translation of 'Automatic Subgroup'.");
  275                 tmpSubgroup->numberOfStudents=stg->numberOfStudents;
  276                 stg->subgroupsList << tmpSubgroup;
  277             }
  278         }
  279     }
  280     //////////
  281     
  282     QSet<StudentsGroup*> allGroupsSet;
  283     QSet<StudentsSubgroup*> allSubgroupsSet;
  284     QList<StudentsGroup*> allGroupsList;
  285     QList<StudentsSubgroup*> allSubgroupsList;
  286     
  287     for(int i=0; i<this->augmentedYearsList.size(); i++){
  288         StudentsYear* sty=this->augmentedYearsList.at(i);
  289         sty->indexInAugmentedYearsList=i;
  290 
  291         for(int j=0; j<sty->groupsList.size(); j++){
  292             StudentsGroup* stg=sty->groupsList.at(j);
  293             if(!allGroupsSet.contains(stg)){
  294                 allGroupsSet.insert(stg);
  295                 allGroupsList.append(stg);
  296                 stg->indexInInternalGroupsList=allGroupsSet.count()-1;
  297             }
  298             
  299             for(int k=0; k<stg->subgroupsList.size(); k++)
  300                 if(!allSubgroupsSet.contains(stg->subgroupsList.at(k))){
  301                     allSubgroupsSet.insert(stg->subgroupsList.at(k));
  302                     allSubgroupsList.append(stg->subgroupsList.at(k));
  303                     stg->subgroupsList.at(k)->indexInInternalSubgroupsList=allSubgroupsSet.count()-1;
  304                 }
  305         }
  306     }
  307     int tmpNSubgroups=allSubgroupsList.count();
  308     if(tmpNSubgroups>MAX_TOTAL_SUBGROUPS){
  309         RulesImpossible::warning(parent, tr("FET information"),
  310          tr("You have too many total subgroups. You need to increase the variable MAX_TOTAL_SUBGROUPS (which is currently %1).")
  311          .arg(MAX_TOTAL_SUBGROUPS));
  312         return false;
  313     }
  314     this->internalSubgroupsList.resize(tmpNSubgroups);
  315 
  316     int counter=0;
  317     for(int i=0; i<this->activitiesList.size(); i++){
  318         Activity* act=this->activitiesList.at(i);
  319         if(act->active)
  320             counter++;
  321     }
  322     if(counter>MAX_ACTIVITIES){
  323         RulesImpossible::warning(parent, tr("FET information"),
  324          tr("You have too many active activities. You need to increase the variable MAX_ACTIVITIES (which is currently %1).")
  325          .arg(MAX_ACTIVITIES));
  326         return false;
  327     }
  328 
  329     if(this->buildingsList.size()>MAX_BUILDINGS){
  330         RulesImpossible::warning(parent, tr("FET information"),
  331          tr("You have too many buildings. You need to increase the variable MAX_BUILDINGS (which is currently %1).")
  332          .arg(MAX_BUILDINGS));
  333         return false;
  334     }
  335     
  336     if(this->roomsList.size()>MAX_ROOMS){
  337         RulesImpossible::warning(parent, tr("FET information"),
  338          tr("You have too many rooms. You need to increase the variable MAX_ROOMS (which is currently %1).")
  339          .arg(MAX_ROOMS));
  340         return false;
  341     }
  342     
  343     assert(this->initialized);
  344 
  345     //days and hours
  346     assert(this->nHoursPerDay>0);
  347     assert(this->nDaysPerWeek>0);
  348     this->nHoursPerWeek=this->nHoursPerDay*this->nDaysPerWeek;
  349 
  350     //teachers
  351     int i;
  352     Teacher* tch;
  353     this->nInternalTeachers=this->teachersList.size();
  354     assert(this->nInternalTeachers<=MAX_TEACHERS);
  355     this->internalTeachersList.resize(this->nInternalTeachers);
  356     for(i=0; i<this->teachersList.size(); i++){
  357         tch=teachersList[i];
  358         this->internalTeachersList[i]=tch;
  359     }
  360     assert(i==this->nInternalTeachers);
  361 
  362     teachersHash.clear();
  363     for(int i=0; i<nInternalTeachers; i++)
  364         teachersHash.insert(internalTeachersList[i]->name, i);
  365 
  366     //subjects
  367     Subject* sbj;
  368     this->nInternalSubjects=this->subjectsList.size();
  369     this->internalSubjectsList.resize(this->nInternalSubjects);
  370     for(i=0; i<this->subjectsList.size(); i++){
  371         sbj=this->subjectsList[i];
  372         this->internalSubjectsList[i]=sbj;
  373     }
  374     assert(i==this->nInternalSubjects);
  375 
  376     subjectsHash.clear();
  377     for(int i=0; i<nInternalSubjects; i++)
  378         subjectsHash.insert(internalSubjectsList[i]->name, i);
  379 
  380     //activity tags
  381     ActivityTag* at;
  382     this->nInternalActivityTags=this->activityTagsList.size();
  383     this->internalActivityTagsList.resize(this->nInternalActivityTags);
  384     for(i=0; i<this->activityTagsList.size(); i++){
  385         at=this->activityTagsList[i];
  386         this->internalActivityTagsList[i]=at;
  387     }
  388     assert(i==this->nInternalActivityTags);
  389 
  390     activityTagsHash.clear();
  391     for(int i=0; i<nInternalActivityTags; i++)
  392         activityTagsHash.insert(internalActivityTagsList[i]->name, i);
  393 
  394     //students
  395     this->nInternalSubgroups=0;
  396     for(int i=0; i<allSubgroupsList.count(); i++){
  397         assert(allSubgroupsList.at(i)->indexInInternalSubgroupsList==i);
  398         this->internalSubgroupsList[this->nInternalSubgroups]=allSubgroupsList.at(i);
  399         this->nInternalSubgroups++;
  400     }
  401 
  402     this->internalGroupsList.clear();
  403     for(int i=0; i<allGroupsList.count(); i++){
  404         assert(allGroupsList.at(i)->indexInInternalGroupsList==i);
  405         this->internalGroupsList.append(allGroupsList.at(i));
  406     }
  407     
  408     studentsHash.clear();
  409     for(StudentsYear* year : qAsConst(augmentedYearsList)){
  410         studentsHash.insert(year->name, year);
  411         for(StudentsGroup* group : qAsConst(year->groupsList)){
  412             studentsHash.insert(group->name, group);
  413             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
  414                 studentsHash.insert(subgroup->name, subgroup);
  415         }
  416     }
  417     
  418     assert(this->nInternalSubgroups==tmpNSubgroups);
  419 
  420     //buildings
  421     internalBuildingsList.resize(buildingsList.size());
  422     this->nInternalBuildings=0;
  423     assert(this->buildingsList.size()<=MAX_BUILDINGS);
  424     for(int i=0; i<this->buildingsList.size(); i++){
  425         Building* bu=this->buildingsList[i];
  426         bu->computeInternalStructure(*this);
  427     }
  428     
  429     for(int i=0; i<this->buildingsList.size(); i++){
  430         Building* bu=this->buildingsList[i];
  431         this->internalBuildingsList[this->nInternalBuildings++]=bu;
  432     }
  433     assert(this->nInternalBuildings==this->buildingsList.size());
  434 
  435     buildingsHash.clear();
  436     for(int i=0; i<nInternalBuildings; i++)
  437         buildingsHash.insert(internalBuildingsList[i]->name, i);
  438 
  439     //rooms
  440     internalRoomsList.resize(roomsList.size());
  441     this->nInternalRooms=0;
  442     assert(this->roomsList.size()<=MAX_ROOMS);
  443     for(int i=0; i<this->roomsList.size(); i++){
  444         Room* rm=this->roomsList[i];
  445         rm->computeInternalStructure(*this);
  446     }
  447     
  448     for(int i=0; i<this->roomsList.size(); i++){
  449         Room* rm=this->roomsList[i];
  450         this->internalRoomsList[this->nInternalRooms++]=rm;
  451     }
  452     assert(this->nInternalRooms==this->roomsList.size());
  453 
  454     roomsHash.clear();
  455     for(int i=0; i<nInternalRooms; i++)
  456         roomsHash.insert(internalRoomsList[i]->name, i);
  457         
  458     for(int i=0; i<nInternalRooms; i++){
  459         Room* rm=internalRoomsList[i];
  460         
  461         if(rm->isVirtual){
  462             if(rm->realRoomsSetsList.count()==0){
  463                 RulesImpossible::warning(parent, tr("FET information"), tr("Virtual room %1 has 0 sets of real rooms to choose"
  464                  " from. The number of sets of real rooms must be at least 2. Please correct this.").arg(rm->name));
  465                 return false;
  466             }
  467             if(rm->realRoomsSetsList.count()==1){
  468                 RulesImpossible::warning(parent, tr("FET information"), tr("Virtual room %1 has only 1 set of real rooms to choose"
  469                  " from. The number of sets of real rooms must be at least 2. Please correct this.").arg(rm->name));
  470                 return false;
  471             }
  472             
  473             int i=0;
  474             for(const QStringList& tl : qAsConst(rm->realRoomsSetsList)){
  475                 if(tl.count()==0){
  476                     RulesImpossible::warning(parent, tr("FET information"), tr("Virtual room %1, in set number %2, has 0 real rooms"
  477                      " to choose from. The number of real rooms from each set must be at least 1. Please correct this.").arg(rm->name).arg(i+1));
  478                     return false;
  479                 }
  480                 
  481                 QStringList tl2;
  482                 QSet<QString> ts;
  483                 for(const QString& t : qAsConst(tl))
  484                     if(!ts.contains(t))
  485                         ts.insert(t);
  486                     else
  487                         tl2.append(t);
  488                 if(!tl2.isEmpty()){
  489                     RulesImpossible::warning(parent, tr("FET information"), tr("Virtual room %1, in set number %2, has these duplicate real rooms names: %3."
  490                      " Please correct this.").arg(rm->name).arg(i+1).arg(tl2.join(", ")));
  491                     return false;
  492                 }
  493                 
  494                 for(const QString& rr : qAsConst(tl)){
  495                     int rri=roomsHash.value(rr, -1);
  496 
  497                     if(rri==-1){
  498                         RulesImpossible::warning(parent, tr("FET information"),
  499                          tr("The virtual room %1 contains the unrecognized real room %2 in the sets of real rooms - please correct this.").arg(rm->name).arg(rr));
  500                         
  501                         return false;
  502                     }
  503                     
  504                     assert(rri>=0);
  505                     if(internalRoomsList[rri]->isVirtual==true){
  506                         RulesImpossible::warning(parent, tr("FET information"), tr("Virtual room %1, in set number %2, contains the virtual room"
  507                          " %3 - please correct this (a virtual room can only contain sets with real rooms).").arg(rm->name).arg(i+1).arg(rr));
  508                         return false;
  509                     }
  510                 }
  511                 
  512                 i++;
  513             }
  514         }
  515 
  516         rm->computeInternalStructureRealRoomsSetsList(*this);
  517     }
  518 
  519     //activities
  520     int range=0;
  521     for(Activity* act : qAsConst(this->activitiesList))
  522         if(act->active)
  523             range++;
  524     QProgressDialog progress(parent);
  525     progress.setWindowTitle(tr("Computing internal structure", "Title of a progress dialog"));
  526     progress.setLabelText(tr("Processing internally the activities ... please wait"));
  527     progress.setRange(0, qMax(range, 1));
  528     progress.setModal(true);
  529     int ttt=0;
  530         
  531     Activity* act;
  532     counter=0;
  533     
  534     this->inactiveActivities.clear();
  535     
  536     for(int i=0; i<this->activitiesList.size(); i++){
  537         act=this->activitiesList[i];
  538         if(act->active){
  539             progress.setValue(ttt);
  540             //pqapplication->processEvents();
  541             if(progress.wasCanceled()){
  542                 progress.setValue(range);
  543                 RulesImpossible::warning(parent, tr("FET information"), tr("Canceled"));
  544                 return false;
  545             }
  546             ttt++;
  547 
  548             counter++;
  549             act->computeInternalStructure(*this);
  550         }
  551         else
  552             inactiveActivities.insert(act->id);
  553     }
  554     
  555     progress.setValue(qMax(range, 1));
  556 
  557     for(int i=0; i<nInternalSubgroups; i++)
  558         internalSubgroupsList[i]->activitiesForSubgroup.clear();
  559     for(int i=0; i<nInternalTeachers; i++)
  560         internalTeachersList[i]->activitiesForTeacher.clear();
  561 
  562     assert(counter<=MAX_ACTIVITIES);
  563     this->nInternalActivities=counter;
  564     this->internalActivitiesList.resize(this->nInternalActivities);
  565     int activei=0;
  566     for(int ai=0; ai<this->activitiesList.size(); ai++){
  567         act=this->activitiesList[ai];
  568         if(act->active){
  569             this->internalActivitiesList[activei]=*act;
  570             
  571             for(int j=0; j<act->iSubgroupsList.count(); j++){
  572                 int k=act->iSubgroupsList.at(j);
  573                 //The test below takes time
  574                 //assert(!internalSubgroupsList[k]->activitiesForSubgroup.contains(activei));
  575                 internalSubgroupsList[k]->activitiesForSubgroup.append(activei);
  576             }
  577             
  578             for(int j=0; j<act->iTeachersList.count(); j++){
  579                 int k=act->iTeachersList.at(j);
  580                 //The test below takes time
  581                 //assert(!internalTeachersList[k]->activitiesForTeacher.contains(activei));
  582                 internalTeachersList[k]->activitiesForTeacher.append(activei);
  583             }
  584             
  585             activei++;
  586         }
  587     }
  588 
  589     activitiesHash.clear();
  590     for(int i=0; i<nInternalActivities; i++){
  591         assert(!activitiesHash.contains(internalActivitiesList[i].id));
  592         activitiesHash.insert(internalActivitiesList[i].id, i);
  593     }
  594 
  595     //activities list for each subject - used for subjects timetable - in order for students and teachers
  596     activitiesForSubjectList.resize(nInternalSubjects);
  597     activitiesForSubjectSet.resize(nInternalSubjects);
  598     for(int sb=0; sb<nInternalSubjects; sb++){
  599         activitiesForSubjectList[sb].clear();
  600         activitiesForSubjectSet[sb].clear();
  601     }
  602 
  603     for(int i=0; i<this->augmentedYearsList.size(); i++){
  604         StudentsYear* sty=this->augmentedYearsList[i];
  605 
  606         for(int j=0; j<sty->groupsList.size(); j++){
  607             StudentsGroup* stg=sty->groupsList[j];
  608 
  609             for(int k=0; k<stg->subgroupsList.size(); k++){
  610                 StudentsSubgroup* sts=stg->subgroupsList[k];
  611                 
  612                 for(int ai : qAsConst(internalSubgroupsList[sts->indexInInternalSubgroupsList]->activitiesForSubgroup))
  613                     if(!activitiesForSubjectSet[internalActivitiesList[ai].subjectIndex].contains(ai)){
  614                         activitiesForSubjectList[internalActivitiesList[ai].subjectIndex].append(ai);
  615                         activitiesForSubjectSet[internalActivitiesList[ai].subjectIndex].insert(ai);
  616                     }
  617             }
  618         }
  619     }
  620     
  621     for(int i=0; i<nInternalTeachers; i++){
  622         for(int ai : qAsConst(internalTeachersList[i]->activitiesForTeacher))
  623             if(!activitiesForSubjectSet[internalActivitiesList[ai].subjectIndex].contains(ai)){
  624                 activitiesForSubjectList[internalActivitiesList[ai].subjectIndex].append(ai);
  625                 activitiesForSubjectSet[internalActivitiesList[ai].subjectIndex].insert(ai);
  626             }
  627     }
  628     
  629     //for activities without students or teachers
  630     for(int ai=0; ai<nInternalActivities; ai++){
  631         int si=internalActivitiesList[ai].subjectIndex;
  632         if(!activitiesForSubjectSet[si].contains(ai)){
  633             activitiesForSubjectList[si].append(ai);
  634             activitiesForSubjectSet[si].insert(ai);
  635         }
  636     }
  637     /////////////////////////////////////////////////////////////////
  638     
  639     //activities list for each activity tag - used for activity tags timetable - in order for students and teachers
  640     activitiesForActivityTagList.resize(nInternalActivityTags);
  641     activitiesForActivityTagSet.resize(nInternalActivityTags);
  642     for(int a=0; a<nInternalActivityTags; a++){
  643         activitiesForActivityTagList[a].clear();
  644         activitiesForActivityTagSet[a].clear();
  645     }
  646 
  647     for(int i=0; i<this->augmentedYearsList.size(); i++){
  648         StudentsYear* sty=this->augmentedYearsList[i];
  649 
  650         for(int j=0; j<sty->groupsList.size(); j++){
  651             StudentsGroup* stg=sty->groupsList[j];
  652 
  653             for(int k=0; k<stg->subgroupsList.size(); k++){
  654                 StudentsSubgroup* sts=stg->subgroupsList[k];
  655                 
  656                 for(int ai : qAsConst(internalSubgroupsList[sts->indexInInternalSubgroupsList]->activitiesForSubgroup))
  657                     for(int activityTagInt : qAsConst(internalActivitiesList[ai].iActivityTagsSet))
  658                         if(!activitiesForActivityTagSet[activityTagInt].contains(ai)){
  659                             activitiesForActivityTagList[activityTagInt].append(ai);
  660                             activitiesForActivityTagSet[activityTagInt].insert(ai);
  661                         }
  662             }
  663         }
  664     }
  665     
  666     for(int i=0; i<nInternalTeachers; i++){
  667         for(int ai : qAsConst(internalTeachersList[i]->activitiesForTeacher))
  668             for(int activityTagInt : qAsConst(internalActivitiesList[ai].iActivityTagsSet))
  669                 if(!activitiesForActivityTagSet[activityTagInt].contains(ai)){
  670                     activitiesForActivityTagList[activityTagInt].append(ai);
  671                     activitiesForActivityTagSet[activityTagInt].insert(ai);
  672                 }
  673     }
  674 
  675     //for activities without students or teachers
  676     for(int ai=0; ai<nInternalActivities; ai++){
  677         for(int ati : qAsConst(internalActivitiesList[ai].iActivityTagsSet)){
  678             if(!activitiesForActivityTagSet[ati].contains(ai)){
  679                 activitiesForActivityTagList[ati].append(ai);
  680                 activitiesForActivityTagSet[ati].insert(ai);
  681             }
  682         }
  683     }
  684     /////////////////////////////////////////////////////////////////
  685 
  686     bool ok=true;
  687 
  688     //time constraints
  689     //progress.reset();
  690     
  691     bool skipInactiveTimeConstraints=false;
  692     
  693     TimeConstraint* tctr;
  694     
  695     QSet<int> toSkipTimeSet;
  696     
  697     int _c=0;
  698     
  699     for(int tctrindex=0; tctrindex<this->timeConstraintsList.size(); tctrindex++){
  700         tctr=this->timeConstraintsList[tctrindex];
  701 
  702         if(!tctr->active){
  703             toSkipTimeSet.insert(tctrindex);
  704         }
  705         else if(tctr->hasInactiveActivities(*this)){
  706             //toSkipTime[tctrindex]=true;
  707             toSkipTimeSet.insert(tctrindex);
  708         
  709             if(!skipInactiveTimeConstraints){
  710                 QString s=tr("The following time constraint is ignored, because it refers to inactive activities:");
  711                 s+="\n";
  712                 s+=tctr->getDetailedDescription(*this);
  713                 
  714                 int t=RulesConstraintIgnored::mediumConfirmation(parent, tr("FET information"), s,
  715                  tr("Skip rest"), tr("See next"), QString(),
  716                  1, 0 );
  717 
  718                 if(t==0)
  719                     skipInactiveTimeConstraints=true;
  720             }
  721         }
  722         else{
  723             //toSkipTime[tctrindex]=false;
  724             _c++;
  725         }
  726     }
  727     
  728     internalTimeConstraintsList.resize(_c);
  729     
  730     progress.setLabelText(tr("Processing internally the time constraints ... please wait"));
  731     progress.setRange(0, qMax(timeConstraintsList.size(), 1));
  732     ttt=0;
  733         
  734     //assert(this->timeConstraintsList.size()<=MAX_TIME_CONSTRAINTS);
  735     int tctri=0;
  736     
  737     for(int tctrindex=0; tctrindex<this->timeConstraintsList.size(); tctrindex++){
  738         progress.setValue(ttt);
  739         //pqapplication->processEvents();
  740         if(progress.wasCanceled()){
  741             progress.setValue(timeConstraintsList.size());
  742             RulesImpossible::warning(parent, tr("FET information"), tr("Canceled"));
  743             return false;
  744         }
  745         ttt++;
  746 
  747         tctr=this->timeConstraintsList[tctrindex];
  748         
  749         if(toSkipTimeSet.contains(tctrindex))
  750             continue;
  751         
  752         if(!tctr->computeInternalStructure(parent, *this)){
  753             //assert(0);
  754             ok=false;
  755             continue;
  756         }
  757         this->internalTimeConstraintsList[tctri++]=tctr;
  758     }
  759 
  760     progress.setValue(qMax(timeConstraintsList.size(), 1));
  761 
  762     this->nInternalTimeConstraints=tctri;
  763     if(VERBOSE){
  764         cout<<_c<<" time constraints after first pass (after removing inactive ones)"<<endl;
  765         cout<<"  "<<this->nInternalTimeConstraints<<" time constraints after second pass (after removing wrong ones)"<<endl;
  766     }
  767     assert(_c>=this->nInternalTimeConstraints); //because some constraints may have toSkipTime false, but computeInternalStructure also false
  768     //assert(this->nInternalTimeConstraints<=MAX_TIME_CONSTRAINTS);
  769     
  770     //space constraints
  771     //progress.reset();
  772     
  773     bool skipInactiveSpaceConstraints=false;
  774     
  775     SpaceConstraint* sctr;
  776     
  777     QSet<int> toSkipSpaceSet;
  778     
  779     _c=0;
  780 
  781     for(int sctrindex=0; sctrindex<this->spaceConstraintsList.size(); sctrindex++){
  782         sctr=this->spaceConstraintsList[sctrindex];
  783 
  784         if(!sctr->active){
  785             toSkipSpaceSet.insert(sctrindex);
  786         }
  787         else if(sctr->hasInactiveActivities(*this)){
  788             //toSkipSpace[sctrindex]=true;
  789             toSkipSpaceSet.insert(sctrindex);
  790         
  791             if(!skipInactiveSpaceConstraints){
  792                 QString s=tr("The following space constraint is ignored, because it refers to inactive activities:");
  793                 s+="\n";
  794                 s+=sctr->getDetailedDescription(*this);
  795                 
  796                 int t=RulesConstraintIgnored::mediumConfirmation(parent, tr("FET information"), s,
  797                  tr("Skip rest"), tr("See next"), QString(),
  798                  1, 0 );
  799 
  800                 if(t==0)
  801                     skipInactiveSpaceConstraints=true;
  802             }
  803         }
  804         else{
  805             _c++;
  806             //toSkipSpace[sctrindex]=false;
  807         }
  808     }
  809     
  810     internalSpaceConstraintsList.resize(_c);
  811     
  812     progress.setLabelText(tr("Processing internally the space constraints ... please wait"));
  813     progress.setRange(0, qMax(spaceConstraintsList.size(), 1));
  814     ttt=0;
  815     //assert(this->spaceConstraintsList.size()<=MAX_SPACE_CONSTRAINTS);
  816 
  817     int sctri=0;
  818 
  819     for(int sctrindex=0; sctrindex<this->spaceConstraintsList.size(); sctrindex++){
  820         progress.setValue(ttt);
  821         //pqapplication->processEvents();
  822         if(progress.wasCanceled()){
  823             progress.setValue(spaceConstraintsList.size());
  824             RulesImpossible::warning(parent, tr("FET information"), tr("Canceled"));
  825             return false;
  826         }
  827         ttt++;
  828 
  829         sctr=this->spaceConstraintsList[sctrindex];
  830     
  831         if(toSkipSpaceSet.contains(sctrindex))
  832             continue;
  833         
  834         if(!sctr->computeInternalStructure(parent, *this)){
  835             //assert(0);
  836             ok=false;
  837             continue;
  838         }
  839         this->internalSpaceConstraintsList[sctri++]=sctr;
  840     }
  841 
  842     progress.setValue(qMax(spaceConstraintsList.size(), 1));
  843 
  844     this->nInternalSpaceConstraints=sctri;
  845     if(VERBOSE){
  846         cout<<_c<<" space constraints after first pass (after removing inactive ones)"<<endl;
  847         cout<<"  "<<this->nInternalSpaceConstraints<<" space constraints after second pass (after removing wrong ones)"<<endl;
  848     }
  849     assert(_c>=this->nInternalSpaceConstraints); //because some constraints may have toSkipSpace false, but computeInternalStructure also false
  850     //assert(this->nInternalSpaceConstraints<=MAX_SPACE_CONSTRAINTS);
  851     
  852     //group activities in initial order
  853     if(groupActivitiesInInitialOrderList.count()>0){
  854         QStringList fetBugs;
  855         QStringList userErrors;
  856     
  857         QSet<int> visitedIds;
  858         for(int j=0; j<groupActivitiesInInitialOrderList.count(); j++){
  859             GroupActivitiesInInitialOrderItem* item=groupActivitiesInInitialOrderList[j];
  860             
  861             if(!item->active)
  862                 continue;
  863             
  864             if(item->ids.count()<2){
  865                 fetBugs.append(tr("All 'group activities in the initial order for timetable generation' items should contain at least two activities ids."
  866                  " This is not true for item number %1. Please report potential bug.").arg(j+1));
  867             }
  868 
  869             item->indices.clear();
  870             for(int id : qAsConst(item->ids)){
  871                 if(visitedIds.contains(id)){
  872                     userErrors.append(tr("All 'group activities in the initial order for timetable generation' items should have different activities ids."
  873                      " (Each activity id must appear at most once in all the items.) This is not true for item number %1 and activity id %2.").arg(j+1).arg(id));
  874                 }
  875                 else{
  876                     visitedIds.insert(id);
  877                     int index=activitiesHash.value(id, -1);
  878                     if(index>=0)
  879                         item->indices.append(index);
  880                 }
  881             }
  882 
  883             if(!fetBugs.isEmpty() || !userErrors.isEmpty()){
  884                 RulesImpossible::warning(parent, tr("FET information"), fetBugs.join("\n\n")+userErrors.join("\n\n"));
  885                 return false;
  886             }
  887         }
  888     }
  889 
  890     //done.
  891     this->internalStructureComputed=ok;
  892     
  893     return ok;
  894 }
  895 
  896 void Rules::kill() //clears memory for the rules, destroys them
  897 {
  898     //Teachers
  899     for(Teacher* tch : qAsConst(teachersList))
  900         delete tch;
  901     teachersList.clear();
  902     //while(!teachersList.isEmpty())
  903     //  delete teachersList.takeFirst();
  904 
  905     //Subjects
  906     for(Subject* sbj : qAsConst(subjectsList))
  907         delete sbj;
  908     subjectsList.clear();
  909     //while(!subjectsList.isEmpty())
  910     //  delete subjectsList.takeFirst();
  911 
  912     //Activity tags
  913     for(ActivityTag* at : qAsConst(activityTagsList))
  914         delete at;
  915     activityTagsList.clear();
  916     //while(!activityTagsList.isEmpty())
  917     //  delete activityTagsList.takeFirst();
  918 
  919     //Years
  920     /*while(!yearsList.isEmpty())
  921         delete yearsList.takeFirst();*/
  922         
  923     //students sets
  924     QSet<StudentsYear*> iyears;
  925     QSet<StudentsGroup*> igroups;
  926     QSet<StudentsSubgroup*> isubgroups;
  927     for(StudentsYear* year : qAsConst(yearsList)){
  928         if(!iyears.contains(year))
  929             iyears.insert(year);
  930         for(StudentsGroup* group : qAsConst(year->groupsList)){
  931             if(!igroups.contains(group))
  932                 igroups.insert(group);
  933             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
  934                 if(!isubgroups.contains(subgroup))
  935                     isubgroups.insert(subgroup);
  936             }
  937         }
  938     }
  939     for(StudentsYear* year : qAsConst(iyears)){
  940         assert(year!=NULL);
  941         delete year;
  942     }
  943     for(StudentsGroup* group : qAsConst(igroups)){
  944         assert(group!=NULL);
  945         delete group;
  946     }
  947     for(StudentsSubgroup* subgroup : qAsConst(isubgroups)){
  948         assert(subgroup!=NULL);
  949         delete subgroup;
  950     }
  951     yearsList.clear();
  952     
  953     permanentStudentsHash.clear();
  954     //////////////////
  955 
  956     //kill augmented students sets
  957     QList<StudentsYear*> ayears;
  958     QList<StudentsGroup*> agroups;
  959     QList<StudentsSubgroup*> asubgroups;
  960     for(StudentsYear* year : qAsConst(augmentedYearsList)){
  961         if(!ayears.contains(year))
  962             ayears.append(year);
  963         for(StudentsGroup* group : qAsConst(year->groupsList)){
  964             if(!agroups.contains(group))
  965                 agroups.append(group);
  966             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
  967                 if(!asubgroups.contains(subgroup))
  968                     asubgroups.append(subgroup);
  969             }
  970         }
  971     }
  972     for(StudentsYear* year : qAsConst(ayears)){
  973         assert(year!=NULL);
  974         delete year;
  975     }
  976     for(StudentsGroup* group : qAsConst(agroups)){
  977         assert(group!=NULL);
  978         delete group;
  979     }
  980     for(StudentsSubgroup* subgroup : qAsConst(asubgroups)){
  981         assert(subgroup!=NULL);
  982         delete subgroup;
  983     }   
  984     augmentedYearsList.clear();
  985     //////////////////
  986     
  987     //Activities
  988     for(Activity* act : qAsConst(activitiesList))
  989         delete act;
  990     activitiesList.clear();
  991     //while(!activitiesList.isEmpty())
  992     //  delete activitiesList.takeFirst();
  993 
  994     //Time constraints
  995     for(TimeConstraint* tc : qAsConst(timeConstraintsList))
  996         delete tc;
  997     timeConstraintsList.clear();
  998     //while(!timeConstraintsList.isEmpty())
  999     //  delete timeConstraintsList.takeFirst();
 1000 
 1001     //Space constraints
 1002     for(SpaceConstraint* sc : qAsConst(spaceConstraintsList))
 1003         delete sc;
 1004     spaceConstraintsList.clear();
 1005     //while(!spaceConstraintsList.isEmpty())
 1006     //  delete spaceConstraintsList.takeFirst();
 1007 
 1008     //Buildings
 1009     for(Building* bu : qAsConst(buildingsList))
 1010         delete bu;
 1011     buildingsList.clear();
 1012     //while(!buildingsList.isEmpty())
 1013     //  delete buildingsList.takeFirst();
 1014 
 1015     //Rooms
 1016     for(Room* rm : qAsConst(roomsList))
 1017         delete rm;
 1018     roomsList.clear();
 1019     //while(!roomsList.isEmpty())
 1020     //  delete roomsList.takeFirst();
 1021         
 1022     for(GroupActivitiesInInitialOrderItem* ga : qAsConst(groupActivitiesInInitialOrderList))
 1023         delete ga;
 1024     groupActivitiesInInitialOrderList.clear();
 1025     //while(!groupActivitiesInInitialOrderList.isEmpty())
 1026     //  delete groupActivitiesInInitialOrderList.takeFirst();
 1027 
 1028     activitiesPointerHash.clear();
 1029     bctSet.clear();
 1030     btSet.clear();
 1031     bcsSet.clear();
 1032     apstHash.clear();
 1033     aprHash.clear();
 1034     mdbaHash.clear();
 1035     tnatHash.clear();
 1036     ssnatHash.clear();
 1037     
 1038     teachersHash.clear();
 1039     subjectsHash.clear();
 1040     activityTagsHash.clear();
 1041     studentsHash.clear();
 1042     buildingsHash.clear();
 1043     roomsHash.clear();
 1044     activitiesHash.clear();
 1045 
 1046     //done
 1047     this->internalStructureComputed=false;
 1048     this->initialized=false;
 1049 
 1050     teachers_schedule_ready=false;
 1051     students_schedule_ready=false;
 1052     rooms_schedule_ready=false;
 1053 }
 1054 
 1055 Rules::Rules()
 1056 {
 1057     this->initialized=false;
 1058     this->modified=false;
 1059 }
 1060 
 1061 Rules::~Rules()
 1062 {
 1063     if(this->initialized)
 1064         this->kill();
 1065 }
 1066 
 1067 void Rules::setInstitutionName(const QString& newInstitutionName)
 1068 {
 1069     this->institutionName=newInstitutionName;
 1070     this->internalStructureComputed=false;
 1071     setRulesModifiedAndOtherThings(this);
 1072 }
 1073 
 1074 void Rules::setComments(const QString& newComments)
 1075 {
 1076     this->comments=newComments;
 1077     this->internalStructureComputed=false;
 1078     setRulesModifiedAndOtherThings(this);
 1079 }
 1080 
 1081 bool Rules::addTeacher(Teacher* teacher)
 1082 {
 1083     for(int i=0; i<this->teachersList.size(); i++){
 1084         Teacher* tch=this->teachersList[i];
 1085         if(tch->name==teacher->name)
 1086             return false;
 1087     }
 1088     
 1089     this->internalStructureComputed=false;
 1090     setRulesModifiedAndOtherThings(this);
 1091 
 1092     teachers_schedule_ready=false;
 1093     students_schedule_ready=false;
 1094     rooms_schedule_ready=false;
 1095 
 1096     this->teachersList.append(teacher);
 1097     return true;
 1098 }
 1099 
 1100 bool Rules::addTeacherFast(Teacher* teacher)
 1101 {
 1102     this->internalStructureComputed=false;
 1103     setRulesModifiedAndOtherThings(this);
 1104 
 1105     teachers_schedule_ready=false;
 1106     students_schedule_ready=false;
 1107     rooms_schedule_ready=false;
 1108 
 1109     this->teachersList.append(teacher);
 1110     return true;
 1111 }
 1112 
 1113 int Rules::searchTeacher(const QString& teacherName)
 1114 {
 1115     for(int i=0; i<this->teachersList.size(); i++)
 1116         if(this->teachersList.at(i)->name==teacherName)
 1117             return i;
 1118 
 1119     return -1;
 1120 }
 1121 
 1122 bool Rules::removeTeacher(const QString& teacherName)
 1123 {
 1124     QList<int> idsToBeRemoved;
 1125     for(Activity* act : qAsConst(activitiesList)){
 1126         bool t=act->removeTeacher(teacherName);
 1127         if(t && act->teachersNames.count()==0)
 1128             idsToBeRemoved.append(act->id);
 1129     }
 1130     removeActivities(idsToBeRemoved, false);
 1131 
 1132     for(int i=0; i<this->teachersList.size(); i++)
 1133         if(this->teachersList.at(i)->name==teacherName){
 1134             Teacher* tch=this->teachersList[i];
 1135             this->teachersList.removeAt(i);
 1136             delete tch;
 1137             break;
 1138         }
 1139     
 1140     updateConstraintsAfterRemoval();
 1141 
 1142     this->internalStructureComputed=false;
 1143     setRulesModifiedAndOtherThings(this);
 1144 
 1145     teachers_schedule_ready=false;
 1146     students_schedule_ready=false;
 1147     rooms_schedule_ready=false;
 1148 
 1149     return true;
 1150 }
 1151 
 1152 bool Rules::modifyTeacher(const QString& initialTeacherName, const QString& finalTeacherName)
 1153 {
 1154     assert(this->searchTeacher(finalTeacherName)==-1);
 1155     assert(this->searchTeacher(initialTeacherName)>=0);
 1156 
 1157     for(int i=0; i<this->activitiesList.size(); i++)
 1158         this->activitiesList.at(i)->renameTeacher(initialTeacherName, finalTeacherName);
 1159         
 1160     for(TimeConstraint* ctr : qAsConst(timeConstraintsList)){
 1161         if(ctr->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
 1162             ConstraintTeacherNotAvailableTimes* crt_constraint=(ConstraintTeacherNotAvailableTimes*)ctr;
 1163             if(initialTeacherName == crt_constraint->teacher)
 1164                 crt_constraint->teacher=finalTeacherName;
 1165         }
 1166         else if(ctr->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_WEEK){
 1167             ConstraintTeacherMaxGapsPerWeek* crt_constraint=(ConstraintTeacherMaxGapsPerWeek*)ctr;
 1168             if(initialTeacherName == crt_constraint->teacherName)
 1169                 crt_constraint->teacherName=finalTeacherName;
 1170         }
 1171         else if(ctr->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_DAY){
 1172             ConstraintTeacherMaxGapsPerDay* crt_constraint=(ConstraintTeacherMaxGapsPerDay*)ctr;
 1173             if(initialTeacherName == crt_constraint->teacherName)
 1174                 crt_constraint->teacherName=finalTeacherName;
 1175         }
 1176         else if(ctr->type==CONSTRAINT_TEACHER_MAX_HOURS_DAILY){
 1177             ConstraintTeacherMaxHoursDaily* crt_constraint=(ConstraintTeacherMaxHoursDaily*)ctr;
 1178             if(initialTeacherName == crt_constraint->teacherName)
 1179                 crt_constraint->teacherName=finalTeacherName;
 1180         }
 1181         else if(ctr->type==CONSTRAINT_TEACHER_MAX_HOURS_CONTINUOUSLY){
 1182             ConstraintTeacherMaxHoursContinuously* crt_constraint=(ConstraintTeacherMaxHoursContinuously*)ctr;
 1183             if(initialTeacherName == crt_constraint->teacherName)
 1184                 crt_constraint->teacherName=finalTeacherName;
 1185         }
 1186         else if(ctr->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 1187             ConstraintTeacherActivityTagMaxHoursContinuously* crt_constraint=(ConstraintTeacherActivityTagMaxHoursContinuously*)ctr;
 1188             if(initialTeacherName == crt_constraint->teacherName)
 1189                 crt_constraint->teacherName=finalTeacherName;
 1190         }
 1191         else if(ctr->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_DAILY){
 1192             ConstraintTeacherActivityTagMaxHoursDaily* crt_constraint=(ConstraintTeacherActivityTagMaxHoursDaily*)ctr;
 1193             if(initialTeacherName == crt_constraint->teacherName)
 1194                 crt_constraint->teacherName=finalTeacherName;
 1195         }
 1196         else if(ctr->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MIN_HOURS_DAILY){
 1197             ConstraintTeacherActivityTagMinHoursDaily* crt_constraint=(ConstraintTeacherActivityTagMinHoursDaily*)ctr;
 1198             if(initialTeacherName == crt_constraint->teacherName)
 1199                 crt_constraint->teacherName=finalTeacherName;
 1200         }
 1201         else if(ctr->type==CONSTRAINT_TEACHER_MIN_HOURS_DAILY){
 1202             ConstraintTeacherMinHoursDaily* crt_constraint=(ConstraintTeacherMinHoursDaily*)ctr;
 1203             if(initialTeacherName == crt_constraint->teacherName)
 1204                 crt_constraint->teacherName=finalTeacherName;
 1205         }
 1206         else if(ctr->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 1207             ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 1208             if(initialTeacherName == crt_constraint->teacher)
 1209                 crt_constraint->teacher=finalTeacherName;
 1210         }
 1211         else if(ctr->type==CONSTRAINT_TEACHER_MAX_DAYS_PER_WEEK){
 1212             ConstraintTeacherMaxDaysPerWeek* crt_constraint=(ConstraintTeacherMaxDaysPerWeek*)ctr;
 1213             if(initialTeacherName == crt_constraint->teacherName)
 1214                 crt_constraint->teacherName=finalTeacherName;
 1215         }
 1216         else if(ctr->type==CONSTRAINT_TEACHER_MIN_DAYS_PER_WEEK){
 1217             ConstraintTeacherMinDaysPerWeek* crt_constraint=(ConstraintTeacherMinDaysPerWeek*)ctr;
 1218             if(initialTeacherName == crt_constraint->teacherName)
 1219                 crt_constraint->teacherName=finalTeacherName;
 1220         }
 1221         else if(ctr->type==CONSTRAINT_TEACHER_INTERVAL_MAX_DAYS_PER_WEEK){
 1222             ConstraintTeacherIntervalMaxDaysPerWeek* crt_constraint=(ConstraintTeacherIntervalMaxDaysPerWeek*)ctr;
 1223             if(initialTeacherName == crt_constraint->teacherName)
 1224                 crt_constraint->teacherName=finalTeacherName;
 1225         }
 1226         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
 1227             ConstraintActivitiesPreferredTimeSlots* crt_constraint=(ConstraintActivitiesPreferredTimeSlots*)ctr;
 1228             if(initialTeacherName == crt_constraint->p_teacherName)
 1229                 crt_constraint->p_teacherName=finalTeacherName;
 1230         }
 1231         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
 1232             ConstraintActivitiesPreferredStartingTimes* crt_constraint=(ConstraintActivitiesPreferredStartingTimes*)ctr;
 1233             if(initialTeacherName == crt_constraint->teacherName)
 1234                 crt_constraint->teacherName=finalTeacherName;
 1235         }
 1236         else if(ctr->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
 1237             ConstraintActivitiesEndStudentsDay* crt_constraint=(ConstraintActivitiesEndStudentsDay*)ctr;
 1238             if(initialTeacherName == crt_constraint->teacherName)
 1239                 crt_constraint->teacherName=finalTeacherName;
 1240         }
 1241         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
 1242             ConstraintSubactivitiesPreferredTimeSlots* crt_constraint=(ConstraintSubactivitiesPreferredTimeSlots*)ctr;
 1243             if(initialTeacherName == crt_constraint->p_teacherName)
 1244                 crt_constraint->p_teacherName=finalTeacherName;
 1245         }
 1246         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
 1247             ConstraintSubactivitiesPreferredStartingTimes* crt_constraint=(ConstraintSubactivitiesPreferredStartingTimes*)ctr;
 1248             if(initialTeacherName == crt_constraint->teacherName)
 1249                 crt_constraint->teacherName=finalTeacherName;
 1250         }
 1251         //2017-02-07
 1252         else if(ctr->type==CONSTRAINT_TEACHER_MAX_SPAN_PER_DAY){
 1253             ConstraintTeacherMaxSpanPerDay* crt_constraint=(ConstraintTeacherMaxSpanPerDay*)ctr;
 1254             if(initialTeacherName == crt_constraint->teacherName)
 1255                 crt_constraint->teacherName=finalTeacherName;
 1256         }
 1257         else if(ctr->type==CONSTRAINT_TEACHER_MIN_RESTING_HOURS){
 1258             ConstraintTeacherMinRestingHours* crt_constraint=(ConstraintTeacherMinRestingHours*)ctr;
 1259             if(initialTeacherName == crt_constraint->teacherName)
 1260                 crt_constraint->teacherName=finalTeacherName;
 1261         }
 1262     }
 1263     
 1264     for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 1265         if(ctr->type==CONSTRAINT_TEACHER_HOME_ROOM){
 1266             ConstraintTeacherHomeRoom* crt_constraint=(ConstraintTeacherHomeRoom*)ctr;
 1267             if(initialTeacherName == crt_constraint->teacherName)
 1268                 crt_constraint->teacherName=finalTeacherName;
 1269         }
 1270         else if(ctr->type==CONSTRAINT_TEACHER_HOME_ROOMS){
 1271             ConstraintTeacherHomeRooms* crt_constraint=(ConstraintTeacherHomeRooms*)ctr;
 1272             if(initialTeacherName == crt_constraint->teacherName)
 1273                 crt_constraint->teacherName=finalTeacherName;
 1274         }
 1275         else if(ctr->type==CONSTRAINT_TEACHER_MAX_BUILDING_CHANGES_PER_DAY){
 1276             ConstraintTeacherMaxBuildingChangesPerDay* crt_constraint=(ConstraintTeacherMaxBuildingChangesPerDay*)ctr;
 1277             if(initialTeacherName == crt_constraint->teacherName)
 1278                 crt_constraint->teacherName=finalTeacherName;
 1279         }
 1280         else if(ctr->type==CONSTRAINT_TEACHER_MAX_BUILDING_CHANGES_PER_WEEK){
 1281             ConstraintTeacherMaxBuildingChangesPerWeek* crt_constraint=(ConstraintTeacherMaxBuildingChangesPerWeek*)ctr;
 1282             if(initialTeacherName == crt_constraint->teacherName)
 1283                 crt_constraint->teacherName=finalTeacherName;
 1284         }
 1285         else if(ctr->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
 1286             ConstraintTeacherMinGapsBetweenBuildingChanges* crt_constraint=(ConstraintTeacherMinGapsBetweenBuildingChanges*)ctr;
 1287             if(initialTeacherName == crt_constraint->teacherName)
 1288                 crt_constraint->teacherName=finalTeacherName;
 1289         }
 1290         else if(ctr->type==CONSTRAINT_TEACHER_MAX_ROOM_CHANGES_PER_DAY){
 1291             ConstraintTeacherMaxRoomChangesPerDay* crt_constraint=(ConstraintTeacherMaxRoomChangesPerDay*)ctr;
 1292             if(initialTeacherName == crt_constraint->teacherName)
 1293                 crt_constraint->teacherName=finalTeacherName;
 1294         }
 1295         else if(ctr->type==CONSTRAINT_TEACHER_MAX_ROOM_CHANGES_PER_WEEK){
 1296             ConstraintTeacherMaxRoomChangesPerWeek* crt_constraint=(ConstraintTeacherMaxRoomChangesPerWeek*)ctr;
 1297             if(initialTeacherName == crt_constraint->teacherName)
 1298                 crt_constraint->teacherName=finalTeacherName;
 1299         }
 1300         else if(ctr->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_ROOM_CHANGES){
 1301             ConstraintTeacherMinGapsBetweenRoomChanges* crt_constraint=(ConstraintTeacherMinGapsBetweenRoomChanges*)ctr;
 1302             if(initialTeacherName == crt_constraint->teacherName)
 1303                 crt_constraint->teacherName=finalTeacherName;
 1304         }
 1305     }
 1306     
 1307     int t=0;
 1308     for(int i=0; i<this->teachersList.size(); i++){
 1309         Teacher* tch=this->teachersList[i];
 1310 
 1311         if(tch->name==initialTeacherName){
 1312             tch->name=finalTeacherName;
 1313             t++;
 1314         }
 1315     }
 1316     assert(t==1);
 1317     
 1318     if(tnatHash.contains(initialTeacherName)){
 1319         QSet<ConstraintTeacherNotAvailableTimes*> cs=tnatHash.value(initialTeacherName);
 1320         tnatHash.remove(initialTeacherName);
 1321         assert(!tnatHash.contains(finalTeacherName));
 1322         tnatHash.insert(finalTeacherName, cs);
 1323     }
 1324 
 1325     this->internalStructureComputed=false;
 1326     setRulesModifiedAndOtherThings(this);
 1327 
 1328     teachers_schedule_ready=false;
 1329     students_schedule_ready=false;
 1330     rooms_schedule_ready=false;
 1331 
 1332     return true;
 1333 }
 1334 
 1335 void Rules::sortTeachersAlphabetically()
 1336 {
 1337     std::stable_sort(this->teachersList.begin(), this->teachersList.end(), teachersAscending);
 1338 
 1339     this->internalStructureComputed=false;
 1340     setRulesModifiedAndOtherThings(this);
 1341 
 1342     teachers_schedule_ready=false;
 1343     students_schedule_ready=false;
 1344     rooms_schedule_ready=false;
 1345 }
 1346 
 1347 bool Rules::addSubject(Subject* subject)
 1348 {
 1349     for(int i=0; i<this->subjectsList.size(); i++){
 1350         Subject* sbj=this->subjectsList[i]; 
 1351         if(sbj->name==subject->name)
 1352             return false;
 1353     }
 1354     
 1355     this->internalStructureComputed=false;
 1356     setRulesModifiedAndOtherThings(this);
 1357 
 1358     teachers_schedule_ready=false;
 1359     students_schedule_ready=false;
 1360     rooms_schedule_ready=false;
 1361 
 1362     this->subjectsList << subject;
 1363     return true;
 1364 }
 1365 
 1366 bool Rules::addSubjectFast(Subject* subject)
 1367 {
 1368     this->internalStructureComputed=false;
 1369     setRulesModifiedAndOtherThings(this);
 1370 
 1371     teachers_schedule_ready=false;
 1372     students_schedule_ready=false;
 1373     rooms_schedule_ready=false;
 1374 
 1375     this->subjectsList << subject;
 1376     return true;
 1377 }
 1378 
 1379 int Rules::searchSubject(const QString& subjectName)
 1380 {
 1381     for(int i=0; i<this->subjectsList.size(); i++)
 1382         if(this->subjectsList.at(i)->name == subjectName)
 1383             return i;
 1384 
 1385     return -1;
 1386 }
 1387 
 1388 bool Rules::removeSubject(const QString& subjectName)
 1389 {
 1390     //check the qualified subjects for teachers
 1391     for(Teacher* tch : qAsConst(teachersList)){
 1392         if(tch->qualifiedSubjectsHash.contains(subjectName)){
 1393             std::list<QString>::iterator it=tch->qualifiedSubjectsHash.value(subjectName);
 1394             assert((*it)==subjectName);
 1395             
 1396             tch->qualifiedSubjectsList.erase(it);
 1397             
 1398             tch->qualifiedSubjectsHash.remove(subjectName);
 1399         }
 1400     }
 1401 
 1402     QList<int> idsToBeRemoved;
 1403     for(Activity* act : qAsConst(activitiesList)){
 1404         if(act->subjectName==subjectName)
 1405             idsToBeRemoved.append(act->id);
 1406     }
 1407     removeActivities(idsToBeRemoved, false);
 1408 
 1409     //remove the subject from the list
 1410     for(int i=0; i<this->subjectsList.size(); i++)
 1411         if(this->subjectsList[i]->name==subjectName){
 1412             Subject* sbj=this->subjectsList[i];
 1413             this->subjectsList.removeAt(i);
 1414             delete sbj;
 1415             break;
 1416         }
 1417     
 1418     updateConstraintsAfterRemoval();
 1419 
 1420     this->internalStructureComputed=false;
 1421     setRulesModifiedAndOtherThings(this);
 1422 
 1423     teachers_schedule_ready=false;
 1424     students_schedule_ready=false;
 1425     rooms_schedule_ready=false;
 1426 
 1427     return true;
 1428 }
 1429 
 1430 bool Rules::modifySubject(const QString& initialSubjectName, const QString& finalSubjectName)
 1431 {
 1432     assert(this->searchSubject(finalSubjectName)==-1);
 1433     assert(this->searchSubject(initialSubjectName)>=0);
 1434 
 1435     //check the qualified subjects for teachers
 1436     for(Teacher* tch : qAsConst(teachersList)){
 1437         if(tch->qualifiedSubjectsHash.contains(initialSubjectName)){
 1438             std::list<QString>::iterator it=tch->qualifiedSubjectsHash.value(initialSubjectName);
 1439             assert((*it)==initialSubjectName);
 1440             
 1441             (*it)=finalSubjectName;
 1442             
 1443             tch->qualifiedSubjectsHash.remove(initialSubjectName);
 1444             tch->qualifiedSubjectsHash.insert(finalSubjectName, it);
 1445         }
 1446     }
 1447 
 1448     //check the activities
 1449     for(int i=0; i<this->activitiesList.size(); i++){
 1450         Activity* act=this->activitiesList[i];
 1451 
 1452         if( act->subjectName == initialSubjectName)
 1453             act->subjectName=finalSubjectName;
 1454     }
 1455     
 1456     //modify the time constraints related to this subject
 1457     for(TimeConstraint* ctr : qAsConst(timeConstraintsList)){
 1458         if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
 1459             ConstraintActivitiesPreferredTimeSlots* crt_constraint=(ConstraintActivitiesPreferredTimeSlots*)ctr;
 1460             if(initialSubjectName == crt_constraint->p_subjectName)
 1461                 crt_constraint->p_subjectName=finalSubjectName;
 1462         }
 1463         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
 1464             ConstraintActivitiesPreferredStartingTimes* crt_constraint=(ConstraintActivitiesPreferredStartingTimes*)ctr;
 1465             if(initialSubjectName == crt_constraint->subjectName)
 1466                 crt_constraint->subjectName=finalSubjectName;
 1467         }
 1468         else if(ctr->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
 1469             ConstraintActivitiesEndStudentsDay* crt_constraint=(ConstraintActivitiesEndStudentsDay*)ctr;
 1470             if(initialSubjectName == crt_constraint->subjectName)
 1471                 crt_constraint->subjectName=finalSubjectName;
 1472         }
 1473         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
 1474             ConstraintSubactivitiesPreferredTimeSlots* crt_constraint=(ConstraintSubactivitiesPreferredTimeSlots*)ctr;
 1475             if(initialSubjectName == crt_constraint->p_subjectName)
 1476                 crt_constraint->p_subjectName=finalSubjectName;
 1477         }
 1478         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
 1479             ConstraintSubactivitiesPreferredStartingTimes* crt_constraint=(ConstraintSubactivitiesPreferredStartingTimes*)ctr;
 1480             if(initialSubjectName == crt_constraint->subjectName)
 1481                 crt_constraint->subjectName=finalSubjectName;
 1482         }
 1483     }
 1484     
 1485     //modify the space constraints related to this subject
 1486     for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 1487         if(ctr->type==CONSTRAINT_SUBJECT_PREFERRED_ROOM){
 1488             ConstraintSubjectPreferredRoom* c=(ConstraintSubjectPreferredRoom*)ctr;
 1489             if(c->subjectName == initialSubjectName)
 1490                 c->subjectName=finalSubjectName;
 1491         }
 1492         else if(ctr->type==CONSTRAINT_SUBJECT_PREFERRED_ROOMS){
 1493             ConstraintSubjectPreferredRooms* c=(ConstraintSubjectPreferredRooms*)ctr;
 1494             if(c->subjectName == initialSubjectName)
 1495                 c->subjectName=finalSubjectName;
 1496         }
 1497         else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOM){
 1498             ConstraintSubjectActivityTagPreferredRoom* c=(ConstraintSubjectActivityTagPreferredRoom*)ctr;
 1499             if(c->subjectName == initialSubjectName)
 1500                 c->subjectName=finalSubjectName;
 1501         }
 1502         else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOMS){
 1503             ConstraintSubjectActivityTagPreferredRooms* c=(ConstraintSubjectActivityTagPreferredRooms*)ctr;
 1504             if(c->subjectName == initialSubjectName)
 1505                 c->subjectName=finalSubjectName;
 1506         }
 1507     }
 1508 
 1509     //rename the subject in the list
 1510     int t=0;
 1511     for(int i=0; i<this->subjectsList.size(); i++){
 1512         Subject* sbj=this->subjectsList[i];
 1513 
 1514         if(sbj->name==initialSubjectName){
 1515             t++;
 1516             sbj->name=finalSubjectName;
 1517         }
 1518     }
 1519     assert(t==1);
 1520 
 1521     this->internalStructureComputed=false;
 1522     setRulesModifiedAndOtherThings(this);
 1523 
 1524     teachers_schedule_ready=false;
 1525     students_schedule_ready=false;
 1526     rooms_schedule_ready=false;
 1527 
 1528     return true;
 1529 }
 1530 
 1531 void Rules::sortSubjectsAlphabetically()
 1532 {
 1533     std::stable_sort(this->subjectsList.begin(), this->subjectsList.end(), subjectsAscending);
 1534 
 1535     this->internalStructureComputed=false;
 1536     setRulesModifiedAndOtherThings(this);
 1537 
 1538     teachers_schedule_ready=false;
 1539     students_schedule_ready=false;
 1540     rooms_schedule_ready=false;
 1541 }
 1542 
 1543 bool Rules::addActivityTag(ActivityTag* activityTag)
 1544 {
 1545     for(int i=0; i<this->activityTagsList.size(); i++){
 1546         ActivityTag* sbt=this->activityTagsList[i];
 1547 
 1548         if(sbt->name==activityTag->name)
 1549             return false;
 1550     }
 1551 
 1552     this->internalStructureComputed=false;
 1553     setRulesModifiedAndOtherThings(this);
 1554 
 1555     teachers_schedule_ready=false;
 1556     students_schedule_ready=false;
 1557     rooms_schedule_ready=false;
 1558 
 1559     this->activityTagsList << activityTag;
 1560     return true;
 1561 }
 1562 
 1563 bool Rules::addActivityTagFast(ActivityTag* activityTag)
 1564 {
 1565     this->internalStructureComputed=false;
 1566     setRulesModifiedAndOtherThings(this);
 1567 
 1568     teachers_schedule_ready=false;
 1569     students_schedule_ready=false;
 1570     rooms_schedule_ready=false;
 1571 
 1572     this->activityTagsList << activityTag;
 1573     return true;
 1574 }
 1575 
 1576 int Rules::searchActivityTag(const QString& activityTagName)
 1577 {
 1578     for(int i=0; i<this->activityTagsList.size(); i++)
 1579         if(this->activityTagsList.at(i)->name==activityTagName)
 1580             return i;
 1581 
 1582     return -1;
 1583 }
 1584 
 1585 bool Rules::removeActivityTag(const QString& activityTagName)
 1586 {
 1587     for(Activity* act : qAsConst(activitiesList))
 1588         if(act->activityTagsNames.contains(activityTagName))
 1589             act->activityTagsNames.removeAll(activityTagName);
 1590 
 1591     //remove the activity tag from the list
 1592     for(int i=0; i<this->activityTagsList.size(); i++)
 1593         if(this->activityTagsList[i]->name==activityTagName){
 1594             ActivityTag* sbt=this->activityTagsList[i];
 1595             this->activityTagsList.removeAt(i);
 1596             delete sbt;
 1597             break;
 1598         }
 1599     
 1600     updateConstraintsAfterRemoval();
 1601 
 1602     this->internalStructureComputed=false;
 1603     setRulesModifiedAndOtherThings(this);
 1604 
 1605     teachers_schedule_ready=false;
 1606     students_schedule_ready=false;
 1607     rooms_schedule_ready=false;
 1608 
 1609     return true;
 1610 }
 1611 
 1612 bool Rules::modifyActivityTag(const QString& initialActivityTagName, const QString& finalActivityTagName)
 1613 {
 1614     assert(this->searchActivityTag(finalActivityTagName)==-1);
 1615     assert(this->searchActivityTag(initialActivityTagName)>=0);
 1616 
 1617     //check the activities first
 1618     for(int i=0; i<this->activitiesList.size(); i++){
 1619         Activity* act=this->activitiesList[i];
 1620 
 1621         for(int kk=0; kk<act->activityTagsNames.count(); kk++)
 1622             if(act->activityTagsNames.at(kk)==initialActivityTagName)
 1623                 act->activityTagsNames[kk]=finalActivityTagName;
 1624     }
 1625     
 1626     //modify the time constraints related to this activity tag
 1627     for(TimeConstraint* ctr : qAsConst(timeConstraintsList)){
 1628         if(ctr->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 1629             ConstraintTeacherActivityTagMaxHoursContinuously* crt_constraint=(ConstraintTeacherActivityTagMaxHoursContinuously*)ctr;
 1630             if(initialActivityTagName == crt_constraint->activityTagName)
 1631                 crt_constraint->activityTagName=finalActivityTagName;
 1632         }
 1633         else if(ctr->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_DAILY){
 1634             ConstraintTeacherActivityTagMaxHoursDaily* crt_constraint=(ConstraintTeacherActivityTagMaxHoursDaily*)ctr;
 1635             if(initialActivityTagName == crt_constraint->activityTagName)
 1636                 crt_constraint->activityTagName=finalActivityTagName;
 1637         }
 1638         else if(ctr->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MIN_HOURS_DAILY){
 1639             ConstraintTeacherActivityTagMinHoursDaily* crt_constraint=(ConstraintTeacherActivityTagMinHoursDaily*)ctr;
 1640             if(initialActivityTagName == crt_constraint->activityTagName)
 1641                 crt_constraint->activityTagName=finalActivityTagName;
 1642         }
 1643         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 1644             ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 1645             if(initialActivityTagName == crt_constraint->firstActivityTag)
 1646                 crt_constraint->firstActivityTag=finalActivityTagName;
 1647             if(initialActivityTagName == crt_constraint->secondActivityTag)
 1648                 crt_constraint->secondActivityTag=finalActivityTagName;
 1649         }
 1650         else if(ctr->type==CONSTRAINT_STUDENTS_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 1651             ConstraintStudentsMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintStudentsMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 1652             if(initialActivityTagName == crt_constraint->firstActivityTag)
 1653                 crt_constraint->firstActivityTag=finalActivityTagName;
 1654             if(initialActivityTagName == crt_constraint->secondActivityTag)
 1655                 crt_constraint->secondActivityTag=finalActivityTagName;
 1656         }
 1657         else if(ctr->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 1658             ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 1659             if(initialActivityTagName == crt_constraint->firstActivityTag)
 1660                 crt_constraint->firstActivityTag=finalActivityTagName;
 1661             if(initialActivityTagName == crt_constraint->secondActivityTag)
 1662                 crt_constraint->secondActivityTag=finalActivityTagName;
 1663         }
 1664         else if(ctr->type==CONSTRAINT_TEACHERS_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 1665             ConstraintTeachersMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintTeachersMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 1666             if(initialActivityTagName == crt_constraint->firstActivityTag)
 1667                 crt_constraint->firstActivityTag=finalActivityTagName;
 1668             if(initialActivityTagName == crt_constraint->secondActivityTag)
 1669                 crt_constraint->secondActivityTag=finalActivityTagName;
 1670         }
 1671         else if(ctr->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 1672             ConstraintTeachersActivityTagMaxHoursContinuously* crt_constraint=(ConstraintTeachersActivityTagMaxHoursContinuously*)ctr;
 1673             if(initialActivityTagName == crt_constraint->activityTagName)
 1674                 crt_constraint->activityTagName=finalActivityTagName;
 1675         }
 1676         else if(ctr->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_DAILY){
 1677             ConstraintTeachersActivityTagMaxHoursDaily* crt_constraint=(ConstraintTeachersActivityTagMaxHoursDaily*)ctr;
 1678             if(initialActivityTagName == crt_constraint->activityTagName)
 1679                 crt_constraint->activityTagName=finalActivityTagName;
 1680         }
 1681         else if(ctr->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MIN_HOURS_DAILY){
 1682             ConstraintTeachersActivityTagMinHoursDaily* crt_constraint=(ConstraintTeachersActivityTagMinHoursDaily*)ctr;
 1683             if(initialActivityTagName == crt_constraint->activityTagName)
 1684                 crt_constraint->activityTagName=finalActivityTagName;
 1685         }
 1686         else if(ctr->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 1687             ConstraintStudentsActivityTagMaxHoursContinuously* crt_constraint=(ConstraintStudentsActivityTagMaxHoursContinuously*)ctr;
 1688             if(initialActivityTagName == crt_constraint->activityTagName)
 1689                 crt_constraint->activityTagName=finalActivityTagName;
 1690         }
 1691         else if(ctr->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_DAILY){
 1692             ConstraintStudentsActivityTagMaxHoursDaily* crt_constraint=(ConstraintStudentsActivityTagMaxHoursDaily*)ctr;
 1693             if(initialActivityTagName == crt_constraint->activityTagName)
 1694                 crt_constraint->activityTagName=finalActivityTagName;
 1695         }
 1696         else if(ctr->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MIN_HOURS_DAILY){
 1697             ConstraintStudentsActivityTagMinHoursDaily* crt_constraint=(ConstraintStudentsActivityTagMinHoursDaily*)ctr;
 1698             if(initialActivityTagName == crt_constraint->activityTagName)
 1699                 crt_constraint->activityTagName=finalActivityTagName;
 1700         }
 1701         else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 1702             ConstraintStudentsSetActivityTagMaxHoursContinuously* crt_constraint=(ConstraintStudentsSetActivityTagMaxHoursContinuously*)ctr;
 1703             if(initialActivityTagName == crt_constraint->activityTagName)
 1704                 crt_constraint->activityTagName=finalActivityTagName;
 1705         }
 1706         else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_DAILY){
 1707             ConstraintStudentsSetActivityTagMaxHoursDaily* crt_constraint=(ConstraintStudentsSetActivityTagMaxHoursDaily*)ctr;
 1708             if(initialActivityTagName == crt_constraint->activityTagName)
 1709                 crt_constraint->activityTagName=finalActivityTagName;
 1710         }
 1711         else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MIN_HOURS_DAILY){
 1712             ConstraintStudentsSetActivityTagMinHoursDaily* crt_constraint=(ConstraintStudentsSetActivityTagMinHoursDaily*)ctr;
 1713             if(initialActivityTagName == crt_constraint->activityTagName)
 1714                 crt_constraint->activityTagName=finalActivityTagName;
 1715         }
 1716         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
 1717             ConstraintActivitiesPreferredTimeSlots* crt_constraint=(ConstraintActivitiesPreferredTimeSlots*)ctr;
 1718             if(initialActivityTagName == crt_constraint->p_activityTagName)
 1719                 crt_constraint->p_activityTagName=finalActivityTagName;
 1720         }
 1721         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
 1722             ConstraintActivitiesPreferredStartingTimes* crt_constraint=(ConstraintActivitiesPreferredStartingTimes*)ctr;
 1723             if(initialActivityTagName == crt_constraint->activityTagName)
 1724                 crt_constraint->activityTagName=finalActivityTagName;
 1725         }
 1726         else if(ctr->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
 1727             ConstraintActivitiesEndStudentsDay* crt_constraint=(ConstraintActivitiesEndStudentsDay*)ctr;
 1728             if(initialActivityTagName == crt_constraint->activityTagName)
 1729                 crt_constraint->activityTagName=finalActivityTagName;
 1730         }
 1731         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
 1732             ConstraintSubactivitiesPreferredTimeSlots* crt_constraint=(ConstraintSubactivitiesPreferredTimeSlots*)ctr;
 1733             if(initialActivityTagName == crt_constraint->p_activityTagName)
 1734                 crt_constraint->p_activityTagName=finalActivityTagName;
 1735         }
 1736         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
 1737             ConstraintSubactivitiesPreferredStartingTimes* crt_constraint=(ConstraintSubactivitiesPreferredStartingTimes*)ctr;
 1738             if(initialActivityTagName == crt_constraint->activityTagName)
 1739                 crt_constraint->activityTagName=finalActivityTagName;
 1740         }
 1741         else if(ctr->type==CONSTRAINT_ACTIVITY_TAGS_NOT_OVERLAPPING){
 1742             ConstraintActivityTagsNotOverlapping* crt_constraint=(ConstraintActivityTagsNotOverlapping*)ctr;
 1743             int cnt=0;
 1744             for(int i=0; i<crt_constraint->activityTagsNames.count(); i++){
 1745                 if(crt_constraint->activityTagsNames.at(i)==initialActivityTagName){
 1746                     crt_constraint->activityTagsNames[i]=finalActivityTagName;
 1747                     cnt++;
 1748                 }
 1749             }
 1750             assert(cnt<=1);
 1751         }
 1752     }
 1753 
 1754     //modify the space constraints related to this activity tag
 1755     for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 1756         if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOM){
 1757             ConstraintSubjectActivityTagPreferredRoom* c=(ConstraintSubjectActivityTagPreferredRoom*)ctr;
 1758             if(c->activityTagName == initialActivityTagName)
 1759                 c->activityTagName=finalActivityTagName;
 1760         }
 1761         else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOMS){
 1762             ConstraintSubjectActivityTagPreferredRooms* c=(ConstraintSubjectActivityTagPreferredRooms*)ctr;
 1763             if(c->activityTagName == initialActivityTagName)
 1764                 c->activityTagName=finalActivityTagName;
 1765         }
 1766         else if(ctr->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOM){
 1767             ConstraintActivityTagPreferredRoom* c=(ConstraintActivityTagPreferredRoom*)ctr;
 1768             if(c->activityTagName == initialActivityTagName)
 1769                 c->activityTagName=finalActivityTagName;
 1770         }
 1771         else if(ctr->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOMS){
 1772             ConstraintActivityTagPreferredRooms* c=(ConstraintActivityTagPreferredRooms*)ctr;
 1773             if(c->activityTagName == initialActivityTagName)
 1774                 c->activityTagName=finalActivityTagName;
 1775         }
 1776     }
 1777 
 1778     //rename the activity tag in the list
 1779     int t=0;
 1780     
 1781     for(int i=0; i<this->activityTagsList.size(); i++){
 1782         ActivityTag* sbt=this->activityTagsList[i];
 1783 
 1784         if(sbt->name==initialActivityTagName){
 1785             t++;
 1786             sbt->name=finalActivityTagName;
 1787         }
 1788     }
 1789     
 1790     assert(t==1);
 1791 
 1792     this->internalStructureComputed=false;
 1793     setRulesModifiedAndOtherThings(this);
 1794 
 1795     teachers_schedule_ready=false;
 1796     students_schedule_ready=false;
 1797     rooms_schedule_ready=false;
 1798 
 1799     return true;
 1800 }
 1801 
 1802 void Rules::sortActivityTagsAlphabetically()
 1803 {
 1804     std::stable_sort(this->activityTagsList.begin(), this->activityTagsList.end(), activityTagsAscending);
 1805 
 1806     this->internalStructureComputed=false;
 1807     setRulesModifiedAndOtherThings(this);
 1808 
 1809     teachers_schedule_ready=false;
 1810     students_schedule_ready=false;
 1811     rooms_schedule_ready=false;
 1812 }
 1813 
 1814 bool Rules::setsShareStudents(const QString& studentsSet1, const QString& studentsSet2)
 1815 {
 1816     StudentsSet* s1=this->searchStudentsSet(studentsSet1);
 1817     StudentsSet* s2=this->searchStudentsSet(studentsSet2);
 1818     assert(s1!=NULL);
 1819     assert(s2!=NULL);
 1820     
 1821     QSet<QString> downwardSets1;
 1822     
 1823     if(s1->type==STUDENTS_YEAR){
 1824         StudentsYear* year1=(StudentsYear*)s1;
 1825         downwardSets1.insert(year1->name);
 1826         for(StudentsGroup* group1 : qAsConst(year1->groupsList)){
 1827             downwardSets1.insert(group1->name);
 1828             for(StudentsSubgroup* subgroup1 : qAsConst(group1->subgroupsList))
 1829                 downwardSets1.insert(subgroup1->name);
 1830         }
 1831     }
 1832     else if(s1->type==STUDENTS_GROUP){
 1833         StudentsGroup* group1=(StudentsGroup*)s1;
 1834         downwardSets1.insert(group1->name);
 1835         for(StudentsSubgroup* subgroup1 : qAsConst(group1->subgroupsList))
 1836             downwardSets1.insert(subgroup1->name);
 1837     }
 1838     else if(s1->type==STUDENTS_SUBGROUP){
 1839         StudentsSubgroup* subgroup1=(StudentsSubgroup*)s1;
 1840         downwardSets1.insert(subgroup1->name);
 1841     }
 1842     else
 1843         assert(0);
 1844         
 1845     if(s2->type==STUDENTS_YEAR){
 1846         StudentsYear* year2=(StudentsYear*)s2;
 1847         if(downwardSets1.contains(year2->name))
 1848             return true;
 1849         for(StudentsGroup* group2 : qAsConst(year2->groupsList)){
 1850             if(downwardSets1.contains(group2->name))
 1851                 return true;
 1852             for(StudentsSubgroup* subgroup2 : qAsConst(group2->subgroupsList))
 1853                 if(downwardSets1.contains(subgroup2->name))
 1854                     return true;
 1855         }
 1856     }
 1857     else if(s2->type==STUDENTS_GROUP){
 1858         StudentsGroup* group2=(StudentsGroup*)s2;
 1859         if(downwardSets1.contains(group2->name))
 1860             return true;
 1861         for(StudentsSubgroup* subgroup2 : qAsConst(group2->subgroupsList))
 1862             if(downwardSets1.contains(subgroup2->name))
 1863                 return true;
 1864     }
 1865     else if(s2->type==STUDENTS_SUBGROUP){
 1866         StudentsSubgroup* subgroup2=(StudentsSubgroup*)s2;
 1867         if(downwardSets1.contains(subgroup2->name))
 1868             return true;
 1869     }
 1870     else
 1871         assert(0);
 1872     
 1873     return false;
 1874     
 1875 }
 1876 
 1877 bool Rules::augmentedSetsShareStudentsFaster(const QString& studentsSet1, const QString& studentsSet2)
 1878 {
 1879     //StudentsSet* s1=this->searchStudentsSet(studentsSet1);
 1880     StudentsSet* s1=studentsHash.value(studentsSet1, NULL);
 1881     //StudentsSet* s2=this->searchStudentsSet(studentsSet2);
 1882     StudentsSet* s2=studentsHash.value(studentsSet2, NULL);
 1883     assert(s1!=NULL);
 1884     assert(s2!=NULL);
 1885     
 1886     QSet<QString> downwardSets1;
 1887     
 1888     if(s1->type==STUDENTS_YEAR){
 1889         StudentsYear* year1=(StudentsYear*)s1;
 1890         downwardSets1.insert(year1->name);
 1891         for(StudentsGroup* group1 : qAsConst(year1->groupsList)){
 1892             downwardSets1.insert(group1->name);
 1893             for(StudentsSubgroup* subgroup1 : qAsConst(group1->subgroupsList))
 1894                 downwardSets1.insert(subgroup1->name);
 1895         }
 1896     }
 1897     else if(s1->type==STUDENTS_GROUP){
 1898         StudentsGroup* group1=(StudentsGroup*)s1;
 1899         downwardSets1.insert(group1->name);
 1900         for(StudentsSubgroup* subgroup1 : qAsConst(group1->subgroupsList))
 1901             downwardSets1.insert(subgroup1->name);
 1902     }
 1903     else if(s1->type==STUDENTS_SUBGROUP){
 1904         StudentsSubgroup* subgroup1=(StudentsSubgroup*)s1;
 1905         downwardSets1.insert(subgroup1->name);
 1906     }
 1907     else
 1908         assert(0);
 1909         
 1910     if(s2->type==STUDENTS_YEAR){
 1911         StudentsYear* year2=(StudentsYear*)s2;
 1912         if(downwardSets1.contains(year2->name))
 1913             return true;
 1914         for(StudentsGroup* group2 : qAsConst(year2->groupsList)){
 1915             if(downwardSets1.contains(group2->name))
 1916                 return true;
 1917             for(StudentsSubgroup* subgroup2 : qAsConst(group2->subgroupsList))
 1918                 if(downwardSets1.contains(subgroup2->name))
 1919                     return true;
 1920         }
 1921     }
 1922     else if(s2->type==STUDENTS_GROUP){
 1923         StudentsGroup* group2=(StudentsGroup*)s2;
 1924         if(downwardSets1.contains(group2->name))
 1925             return true;
 1926         for(StudentsSubgroup* subgroup2 : qAsConst(group2->subgroupsList))
 1927             if(downwardSets1.contains(subgroup2->name))
 1928                 return true;
 1929     }
 1930     else if(s2->type==STUDENTS_SUBGROUP){
 1931         StudentsSubgroup* subgroup2=(StudentsSubgroup*)s2;
 1932         if(downwardSets1.contains(subgroup2->name))
 1933             return true;
 1934     }
 1935     else
 1936         assert(0);
 1937     
 1938     return false;
 1939     
 1940 }
 1941 
 1942 void Rules::computePermanentStudentsHash()
 1943 {
 1944     //The commented tests are good, but bring a somewhat slowdown.
 1945     permanentStudentsHash.clear();
 1946     
 1947     for(StudentsYear* year : qAsConst(yearsList)){
 1948         assert(!permanentStudentsHash.contains(year->name));
 1949         permanentStudentsHash.insert(year->name, year);
 1950         
 1951         //QSet<QString> groupsInYear;
 1952         
 1953         for(StudentsGroup* group : qAsConst(year->groupsList)){
 1954             //assert(!groupsInYear.contains(group->name));
 1955             //groupsInYear.insert(group->name);
 1956         
 1957             if(!permanentStudentsHash.contains(group->name))
 1958                 permanentStudentsHash.insert(group->name, group);
 1959             else
 1960                 assert(permanentStudentsHash.value(group->name)==group);
 1961             
 1962             //QSet<QString> subgroupsInGroup;
 1963             
 1964             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
 1965                 //assert(!subgroupsInGroup.contains(subgroup->name));
 1966                 //subgroupsInGroup.insert(subgroup->name);
 1967             
 1968                 if(!permanentStudentsHash.contains(subgroup->name))
 1969                     permanentStudentsHash.insert(subgroup->name, subgroup);
 1970                 else
 1971                     assert(permanentStudentsHash.value(subgroup->name)==subgroup);
 1972             }
 1973         }
 1974     }
 1975 }
 1976 
 1977 StudentsSet* Rules::searchStudentsSet(const QString& setName)
 1978 {
 1979     return permanentStudentsHash.value(setName, NULL);
 1980 
 1981     /*for(int i=0; i<this->yearsList.size(); i++){
 1982         StudentsYear* sty=this->yearsList[i];
 1983         if(sty->name==setName)
 1984             return sty;
 1985         for(int j=0; j<sty->groupsList.size(); j++){
 1986             StudentsGroup* stg=sty->groupsList[j];
 1987             if(stg->name==setName)
 1988                 return stg;
 1989             for(int k=0; k<stg->subgroupsList.size(); k++){
 1990                 StudentsSubgroup* sts=stg->subgroupsList[k];
 1991                 if(sts->name==setName)
 1992                     return sts;
 1993             }
 1994         }
 1995     }
 1996     return NULL;*/
 1997 }
 1998 
 1999 StudentsSet* Rules::searchAugmentedStudentsSet(const QString& setName)
 2000 {
 2001     for(int i=0; i<this->augmentedYearsList.size(); i++){
 2002         StudentsYear* sty=this->augmentedYearsList[i];
 2003         if(sty->name==setName)
 2004             return sty;
 2005         for(int j=0; j<sty->groupsList.size(); j++){
 2006             StudentsGroup* stg=sty->groupsList[j];
 2007             if(stg->name==setName)
 2008                 return stg;
 2009             for(int k=0; k<stg->subgroupsList.size(); k++){
 2010                 StudentsSubgroup* sts=stg->subgroupsList[k];
 2011                 if(sts->name==setName)
 2012                     return sts;
 2013             }
 2014         }
 2015     }
 2016     return NULL;
 2017 }
 2018 
 2019 bool Rules::addYear(StudentsYear* year)
 2020 {
 2021     //already existing?
 2022     for(StudentsYear* ty : qAsConst(yearsList))
 2023         if(ty->name==year->name)
 2024             return false;
 2025     //if(this->searchStudentsSet(year->name)!=NULL)
 2026     //  return false;
 2027     this->yearsList << year;
 2028     
 2029     assert(!permanentStudentsHash.contains(year->name));
 2030     permanentStudentsHash.insert(year->name, year);
 2031     
 2032     this->internalStructureComputed=false;
 2033     setRulesModifiedAndOtherThings(this);
 2034 
 2035     teachers_schedule_ready=false;
 2036     students_schedule_ready=false;
 2037     rooms_schedule_ready=false;
 2038 
 2039     return true;
 2040 }
 2041 
 2042 bool Rules::addYearFast(StudentsYear* year)
 2043 {
 2044     this->yearsList << year;
 2045     this->internalStructureComputed=false;
 2046     setRulesModifiedAndOtherThings(this);
 2047 
 2048     teachers_schedule_ready=false;
 2049     students_schedule_ready=false;
 2050     rooms_schedule_ready=false;
 2051 
 2052     return true;
 2053 }
 2054 
 2055 /*bool Rules::removeYear(const QString& yearName)
 2056 {
 2057     return removeYear(yearName, true);
 2058 }
 2059 
 2060 bool Rules::emptyYear(const QString& yearName)
 2061 {
 2062     return removeYear(yearName, false);
 2063 }*/
 2064 
 2065 bool Rules::removeYear(const QString& yearName/*, bool removeAlsoThisYear*/)
 2066 {
 2067     const bool removeAlsoThisYear=true;
 2068 
 2069     StudentsYear* yearPointer=NULL;
 2070     for(StudentsYear* ty : qAsConst(this->yearsList)){
 2071         if(ty->name==yearName){
 2072             yearPointer=ty;
 2073             break;
 2074         }
 2075     }
 2076 
 2077     assert(yearPointer!=NULL);
 2078     
 2079     //pointers
 2080     QSet<StudentsSet*> tmpSet;
 2081     for(StudentsYear* year : qAsConst(yearsList))
 2082         if(year->name!=yearName){
 2083             tmpSet.insert(year);
 2084             for(StudentsGroup* group : qAsConst(year->groupsList)){
 2085                 tmpSet.insert(group);
 2086                 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
 2087                     tmpSet.insert(subgroup);
 2088             }
 2089         }
 2090     
 2091     QSet<StudentsSet*> toBeRemoved;
 2092     if(removeAlsoThisYear)
 2093         toBeRemoved.insert(yearPointer);
 2094     for(StudentsGroup* group : qAsConst(yearPointer->groupsList)){
 2095         assert(!toBeRemoved.contains(group));
 2096         if(!tmpSet.contains(group))
 2097             toBeRemoved.insert(group);
 2098         for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
 2099             //assert(!toBeRemoved.contains(subgroup));
 2100             if(!tmpSet.contains(subgroup) && !toBeRemoved.contains(subgroup))
 2101                 toBeRemoved.insert(subgroup);
 2102         }
 2103     }
 2104     
 2105     updateActivitiesWhenRemovingStudents(toBeRemoved, false);
 2106     
 2107     if(removeAlsoThisYear){
 2108         for(int i=0; i<yearsList.count(); i++)
 2109             if(yearsList.at(i)==yearPointer){
 2110                 yearsList.removeAt(i);
 2111                 break;
 2112             }
 2113     }
 2114     else{
 2115         yearPointer->groupsList.clear();
 2116     }
 2117     
 2118     for(StudentsSet* studentsSet : qAsConst(toBeRemoved)){
 2119         assert(permanentStudentsHash.contains(studentsSet->name));
 2120         permanentStudentsHash.remove(studentsSet->name);
 2121     
 2122         delete studentsSet;
 2123     }
 2124         
 2125     if(toBeRemoved.count()>0)
 2126         updateConstraintsAfterRemoval();
 2127     
 2128     this->internalStructureComputed=false;
 2129     setRulesModifiedAndOtherThings(this);
 2130 
 2131     teachers_schedule_ready=false;
 2132     students_schedule_ready=false;
 2133     rooms_schedule_ready=false;
 2134 
 2135     return true;
 2136 }
 2137 
 2138 bool Rules::removeYearPointerAfterSplit(StudentsYear* yearPointer)
 2139 {
 2140     assert(yearPointer!=NULL);
 2141     
 2142     //names
 2143     QSet<StudentsSet*> toBeRemoved;
 2144 
 2145     //Not here, because there exists another pointer with the same name (to the new year),
 2146     //and I don't want to remove the activities with this year name
 2147     //toBeRemoved.insert(yearPointer);
 2148     for(StudentsGroup* group : qAsConst(yearPointer->groupsList)){
 2149         assert(!toBeRemoved.contains(group));
 2150         if(!permanentStudentsHash.contains(group->name))
 2151             toBeRemoved.insert(group);
 2152         for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
 2153             //assert(!toBeRemoved.contains(subgroup));
 2154             if(!permanentStudentsHash.contains(subgroup->name) && !toBeRemoved.contains(subgroup))
 2155                 toBeRemoved.insert(subgroup);
 2156         }
 2157     }
 2158     
 2159     updateActivitiesWhenRemovingStudents(toBeRemoved, false);
 2160     
 2161     toBeRemoved.insert(yearPointer);
 2162     for(StudentsSet* studentsSet : qAsConst(toBeRemoved))
 2163         delete studentsSet;
 2164         
 2165     if(toBeRemoved.count()>1)
 2166         updateConstraintsAfterRemoval();
 2167     
 2168     this->internalStructureComputed=false;
 2169     setRulesModifiedAndOtherThings(this);
 2170 
 2171     teachers_schedule_ready=false;
 2172     students_schedule_ready=false;
 2173     rooms_schedule_ready=false;
 2174 
 2175     return true;
 2176 }
 2177 
 2178 int Rules::searchYear(const QString& yearName)
 2179 {
 2180     for(int i=0; i<this->yearsList.size(); i++)
 2181         if(this->yearsList[i]->name==yearName)
 2182             return i;
 2183 
 2184     return -1;
 2185 }
 2186 
 2187 int Rules::searchAugmentedYear(const QString& yearName)
 2188 {
 2189     for(int i=0; i<this->augmentedYearsList.size(); i++)
 2190         if(this->augmentedYearsList[i]->name==yearName)
 2191             return i;
 2192 
 2193     return -1;
 2194 }
 2195 
 2196 bool Rules::modifyStudentsSet(const QString& initialStudentsSetName, const QString& finalStudentsSetName, int finalNumberOfStudents)
 2197 {
 2198     StudentsSet* studentsSet=searchStudentsSet(initialStudentsSetName);
 2199     assert(studentsSet!=NULL);
 2200     if(initialStudentsSetName!=finalStudentsSetName)
 2201         assert(searchStudentsSet(finalStudentsSetName)==NULL);
 2202     int initialNumberOfStudents=studentsSet->numberOfStudents;
 2203     
 2204     for(Activity* act : qAsConst(activitiesList))
 2205         act->renameStudents(*this, initialStudentsSetName, finalStudentsSetName, initialNumberOfStudents, finalNumberOfStudents);
 2206     
 2207     if(initialStudentsSetName!=finalStudentsSetName){
 2208         for(TimeConstraint* ctr : qAsConst(timeConstraintsList)){
 2209             if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 2210                 ConstraintStudentsSetNotAvailableTimes* crt_constraint=(ConstraintStudentsSetNotAvailableTimes*)ctr;
 2211                 if(initialStudentsSetName == crt_constraint->students)
 2212                     crt_constraint->students=finalStudentsSetName;
 2213             }
 2214             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_DAILY){
 2215                 ConstraintStudentsSetMaxHoursDaily* crt_constraint=(ConstraintStudentsSetMaxHoursDaily*)ctr;
 2216                 if(initialStudentsSetName == crt_constraint->students)
 2217                     crt_constraint->students=finalStudentsSetName;
 2218             }
 2219             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_DAYS_PER_WEEK){
 2220                 ConstraintStudentsSetMaxDaysPerWeek* crt_constraint=(ConstraintStudentsSetMaxDaysPerWeek*)ctr;
 2221                 if(initialStudentsSetName == crt_constraint->students)
 2222                     crt_constraint->students=finalStudentsSetName;
 2223             }
 2224             else if(ctr->type==CONSTRAINT_STUDENTS_SET_INTERVAL_MAX_DAYS_PER_WEEK){
 2225                 ConstraintStudentsSetIntervalMaxDaysPerWeek* crt_constraint=(ConstraintStudentsSetIntervalMaxDaysPerWeek*)ctr;
 2226                 if(initialStudentsSetName == crt_constraint->students)
 2227                     crt_constraint->students=finalStudentsSetName;
 2228             }
 2229             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_CONTINUOUSLY){
 2230                 ConstraintStudentsSetMaxHoursContinuously* crt_constraint=(ConstraintStudentsSetMaxHoursContinuously*)ctr;
 2231                 if(initialStudentsSetName == crt_constraint->students)
 2232                     crt_constraint->students=finalStudentsSetName;
 2233             }
 2234             else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 2235                 ConstraintStudentsSetActivityTagMaxHoursContinuously* crt_constraint=(ConstraintStudentsSetActivityTagMaxHoursContinuously*)ctr;
 2236                 if(initialStudentsSetName == crt_constraint->students)
 2237                     crt_constraint->students=finalStudentsSetName;
 2238             }
 2239             else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_DAILY){
 2240                 ConstraintStudentsSetActivityTagMaxHoursDaily* crt_constraint=(ConstraintStudentsSetActivityTagMaxHoursDaily*)ctr;
 2241                 if(initialStudentsSetName == crt_constraint->students)
 2242                     crt_constraint->students=finalStudentsSetName;
 2243             }
 2244             else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MIN_HOURS_DAILY){
 2245                 ConstraintStudentsSetActivityTagMinHoursDaily* crt_constraint=(ConstraintStudentsSetActivityTagMinHoursDaily*)ctr;
 2246                 if(initialStudentsSetName == crt_constraint->students)
 2247                     crt_constraint->students=finalStudentsSetName;
 2248             }
 2249             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_HOURS_DAILY){
 2250                 ConstraintStudentsSetMinHoursDaily* crt_constraint=(ConstraintStudentsSetMinHoursDaily*)ctr;
 2251                 if(initialStudentsSetName == crt_constraint->students)
 2252                     crt_constraint->students=finalStudentsSetName;
 2253             }
 2254             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 2255                 ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 2256                 if(initialStudentsSetName == crt_constraint->students)
 2257                     crt_constraint->students=finalStudentsSetName;
 2258             }
 2259             else if(ctr->type==CONSTRAINT_STUDENTS_SET_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
 2260                 ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour* crt_constraint=(ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour*)ctr;
 2261                 if(initialStudentsSetName == crt_constraint->students)
 2262                     crt_constraint->students=finalStudentsSetName;
 2263             }
 2264             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_WEEK){
 2265                 ConstraintStudentsSetMaxGapsPerWeek* crt_constraint=(ConstraintStudentsSetMaxGapsPerWeek*)ctr;
 2266                 if(initialStudentsSetName == crt_constraint->students)
 2267                     crt_constraint->students=finalStudentsSetName;
 2268             }
 2269             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_DAY){
 2270                 ConstraintStudentsSetMaxGapsPerDay* crt_constraint=(ConstraintStudentsSetMaxGapsPerDay*)ctr;
 2271                 if(initialStudentsSetName == crt_constraint->students)
 2272                     crt_constraint->students=finalStudentsSetName;
 2273             }
 2274             else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
 2275                 ConstraintActivitiesPreferredTimeSlots* crt_constraint=(ConstraintActivitiesPreferredTimeSlots*)ctr;
 2276                 if(initialStudentsSetName == crt_constraint->p_studentsName)
 2277                     crt_constraint->p_studentsName=finalStudentsSetName;
 2278             }
 2279             else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
 2280                 ConstraintActivitiesPreferredStartingTimes* crt_constraint=(ConstraintActivitiesPreferredStartingTimes*)ctr;
 2281                 if(initialStudentsSetName == crt_constraint->studentsName)
 2282                     crt_constraint->studentsName=finalStudentsSetName;
 2283             }
 2284             else if(ctr->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
 2285                 ConstraintActivitiesEndStudentsDay* crt_constraint=(ConstraintActivitiesEndStudentsDay*)ctr;
 2286                 if(initialStudentsSetName == crt_constraint->studentsName)
 2287                     crt_constraint->studentsName=finalStudentsSetName;
 2288             }
 2289             else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
 2290                 ConstraintSubactivitiesPreferredTimeSlots* crt_constraint=(ConstraintSubactivitiesPreferredTimeSlots*)ctr;
 2291                 if(initialStudentsSetName == crt_constraint->p_studentsName)
 2292                     crt_constraint->p_studentsName=finalStudentsSetName;
 2293             }
 2294             else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
 2295                 ConstraintSubactivitiesPreferredStartingTimes* crt_constraint=(ConstraintSubactivitiesPreferredStartingTimes*)ctr;
 2296                 if(initialStudentsSetName == crt_constraint->studentsName)
 2297                     crt_constraint->studentsName=finalStudentsSetName;
 2298             }
 2299             //2017-02-07
 2300             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_SPAN_PER_DAY){
 2301                 ConstraintStudentsSetMaxSpanPerDay* crt_constraint=(ConstraintStudentsSetMaxSpanPerDay*)ctr;
 2302                 if(initialStudentsSetName == crt_constraint->students)
 2303                     crt_constraint->students=finalStudentsSetName;
 2304             }
 2305             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_RESTING_HOURS){
 2306                 ConstraintStudentsSetMinRestingHours* crt_constraint=(ConstraintStudentsSetMinRestingHours*)ctr;
 2307                 if(initialStudentsSetName == crt_constraint->students)
 2308                     crt_constraint->students=finalStudentsSetName;
 2309             }
 2310         }
 2311 
 2312         for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 2313             if(ctr->type==CONSTRAINT_STUDENTS_SET_HOME_ROOM){
 2314                 ConstraintStudentsSetHomeRoom* crt_constraint=(ConstraintStudentsSetHomeRoom*)ctr;
 2315                 if(initialStudentsSetName == crt_constraint->studentsName)
 2316                     crt_constraint->studentsName=finalStudentsSetName;
 2317             }
 2318             else if(ctr->type==CONSTRAINT_STUDENTS_SET_HOME_ROOMS){
 2319                 ConstraintStudentsSetHomeRooms* crt_constraint=(ConstraintStudentsSetHomeRooms*)ctr;
 2320                 if(initialStudentsSetName == crt_constraint->studentsName)
 2321                     crt_constraint->studentsName=finalStudentsSetName;
 2322             }
 2323             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_BUILDING_CHANGES_PER_DAY){
 2324                 ConstraintStudentsSetMaxBuildingChangesPerDay* crt_constraint=(ConstraintStudentsSetMaxBuildingChangesPerDay*)ctr;
 2325                 if(initialStudentsSetName == crt_constraint->studentsName)
 2326                     crt_constraint->studentsName=finalStudentsSetName;
 2327             }
 2328             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_BUILDING_CHANGES_PER_WEEK){
 2329                 ConstraintStudentsSetMaxBuildingChangesPerWeek* crt_constraint=(ConstraintStudentsSetMaxBuildingChangesPerWeek*)ctr;
 2330                 if(initialStudentsSetName == crt_constraint->studentsName)
 2331                     crt_constraint->studentsName=finalStudentsSetName;
 2332             }
 2333             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
 2334                 ConstraintStudentsSetMinGapsBetweenBuildingChanges* crt_constraint=(ConstraintStudentsSetMinGapsBetweenBuildingChanges*)ctr;
 2335                 if(initialStudentsSetName == crt_constraint->studentsName)
 2336                     crt_constraint->studentsName=finalStudentsSetName;
 2337             }
 2338             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_DAY){
 2339                 ConstraintStudentsSetMaxRoomChangesPerDay* crt_constraint=(ConstraintStudentsSetMaxRoomChangesPerDay*)ctr;
 2340                 if(initialStudentsSetName == crt_constraint->studentsName)
 2341                     crt_constraint->studentsName=finalStudentsSetName;
 2342             }
 2343             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_WEEK){
 2344                 ConstraintStudentsSetMaxRoomChangesPerWeek* crt_constraint=(ConstraintStudentsSetMaxRoomChangesPerWeek*)ctr;
 2345                 if(initialStudentsSetName == crt_constraint->studentsName)
 2346                     crt_constraint->studentsName=finalStudentsSetName;
 2347             }
 2348             else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ROOM_CHANGES){
 2349                 ConstraintStudentsSetMinGapsBetweenRoomChanges* crt_constraint=(ConstraintStudentsSetMinGapsBetweenRoomChanges*)ctr;
 2350                 if(initialStudentsSetName == crt_constraint->studentsName)
 2351                     crt_constraint->studentsName=finalStudentsSetName;
 2352             }
 2353         }
 2354     }
 2355 
 2356     assert(studentsSet->name==initialStudentsSetName);
 2357     assert(studentsSet->numberOfStudents==initialNumberOfStudents);
 2358     studentsSet->name=finalStudentsSetName;
 2359     studentsSet->numberOfStudents=finalNumberOfStudents;
 2360     
 2361     assert(permanentStudentsHash.contains(initialStudentsSetName));
 2362     if(initialStudentsSetName!=finalStudentsSetName){
 2363         permanentStudentsHash.remove(initialStudentsSetName);
 2364         permanentStudentsHash.insert(studentsSet->name, studentsSet);
 2365     }
 2366 
 2367     if(initialStudentsSetName!=finalStudentsSetName){
 2368         if(ssnatHash.contains(initialStudentsSetName)){
 2369             QSet<ConstraintStudentsSetNotAvailableTimes*> cs=ssnatHash.value(initialStudentsSetName);
 2370             ssnatHash.remove(initialStudentsSetName);
 2371             assert(!ssnatHash.contains(finalStudentsSetName));
 2372             ssnatHash.insert(finalStudentsSetName, cs);
 2373         }
 2374     }
 2375     
 2376     this->internalStructureComputed=false;
 2377     setRulesModifiedAndOtherThings(this);
 2378 
 2379     teachers_schedule_ready=false;
 2380     students_schedule_ready=false;
 2381     rooms_schedule_ready=false;
 2382     
 2383     return true;
 2384 }
 2385 
 2386 //by Volker Dirr (start) - very similar to Liviu's modifyStudentsSet
 2387 bool Rules::modifyStudentsSets(const QHash<QString, QString>& oldAndNewStudentsSetNames){
 2388     if(oldAndNewStudentsSetNames.isEmpty())
 2389         return true;
 2390 
 2391     for(Activity* act : qAsConst(activitiesList)){
 2392         for(int i=0; i<act->studentsNames.count(); i++)
 2393             if(oldAndNewStudentsSetNames.contains(act->studentsNames.at(i)))
 2394                 act->studentsNames[i]=oldAndNewStudentsSetNames.value(act->studentsNames.at(i));
 2395     }
 2396     
 2397     for(TimeConstraint* ctr : qAsConst(timeConstraintsList)){
 2398         if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 2399             ConstraintStudentsSetNotAvailableTimes* crt_constraint=(ConstraintStudentsSetNotAvailableTimes*)ctr;
 2400             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2401                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2402         }
 2403         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_DAILY){
 2404             ConstraintStudentsSetMaxHoursDaily* crt_constraint=(ConstraintStudentsSetMaxHoursDaily*)ctr;
 2405             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2406                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2407         }
 2408         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_DAYS_PER_WEEK){
 2409             ConstraintStudentsSetMaxDaysPerWeek* crt_constraint=(ConstraintStudentsSetMaxDaysPerWeek*)ctr;
 2410             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2411                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2412         }
 2413         else if(ctr->type==CONSTRAINT_STUDENTS_SET_INTERVAL_MAX_DAYS_PER_WEEK){
 2414             ConstraintStudentsSetIntervalMaxDaysPerWeek* crt_constraint=(ConstraintStudentsSetIntervalMaxDaysPerWeek*)ctr;
 2415             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2416                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2417         }
 2418         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_CONTINUOUSLY){
 2419             ConstraintStudentsSetMaxHoursContinuously* crt_constraint=(ConstraintStudentsSetMaxHoursContinuously*)ctr;
 2420             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2421                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2422         }
 2423         else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 2424             ConstraintStudentsSetActivityTagMaxHoursContinuously* crt_constraint=(ConstraintStudentsSetActivityTagMaxHoursContinuously*)ctr;
 2425             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2426                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2427         }
 2428         else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_DAILY){
 2429             ConstraintStudentsSetActivityTagMaxHoursDaily* crt_constraint=(ConstraintStudentsSetActivityTagMaxHoursDaily*)ctr;
 2430             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2431                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2432         }
 2433         else if(ctr->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MIN_HOURS_DAILY){
 2434             ConstraintStudentsSetActivityTagMinHoursDaily* crt_constraint=(ConstraintStudentsSetActivityTagMinHoursDaily*)ctr;
 2435             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2436                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2437         }
 2438         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_HOURS_DAILY){
 2439             ConstraintStudentsSetMinHoursDaily* crt_constraint=(ConstraintStudentsSetMinHoursDaily*)ctr;
 2440             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2441                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2442         }
 2443         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 2444             ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags* crt_constraint=(ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags*)ctr;
 2445             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2446                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2447         }
 2448         else if(ctr->type==CONSTRAINT_STUDENTS_SET_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
 2449             ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour* crt_constraint=(ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour*)ctr;
 2450             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2451                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2452         }
 2453         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_WEEK){
 2454             ConstraintStudentsSetMaxGapsPerWeek* crt_constraint=(ConstraintStudentsSetMaxGapsPerWeek*)ctr;
 2455             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2456                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2457         }
 2458         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_DAY){
 2459             ConstraintStudentsSetMaxGapsPerDay* crt_constraint=(ConstraintStudentsSetMaxGapsPerDay*)ctr;
 2460             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2461                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2462         }
 2463         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
 2464             ConstraintActivitiesPreferredTimeSlots* crt_constraint=(ConstraintActivitiesPreferredTimeSlots*)ctr;
 2465             if(oldAndNewStudentsSetNames.contains(crt_constraint->p_studentsName))
 2466                 crt_constraint->p_studentsName=oldAndNewStudentsSetNames.value(crt_constraint->p_studentsName);
 2467         }
 2468         else if(ctr->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
 2469             ConstraintActivitiesPreferredStartingTimes* crt_constraint=(ConstraintActivitiesPreferredStartingTimes*)ctr;
 2470             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2471                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2472         }
 2473         else if(ctr->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
 2474             ConstraintActivitiesEndStudentsDay* crt_constraint=(ConstraintActivitiesEndStudentsDay*)ctr;
 2475             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2476                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2477         }
 2478         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
 2479             ConstraintSubactivitiesPreferredTimeSlots* crt_constraint=(ConstraintSubactivitiesPreferredTimeSlots*)ctr;
 2480             if(oldAndNewStudentsSetNames.contains(crt_constraint->p_studentsName))
 2481                 crt_constraint->p_studentsName=oldAndNewStudentsSetNames.value(crt_constraint->p_studentsName);
 2482         }
 2483         else if(ctr->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
 2484             ConstraintSubactivitiesPreferredStartingTimes* crt_constraint=(ConstraintSubactivitiesPreferredStartingTimes*)ctr;
 2485             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2486                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2487         }
 2488         //2017-02-07
 2489         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_SPAN_PER_DAY){
 2490             ConstraintStudentsSetMaxSpanPerDay* crt_constraint=(ConstraintStudentsSetMaxSpanPerDay*)ctr;
 2491             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2492                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2493         }
 2494         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_RESTING_HOURS){
 2495             ConstraintStudentsSetMinRestingHours* crt_constraint=(ConstraintStudentsSetMinRestingHours*)ctr;
 2496             if(oldAndNewStudentsSetNames.contains(crt_constraint->students))
 2497                 crt_constraint->students=oldAndNewStudentsSetNames.value(crt_constraint->students);
 2498         }
 2499     }
 2500 
 2501     for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 2502         if(ctr->type==CONSTRAINT_STUDENTS_SET_HOME_ROOM){
 2503             ConstraintStudentsSetHomeRoom* crt_constraint=(ConstraintStudentsSetHomeRoom*)ctr;
 2504             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2505                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2506         }
 2507         else if(ctr->type==CONSTRAINT_STUDENTS_SET_HOME_ROOMS){
 2508             ConstraintStudentsSetHomeRooms* crt_constraint=(ConstraintStudentsSetHomeRooms*)ctr;
 2509             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2510                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2511         }
 2512         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_BUILDING_CHANGES_PER_DAY){
 2513             ConstraintStudentsSetMaxBuildingChangesPerDay* crt_constraint=(ConstraintStudentsSetMaxBuildingChangesPerDay*)ctr;
 2514             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2515                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2516         }
 2517         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_BUILDING_CHANGES_PER_WEEK){
 2518             ConstraintStudentsSetMaxBuildingChangesPerWeek* crt_constraint=(ConstraintStudentsSetMaxBuildingChangesPerWeek*)ctr;
 2519             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2520                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2521         }
 2522         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
 2523             ConstraintStudentsSetMinGapsBetweenBuildingChanges* crt_constraint=(ConstraintStudentsSetMinGapsBetweenBuildingChanges*)ctr;
 2524             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2525                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2526         }
 2527         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_DAY){
 2528             ConstraintStudentsSetMaxRoomChangesPerDay* crt_constraint=(ConstraintStudentsSetMaxRoomChangesPerDay*)ctr;
 2529             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2530                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2531         }
 2532         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_WEEK){
 2533             ConstraintStudentsSetMaxRoomChangesPerWeek* crt_constraint=(ConstraintStudentsSetMaxRoomChangesPerWeek*)ctr;
 2534             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2535                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2536         }
 2537         else if(ctr->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ROOM_CHANGES){
 2538             ConstraintStudentsSetMinGapsBetweenRoomChanges* crt_constraint=(ConstraintStudentsSetMinGapsBetweenRoomChanges*)ctr;
 2539             if(oldAndNewStudentsSetNames.contains(crt_constraint->studentsName))
 2540                 crt_constraint->studentsName=oldAndNewStudentsSetNames.value(crt_constraint->studentsName);
 2541         }
 2542     }
 2543 
 2544     QHash<QString, QString>::const_iterator i=oldAndNewStudentsSetNames.constBegin();
 2545     while(i!=oldAndNewStudentsSetNames.constEnd()) {
 2546         StudentsSet* studentsSet=searchStudentsSet(i.key());
 2547         assert(studentsSet!=NULL);
 2548         studentsSet->name=i.value();
 2549         
 2550         assert(permanentStudentsHash.contains(i.key()));
 2551         permanentStudentsHash.remove(i.key());
 2552         permanentStudentsHash.insert(studentsSet->name, studentsSet);
 2553 
 2554         assert(i.key()!=i.value());
 2555         if(ssnatHash.contains(i.key())){
 2556             QSet<ConstraintStudentsSetNotAvailableTimes*> cs=ssnatHash.value(i.key());
 2557             ssnatHash.remove(i.key());
 2558             assert(!ssnatHash.contains(i.value()));
 2559             ssnatHash.insert(i.value(), cs);
 2560         }
 2561         i++;
 2562     }
 2563     
 2564     this->internalStructureComputed=false;
 2565     setRulesModifiedAndOtherThings(this);
 2566     
 2567     teachers_schedule_ready=false;
 2568     students_schedule_ready=false;
 2569     rooms_schedule_ready=false;
 2570 
 2571     return true;
 2572 }
 2573 //by Volker Dirr (end) - very similar to Liviu's modifyStudentsSet
 2574 
 2575 void Rules::sortYearsAlphabetically()
 2576 {
 2577     std::stable_sort(this->yearsList.begin(), this->yearsList.end(), yearsAscending);
 2578 
 2579     this->internalStructureComputed=false;
 2580     setRulesModifiedAndOtherThings(this);
 2581 
 2582     teachers_schedule_ready=false;
 2583     students_schedule_ready=false;
 2584     rooms_schedule_ready=false;
 2585 }
 2586 
 2587 bool Rules::addGroup(const QString& yearName, StudentsGroup* group)
 2588 {
 2589     StudentsYear* sty=NULL;
 2590     for(int i=0; i<this->yearsList.size(); i++){
 2591         sty=yearsList[i];
 2592         if(sty->name==yearName)
 2593             break;
 2594     }
 2595     assert(sty);
 2596     
 2597     for(int i=0; i<sty->groupsList.size(); i++){
 2598         StudentsGroup* stg=sty->groupsList[i];
 2599         if(stg->name==group->name)
 2600             return false;
 2601     }
 2602     
 2603     sty->groupsList << group; //append
 2604     
 2605     if(!permanentStudentsHash.contains(group->name))
 2606         permanentStudentsHash.insert(group->name, group);
 2607 
 2608     this->internalStructureComputed=false;
 2609     setRulesModifiedAndOtherThings(this);
 2610 
 2611     teachers_schedule_ready=false;
 2612     students_schedule_ready=false;
 2613     rooms_schedule_ready=false;
 2614 
 2615     return true;
 2616 }
 2617 
 2618 bool Rules::addGroupFast(StudentsYear* year, StudentsGroup* group)
 2619 {
 2620     year->groupsList << group; //append
 2621 
 2622     this->internalStructureComputed=false;
 2623     setRulesModifiedAndOtherThings(this);
 2624 
 2625     teachers_schedule_ready=false;
 2626     students_schedule_ready=false;
 2627     rooms_schedule_ready=false;
 2628 
 2629     return true;
 2630 }
 2631 
 2632 bool Rules::removeGroup(const QString& yearName, const QString& groupName)
 2633 {
 2634     StudentsYear* yearPointer=NULL;
 2635     for(StudentsYear* ty : qAsConst(this->yearsList)){
 2636         if(ty->name==yearName){
 2637             yearPointer=ty;
 2638             break;
 2639         }
 2640     }
 2641 
 2642     assert(yearPointer!=NULL);
 2643     
 2644     StudentsGroup* groupPointer=NULL;
 2645     for(StudentsGroup* tg : qAsConst(yearPointer->groupsList)){
 2646         if(tg->name==groupName){
 2647             groupPointer=tg;
 2648             break;
 2649         }
 2650     }
 2651     
 2652     assert(groupPointer!=NULL);
 2653 
 2654     //pointers
 2655     QSet<StudentsSet*> tmpSet;
 2656     for(StudentsYear* year : qAsConst(yearsList)){
 2657         if(year->name!=yearName){
 2658             //tmpSet.insert(year); useless
 2659             for(StudentsGroup* group : qAsConst(year->groupsList)){
 2660                 if(group->name==groupName) //we shall not purge groupName, because it still exists in the current year
 2661                     tmpSet.insert(group);
 2662                 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
 2663                     tmpSet.insert(subgroup);
 2664             }
 2665         }
 2666         else{
 2667             for(StudentsGroup* group : qAsConst(year->groupsList))
 2668                 if(group->name!=groupName){
 2669                     //tmpSet.insert(group); //useless
 2670                     for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
 2671                         tmpSet.insert(subgroup);
 2672                 }
 2673         }
 2674     }
 2675     
 2676     QSet<StudentsSet*> toBeRemoved;
 2677     if(!tmpSet.contains(groupPointer))
 2678         toBeRemoved.insert(groupPointer);
 2679     for(StudentsSubgroup* subgroup : qAsConst(groupPointer->subgroupsList)){
 2680         assert(!toBeRemoved.contains(subgroup));
 2681         if(!tmpSet.contains(subgroup))
 2682             toBeRemoved.insert(subgroup);
 2683     }
 2684     
 2685     updateActivitiesWhenRemovingStudents(toBeRemoved, false);
 2686     
 2687     for(int i=0; i<yearPointer->groupsList.count(); i++)
 2688         if(yearPointer->groupsList.at(i)==groupPointer){
 2689             yearPointer->groupsList.removeAt(i);
 2690             break;
 2691         }
 2692     
 2693     for(StudentsSet* studentsSet : qAsConst(toBeRemoved)){
 2694         assert(permanentStudentsHash.contains(studentsSet->name));
 2695         permanentStudentsHash.remove(studentsSet->name);
 2696     
 2697         delete studentsSet;
 2698     }
 2699         
 2700     if(toBeRemoved.count()>0)
 2701         updateConstraintsAfterRemoval();
 2702     
 2703     this->internalStructureComputed=false;
 2704     setRulesModifiedAndOtherThings(this);
 2705 
 2706     teachers_schedule_ready=false;
 2707     students_schedule_ready=false;
 2708     rooms_schedule_ready=false;
 2709 
 2710     return true;
 2711 }
 2712 
 2713 bool Rules::purgeGroup(const QString& groupName)
 2714 {
 2715     StudentsGroup* groupPointer=NULL;
 2716     for(StudentsYear* year : qAsConst(yearsList)){
 2717         int j=-1;
 2718         for(int i=0; i<year->groupsList.count(); i++){
 2719             if(year->groupsList.at(i)->name==groupName){
 2720                 j=i;
 2721                 if(groupPointer==NULL)
 2722                     groupPointer=year->groupsList.at(i);
 2723                 else
 2724                     assert(groupPointer==year->groupsList.at(i));
 2725                 break;
 2726             }
 2727         }
 2728         if(j>=0)
 2729             year->groupsList.removeAt(j);
 2730     }
 2731     
 2732     assert(groupPointer!=NULL);
 2733 
 2734     //pointers
 2735     QSet<StudentsSet*> tmpSet;
 2736     for(StudentsYear* year : qAsConst(yearsList))
 2737         for(StudentsGroup* group : qAsConst(year->groupsList))
 2738             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
 2739                 tmpSet.insert(subgroup);
 2740     
 2741     QSet<StudentsSet*> toBeRemoved;
 2742     if(!tmpSet.contains(groupPointer))
 2743         toBeRemoved.insert(groupPointer);
 2744     else
 2745         assert(0);
 2746     for(StudentsSubgroup* subgroup : qAsConst(groupPointer->subgroupsList)){
 2747         assert(!toBeRemoved.contains(subgroup));
 2748         if(!tmpSet.contains(subgroup))
 2749             toBeRemoved.insert(subgroup);
 2750     }
 2751     
 2752     updateActivitiesWhenRemovingStudents(toBeRemoved, false);
 2753     
 2754     for(StudentsSet* studentsSet : qAsConst(toBeRemoved)){
 2755         assert(permanentStudentsHash.contains(studentsSet->name));
 2756         permanentStudentsHash.remove(studentsSet->name);
 2757     
 2758         delete studentsSet;
 2759     }
 2760         
 2761     if(toBeRemoved.count()>0)
 2762         updateConstraintsAfterRemoval();
 2763     
 2764     this->internalStructureComputed=false;
 2765     setRulesModifiedAndOtherThings(this);
 2766 
 2767     teachers_schedule_ready=false;
 2768     students_schedule_ready=false;
 2769     rooms_schedule_ready=false;
 2770 
 2771     return true;
 2772 }
 2773 
 2774 int Rules::searchGroup(const QString& yearName, const QString& groupName)
 2775 {
 2776     StudentsYear* sty=NULL;
 2777     for(StudentsYear* ty : qAsConst(yearsList))
 2778         if(ty->name==yearName){
 2779             sty=ty;
 2780             break;
 2781         }
 2782     assert(sty!=NULL);
 2783 
 2784     for(int i=0; i<sty->groupsList.size(); i++)
 2785         if(sty->groupsList[i]->name==groupName)
 2786             return i;
 2787     
 2788     return -1;
 2789 }
 2790 
 2791 int Rules::searchAugmentedGroup(const QString& yearName, const QString& groupName)
 2792 {
 2793     StudentsYear* sty=NULL;
 2794     for(StudentsYear* ty : qAsConst(augmentedYearsList))
 2795         if(ty->name==yearName){
 2796             sty=ty;
 2797             break;
 2798         }
 2799     assert(sty!=NULL);
 2800     
 2801     for(int i=0; i<sty->groupsList.size(); i++)
 2802         if(sty->groupsList[i]->name==groupName)
 2803             return i;
 2804     
 2805     return -1;
 2806 }
 2807 
 2808 void Rules::sortGroupsAlphabetically(const QString& yearName)
 2809 {
 2810     StudentsYear* sty=this->yearsList[this->searchYear(yearName)];
 2811     assert(sty);
 2812 
 2813     std::stable_sort(sty->groupsList.begin(), sty->groupsList.end(), groupsAscending);
 2814 
 2815     this->internalStructureComputed=false;
 2816     setRulesModifiedAndOtherThings(this);
 2817 
 2818     teachers_schedule_ready=false;
 2819     students_schedule_ready=false;
 2820     rooms_schedule_ready=false;
 2821 }
 2822 
 2823 bool Rules::addSubgroup(const QString& yearName, const QString& groupName, StudentsSubgroup* subgroup)
 2824 {
 2825     StudentsYear* sty=this->yearsList.at(this->searchYear(yearName));
 2826     assert(sty);
 2827     StudentsGroup* stg=sty->groupsList.at(this->searchGroup(yearName, groupName));
 2828     assert(stg);
 2829 
 2830     for(int i=0; i<stg->subgroupsList.size(); i++){
 2831         StudentsSubgroup* sts=stg->subgroupsList[i];
 2832         if(sts->name==subgroup->name)
 2833             return false;
 2834     }
 2835     
 2836     stg->subgroupsList << subgroup; //append
 2837     
 2838     if(!permanentStudentsHash.contains(subgroup->name))
 2839         permanentStudentsHash.insert(subgroup->name, subgroup);
 2840 
 2841     this->internalStructureComputed=false;
 2842     setRulesModifiedAndOtherThings(this);
 2843 
 2844     teachers_schedule_ready=false;
 2845     students_schedule_ready=false;
 2846     rooms_schedule_ready=false;
 2847 
 2848     return true;
 2849 }
 2850 
 2851 bool Rules::addSubgroupFast(StudentsYear* year, StudentsGroup* group, StudentsSubgroup* subgroup)
 2852 {
 2853     Q_UNUSED(year);
 2854 
 2855     group->subgroupsList << subgroup; //append
 2856 
 2857     this->internalStructureComputed=false;
 2858     setRulesModifiedAndOtherThings(this);
 2859 
 2860     teachers_schedule_ready=false;
 2861     students_schedule_ready=false;
 2862     rooms_schedule_ready=false;
 2863 
 2864     return true;
 2865 }
 2866 
 2867 bool Rules::removeSubgroup(const QString& yearName, const QString& groupName, const QString& subgroupName)
 2868 {
 2869     StudentsYear* yearPointer=NULL;
 2870     for(StudentsYear* ty : qAsConst(this->yearsList)){
 2871         if(ty->name==yearName){
 2872             yearPointer=ty;
 2873             break;
 2874         }
 2875     }
 2876 
 2877     assert(yearPointer!=NULL);
 2878     
 2879     StudentsGroup* groupPointer=NULL;
 2880     for(StudentsGroup* tg : qAsConst(yearPointer->groupsList)){
 2881         if(tg->name==groupName){
 2882             groupPointer=tg;
 2883             break;
 2884         }
 2885     }
 2886     
 2887     assert(groupPointer!=NULL);
 2888     
 2889     StudentsSubgroup* subgroupPointer=NULL;
 2890     for(StudentsSubgroup* ts : qAsConst(groupPointer->subgroupsList)){
 2891         if(ts->name==subgroupName){
 2892             subgroupPointer=ts;
 2893             break;
 2894         }
 2895     }
 2896     
 2897     assert(subgroupPointer!=NULL);
 2898     
 2899     //pointers
 2900     QSet<StudentsSet*> toBeRemoved;
 2901     toBeRemoved.insert(subgroupPointer);
 2902     for(StudentsYear* year : qAsConst(yearsList))
 2903         for(StudentsGroup* group : qAsConst(year->groupsList))
 2904             for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
 2905                 if(subgroup->name==subgroupName && (year->name!=yearName || group->name!=groupName))
 2906                     toBeRemoved.remove(subgroupPointer);
 2907                     
 2908     updateActivitiesWhenRemovingStudents(toBeRemoved, false);
 2909     
 2910     for(int i=0; i<groupPointer->subgroupsList.count(); i++)
 2911         if(groupPointer->subgroupsList.at(i)==subgroupPointer){
 2912             groupPointer->subgroupsList.removeAt(i);
 2913             break;
 2914         }
 2915     
 2916     for(StudentsSet* studentsSet : qAsConst(toBeRemoved)){
 2917         assert(permanentStudentsHash.contains(studentsSet->name));
 2918         permanentStudentsHash.remove(studentsSet->name);
 2919     
 2920         delete studentsSet;
 2921     }
 2922         
 2923     if(toBeRemoved.count()>0)
 2924         updateConstraintsAfterRemoval();
 2925     
 2926     this->internalStructureComputed=false;
 2927     setRulesModifiedAndOtherThings(this);
 2928 
 2929     teachers_schedule_ready=false;
 2930     students_schedule_ready=false;
 2931     rooms_schedule_ready=false;
 2932 
 2933     return true;
 2934 }
 2935 
 2936 bool Rules::purgeSubgroup(const QString& subgroupName)
 2937 {
 2938     StudentsSubgroup* subgroupPointer=NULL;
 2939     for(StudentsYear* year : qAsConst(yearsList))
 2940         for(StudentsGroup* group : qAsConst(year->groupsList)){
 2941             int j=-1;
 2942             for(int i=0; i<group->subgroupsList.count(); i++){
 2943                 if(group->subgroupsList.at(i)->name==subgroupName){
 2944                     j=i;
 2945                     if(subgroupPointer==NULL)
 2946                         subgroupPointer=group->subgroupsList.at(i);
 2947                     else
 2948                         assert(subgroupPointer==group->subgroupsList.at(i));
 2949                     break;
 2950                 }
 2951             }
 2952             if(j>=0)
 2953                 group->subgroupsList.removeAt(j);
 2954         }
 2955 
 2956     assert(subgroupPointer!=NULL);
 2957     
 2958     //pointers
 2959     QSet<StudentsSet*> toBeRemoved;
 2960     toBeRemoved.insert(subgroupPointer);
 2961     
 2962     updateActivitiesWhenRemovingStudents(toBeRemoved, false);
 2963     
 2964     for(StudentsSet* studentsSet : qAsConst(toBeRemoved)){
 2965         assert(permanentStudentsHash.contains(studentsSet->name));
 2966         permanentStudentsHash.remove(studentsSet->name);
 2967     
 2968         delete studentsSet;
 2969     }
 2970     
 2971     if(toBeRemoved.count()>0)
 2972         updateConstraintsAfterRemoval();
 2973     
 2974     this->internalStructureComputed=false;
 2975     setRulesModifiedAndOtherThings(this);
 2976 
 2977     teachers_schedule_ready=false;
 2978     students_schedule_ready=false;
 2979     rooms_schedule_ready=false;
 2980 
 2981     return true;
 2982 }
 2983 
 2984 int Rules::searchSubgroup(const QString& yearName, const QString& groupName, const QString& subgroupName)
 2985 {
 2986     StudentsYear* sty=NULL;
 2987     for(StudentsYear* ty : qAsConst(yearsList))
 2988         if(ty->name==yearName){
 2989             sty=ty;
 2990             break;
 2991         }
 2992     assert(sty!=NULL);
 2993 
 2994     StudentsGroup* stg=NULL;
 2995     for(StudentsGroup* tg : qAsConst(sty->groupsList))
 2996         if(tg->name==groupName){
 2997             stg=tg;
 2998             break;
 2999         }
 3000     assert(stg!=NULL);
 3001 
 3002     for(int i=0; i<stg->subgroupsList.size(); i++)
 3003         if(stg->subgroupsList[i]->name==subgroupName)
 3004             return i;
 3005     
 3006     return -1;
 3007 }
 3008 
 3009 int Rules::searchAugmentedSubgroup(const QString& yearName, const QString& groupName, const QString& subgroupName)
 3010 {
 3011     StudentsYear* sty=NULL;
 3012     for(StudentsYear* ty : qAsConst(augmentedYearsList))
 3013         if(ty->name==yearName){
 3014             sty=ty;
 3015             break;
 3016         }
 3017     assert(sty!=NULL);
 3018 
 3019     StudentsGroup* stg=NULL;
 3020     for(StudentsGroup* tg : qAsConst(sty->groupsList))
 3021         if(tg->name==groupName){
 3022             stg=tg;
 3023             break;
 3024         }
 3025     assert(stg!=NULL);
 3026 
 3027     for(int i=0; i<stg->subgroupsList.size(); i++)
 3028         if(stg->subgroupsList[i]->name==subgroupName)
 3029             return i;
 3030     
 3031     return -1;
 3032 }
 3033 
 3034 void Rules::sortSubgroupsAlphabetically(const QString& yearName, const QString& groupName)
 3035 {
 3036     StudentsYear* sty=this->yearsList.at(this->searchYear(yearName));
 3037     assert(sty);
 3038     StudentsGroup* stg=sty->groupsList.at(this->searchGroup(yearName, groupName));
 3039     assert(stg);
 3040 
 3041     std::stable_sort(stg->subgroupsList.begin(), stg->subgroupsList.end(), subgroupsAscending);
 3042     
 3043     this->internalStructureComputed=false;
 3044     setRulesModifiedAndOtherThings(this);
 3045 
 3046     teachers_schedule_ready=false;
 3047     students_schedule_ready=false;
 3048     rooms_schedule_ready=false;
 3049 }
 3050 
 3051 bool Rules::addSimpleActivityFast(
 3052     QWidget* parent,
 3053     int _id,
 3054     int _activityGroupId,
 3055     const QStringList& _teachersNames,
 3056     const QString& _subjectName,
 3057     const QStringList& _activityTagsNames,
 3058     const QStringList& _studentsNames,
 3059     int _duration,
 3060     int _totalDuration,
 3061     bool _active,
 3062     bool _computeNTotalStudents,
 3063     int _nTotalStudents,
 3064     int _computedNumberOfStudents)
 3065 {
 3066     //check for duplicates - idea and code by Volker Dirr
 3067     int t=QStringList(_teachersNames).removeDuplicates();
 3068     if(t>0)
 3069         RulesReconcilableMessage::warning(parent, tr("FET warning"), tr("Activity with Id=%1 contains %2 duplicate teachers - please correct that")
 3070          .arg(_id).arg(t));
 3071 
 3072     t=QStringList(_studentsNames).removeDuplicates();
 3073     if(t>0)
 3074         RulesReconcilableMessage::warning(parent, tr("FET warning"), tr("Activity with Id=%1 contains %2 duplicate students sets - please correct that")
 3075          .arg(_id).arg(t));
 3076 
 3077     t=QStringList(_activityTagsNames).removeDuplicates();
 3078     if(t>0)
 3079         RulesReconcilableMessage::warning(parent, tr("FET warning"), tr("Activity with Id=%1 contains %2 duplicate activity tags - please correct that")
 3080          .arg(_id).arg(t));
 3081 
 3082     Activity *act=new Activity(*this, _id, _activityGroupId, _teachersNames, _subjectName, _activityTagsNames,
 3083         _studentsNames, _duration, _totalDuration, _active, _computeNTotalStudents, _nTotalStudents, _computedNumberOfStudents);
 3084 
 3085     this->activitiesList << act; //append
 3086 
 3087     assert(!activitiesPointerHash.contains(act->id));
 3088     activitiesPointerHash.insert(act->id, act);
 3089 
 3090     this->internalStructureComputed=false;
 3091     setRulesModifiedAndOtherThings(this);
 3092 
 3093     teachers_schedule_ready=false;
 3094     students_schedule_ready=false;
 3095     rooms_schedule_ready=false;
 3096 
 3097     return true;
 3098 }
 3099 
 3100 bool Rules::addSplitActivityFast(
 3101     QWidget* parent,
 3102     int _firstActivityId,
 3103     int _activityGroupId,
 3104     const QStringList& _teachersNames,
 3105     const QString& _subjectName,
 3106     const QStringList& _activityTagsNames,
 3107     const QStringList& _studentsNames,
 3108     int _nSplits,
 3109     int _totalDuration,
 3110     int _durations[],
 3111     bool _active[],
 3112     int _minDayDistance,
 3113     double _weightPercentage,
 3114     bool _consecutiveIfSameDay,
 3115     bool _computeNTotalStudents,
 3116     int _nTotalStudents,
 3117     int _computedNumberOfStudents)
 3118 {
 3119     //check for duplicates - idea and code by Volker Dirr
 3120     int t=QStringList(_teachersNames).removeDuplicates();
 3121     if(t>0)
 3122         RulesReconcilableMessage::warning(parent, tr("FET warning"), tr("Activities with group_Id=%1 contain %2 duplicate teachers - please correct that")
 3123          .arg(_activityGroupId).arg(t));
 3124 
 3125     t=QStringList(_studentsNames).removeDuplicates();
 3126     if(t>0)
 3127         RulesReconcilableMessage::warning(parent, tr("FET warning"), tr("Activities with group_Id=%1 contain %2 duplicate students sets - please correct that")
 3128          .arg(_activityGroupId).arg(t));
 3129 
 3130     t=QStringList(_activityTagsNames).removeDuplicates();
 3131     if(t>0)
 3132         RulesReconcilableMessage::warning(parent, tr("FET warning"), tr("Activities with group_Id=%1 contain %2 duplicate activity tags - please correct that")
 3133          .arg(_activityGroupId).arg(t));
 3134 
 3135     assert(_firstActivityId==_activityGroupId);
 3136 
 3137     QList<int> acts;
 3138 
 3139     acts.clear();
 3140     for(int i=0; i<_nSplits; i++){
 3141         Activity *act=new Activity(*this, _firstActivityId+i, _activityGroupId,
 3142          _teachersNames, _subjectName, _activityTagsNames, _studentsNames,
 3143          _durations[i], _totalDuration, _active[i], _computeNTotalStudents, _nTotalStudents, _computedNumberOfStudents);
 3144 
 3145         this->activitiesList << act; //append
 3146 
 3147         assert(!activitiesPointerHash.contains(act->id));
 3148         activitiesPointerHash.insert(act->id, act);
 3149 
 3150         acts.append(_firstActivityId+i);
 3151     }
 3152 
 3153     if(_minDayDistance>0){
 3154         TimeConstraint *constr=new ConstraintMinDaysBetweenActivities(_weightPercentage, _consecutiveIfSameDay, _nSplits, acts, _minDayDistance);
 3155         bool tmp=this->addTimeConstraint(constr);
 3156         assert(tmp);
 3157     }
 3158 
 3159     this->internalStructureComputed=false;
 3160     setRulesModifiedAndOtherThings(this);
 3161 
 3162     teachers_schedule_ready=false;
 3163     students_schedule_ready=false;
 3164     rooms_schedule_ready=false;
 3165 
 3166     return true;
 3167 }
 3168 
 3169 /*void Rules::removeActivity(int _id)
 3170 {
 3171     QList<int> tmpList;
 3172     tmpList.append(_id);
 3173     removeActivities(tmpList, true);
 3174 }*/
 3175 
 3176 void Rules::removeActivity(int _id, int _activityGroupId)
 3177 {
 3178     QList<int> tmpList;
 3179     for(Activity* act : qAsConst(activitiesList))
 3180         if(_id==act->id || (_activityGroupId>0 && _activityGroupId==act->activityGroupId))
 3181             tmpList.append(act->id);
 3182     removeActivities(tmpList, true);
 3183 }
 3184 
 3185 void Rules::removeActivities(const QList<int>& _idsList, bool updateConstraints)
 3186 {
 3187     if(_idsList.count()==0)
 3188         return;
 3189 
 3190 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
 3191     QSet<int> _removedIdsSet=QSet<int>(_idsList.begin(), _idsList.end());
 3192 #else
 3193     QSet<int> _removedIdsSet=_idsList.toSet();
 3194 #endif
 3195     
 3196     QSet<int> _groupIdsSet;
 3197     for(Activity* act : qAsConst(activitiesList))
 3198         if(act->activityGroupId>0 && _removedIdsSet.contains(act->id))
 3199             _groupIdsSet.insert(act->activityGroupId);
 3200     for(Activity* act : qAsConst(activitiesList))
 3201         if(act->activityGroupId>0 && _groupIdsSet.contains(act->activityGroupId))
 3202             _removedIdsSet.insert(act->id);
 3203     
 3204     ActivitiesList newActivitiesList;
 3205     ActivitiesList toBeRemoved;
 3206     
 3207     for(int i=0; i<activitiesList.count(); i++){
 3208         int id=activitiesList.at(i)->id;
 3209         if(!_removedIdsSet.contains(id)){
 3210             newActivitiesList.append(activitiesList[i]);
 3211         }
 3212         else{
 3213             toBeRemoved.append(activitiesList[i]);
 3214 
 3215             assert(activitiesPointerHash.contains(id));
 3216             activitiesPointerHash.remove(id);
 3217             
 3218             if(mdbaHash.contains(id)){
 3219                 int t=mdbaHash.remove(id);
 3220                 assert(t==1);
 3221             }
 3222         }
 3223     }
 3224 
 3225     for(Activity* act : qAsConst(toBeRemoved))
 3226         delete act;
 3227     toBeRemoved.clear();
 3228     //while(!toBeRemoved.isEmpty())
 3229     //  delete toBeRemoved.takeFirst();
 3230         
 3231     activitiesList=newActivitiesList;
 3232     
 3233     updateGroupActivitiesInInitialOrderAfterRemoval();
 3234     if(updateConstraints)
 3235         updateConstraintsAfterRemoval();
 3236     
 3237     this->internalStructureComputed=false;
 3238     setRulesModifiedAndOtherThings(this);
 3239 
 3240     teachers_schedule_ready=false;
 3241     students_schedule_ready=false;
 3242     rooms_schedule_ready=false;
 3243 }
 3244 
 3245 void Rules::modifyActivity(
 3246     int _id,
 3247     int _activityGroupId,
 3248     const QStringList& _teachersNames,
 3249     const QString& _subjectName,
 3250     const QStringList& _activityTagsNames,
 3251     const QStringList& _studentsNames,
 3252     //int _nTotalStudents,
 3253     int _nSplits,
 3254     int _totalDuration,
 3255     int _durations[],
 3256     //int _parities[],
 3257     bool _active[],
 3258     bool _computeNTotalStudents,
 3259     int _nTotalStudents)
 3260 {
 3261     int i=0;
 3262     for(int j=0; j<this->activitiesList.size(); j++){
 3263         Activity* act=this->activitiesList[j];
 3264         if((_activityGroupId==0 && act->id==_id) || (_activityGroupId!=0 && act->activityGroupId==_activityGroupId)){
 3265             act->teachersNames=_teachersNames;
 3266             act->subjectName=_subjectName;
 3267             act->activityTagsNames=_activityTagsNames;
 3268             act->studentsNames=_studentsNames;
 3269             act->duration=_durations[i];
 3270             //act->parity=_parities[i];
 3271             act->active=_active[i];
 3272             act->totalDuration=_totalDuration;
 3273             act->computeNTotalStudents=_computeNTotalStudents;
 3274             act->nTotalStudents=_nTotalStudents;
 3275             i++;
 3276         }
 3277     }
 3278     
 3279     assert(i==_nSplits);
 3280     
 3281     this->internalStructureComputed=false;
 3282     setRulesModifiedAndOtherThings(this);
 3283 
 3284     teachers_schedule_ready=false;
 3285     students_schedule_ready=false;
 3286     rooms_schedule_ready=false;
 3287 }
 3288 
 3289 void Rules::modifySubactivity(
 3290     int _id,
 3291     int _activityGroupId,
 3292     const QStringList& _teachersNames,
 3293     const QString& _subjectName,
 3294     const QStringList& _activityTagsNames,
 3295     const QStringList& _studentsNames,
 3296     int _duration,
 3297     bool _active,
 3298     bool _computeNTotalStudents,
 3299     int _nTotalStudents)
 3300 {
 3301     QList<Activity*> actsList;
 3302     Activity* crtAct=NULL;
 3303     
 3304     for(Activity* act : qAsConst(this->activitiesList)){
 3305         if(act->id==_id && act->activityGroupId==_activityGroupId){
 3306             crtAct=act;
 3307             //actsList.append(act);
 3308         }
 3309         else if(act->activityGroupId!=0 && _activityGroupId!=0 && act->activityGroupId==_activityGroupId){
 3310             actsList.append(act);
 3311         }
 3312     }
 3313     
 3314     assert(crtAct!=NULL);
 3315     
 3316     int td=0;
 3317     for(Activity* act : qAsConst(actsList))
 3318         td+=act->duration;
 3319     td+=_duration; //crtAct->duration;
 3320     for(Activity* act : qAsConst(actsList))
 3321         act->totalDuration=td;
 3322 
 3323     crtAct->teachersNames=_teachersNames;
 3324     crtAct->subjectName=_subjectName;
 3325     crtAct->activityTagsNames=_activityTagsNames;
 3326     crtAct->studentsNames=_studentsNames;
 3327     crtAct->duration=_duration;
 3328     crtAct->totalDuration=td;
 3329     crtAct->active=_active;
 3330     crtAct->computeNTotalStudents=_computeNTotalStudents;
 3331     crtAct->nTotalStudents=_nTotalStudents;
 3332     
 3333     this->internalStructureComputed=false;
 3334     setRulesModifiedAndOtherThings(this);
 3335 
 3336     teachers_schedule_ready=false;
 3337     students_schedule_ready=false;
 3338     rooms_schedule_ready=false;
 3339 }
 3340 
 3341 bool Rules::addRoom(Room* rm)
 3342 {
 3343     if(this->searchRoom(rm->name) >= 0)
 3344         return false;
 3345     this->roomsList << rm; //append
 3346     this->internalStructureComputed=false;
 3347     setRulesModifiedAndOtherThings(this);
 3348 
 3349     teachers_schedule_ready=false;
 3350     students_schedule_ready=false;
 3351     rooms_schedule_ready=false;
 3352 
 3353     return true;
 3354 }
 3355 
 3356 bool Rules::addRoomFast(Room* rm)
 3357 {
 3358     this->roomsList << rm; //append
 3359     this->internalStructureComputed=false;
 3360     setRulesModifiedAndOtherThings(this);
 3361 
 3362     teachers_schedule_ready=false;
 3363     students_schedule_ready=false;
 3364     rooms_schedule_ready=false;
 3365 
 3366     return true;
 3367 }
 3368 
 3369 int Rules::searchRoom(const QString& roomName)
 3370 {
 3371     for(int i=0; i<this->roomsList.size(); i++)
 3372         if(this->roomsList[i]->name==roomName)
 3373             return i;
 3374     
 3375     return -1;
 3376 }
 3377 
 3378 bool Rules::removeRoom(const QString& roomName)
 3379 {
 3380     int i=this->searchRoom(roomName);
 3381     if(i<0)
 3382         return false;
 3383 
 3384     Room* searchedRoom=this->roomsList[i];
 3385     assert(searchedRoom->name==roomName);
 3386     
 3387     //the real room to be removed may be found in some virtual rooms' sets
 3388     if(searchedRoom->isVirtual==false){
 3389         for(Room* r : qAsConst(roomsList)){
 3390             if(r->isVirtual==true){
 3391                 for(int j=0; j<r->realRoomsSetsList.count(); j++){
 3392                     QStringList& sl=r->realRoomsSetsList[j];
 3393                     if(sl.contains(roomName)){
 3394                         int t=sl.removeAll(roomName);
 3395                         assert(t==1);
 3396                     }
 3397                 }
 3398             }
 3399         }
 3400     }
 3401     
 3402     for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 3403         if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
 3404             ConstraintActivityPreferredRoom* c=(ConstraintActivityPreferredRoom*)ctr;
 3405             
 3406             if(c->preferredRealRoomsNames.contains(roomName))
 3407                 c->preferredRealRoomsNames.removeAll(roomName);
 3408         }
 3409     }
 3410 
 3411     delete this->roomsList[i];
 3412     this->roomsList.removeAt(i);
 3413 
 3414     updateConstraintsAfterRemoval();
 3415 
 3416     this->internalStructureComputed=false;
 3417     setRulesModifiedAndOtherThings(this);
 3418 
 3419     teachers_schedule_ready=false;
 3420     students_schedule_ready=false;
 3421     rooms_schedule_ready=false;
 3422 
 3423     return true;
 3424 }
 3425 
 3426 bool Rules::modifyRoom(const QString& initialRoomName, const QString& finalRoomName, const QString& building, int capacity)
 3427 {
 3428     int i=this->searchRoom(initialRoomName);
 3429     if(i<0)
 3430         return false;
 3431 
 3432     Room* searchedRoom=this->roomsList[i];
 3433     assert(searchedRoom->name==initialRoomName);
 3434     
 3435     //the real room to be renamed may be found in some virtual rooms' sets
 3436     if(initialRoomName!=finalRoomName){
 3437         if(searchedRoom->isVirtual==false){
 3438             for(Room* r : qAsConst(roomsList)){
 3439                 if(r->isVirtual==true){
 3440                     for(int j=0; j<r->realRoomsSetsList.count(); j++){
 3441                         QStringList& sl=r->realRoomsSetsList[j];
 3442                         for(int k=0; k<sl.count(); k++){
 3443                             if(sl[k]==initialRoomName){
 3444                                 sl[k]=finalRoomName;
 3445                             }
 3446                         }
 3447                     }
 3448                 }
 3449             }
 3450         }
 3451     }
 3452 
 3453     for(SpaceConstraint* ctr : qAsConst(spaceConstraintsList)){
 3454         if(ctr->type==CONSTRAINT_ROOM_NOT_AVAILABLE_TIMES){
 3455             ConstraintRoomNotAvailableTimes* crna=(ConstraintRoomNotAvailableTimes*)ctr;
 3456             if(crna->room==initialRoomName)
 3457                 crna->room=finalRoomName;
 3458         }
 3459         else if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
 3460             ConstraintActivityPreferredRoom* c=(ConstraintActivityPreferredRoom*)ctr;
 3461             if(c->roomName==initialRoomName)
 3462                 c->roomName=finalRoomName;
 3463                 
 3464             for(int i=0; i<c->preferredRealRoomsNames.count(); i++)
 3465                 if(c->preferredRealRoomsNames.at(i)==initialRoomName)
 3466                     c->preferredRealRoomsNames[i]=finalRoomName;
 3467         }
 3468         else if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOMS){
 3469             ConstraintActivityPreferredRooms* c=(ConstraintActivityPreferredRooms*)ctr;
 3470             int t=0;
 3471             for(QStringList::iterator it=c->roomsNames.begin(); it!=c->roomsNames.end(); it++){
 3472                 if((*it)==initialRoomName){
 3473                     *it=finalRoomName;
 3474                     t++;
 3475                 }
 3476             }
 3477             assert(t<=1);
 3478         }
 3479         else if(ctr->type==CONSTRAINT_STUDENTS_SET_HOME_ROOM){
 3480             ConstraintStudentsSetHomeRoom* c=(ConstraintStudentsSetHomeRoom*)ctr;
 3481             if(c->roomName==initialRoomName)
 3482                 c->roomName=finalRoomName;
 3483         }
 3484         else if(ctr->type==CONSTRAINT_STUDENTS_SET_HOME_ROOMS){
 3485             ConstraintStudentsSetHomeRooms* c=(ConstraintStudentsSetHomeRooms*)ctr;
 3486             int t=0;
 3487             for(QStringList::iterator it=c->roomsNames.begin(); it!=c->roomsNames.end(); it++){
 3488                 if((*it)==initialRoomName){
 3489                     *it=finalRoomName;
 3490                     t++;
 3491                 }
 3492             }
 3493             assert(t<=1);
 3494         }
 3495         else if(ctr->type==CONSTRAINT_TEACHER_HOME_ROOM){
 3496             ConstraintTeacherHomeRoom* c=(ConstraintTeacherHomeRoom*)ctr;
 3497             if(c->roomName==initialRoomName)
 3498                 c->roomName=finalRoomName;
 3499         }
 3500         else if(ctr->type==CONSTRAINT_TEACHER_HOME_ROOMS){
 3501             ConstraintTeacherHomeRooms* c=(ConstraintTeacherHomeRooms*)ctr;
 3502             int t=0;
 3503             for(QStringList::iterator it=c->roomsNames.begin(); it!=c->roomsNames.end(); it++){
 3504                 if((*it)==initialRoomName){
 3505                     *it=finalRoomName;
 3506                     t++;
 3507                 }
 3508             }
 3509             assert(t<=1);
 3510         }
 3511         else if(ctr->type==CONSTRAINT_SUBJECT_PREFERRED_ROOM){
 3512             ConstraintSubjectPreferredRoom* c=(ConstraintSubjectPreferredRoom*)ctr;
 3513             if(c->roomName==initialRoomName)
 3514                 c->roomName=finalRoomName;
 3515         }
 3516         else if(ctr->type==CONSTRAINT_SUBJECT_PREFERRED_ROOMS){
 3517             ConstraintSubjectPreferredRooms* c=(ConstraintSubjectPreferredRooms*)ctr;
 3518             int t=0;
 3519             for(QStringList::iterator it=c->roomsNames.begin(); it!=c->roomsNames.end(); it++){
 3520                 if((*it)==initialRoomName){
 3521                     *it=finalRoomName;
 3522                     t++;
 3523                 }
 3524             }
 3525             assert(t<=1);
 3526         }
 3527         else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOM){
 3528             ConstraintSubjectActivityTagPreferredRoom* c=(ConstraintSubjectActivityTagPreferredRoom*)ctr;
 3529             if(c->roomName==initialRoomName)
 3530                 c->roomName=finalRoomName;
 3531         }
 3532         else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOMS){
 3533             ConstraintSubjectActivityTagPreferredRooms* c=(ConstraintSubjectActivityTagPreferredRooms*)ctr;
 3534             int t=0;
 3535             for(QStringList::iterator it=c->roomsNames.begin(); it!=c->roomsNames.end(); it++){
 3536                 if((*it)==initialRoomName){
 3537                     *it=finalRoomName;
 3538                     t++;
 3539                 }
 3540             }
 3541             assert(t<=1);
 3542         }
 3543         else if(ctr->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOM){
 3544             ConstraintActivityTagPreferredRoom* c=(ConstraintActivityTagPreferredRoom*)ctr;
 3545             if(c->roomName==initialRoomName)
 3546                 c->roomName=finalRoomName;
 3547         }
 3548         else if(ctr->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOMS){
 3549             ConstraintActivityTagPreferredRooms* c=(ConstraintActivityTagPreferredRooms*)ctr;
 3550             int t=0;
 3551             for(QStringList::iterator it=c->roomsNames.begin(); it!=c->roomsNames.end(); it++){
 3552                 if((*it)==initialRoomName){
 3553                     *it=finalRoomName;
 3554                     t++;
 3555                 }
 3556             }
 3557             assert(t<=1);
 3558         }
 3559     }
 3560 
 3561     searchedRoom->name=finalRoomName;
 3562     searchedRoom->building=building;
 3563     searchedRoom->capacity=capacity;
 3564 
 3565     this->internalStructureComputed=false;
 3566     setRulesModifiedAndOtherThings(this);
 3567 
 3568     teachers_schedule_ready=false;
 3569     students_schedule_ready=false;
 3570     rooms_schedule_ready=false;
 3571 
 3572     return true;
 3573 }
 3574 
 3575 void Rules::sortRoomsAlphabetically()
 3576 {
 3577     std::stable_sort(this->roomsList.begin(), this->roomsList.end(), roomsAscending);
 3578 
 3579     this->internalStructureComputed=false;
 3580     setRulesModifiedAndOtherThings(this);
 3581 
 3582     teachers_schedule_ready=false;
 3583     students_schedule_ready=false;
 3584     rooms_schedule_ready=false;
 3585 }
 3586 
 3587 bool Rules::addBuilding(Building* bu)
 3588 {
 3589     if(this->searchBuilding(bu->name) >= 0)
 3590         return false;
 3591     this->buildingsList << bu; //append
 3592     this->internalStructureComputed=false;
 3593     setRulesModifiedAndOtherThings(this);
 3594 
 3595     teachers_schedule_ready=false;
 3596     students_schedule_ready=false;
 3597     rooms_schedule_ready=false;
 3598 
 3599     return true;
 3600 }
 3601 
 3602 bool Rules::addBuildingFast(Building* bu)
 3603 {
 3604     this->buildingsList << bu; //append
 3605     this->internalStructureComputed=false;
 3606     setRulesModifiedAndOtherThings(this);
 3607 
 3608     teachers_schedule_ready=false;
 3609     students_schedule_ready=false;
 3610     rooms_schedule_ready=false;
 3611 
 3612     return true;
 3613 }
 3614 
 3615 int Rules::searchBuilding(const QString& buildingName)
 3616 {
 3617     for(int i=0; i<this->buildingsList.size(); i++)
 3618         if(this->buildingsList[i]->name==buildingName)
 3619             return i;
 3620     
 3621     return -1;
 3622 }
 3623 
 3624 bool Rules::removeBuilding(const QString& buildingName)
 3625 {
 3626     for(Room* rm : qAsConst(this->roomsList))
 3627         if(rm->building==buildingName)
 3628             rm->building="";
 3629 
 3630     int i=this->searchBuilding(buildingName);
 3631     if(i<0)
 3632         return false;
 3633 
 3634     Building* searchedBuilding=this->buildingsList[i];
 3635     assert(searchedBuilding->name==buildingName);
 3636 
 3637     delete this->buildingsList[i];
 3638     this->buildingsList.removeAt(i);
 3639     
 3640     this->internalStructureComputed=false;
 3641     setRulesModifiedAndOtherThings(this);
 3642 
 3643     teachers_schedule_ready=false;
 3644     students_schedule_ready=false;
 3645     rooms_schedule_ready=false;
 3646 
 3647     return true;
 3648 }
 3649 
 3650 bool Rules::modifyBuilding(const QString& initialBuildingName, const QString& finalBuildingName)
 3651 {
 3652     for(Room* rm : qAsConst(roomsList))
 3653         if(rm->building==initialBuildingName)
 3654             rm->building=finalBuildingName;
 3655 
 3656     int i=this->searchBuilding(initialBuildingName);
 3657     if(i<0)
 3658         return false;
 3659 
 3660     Building* searchedBuilding=this->buildingsList[i];
 3661     assert(searchedBuilding->name==initialBuildingName);
 3662     searchedBuilding->name=finalBuildingName;
 3663 
 3664     this->internalStructureComputed=false;
 3665     setRulesModifiedAndOtherThings(this);
 3666 
 3667     teachers_schedule_ready=false;
 3668     students_schedule_ready=false;
 3669     rooms_schedule_ready=false;
 3670 
 3671     return true;
 3672 }
 3673 
 3674 void Rules::sortBuildingsAlphabetically()
 3675 {
 3676     std::stable_sort(this->buildingsList.begin(), this->buildingsList.end(), buildingsAscending);
 3677 
 3678     this->internalStructureComputed=false;
 3679     setRulesModifiedAndOtherThings(this);
 3680 
 3681     teachers_schedule_ready=false;
 3682     students_schedule_ready=false;
 3683     rooms_schedule_ready=false;
 3684 }
 3685 
 3686 bool Rules::addTimeConstraint(TimeConstraint* ctr)
 3687 {
 3688     bool ok=true;
 3689 
 3690     //TODO: improve this
 3691 
 3692     //check if this constraint is already added, for ConstraintActivityPreferredStartingTime
 3693     if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME){
 3694         ConstraintActivityPreferredStartingTime* c=(ConstraintActivityPreferredStartingTime*) ctr;
 3695         QSet<ConstraintActivityPreferredStartingTime*> cs=apstHash.value(c->activityId, QSet<ConstraintActivityPreferredStartingTime*>());
 3696         for(ConstraintActivityPreferredStartingTime* oldc : qAsConst(cs)){
 3697             if((*oldc)==(*c)){
 3698                 ok=false;
 3699                 break;
 3700             }
 3701         }
 3702 
 3703         /*int i;
 3704         for(i=0; i<this->timeConstraintsList.size(); i++){
 3705             TimeConstraint* ctr2=this->timeConstraintsList[i];
 3706             if(ctr2->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME)
 3707                 if(
 3708                  *((ConstraintActivityPreferredStartingTime*)ctr2)
 3709                  ==
 3710                  *((ConstraintActivityPreferredStartingTime*)ctr)
 3711                 )
 3712                     break;
 3713         }
 3714                 
 3715         if(i<this->timeConstraintsList.size())
 3716             ok=false;*/
 3717     }
 3718 
 3719     //check if this constraint is already added, for ConstraintMinDaysBetweenActivities
 3720     else if(ctr->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
 3721         ConstraintMinDaysBetweenActivities* c=(ConstraintMinDaysBetweenActivities*) ctr;
 3722         for(int aid : qAsConst(c->activitiesId)){
 3723             QSet<ConstraintMinDaysBetweenActivities*> cs=mdbaHash.value(aid, QSet<ConstraintMinDaysBetweenActivities*>());
 3724             for(ConstraintMinDaysBetweenActivities* oldc : qAsConst(cs)){
 3725                 if((*oldc)==(*c)){
 3726                     ok=false;
 3727                     break;
 3728                 }
 3729             }
 3730             if(!ok)
 3731                 break;
 3732         }
 3733 
 3734         /*int i;
 3735         for(i=0; i<this->timeConstraintsList.size(); i++){
 3736             TimeConstraint* ctr2=this->timeConstraintsList[i];
 3737             if(ctr2->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES)
 3738                 if(
 3739                  *((ConstraintMinDaysBetweenActivities*)ctr2)
 3740                  ==
 3741                  *((ConstraintMinDaysBetweenActivities*)ctr)
 3742                  )
 3743                     break;
 3744         }
 3745 
 3746         if(i<this->timeConstraintsList.size())
 3747             ok=false;*/
 3748     }
 3749     
 3750     else if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 3751         ConstraintStudentsSetNotAvailableTimes* c=(ConstraintStudentsSetNotAvailableTimes*) ctr;
 3752         QSet<ConstraintStudentsSetNotAvailableTimes*> cs=ssnatHash.value(c->students, QSet<ConstraintStudentsSetNotAvailableTimes*>());
 3753         for(ConstraintStudentsSetNotAvailableTimes* oldc : qAsConst(cs)){
 3754             if(oldc->students==c->students){
 3755                 ok=false;
 3756                 break;
 3757             }
 3758         }
 3759 
 3760         /*int i;
 3761         ConstraintStudentsSetNotAvailableTimes* ssna=(ConstraintStudentsSetNotAvailableTimes*)ctr;
 3762         for(i=0; i<this->timeConstraintsList.size(); i++){
 3763             TimeConstraint* ctr2=this->timeConstraintsList[i];
 3764             if(ctr2->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES) {
 3765                 ConstraintStudentsSetNotAvailableTimes* ssna2=(ConstraintStudentsSetNotAvailableTimes*)ctr2;
 3766                 if(ssna->students==ssna2->students)
 3767                     break;
 3768             }
 3769         }
 3770                 
 3771         if(i<this->timeConstraintsList.size())
 3772             ok=false;*/
 3773     }
 3774     
 3775     else if(ctr->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
 3776         ConstraintTeacherNotAvailableTimes* c=(ConstraintTeacherNotAvailableTimes*) ctr;
 3777         QSet<ConstraintTeacherNotAvailableTimes*> cs=tnatHash.value(c->teacher, QSet<ConstraintTeacherNotAvailableTimes*>());
 3778         for(ConstraintTeacherNotAvailableTimes* oldc : qAsConst(cs)){
 3779             if(oldc->teacher==c->teacher){
 3780                 ok=false;
 3781                 break;
 3782             }
 3783         }
 3784 
 3785         /*int i;
 3786         ConstraintTeacherNotAvailableTimes* tna=(ConstraintTeacherNotAvailableTimes*)ctr;
 3787         for(i=0; i<this->timeConstraintsList.size(); i++){
 3788             TimeConstraint* ctr2=this->timeConstraintsList[i];
 3789             if(ctr2->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES) {
 3790                 ConstraintTeacherNotAvailableTimes* tna2=(ConstraintTeacherNotAvailableTimes*)ctr2;
 3791                 if(tna->teacher==tna2->teacher)
 3792                     break;
 3793             }
 3794         }
 3795                 
 3796         if(i<this->timeConstraintsList.size())
 3797             ok=false;*/
 3798     }
 3799     
 3800     else if(ctr->type==CONSTRAINT_BREAK_TIMES){
 3801         //ConstraintBreakTimes* c=(ConstraintBreakTimes*) ctr;
 3802         QSet<ConstraintBreakTimes*> cs=btSet;
 3803         if(cs.count()>0)
 3804             ok=false;
 3805         /*int i;
 3806         for(i=0; i<this->timeConstraintsList.size(); i++){
 3807             TimeConstraint* ctr2=this->timeConstraintsList[i];
 3808             if(ctr2->type==CONSTRAINT_BREAK_TIMES)
 3809                 break;
 3810         }
 3811                 
 3812         if(i<this->timeConstraintsList.size())
 3813             ok=false;*/
 3814     }
 3815     
 3816     else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_TIME){
 3817         //ConstraintBasicCompulsoryTime* c=(ConstraintBasicCompulsoryTime*) ctr;
 3818         QSet<ConstraintBasicCompulsoryTime*> cs=bctSet;
 3819         if(cs.count()>0)
 3820             ok=false;
 3821         /*int i;
 3822         for(i=0; i<this->timeConstraintsList.size(); i++){
 3823             TimeConstraint* ctr2=this->timeConstraintsList[i];
 3824             if(ctr2->type==CONSTRAINT_BASIC_COMPULSORY_TIME)
 3825                 break;
 3826         }
 3827                 
 3828         if(i<this->timeConstraintsList.size())
 3829             ok=false;*/
 3830     }
 3831     
 3832     if(ok){
 3833         this->timeConstraintsList << ctr; //append
 3834         
 3835         if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME){
 3836             ConstraintActivityPreferredStartingTime* c=(ConstraintActivityPreferredStartingTime*) ctr;
 3837             QSet<ConstraintActivityPreferredStartingTime*> cs=apstHash.value(c->activityId, QSet<ConstraintActivityPreferredStartingTime*>());
 3838             assert(!cs.contains(c));
 3839             cs.insert(c);
 3840             apstHash.insert(c->activityId, cs);
 3841         }
 3842 
 3843         else if(ctr->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
 3844             ConstraintMinDaysBetweenActivities* c=(ConstraintMinDaysBetweenActivities*) ctr;
 3845             for(int aid : qAsConst(c->activitiesId)){
 3846                 QSet<ConstraintMinDaysBetweenActivities*> cs=mdbaHash.value(aid, QSet<ConstraintMinDaysBetweenActivities*>());
 3847                 assert(!cs.contains(c));
 3848                 cs.insert(c);
 3849                 mdbaHash.insert(aid, cs);
 3850             }
 3851         }
 3852 
 3853         else if(ctr->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
 3854             ConstraintTeacherNotAvailableTimes* c=(ConstraintTeacherNotAvailableTimes*) ctr;
 3855             QSet<ConstraintTeacherNotAvailableTimes*> cs=tnatHash.value(c->teacher, QSet<ConstraintTeacherNotAvailableTimes*>());
 3856             assert(!cs.contains(c));
 3857             cs.insert(c);
 3858             tnatHash.insert(c->teacher, cs);
 3859         }
 3860 
 3861         else if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 3862             ConstraintStudentsSetNotAvailableTimes* c=(ConstraintStudentsSetNotAvailableTimes*) ctr;
 3863             QSet<ConstraintStudentsSetNotAvailableTimes*> cs=ssnatHash.value(c->students, QSet<ConstraintStudentsSetNotAvailableTimes*>());
 3864             assert(!cs.contains(c));
 3865             cs.insert(c);
 3866             ssnatHash.insert(c->students, cs);
 3867         }
 3868         else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_TIME){
 3869             ConstraintBasicCompulsoryTime* c=(ConstraintBasicCompulsoryTime*) ctr;
 3870             QSet<ConstraintBasicCompulsoryTime*> &cs=bctSet;
 3871             assert(!cs.contains(c));
 3872             cs.insert(c);
 3873         }
 3874         else if(ctr->type==CONSTRAINT_BREAK_TIMES){
 3875             ConstraintBreakTimes* c=(ConstraintBreakTimes*) ctr;
 3876             QSet<ConstraintBreakTimes*> &cs=btSet;
 3877             assert(!cs.contains(c));
 3878             cs.insert(c);
 3879         }
 3880 
 3881         this->internalStructureComputed=false;
 3882         setRulesModifiedAndOtherThings(this);
 3883         return true;
 3884     }
 3885     else
 3886         return false;
 3887 }
 3888 
 3889 bool Rules::removeTimeConstraint(TimeConstraint* ctr)
 3890 {
 3891     for(int i=0; i<this->timeConstraintsList.size(); i++){
 3892         if(this->timeConstraintsList[i]==ctr){
 3893             if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME){
 3894                 ConstraintActivityPreferredStartingTime* c=(ConstraintActivityPreferredStartingTime*) ctr;
 3895                 QSet<ConstraintActivityPreferredStartingTime*> cs=apstHash.value(c->activityId, QSet<ConstraintActivityPreferredStartingTime*>());
 3896                 assert(cs.contains(c));
 3897                 cs.remove(c);
 3898                 if(!cs.isEmpty()){
 3899                     apstHash.insert(c->activityId, cs);
 3900                 }
 3901                 else{
 3902                     int t=apstHash.remove(c->activityId);
 3903                     assert(t==1);
 3904                 }
 3905             }
 3906 
 3907             else if(ctr->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
 3908                 ConstraintMinDaysBetweenActivities* c=(ConstraintMinDaysBetweenActivities*) ctr;
 3909                 for(int aid : qAsConst(c->activitiesId)){
 3910                     QSet<ConstraintMinDaysBetweenActivities*> cs=mdbaHash.value(aid, QSet<ConstraintMinDaysBetweenActivities*>());
 3911                     assert(cs.contains(c));
 3912                     cs.remove(c);
 3913                     if(!cs.isEmpty()){
 3914                         mdbaHash.insert(aid, cs);
 3915                     }
 3916                     else{
 3917                         int t=mdbaHash.remove(aid);
 3918                         assert(t==1);
 3919                     }
 3920                 }
 3921             }
 3922 
 3923             else if(ctr->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
 3924                 ConstraintTeacherNotAvailableTimes* c=(ConstraintTeacherNotAvailableTimes*) ctr;
 3925                 QSet<ConstraintTeacherNotAvailableTimes*> cs=tnatHash.value(c->teacher, QSet<ConstraintTeacherNotAvailableTimes*>());
 3926                 assert(cs.contains(c));
 3927                 cs.remove(c);
 3928                 if(!cs.isEmpty()){
 3929                     assert(0);
 3930                     tnatHash.insert(c->teacher, cs);
 3931                 }
 3932                 else{
 3933                     int t=tnatHash.remove(c->teacher);
 3934                     assert(t==1);
 3935                 }
 3936             }
 3937 
 3938             else if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 3939                 ConstraintStudentsSetNotAvailableTimes* c=(ConstraintStudentsSetNotAvailableTimes*) ctr;
 3940                 QSet<ConstraintStudentsSetNotAvailableTimes*> cs=ssnatHash.value(c->students, QSet<ConstraintStudentsSetNotAvailableTimes*>());
 3941                 assert(cs.contains(c));
 3942                 cs.remove(c);
 3943                 if(!cs.isEmpty()){
 3944                     assert(0);
 3945                     ssnatHash.insert(c->students, cs);
 3946                 }
 3947                 else{
 3948                     int t=ssnatHash.remove(c->students);
 3949                     assert(t==1);
 3950                 }
 3951             }
 3952             else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_TIME){
 3953                 ConstraintBasicCompulsoryTime* c=(ConstraintBasicCompulsoryTime*) ctr;
 3954                 QSet<ConstraintBasicCompulsoryTime*> &cs=bctSet;
 3955                 assert(cs.contains(c));
 3956                 cs.remove(c);
 3957             }
 3958             else if(ctr->type==CONSTRAINT_BREAK_TIMES){
 3959                 ConstraintBreakTimes* c=(ConstraintBreakTimes*) ctr;
 3960                 QSet<ConstraintBreakTimes*> &cs=btSet;
 3961                 assert(cs.contains(c));
 3962                 cs.remove(c);
 3963             }
 3964     
 3965             delete ctr;
 3966             this->timeConstraintsList.removeAt(i);
 3967             this->internalStructureComputed=false;
 3968             setRulesModifiedAndOtherThings(this);
 3969 
 3970             return true;
 3971         }
 3972     }
 3973 
 3974     return false;
 3975 }
 3976 
 3977 bool Rules::removeTimeConstraints(QList<TimeConstraint*> _tcl)
 3978 {
 3979 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
 3980     QSet<TimeConstraint*> _tcs=QSet<TimeConstraint*>(_tcl.begin(), _tcl.end());
 3981 #else
 3982     QSet<TimeConstraint*> _tcs=_tcl.toSet();
 3983 #endif
 3984     QList<TimeConstraint*> remaining;
 3985 
 3986     for(int i=0; i<this->timeConstraintsList.size(); i++){
 3987         TimeConstraint* ctr=timeConstraintsList[i];
 3988         if(_tcs.contains(ctr)){
 3989             if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME){
 3990                 ConstraintActivityPreferredStartingTime* c=(ConstraintActivityPreferredStartingTime*) ctr;
 3991                 QSet<ConstraintActivityPreferredStartingTime*> cs=apstHash.value(c->activityId, QSet<ConstraintActivityPreferredStartingTime*>());
 3992                 assert(cs.contains(c));
 3993                 cs.remove(c);
 3994                 if(!cs.isEmpty()){
 3995                     apstHash.insert(c->activityId, cs);
 3996                 }
 3997                 else{
 3998                     int t=apstHash.remove(c->activityId);
 3999                     assert(t==1);
 4000                 }
 4001             }
 4002 
 4003             else if(ctr->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
 4004                 ConstraintMinDaysBetweenActivities* c=(ConstraintMinDaysBetweenActivities*) ctr;
 4005                 for(int aid : qAsConst(c->activitiesId)){
 4006                     QSet<ConstraintMinDaysBetweenActivities*> cs=mdbaHash.value(aid, QSet<ConstraintMinDaysBetweenActivities*>());
 4007                     assert(cs.contains(c));
 4008                     cs.remove(c);
 4009                     if(!cs.isEmpty()){
 4010                         mdbaHash.insert(aid, cs);
 4011                     }
 4012                     else{
 4013                         int t=mdbaHash.remove(aid);
 4014                         assert(t==1);
 4015                     }
 4016                 }
 4017             }
 4018 
 4019             else if(ctr->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
 4020                 ConstraintTeacherNotAvailableTimes* c=(ConstraintTeacherNotAvailableTimes*) ctr;
 4021                 QSet<ConstraintTeacherNotAvailableTimes*> cs=tnatHash.value(c->teacher, QSet<ConstraintTeacherNotAvailableTimes*>());
 4022                 assert(cs.contains(c));
 4023                 cs.remove(c);
 4024                 if(!cs.isEmpty()){
 4025                     assert(0);
 4026                     tnatHash.insert(c->teacher, cs);
 4027                 }
 4028                 else{
 4029                     int t=tnatHash.remove(c->teacher);
 4030                     assert(t==1);
 4031                 }
 4032             }
 4033 
 4034             else if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 4035                 ConstraintStudentsSetNotAvailableTimes* c=(ConstraintStudentsSetNotAvailableTimes*) ctr;
 4036                 QSet<ConstraintStudentsSetNotAvailableTimes*> cs=ssnatHash.value(c->students, QSet<ConstraintStudentsSetNotAvailableTimes*>());
 4037                 assert(cs.contains(c));
 4038                 cs.remove(c);
 4039                 if(!cs.isEmpty()){
 4040                     assert(0);
 4041                     ssnatHash.insert(c->students, cs);
 4042                 }
 4043                 else{
 4044                     int t=ssnatHash.remove(c->students);
 4045                     assert(t==1);
 4046                 }
 4047             }
 4048             else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_TIME){
 4049                 ConstraintBasicCompulsoryTime* c=(ConstraintBasicCompulsoryTime*) ctr;
 4050                 QSet<ConstraintBasicCompulsoryTime*> &cs=bctSet;
 4051                 assert(cs.contains(c));
 4052                 cs.remove(c);
 4053             }
 4054             else if(ctr->type==CONSTRAINT_BREAK_TIMES){
 4055                 ConstraintBreakTimes* c=(ConstraintBreakTimes*) ctr;
 4056                 QSet<ConstraintBreakTimes*> &cs=btSet;
 4057                 assert(cs.contains(c));
 4058                 cs.remove(c);
 4059             }
 4060     
 4061             //_tcs.remove(ctr);
 4062             delete ctr;
 4063         }
 4064         else
 4065             remaining.append(ctr);
 4066     }
 4067     
 4068     bool ok;
 4069     assert(timeConstraintsList.count()<=remaining.count()+_tcs.count());
 4070     if(timeConstraintsList.count()==remaining.count()+_tcs.count())
 4071         ok=true;
 4072     else
 4073         ok=false;
 4074 
 4075     if(remaining.count()!=timeConstraintsList.count()){
 4076         timeConstraintsList=remaining;
 4077     
 4078         this->internalStructureComputed=false;
 4079         setRulesModifiedAndOtherThings(this);
 4080     }
 4081 
 4082     return ok;
 4083 }
 4084 
 4085 bool Rules::addSpaceConstraint(SpaceConstraint* ctr)
 4086 {
 4087     bool ok=true;
 4088 
 4089     //TODO: check if this constraint is already added...(if any possibility of duplicates)
 4090     if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
 4091         ConstraintActivityPreferredRoom* c=(ConstraintActivityPreferredRoom*) ctr;
 4092         QSet<ConstraintActivityPreferredRoom*> cs=aprHash.value(c->activityId, QSet<ConstraintActivityPreferredRoom*>());
 4093         for(ConstraintActivityPreferredRoom* oldc : qAsConst(cs)){
 4094             if((*oldc)==(*c)){
 4095                 ok=false;
 4096                 break;
 4097             }
 4098         }
 4099 
 4100         /*int i;
 4101         for(i=0; i<this->spaceConstraintsList.size(); i++){
 4102             SpaceConstraint* ctr2=this->spaceConstraintsList[i];
 4103             if(ctr2->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM)
 4104                 if(
 4105                  *((ConstraintActivityPreferredRoom*)ctr2)
 4106                  ==
 4107                  *((ConstraintActivityPreferredRoom*)ctr)
 4108                 )
 4109                     break;
 4110         }
 4111         
 4112         if(i<this->spaceConstraintsList.size())
 4113             ok=false;*/
 4114     }
 4115 /*  else if(ctr->type==CONSTRAINT_ROOM_NOT_AVAILABLE_TIMES){
 4116         int i;
 4117         ConstraintRoomNotAvailableTimes* c=(ConstraintRoomNotAvailableTimes*)ctr;
 4118         for(i=0; i<this->spaceConstraintsList.size(); i++){
 4119             SpaceConstraint* ctr2=this->spaceConstraintsList[i];
 4120             if(ctr2->type==CONSTRAINT_ROOM_NOT_AVAILABLE_TIMES){
 4121                 ConstraintRoomNotAvailableTimes* c2=(ConstraintRoomNotAvailableTimes*)ctr2;             
 4122                 if(c->room==c2->room)
 4123                     break;
 4124             }
 4125         }
 4126         
 4127         if(i<this->spaceConstraintsList.size())
 4128             ok=false;
 4129     }*/
 4130     else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_SPACE){
 4131         //ConstraintBasicCompulsorySpace* c=(ConstraintBasicCompulsorySpace*) ctr;
 4132         QSet<ConstraintBasicCompulsorySpace*> cs=bcsSet;
 4133         if(cs.count()>0)
 4134             ok=false;
 4135         /*int i;
 4136         for(i=0; i<this->spaceConstraintsList.size(); i++){
 4137             SpaceConstraint* ctr2=this->spaceConstraintsList[i];
 4138             if(ctr2->type==CONSTRAINT_BASIC_COMPULSORY_SPACE)
 4139                 break;
 4140         }
 4141                 
 4142         if(i<this->spaceConstraintsList.size())
 4143             ok=false;*/
 4144     }
 4145 
 4146     if(ok){
 4147         this->spaceConstraintsList << ctr; //append
 4148         
 4149         if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
 4150             ConstraintActivityPreferredRoom* c=(ConstraintActivityPreferredRoom*) ctr;
 4151             QSet<ConstraintActivityPreferredRoom*> cs=aprHash.value(c->activityId, QSet<ConstraintActivityPreferredRoom*>());
 4152             assert(!cs.contains(c));
 4153             cs.insert(c);
 4154             aprHash.insert(c->activityId, cs);
 4155         }
 4156         else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_SPACE){
 4157             ConstraintBasicCompulsorySpace* c=(ConstraintBasicCompulsorySpace*) ctr;
 4158             QSet<ConstraintBasicCompulsorySpace*> &cs=bcsSet;
 4159             assert(!cs.contains(c));
 4160             cs.insert(c);
 4161         }
 4162         
 4163         this->internalStructureComputed=false;
 4164         setRulesModifiedAndOtherThings(this);
 4165         return true;
 4166     }
 4167     else
 4168         return false;
 4169 }
 4170 
 4171 bool Rules::removeSpaceConstraint(SpaceConstraint* ctr)
 4172 {
 4173     for(int i=0; i<this->spaceConstraintsList.size(); i++){
 4174         if(this->spaceConstraintsList[i]==ctr){
 4175             if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
 4176                 ConstraintActivityPreferredRoom* c=(ConstraintActivityPreferredRoom*) ctr;
 4177                 QSet<ConstraintActivityPreferredRoom*> cs=aprHash.value(c->activityId, QSet<ConstraintActivityPreferredRoom*>());
 4178                 assert(cs.contains(c));
 4179                 cs.remove(c);
 4180                 aprHash.insert(c->activityId, cs);
 4181             }
 4182 
 4183             else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_SPACE){
 4184                 ConstraintBasicCompulsorySpace* c=(ConstraintBasicCompulsorySpace*) ctr;
 4185                 QSet<ConstraintBasicCompulsorySpace*> &cs=bcsSet;
 4186                 assert(cs.contains(c));
 4187                 cs.remove(c);
 4188             }
 4189     
 4190             delete ctr;
 4191             this->spaceConstraintsList.removeAt(i);
 4192             this->internalStructureComputed=false;
 4193             setRulesModifiedAndOtherThings(this);
 4194 
 4195             return true;
 4196         }
 4197     }
 4198 
 4199     return false;
 4200 }
 4201 
 4202 bool Rules::removeSpaceConstraints(QList<SpaceConstraint*> _scl)
 4203 {
 4204 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
 4205     QSet<SpaceConstraint*> _scs=QSet<SpaceConstraint*>(_scl.begin(), _scl.end());
 4206 #else
 4207     QSet<SpaceConstraint*> _scs=_scl.toSet();
 4208 #endif
 4209     QList<SpaceConstraint*> remaining;
 4210 
 4211     for(int i=0; i<this->spaceConstraintsList.size(); i++){
 4212         SpaceConstraint* ctr=spaceConstraintsList[i];
 4213         if(_scs.contains(ctr)){
 4214             if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
 4215                 ConstraintActivityPreferredRoom* c=(ConstraintActivityPreferredRoom*) ctr;
 4216                 QSet<ConstraintActivityPreferredRoom*> cs=aprHash.value(c->activityId, QSet<ConstraintActivityPreferredRoom*>());
 4217                 assert(cs.contains(c));
 4218                 cs.remove(c);
 4219                 aprHash.insert(c->activityId, cs);
 4220             }
 4221 
 4222             else if(ctr->type==CONSTRAINT_BASIC_COMPULSORY_SPACE){
 4223                 ConstraintBasicCompulsorySpace* c=(ConstraintBasicCompulsorySpace*) ctr;
 4224                 QSet<ConstraintBasicCompulsorySpace*> &cs=bcsSet;
 4225                 assert(cs.contains(c));
 4226                 cs.remove(c);
 4227             }
 4228     
 4229             //_scs.remove(ctr);
 4230             delete ctr;
 4231         }
 4232         else
 4233             remaining.append(ctr);
 4234     }
 4235 
 4236     bool ok;
 4237     assert(spaceConstraintsList.count()<=remaining.count()+_scs.count());
 4238     if(spaceConstraintsList.count()==remaining.count()+_scs.count())
 4239         ok=true;
 4240     else
 4241         ok=false;
 4242         
 4243     if(remaining.count()!=spaceConstraintsList.count()){
 4244         spaceConstraintsList=remaining;
 4245         
 4246         this->internalStructureComputed=false;
 4247         setRulesModifiedAndOtherThings(this);
 4248     }
 4249     
 4250     return ok;
 4251 }
 4252 
 4253 void Rules::updateGroupActivitiesInInitialOrderAfterRemoval()
 4254 {
 4255     GroupActivitiesInInitialOrderList newList;
 4256     GroupActivitiesInInitialOrderList toBeRemovedList;
 4257     
 4258     for(GroupActivitiesInInitialOrderItem* item : qAsConst(groupActivitiesInInitialOrderList)){
 4259         item->removeUseless(*this);
 4260         if(item->ids.count()<2)
 4261             toBeRemovedList.append(item);
 4262         else
 4263             newList.append(item);
 4264     }
 4265     
 4266     groupActivitiesInInitialOrderList=newList;
 4267     
 4268     for(GroupActivitiesInInitialOrderItem* ga : qAsConst(toBeRemovedList))
 4269         delete ga;
 4270     toBeRemovedList.clear();
 4271     //while(!toBeRemovedList.isEmpty())
 4272     //  delete toBeRemovedList.takeFirst();
 4273 }
 4274 
 4275 void Rules::updateActivitiesWhenRemovingStudents(const QSet<StudentsSet*>& studentsSets, bool updateConstraints)
 4276 {
 4277     if(studentsSets.count()==0)
 4278         return;
 4279 
 4280     QList<int> toBeRemovedIds;
 4281 
 4282     QHash<QString, int> numberOfStudentsPerSet;
 4283     
 4284     for(StudentsSet* studentsSet : qAsConst(studentsSets))
 4285         numberOfStudentsPerSet.insert(studentsSet->name, studentsSet->numberOfStudents);
 4286         
 4287     for(Activity* act : qAsConst(activitiesList)){
 4288         QStringList newStudents;
 4289         for(const QString& st : qAsConst(act->studentsNames)){
 4290             if(!numberOfStudentsPerSet.contains(st)){
 4291                 newStudents.append(st);
 4292             }
 4293             else{
 4294                 if(act->computeNTotalStudents){
 4295                     act->nTotalStudents-=numberOfStudentsPerSet.value(st);
 4296                     assert(act->nTotalStudents>=0);
 4297                 }
 4298             }
 4299         }
 4300         if(act->studentsNames.count()>0 && newStudents.count()==0)
 4301             toBeRemovedIds.append(act->id);
 4302         act->studentsNames=newStudents;
 4303     }
 4304     
 4305     removeActivities(toBeRemovedIds, updateConstraints);
 4306 }
 4307 
 4308 void Rules::updateConstraintsAfterRemoval()
 4309 {
 4310     bool recomputeTime=false;
 4311     bool recomputeSpace=false;
 4312 
 4313     QSet<int> existingActivitiesIds;
 4314     QSet<QString> existingTeachersNames;
 4315     //QSet<QString> existingStudentsNames;
 4316     QSet<QString> existingSubjectsNames;
 4317     QSet<QString> existingActivityTagsNames;
 4318     QSet<QString> existingRoomsNames;
 4319     
 4320     QList<TimeConstraint*> toBeRemovedTime;
 4321     QList<SpaceConstraint*> toBeRemovedSpace;
 4322     
 4323     for(Activity* act : qAsConst(activitiesList))
 4324         existingActivitiesIds.insert(act->id);
 4325         
 4326     for(Teacher* tch : qAsConst(teachersList))
 4327         existingTeachersNames.insert(tch->name);
 4328         
 4329     for(Subject* sbj : qAsConst(subjectsList))
 4330         existingSubjectsNames.insert(sbj->name);
 4331         
 4332     for(ActivityTag* at : qAsConst(activityTagsList))
 4333         existingActivityTagsNames.insert(at->name);
 4334         
 4335     for(Room* rm : qAsConst(roomsList))
 4336         existingRoomsNames.insert(rm->name);
 4337         
 4338     for(TimeConstraint* tc : qAsConst(timeConstraintsList)){
 4339         if(tc->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
 4340             ConstraintTeacherNotAvailableTimes* c=(ConstraintTeacherNotAvailableTimes*)tc;
 4341             if(!existingTeachersNames.contains(c->teacher))
 4342                 toBeRemovedTime.append(tc);
 4343         }
 4344         else if(tc->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
 4345             ConstraintStudentsSetNotAvailableTimes* c=(ConstraintStudentsSetNotAvailableTimes*)tc;
 4346             if(!permanentStudentsHash.contains(c->students))
 4347                 toBeRemovedTime.append(tc);
 4348         }
 4349         else if(tc->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_TIME){
 4350             ConstraintActivitiesSameStartingTime* c=(ConstraintActivitiesSameStartingTime*)tc;
 4351             c->removeUseless(*this);
 4352             if(c->n_activities<2)
 4353                 toBeRemovedTime.append(tc);
 4354         }
 4355         else if(tc->type==CONSTRAINT_ACTIVITIES_NOT_OVERLAPPING){
 4356             ConstraintActivitiesNotOverlapping* c=(ConstraintActivitiesNotOverlapping*)tc;
 4357             c->removeUseless(*this);
 4358             if(c->n_activities<2)
 4359                 toBeRemovedTime.append(tc);
 4360         }
 4361         else if(tc->type==CONSTRAINT_ACTIVITY_TAGS_NOT_OVERLAPPING){
 4362             ConstraintActivityTagsNotOverlapping* c=(ConstraintActivityTagsNotOverlapping*)tc;
 4363 
 4364             QStringList atl;
 4365             for(const QString& at : qAsConst(c->activityTagsNames))
 4366                 if(existingActivityTagsNames.contains(at))
 4367                     atl.append(at);
 4368             c->activityTagsNames=atl;
 4369 
 4370             if(c->activityTagsNames.count()<2)
 4371                 toBeRemovedTime.append(tc);
 4372         }
 4373         else if(tc->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
 4374             ConstraintMinDaysBetweenActivities* c=(ConstraintMinDaysBetweenActivities*)tc;
 4375             c->removeUseless(*this);
 4376             if(c->n_activities<2)
 4377                 toBeRemovedTime.append(tc);
 4378         }
 4379         else if(tc->type==CONSTRAINT_MAX_DAYS_BETWEEN_ACTIVITIES){
 4380             ConstraintMaxDaysBetweenActivities* c=(ConstraintMaxDaysBetweenActivities*)tc;
 4381             c->removeUseless(*this);
 4382             if(c->n_activities<2)
 4383                 toBeRemovedTime.append(tc);
 4384         }
 4385         else if(tc->type==CONSTRAINT_MIN_GAPS_BETWEEN_ACTIVITIES){
 4386             ConstraintMinGapsBetweenActivities* c=(ConstraintMinGapsBetweenActivities*)tc;
 4387             c->removeUseless(*this);
 4388             if(c->n_activities<2)
 4389                 toBeRemovedTime.append(tc);
 4390         }
 4391         else if(tc->type==CONSTRAINT_TEACHER_MAX_HOURS_DAILY){
 4392             ConstraintTeacherMaxHoursDaily* c=(ConstraintTeacherMaxHoursDaily*)tc;
 4393             if(!existingTeachersNames.contains(c->teacherName))
 4394                 toBeRemovedTime.append(tc);
 4395         }
 4396         else if(tc->type==CONSTRAINT_TEACHER_MAX_HOURS_CONTINUOUSLY){
 4397             ConstraintTeacherMaxHoursContinuously* c=(ConstraintTeacherMaxHoursContinuously*)tc;
 4398             if(!existingTeachersNames.contains(c->teacherName))
 4399                 toBeRemovedTime.append(tc);
 4400         }
 4401         else if(tc->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 4402             ConstraintTeachersActivityTagMaxHoursContinuously* c=(ConstraintTeachersActivityTagMaxHoursContinuously*)tc;
 4403             if(!existingActivityTagsNames.contains(c->activityTagName))
 4404                 toBeRemovedTime.append(tc);
 4405         }
 4406         else if(tc->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 4407             ConstraintTeacherActivityTagMaxHoursContinuously* c=(ConstraintTeacherActivityTagMaxHoursContinuously*)tc;
 4408             if(!existingActivityTagsNames.contains(c->activityTagName) || !existingTeachersNames.contains(c->teacherName))
 4409                 toBeRemovedTime.append(tc);
 4410         }
 4411         else if(tc->type==CONSTRAINT_TEACHER_MAX_DAYS_PER_WEEK){
 4412             ConstraintTeacherMaxDaysPerWeek* c=(ConstraintTeacherMaxDaysPerWeek*)tc;
 4413             if(!existingTeachersNames.contains(c->teacherName))
 4414                 toBeRemovedTime.append(tc);
 4415         }
 4416         else if(tc->type==CONSTRAINT_TEACHER_MIN_DAYS_PER_WEEK){
 4417             ConstraintTeacherMinDaysPerWeek* c=(ConstraintTeacherMinDaysPerWeek*)tc;
 4418             if(!existingTeachersNames.contains(c->teacherName))
 4419                 toBeRemovedTime.append(tc);
 4420         }
 4421         else if(tc->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_WEEK){
 4422             ConstraintStudentsSetMaxGapsPerWeek* c=(ConstraintStudentsSetMaxGapsPerWeek*)tc;
 4423             if(!permanentStudentsHash.contains(c->students))
 4424                 toBeRemovedTime.append(tc);
 4425         }
 4426         else if(tc->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_WEEK){
 4427             ConstraintTeacherMaxGapsPerWeek* c=(ConstraintTeacherMaxGapsPerWeek*)tc;
 4428             if(!existingTeachersNames.contains(c->teacherName))
 4429                 toBeRemovedTime.append(tc);
 4430         }
 4431         else if(tc->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_DAY){
 4432             ConstraintTeacherMaxGapsPerDay* c=(ConstraintTeacherMaxGapsPerDay*)tc;
 4433             if(!existingTeachersNames.contains(c->teacherName))
 4434                 toBeRemovedTime.append(tc);
 4435         }
 4436         else if(tc->type==CONSTRAINT_STUDENTS_SET_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
 4437             ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour* c=(ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour*)tc;
 4438             if(!permanentStudentsHash.contains(c->students))
 4439                 toBeRemovedTime.append(tc);
 4440         }
 4441         else if(tc->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_DAILY){
 4442             ConstraintStudentsSetMaxHoursDaily* c=(ConstraintStudentsSetMaxHoursDaily*)tc;
 4443             if(!permanentStudentsHash.contains(c->students))
 4444                 toBeRemovedTime.append(tc);
 4445         }
 4446         else if(tc->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_CONTINUOUSLY){
 4447             ConstraintStudentsSetMaxHoursContinuously* c=(ConstraintStudentsSetMaxHoursContinuously*)tc;
 4448             if(!permanentStudentsHash.contains(c->students))
 4449                 toBeRemovedTime.append(tc);
 4450         }
 4451         else if(tc->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 4452             ConstraintStudentsActivityTagMaxHoursContinuously* c=(ConstraintStudentsActivityTagMaxHoursContinuously*)tc;
 4453             if(!existingActivityTagsNames.contains(c->activityTagName))
 4454                 toBeRemovedTime.append(tc);
 4455         }
 4456         else if(tc->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
 4457             ConstraintStudentsSetActivityTagMaxHoursContinuously* c=(ConstraintStudentsSetActivityTagMaxHoursContinuously*)tc;
 4458             if(!existingActivityTagsNames.contains(c->activityTagName) || !permanentStudentsHash.contains(c->students))
 4459                 toBeRemovedTime.append(tc);
 4460         }
 4461         else if(tc->type==CONSTRAINT_STUDENTS_SET_MIN_HOURS_DAILY){
 4462             ConstraintStudentsSetMinHoursDaily* c=(ConstraintStudentsSetMinHoursDaily*)tc;
 4463             if(!permanentStudentsHash.contains(c->students))
 4464                 toBeRemovedTime.append(tc);
 4465         }
 4466         else if(tc->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 4467             ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags* c=(ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags*)tc;
 4468             if(!permanentStudentsHash.contains(c->students) ||
 4469              !existingActivityTagsNames.contains(c->firstActivityTag) ||
 4470              !existingActivityTagsNames.contains(c->secondActivityTag))
 4471                 toBeRemovedTime.append(tc);
 4472         }
 4473         else if(tc->type==CONSTRAINT_STUDENTS_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 4474             ConstraintStudentsMinGapsBetweenOrderedPairOfActivityTags* c=(ConstraintStudentsMinGapsBetweenOrderedPairOfActivityTags*)tc;
 4475             if(!existingActivityTagsNames.contains(c->firstActivityTag) ||
 4476              !existingActivityTagsNames.contains(c->secondActivityTag))
 4477                 toBeRemovedTime.append(tc);
 4478         }
 4479         else if(tc->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 4480             ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags* c=(ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags*)tc;
 4481             if(!existingTeachersNames.contains(c->teacher) ||
 4482              !existingActivityTagsNames.contains(c->firstActivityTag) ||
 4483              !existingActivityTagsNames.contains(c->secondActivityTag))
 4484                 toBeRemovedTime.append(tc);
 4485         }
 4486         else if(tc->type==CONSTRAINT_TEACHERS_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
 4487             ConstraintTeachersMinGapsBetweenOrderedPairOfActivityTags* c=(ConstraintTeachersMinGapsBetweenOrderedPairOfActivityTags*)tc;
 4488             if(!existingActivityTagsNames.contains(c->firstActivityTag) ||
 4489              !existingActivityTagsNames.contains(c->secondActivityTag))
 4490                 toBeRemovedTime.append(tc);
 4491         }
 4492         else if(tc->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME){
 4493             ConstraintActivityPreferredStartingTime* c=(ConstraintActivityPreferredStartingTime*)tc;
 4494             if(!existingActivitiesIds.contains(c->activityId)){
 4495                 toBeRemovedTime.append(tc);
 4496                 recomputeTime=true;
 4497             }
 4498         }
 4499         else if(tc->type==CONSTRAINT_ACTIVITY_PREFERRED_TIME_SLOTS){
 4500             ConstraintActivityPreferredTimeSlots* c=(ConstraintActivityPreferredTimeSlots*)tc;
 4501             if(!existingActivitiesIds.contains(c->p_activityId))
 4502                 toBeRemovedTime.append(tc);
 4503         }
 4504         else if(tc->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIMES){
 4505             ConstraintActivityPreferredStartingTimes* c=(ConstraintActivityPreferredStartingTimes*)tc;
 4506             if(!existingActivitiesIds.contains(c->activityId))
 4507                 toBeRemovedTime.append(tc);
 4508         }
 4509         else if(tc->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
 4510             ConstraintActivitiesPreferredTimeSlots* c=(ConstraintActivitiesPreferredTimeSlots*)tc;
 4511             if( (c->p_teacherName!="" && !existingTeachersNames.contains(c->p_teacherName)) ||
 4512              (c->p_studentsName!="" && !permanentStudentsHash.contains(c->p_studentsName)) ||
 4513              (c->p_subjectName!="" && !existingSubjectsNames.contains(c->p_subjectName)) ||
 4514              (c->p_activityTagName!="" && !existingActivityTagsNames.contains(c->p_activityTagName)) )
 4515                 toBeRemovedTime.append(tc);
 4516         }
 4517         else if(tc->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
 4518             ConstraintSubactivitiesPreferredTimeSlots* c=(ConstraintSubactivitiesPreferredTimeSlots*)tc;
 4519             if( (c->p_teacherName!="" && !existingTeachersNames.contains(c->p_teacherName)) ||
 4520              (c->p_studentsName!="" && !permanentStudentsHash.contains(c->p_studentsName)) ||
 4521              (c->p_subjectName!="" && !existingSubjectsNames.contains(c->p_subjectName)) ||
 4522              (c->p_activityTagName!="" && !existingActivityTagsNames.contains(c->p_activityTagName)) )
 4523                 toBeRemovedTime.append(tc);
 4524         }
 4525         else if(tc->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
 4526             ConstraintActivitiesPreferredStartingTimes* c=(ConstraintActivitiesPreferredStartingTimes*)tc;
 4527             if( (c->teacherName!="" && !existingTeachersNames.contains(c->teacherName)) ||
 4528              (c->studentsName!="" && !permanentStudentsHash.contains(c->studentsName)) ||
 4529              (c->subjectName!="" && !existingSubjectsNames.contains(c->subjectName)) ||
 4530              (c->activityTagName!="" && !existingActivityTagsNames.contains(c->activityTagName)) )
 4531                 toBeRemovedTime.append(tc);
 4532         }
 4533         else if(tc->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
 4534             ConstraintSubactivitiesPreferredStartingTimes* c=(ConstraintSubactivitiesPreferredStartingTimes*)tc;
 4535             if( (c->teacherName!="" && !existingTeachersNames.contains(c->teacherName)) ||
 4536              (c->studentsName!="" && !permanentStudentsHash.contains(c->studentsName)) ||
 4537              (c->subjectName!="" && !existingSubjectsNames.contains(c->subjectName)) ||
 4538              (c->activityTagName!="" && !existingActivityTagsNames.contains(c->activityTagName)) )
 4539                 toBeRemovedTime.append(tc);
 4540         }
 4541         else if(tc->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_HOUR){
 4542             ConstraintActivitiesSameStartingHour* c=(ConstraintActivitiesSameStartingHour*)tc;
 4543             c->removeUseless(*this);
 4544             if(c->n_activities<2)
 4545                 toBeRemovedTime.append(tc);
 4546         }
 4547         else if(tc->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_DAY){
 4548             ConstraintActivitiesSameStartingDay* c=(ConstraintActivitiesSameStartingDay*)tc;
 4549             c->removeUseless(*this);
 4550             if(c->n_activities<2)
 4551                 toBeRemovedTime.append(tc);
 4552         }
 4553         else if(tc->type==CONSTRAINT_TWO_ACTIVITIES_CONSECUTIVE){
 4554             ConstraintTwoActivitiesConsecutive* c=(ConstraintTwoActivitiesConsecutive*)tc;
 4555             if( !existingActivitiesIds.contains(c->firstActivityId) ||
 4556              !existingActivitiesIds.contains(c->secondActivityId) )
 4557                 toBeRemovedTime.append(tc);
 4558         }
 4559         else if(tc->type==CONSTRAINT_TWO_ACTIVITIES_GROUPED){
 4560             ConstraintTwoActivitiesGrouped* c=(ConstraintTwoActivitiesGrouped*)tc;
 4561             if( !existingActivitiesIds.contains(c->firstActivityId) ||
 4562              !existingActivitiesIds.contains(c->secondActivityId) )
 4563                 toBeRemovedTime.append(tc);
 4564         }
 4565         else if(tc->type==CONSTRAINT_THREE_ACTIVITIES_GROUPED){
 4566             ConstraintThreeActivitiesGrouped* c=(ConstraintThreeActivitiesGrouped*)tc;
 4567             if( !existingActivitiesIds.contains(c->firstActivityId) ||
 4568              !existingActivitiesIds.contains(c->secondActivityId) ||
 4569              !existingActivitiesIds.contains(c->thirdActivityId) )
 4570                 toBeRemovedTime.append(tc);
 4571         }
 4572         else if(tc->type==CONSTRAINT_TWO_ACTIVITIES_ORDERED){
 4573             ConstraintTwoActivitiesOrdered* c=(ConstraintTwoActivitiesOrdered*)tc;
 4574             if( !existingActivitiesIds.contains(c->firstActivityId) ||
 4575              !existingActivitiesIds.contains(c->secondActivityId) )
 4576                 toBeRemovedTime.append(tc);
 4577         }
 4578         else if(tc->type==CONSTRAINT_TWO_ACTIVITIES_ORDERED_IF_SAME_DAY){
 4579             ConstraintTwoActivitiesOrderedIfSameDay* c=(ConstraintTwoActivitiesOrderedIfSameDay*)tc;
 4580             if( !existingActivitiesIds.contains(c->firstActivityId) ||
 4581              !existingActivitiesIds.contains(c->secondActivityId) )
 4582                 toBeRemovedTime.append(tc);
 4583         }
 4584         else if(tc->type==CONSTRAINT_ACTIVITY_ENDS_STUDENTS_DAY){
 4585             ConstraintActivityEndsStudentsDay* c=(ConstraintActivityEndsStudentsDay*)tc;
 4586             if(!existingActivitiesIds.contains(c->activityId))
 4587                 toBeRemovedTime.append(tc);
 4588         }
 4589         else if(tc->type==CONSTRAINT_TEACHER_MIN_HOURS_DAILY){
 4590             ConstraintTeacherMinHoursDaily* c=(ConstraintTeacherMinHoursDaily*)tc;
 4591             if(!existingTeachersNames.contains(c->teacherName))
 4592                 toBeRemovedTime.append(tc);
 4593         }
 4594         else if(tc->type==CONSTRAINT_TEACHER_INTERVAL_MAX_DAYS_PER_WEEK){
 4595             ConstraintTeacherIntervalMaxDaysPerWeek* c=(ConstraintTeacherIntervalMaxDaysPerWeek*)tc;
 4596             if(!existingTeachersNames.contains(c->teacherName))
 4597                 toBeRemovedTime.append(tc);
 4598         }
 4599         else if(tc->type==CONSTRAINT_STUDENTS_SET_INTERVAL_MAX_DAYS_PER_WEEK){
 4600             ConstraintStudentsSetIntervalMaxDaysPerWeek* c=(ConstraintStudentsSetIntervalMaxDaysPerWeek*)tc;
 4601             if(!permanentStudentsHash.contains(c->students))
 4602                 toBeRemovedTime.append(tc);
 4603         }
 4604         else if(tc->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
 4605             ConstraintActivitiesEndStudentsDay* c=(ConstraintActivitiesEndStudentsDay*)tc;
 4606             if( (c->teacherName!="" && !existingTeachersNames.contains(c->teacherName)) ||
 4607              (c->studentsName!="" && !permanentStudentsHash.contains(c->studentsName)) ||
 4608              (c->subjectName!="" && !existingSubjectsNames.contains(c->subjectName)) ||
 4609              (c->activityTagName!="" && !existingActivityTagsNames.contains(c->activityTagName)) )
 4610                 toBeRemovedTime.append(tc);
 4611         }
 4612         else if(tc->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_DAILY){
 4613             ConstraintTeachersActivityTagMaxHoursDaily* c=(ConstraintTeachersActivityTagMaxHoursDaily*)tc;
 4614             if(!existingActivityTagsNames.contains(c->activityTagName))
 4615                 toBeRemovedTime.append(tc);
 4616         }
 4617         else if(tc->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_DAILY){
 4618             ConstraintTeacherActivityTagMaxHoursDaily* c=(ConstraintTeacherActivityTagMaxHoursDaily*)tc;
 4619             if(!existingActivityTagsNames.contains(c->activityTagName) || !existingTeachersNames.contains(c->teacherName))
 4620                 toBeRemovedTime.append(tc);
 4621         }
 4622         else if(tc->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_DAILY){
 4623             ConstraintStudentsActivityTagMaxHoursDaily* c=(ConstraintStudentsActivityTagMaxHoursDaily*)tc;
 4624             if(!existingActivityTagsNames.contains(c->activityTagName))
 4625                 toBeRemovedTime.append(tc);
 4626         }
 4627         else if(tc->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_DAILY){
 4628             ConstraintStudentsSetActivityTagMaxHoursDaily* c=(ConstraintStudentsSetActivityTagMaxHoursDaily*)tc;
 4629             if(!existingActivityTagsNames.contains(c->activityTagName) || !permanentStudentsHash.contains(c->students))
 4630                 toBeRemovedTime.append(tc);
 4631         }
 4632         else if(tc->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MIN_HOURS_DAILY){
 4633             ConstraintTeachersActivityTagMinHoursDaily* c=(ConstraintTeachersActivityTagMinHoursDaily*)tc;
 4634             if(!existingActivityTagsNames.contains(c->activityTagName))
 4635                 toBeRemovedTime.append(tc);
 4636         }
 4637         else if(tc->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MIN_HOURS_DAILY){
 4638             ConstraintTeacherActivityTagMinHoursDaily* c=(ConstraintTeacherActivityTagMinHoursDaily*)tc;
 4639             if(!existingActivityTagsNames.contains(c->activityTagName) || !existingTeachersNames.contains(c->teacherName))
 4640                 toBeRemovedTime.append(tc);
 4641         }
 4642         else if(tc->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MIN_HOURS_DAILY){
 4643             ConstraintStudentsActivityTagMinHoursDaily* c=(ConstraintStudentsActivityTagMinHoursDaily*)tc;
 4644             if(!existingActivityTagsNames.contains(c->activityTagName))
 4645                 toBeRemovedTime.append(tc);
 4646         }
 4647         else if(tc->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MIN_HOURS_DAILY){
 4648             ConstraintStudentsSetActivityTagMinHoursDaily* c=(ConstraintStudentsSetActivityTagMinHoursDaily*)tc;
 4649             if(!existingActivityTagsNames.contains(c->activityTagName) || !permanentStudentsHash.contains(c->students))
 4650                 toBeRemovedTime.append(tc);
 4651         }
 4652         else if(tc->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_DAY){
 4653             ConstraintStudentsSetMaxGapsPerDay* c=(ConstraintStudentsSetMaxGapsPerDay*)tc;
 4654             if(!permanentStudentsHash.contains(c->students))
 4655                 toBeRemovedTime.append(tc);