/***************************************************************************
 *   Copyright (C) 2007 by Muylkens Toon   *
 *   toon.muylkens@student.kuleuven.be   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "ConfigFileHandlerPowerTraining.h"
//      #include <stdio.h>
//       #include <iostream>
//        using namespace std;

/**
 * the constructor
 * handles all the configfiles and data
 * @param profilename is the name of the profile. It's a QString
 */
ConfigFileHandlerPowerTraining::ConfigFileHandlerPowerTraining(QString profilename, ExerciseHandler *exercise, QObject *parent)
:ConfigFileHandler(profilename,parent)
{
QObject::connect(exercise, SIGNAL(saveDataRequest()),this,SLOT(savedata()));

//ConfigFileHandler::ConfigFileHandler(profilename);
sport = QString("PowerTraining");
//defaultValueForRepetitions=10;
this->exercise = exercise;
//makeAllHashesAndLists();

// listnames = new QList<QString>();
// listdates = new QList<QString>();
// listweights = new QList<int>();
// listrepetitions=new QList<int>();

trainingList=new QMap<StringDate, Training*>();

trainingScheduleList = new QMap<QString,TrainingSchedule*>();
//possibleExerciseTagList = new QStringList(); ///TODO move to exerciseHandler
scheduleOccurrenceList = new QMap<QString, QList<ScheduleOccurrence>*>();
//loaddata(profilename);

///NORMALIZE_FACTOR =  -0.035714285; ///-> oude factor berekend via originele plots, bleek iets te groot
//NORMALIZE_FACTOR =  -0.023256;
setprofilename(profilename);

}



ExerciseHandler *ConfigFileHandlerPowerTraining::getExercise()
{
return this->exercise;
}

// ConfigFileHandlerPowerTraining::ConfigFileHandlerPowerTraining():QObject()
// {
// 
// }

/**
 * This method fills hashesOfExercises with hashes. If you want information about the hash. Ask Exercises
 * with the same index as this hash
 */
//void ConfigFileHandlerPowerTraining::makeAllHashesAndLists()
//{
///TODO remove method when not needed anymore
/*hashesOfExercises = new QList<QMultiHash<QString, int>* >();
	for(int i = 0; i<exercise->getNbOfExercises();i++)
	{
	hashesOfExercises->insert(i,new QMultiHash<QString, int>());
	}
pointsToPlotOfExercise = new QList<int>();*/
//}

/**
 * clear/delete all data from all the hashes
 * we don't want to keep old data from old profile when opening a new one.
 */
void ConfigFileHandlerPowerTraining::clearalldatahashes()
{
getExercise()->clear(); ///added by toon 02/11/07
trainingList->clear();
//possibleExerciseTagList->clear();
trainingScheduleList->clear();
scheduleOccurrenceList->clear();
/*this->listdates->clear();
this->listweights->clear();
this->listrepetitions->clear();
this->listnames->clear();*/
}

/**
*destruct all Trainings.
*/
void ConfigFileHandlerPowerTraining::logout(){
// QHashIterator<QString, Training*> i(*this->trainingList);
// while (i.hasNext()) {
// 	i.next();
// 	Training *temp = i.value();
// 	this->trainingList->remove(i.key());
// 	delete temp;
//  }

QMapIterator<StringDate, Training*> i(*this->trainingList);
while (i.hasNext()) {
	i.next();
	Training *temp = i.value();
	this->trainingList->remove(i.key());
	delete temp;
 }
clearalldatahashes(); ///added  by toon: 02/11/07
}


void ConfigFileHandlerPowerTraining::loaddata(QString profilename)
{
ConfigFileHandler::loaddata(profilename);
setSaveEnable(false);
///remove all data from Hashes because we only add/insert things.
///we don't want to keep old data from old profile when opening a new one.
clearalldatahashes();
QFile file;
 	QSettings settings("ToonSoft", "Qtrainer");
	settings.beginGroup("ProgramSettings");
	QString profilePath=(settings.value("Profile_Path")).toString();
	settings.endGroup();
QDir::setCurrent(profilePath);
file.setFileName((profilename).append(".QProfile"));
file.open(QIODevice::ReadOnly);
     	QTextStream in(&file);
	int i=1;
	while (!in.atEnd()) {
       	QString line = in.readLine();
        processline(line);
	i++;
}

setSaveEnable(true);
if(!exercise->getPossibleExerciseTagList().contains(tr("No tag"))) {
	///for compatibalty with old profiles
	exercise->addExerciseTag(tr("No tag"));
	}
}

/**
*the line "line" is read and anylised. When it contains information about the profile it is extracted from
*that line/
*/
void ConfigFileHandlerPowerTraining::processline(QString line)
{
// 	QTextStream cout(stdout, QIODevice::WriteOnly);
// 	cout<<line<<endl;

	QString str="0";int intvalue=0;QString key="0";QString name="";QString tag=tr("No tag");

	///EXERCISES
	if(line.startsWith("<Exercise>")){
	name = line.section('!', 1, 1);
	str=line.section('!',2,2);

	QStringList list = QStringList();
	int i=3;
	while (line.section('!',i,i).size()!=0){
		QString section = line.section('!',i,i);

		if (!section.contains("tag=")){
			list <<line.section('!',i,i);
			i++;
			}
		else{
			///this is a tag and not a muscle. We need to test on tag=... 
			///because to keep old profiles
			///working in the new QTrainer, the tag section was added in Qtrainer0.5
			tag = section.section('=',1,1);
			i++;
			}
		}
	if(!exercise->isAlreadyStored(name)){
		exercise->addExercise(name, str,list,tag);
//		addQMultiHash();
		}
	}
	///NUMBER of POINTS to PLOT
	///and
	///PLOT METHODS
if(line.startsWith(QString("<NumberOf")) || line.startsWith(QString("<PlotMethodFor"))){
	for(int i=0;i<exercise->getNbOfExercises();i++)
	{
	int index = getExercise()->getIndexes().at(i);
	///number of points to plot
	name="<NumberOf";
	name.append(exercise->getName(index));
	name.append("PointsToPlot>");
	if(line.startsWith(name)){
		str = line.section('!', 1, 1);intvalue=str.toInt();
		exercise->getExercise(index)->setNbOfPointsToPlot(intvalue);
// 		pointsToPlotOfExercise->insert(i,intvalue);
		}
	///plot method
	name="<PlotMethodFor";
	name.append(exercise->getName(index));
	if(line.startsWith(name)){
		QString first = line.section('!', 1, 1);
		QString second = line.section('!', 2, 2);
		QString third = line.section('!', 3, 3);
		QStringList tempList = QStringList();
		if(first=="Bevier" || second=="Bevier" || third=="Bevier") {tempList<<"Bevier";}
		if(first=="Spline" || second=="Spline" || third=="Spline") {tempList<<"Spline";}
		if(first=="Line" || second=="Line" || third=="Line") {tempList<<"Line";}
		exercise->getExercise(index)->setPlotMethod(tempList);
		}
	}
}	

	///hashesOfExercices big enough?
	//addQMultiHash(); ///when neceserry normally not
	///DATA
	for(int i=0;i<exercise->getNbOfExercises();i++)
	{
	int index = getExercise()->getIndexes().at(i);
	name="<";
	name.append(exercise->getName(index));
	name.append(">");
	if(line.startsWith(name)){
		Exercise *ex = exercise->getExercise(index);
		key=line.section('!', 1, 1);  ///datum
		str=line.section('!', 2, 2);int weight=str.toInt();
		str=line.section('!', 3, 3);int reps=str.toInt(); ///repetitions
		PowerTrainingMeasurement *mes = new PowerTrainingMeasurement(weight,reps,StringDate(key),ex);
		ex->linkMeasurement(mes);		
// 		(hashesOfExercises->at(i))->insert(key,intvalue);
// 		str=line.section('!', 3, 3);intvalue=str.toInt();	
// 		hashesOfExercises->at(i)->insert(key,intvalue);
		}
	}

	///trainings
	name="<Training> !";
	if(line.startsWith(name)){
	QString date=line.section('!', 1, 1);
	QString dayS=date.section('.',0,0);
	QString monthS=date.section('.',1,1);
	QString yearS=date.section('.',2,2);
	int day=dayS.toInt();
	int month=monthS.toInt();
	int year=yearS.toInt();
	QString start=line.section('!', 2, 2);
	QString startHoursS=start.section(':',0,0);
	QString startMinutesS=start.section(':',1,1);
	int startHours=startHoursS.toInt();
	int startMinutes=startMinutesS.toInt();
	QString end=line.section('!', 3, 3);
	QString endHoursS=end.section(':',0,0);
	QString endMinutesS=end.section(':',1,1);
	int endHours=endHoursS.toInt();
	int endMinutes=endMinutesS.toInt();
	QString title=line.section('!', 4, 4);
	QString explaination=line.section('!', 5, 5);
	QMap<QString,QStringList> scheduleMap = QMap<QString,QStringList>();
	QList<QString> orderList = QList<QString>();
	int i=6;
	while (line.section('!',i,i).size()!=0){
		///iterating over the Schedules of this Training
		QString oneSchedule = line.section('!',i,i);
		i++;
		QStringList scheduleList = QStringList();
		QString scheduleName = oneSchedule.section('_',1,1);
		int j=2;
			while (oneSchedule.section('_',j,j).size()!=0){
			///iterating over the Exercises of this Schedule
			scheduleList<<oneSchedule.section('_',j,j);
			j++;
			}
		scheduleMap.insert(scheduleName,scheduleList);
		orderList.append(scheduleName);
		}
	Training *myTraining = new Training(scheduleMap,orderList,QDate(year,month,day), QTime(startHours,startMinutes),QTime(endHours,endMinutes),title,explaination);
	planTraining(myTraining,false);
	}

	///TrainingSchedules
	name="<TrainingSchedule> !";
	TrainingSchedule *schedule = new TrainingSchedule();
	if(line.startsWith(name)){
	QString name=line.section('!', 1, 1);
	QString explanation=line.section('!', 2, 2);
	QStringList list; ///list will contain all the Rotations and Iterations and their options
	int i=3;
	while (line.section('!',i,i).size()!=0){
		list <<line.section('!',i,i);
		i++;
		}
	for(int j=0;j<list.size();j++){
		//int nbOfRotation=  (list.at(j).section('_',1,1)).toInt();
		//int nbOfIteration=(list.at(j).section('_',2,2)).toInt();
		int nbOfRotation=((list.at(j).section("Rotation_",1,1)).section("_",0,0)).toInt();
		int nbOfIteration=((list.at(j).section("Iteration_",1,1)).section("_",0,0)).toInt();
		int performance = ((list.at(j).section("Performance_",1,1)).section("_",0,0)).toInt();
		int repetitions = ((list.at(j).section("Repetitions_",1,1)).section("_",0,0)).toInt();

		while(nbOfRotation>=schedule->getNumberOfRotations()){
		schedule->addRotation();
		}
			
		while(nbOfIteration>=schedule->getNumberOfTimesExerciseIsRepeatedInARotation(nbOfRotation)){
		schedule->addRepetition(nbOfRotation);
		}
	
		schedule->setPerformance(nbOfRotation,nbOfIteration,performance);
		schedule->setNumberOfTimesExerciseIsDone(nbOfRotation,nbOfIteration,repetitions);
		schedule->setName(name);	
		schedule->setExplaination(explanation);
		}
	this->trainingScheduleList->insert(schedule->getName(),schedule);
	}

	///ExerciseTags
	name="<ExerciseTag> !";
	if(line.startsWith(name)){
	int i=1;
	while (line.section('!',i,i).size()!=0){
		exercise->
		addExerciseTag(line.section('!',i,i));
		i++;
		}
	}
	
	///scheduleOccurrences
	name="<ScheduleOccurrence> !";
	if(line.startsWith(name)){
		StringDate dateS = StringDate(line.section('!',1,1));
		QDate date = dateS.getQDate();
		QString scheduleName = line.section('!',2,2);
		QString exercisesS = line.section('!',3,3);
		QString weightsS = line.section('!',4,4);
		QString repetitionsS = line.section('!',5,5);
		QStringList exercises = QStringList();
		QList<int> weights = QList<int>();
		QList<int> repetitions = QList<int>();
		int i=1;
		while (exercisesS.section('_',i,i).size()!=0){
			exercises<<exercisesS.section('_',i,i);
			i++;
			}
		i=1;
		while (weightsS.section('_',i,i).size()!=0){
			weights<<weightsS.section('_',i,i).toInt();
			i++;
			}
		i=1;
		while (repetitionsS.section('_',i,i).size()!=0){
			repetitions<<repetitionsS.section('_',i,i).toInt();
			i++;
			}		
		ScheduleOccurrence *scheduleOc = new ScheduleOccurrence(scheduleName,date,exercises,weights,repetitions);
		addScheduleOccurrence(scheduleOc);
	}


}

/**
*returns a list with all the tags for exercises that are saved into this profile
*/
//QStringList ConfigFileHandlerPowerTraining::getPossibleExerciseTagList(){
//return QStringList(*possibleExerciseTagList);
//}

/**
 * This method adds new QMultiHashes to the hashesOfExercises to store values and weights by key=exercisename
 */
// void ConfigFileHandlerPowerTraining::addQMultiHash()
// {	
//  while(hashesOfExercises->size()<exercise->getNbOfExercises()) {
// 	hashesOfExercises->append(new QMultiHash<QString, int>());
// 	//cout <<"we are adding new QMulitHash for storing exercises"<<endl;
// 	}	
// }

/**
 * Remove the data from exercise with index 'index'.
 * @param index 
 */
// void ConfigFileHandlerPowerTraining::removeQMultiHash(int index)
// {
// pointsToPlotOfExercise->removeAt(index);
// *hashesOfExercises->at(index);
// removeFromOrderedLists(*hashesOfExercises->at(index)); ///so it is removed from the table
// hashesOfExercises->removeAt(index);
// }

/**
 * Add an exercise, and save the configfile.
 * @param name string: name
 * @param explaination string short explaination
 */
void ConfigFileHandlerPowerTraining::addExercise(QString exercisename, QString explaination, QStringList muscleList, QString tag)
{
	if(!exercise->isAlreadyStored(exercisename)){
		exercise->addExercise(exercisename, explaination, muscleList,tag);
		//savedata(); ///TODO make exercise emit the savedata signal!
		}
}

/**
 * Adds an exercisetag to the profile and saves the profile.
 * @param tag string: tagname
 */
// void ConfigFileHandlerPowerTraining::addExerciseTag(QString tag)
// {
// if(!tag.contains("!") && !possibleExerciseTagList->contains(tag)){
// 	possibleExerciseTagList->append(tag);	
// 	savedata();
// 	QStringList newList = QStringList(*this->possibleExerciseTagList);
// 	emit exerciseTagListChanged(newList);
// 	emit exerciseTagListChanged();
// }
// }



/**
*This method adds the schedule to the lists of Training Schedules.
*When another schedule exists with the same name, it is overridden!!
*The profile is then saved to disk.
*/	
void ConfigFileHandlerPowerTraining::addSchedule(TrainingSchedule *schedule){
trainingScheduleList->insert(schedule->getName(),schedule); ///insert will override when key already present.
savedata();
}


/**
*This method adds the scheduleOccurrence to the lists of TrainingScheduleOccurrences.
*When another scheduleOc exists with the same data and name, it is overridden!!
*The profile is then saved to disk.
*/	
void ConfigFileHandlerPowerTraining::addScheduleOccurrence(ScheduleOccurrence *scheduleOc){
QString date = StringDate(scheduleOc->getDate()).getQString();
if(scheduleOccurrenceList->contains(date)) {
	QList<ScheduleOccurrence> *list = scheduleOccurrenceList->value(date);
	bool override = false;
	for(int i=0;i<list->size();i++){
		if(list->at(i).getName()==scheduleOc->getName()){
			override=true;
			list->replace(i,*scheduleOc);
			}
		}
	if(!override) {list->append(*scheduleOc);}
	}
else{
	scheduleOccurrenceList->insert(date,new QList<ScheduleOccurrence>());
	QList<ScheduleOccurrence> *list = scheduleOccurrenceList->value(date);
	list->append(*scheduleOc);
	}
savedata();
}



/**
*This method registers a training on date from starttime untill endtime
*If a training already exists with that date, it is overriden
*/
void ConfigFileHandlerPowerTraining::planTraining(Training *training,bool withsaving){
///TODO: change withsaving stuff with the filehandler->enableSaving() stuff
trainingList->insert(StringDate(training->getDate()),training);
if(withsaving){savedata();}
}

/**
 * Saves the number of data that needs to be plotted, we don't want old data to be plotted
 * @param number integer value <number> is the number of points to use.
 * @post this funciton MUST call savedata() at the end, other functions will count on that
 */
void ConfigFileHandlerPowerTraining::savenumberofpointstoplot(QString exercisename, int number)
{
	exercise->getExercise(exercisename)->setNbOfPointsToPlot(number);
// 	pointsToPlotOfExercise->replace(exercise->getindex(exercisename), number);
	//savedata(); ///todo make exercisehandler emit the savedata signal
}

/**
 * Saves the exercises which was changed
 * @param newname 
 * @param newexplaination 
 * @param index 
 */
void ConfigFileHandlerPowerTraining::saveExercise(QString newname, QString newexplaination,QStringList newMuscleList, QString newTag, int index)
{
exercise->replaceName(newname, index);
exercise->replaceExplaination(newexplaination, index);
exercise->replaceMuscle(newMuscleList, index);
exercise->replaceTag(newTag, index);
savedata();
}

/**
 * remove the exercise with index index from the list + remove the data
 * @param index 
 */
void ConfigFileHandlerPowerTraining::deleteExercise(int index)
{
//removeQMultiHash(index);
exercise->deleteExercise(index); //remove the exercise from the lists; IMPORTANT: execute after removeQMultiHash

 savedata();
}

/**
*removes the training with the name 'name' from the list
*and saves the profile
*/
void ConfigFileHandlerPowerTraining::deleteTrainingSchedule(QString name){
trainingScheduleList->remove(name);
savedata();
}


/**
*SLOT: the name of a trainingschedule may be changed => delete all schedule occurrences!
* and all trainings that are planned!
*/
void ConfigFileHandlerPowerTraining::someTrainingScheduleChanged(QString oldName, TrainingSchedule *newschedule){
bool needtosave=false;
 if(oldName!=newschedule->getName()){
	needtosave=true;
 	///change all planned trainings :-) nice
// 	QHashIterator<QString, Training*> i(*trainingList);
//  	while (i.hasNext()) {
//  		i.next();
//  		i.value()->renameTrainingSchedules(oldName, newschedule->getName());
// 		}

	QMapIterator<StringDate, Training*> i(*trainingList);
 	while (i.hasNext()) {
 		i.next();
 		i.value()->renameTrainingSchedules(oldName, newschedule->getName());
		}


	}
///delete all ScheduleOccurrences!  Not so nice
QMapIterator<QString, QList<ScheduleOccurrence>* > j(*scheduleOccurrenceList);
while(j.hasNext()){
	j.next();
	QList<ScheduleOccurrence> *temp = j.value();
	for(int e = 0;e<temp->size();e++){
		if(temp->at(e).getName() == oldName){temp->removeAt(e); needtosave=true;}
		}
	}
if(needtosave){savedata();}
}




void ConfigFileHandlerPowerTraining::savedata()
{	

	ConfigFileHandler::savedata();

if(getSaveEnable()){
	QList<Exercise*> exerciseList = exercise->getExercises();
 	int maxfori = exerciseList.size();
	
	///make sure there are enough objects in hashesOfExercises
//	addQMultiHash();
	///PROFILE-SETTINGS
	QString name;
	QList<int> values;
	QString str(this->profilename);
		QSettings settings("ToonSoft", "Qtrainer");
		settings.beginGroup("ProgramSettings");
		QString profilePath=(settings.value("Profile_Path")).toString();
		settings.endGroup();
	QDir::setCurrent(profilePath);
	QFile file((str).append(".QProfile"));
     	if (!file.open(QIODevice::WriteOnly | QIODevice::Text)){/*cout<<"fault"<<endl;*/   return;}

     	QTextStream out(&file);
	out << "PROFILE INFORMATION: \n";
     	out << "<ProfileName> !" <<(this->profilename)<< "! \n";
	out << "THE FOLLOWING 3 CAN CHANGE BUT ONLY ONE OF THEM CAN BE TRUE: \n";
 	out << "<PowerTraining> !true! \n";
 	out << "EXERCISES: !NAME!EXPLANATION!TAG!MUSCLE!MUSCLE!....! \n";
	///Not-Hard-coded: Exercises

	for(int i=0;i<maxfori;i++)
 	{
 	name="<Exercise> !";
	Exercise *ex = exerciseList.at(i);
  	name.append(ex->toString());
	out <<name;
 	}
	out << "PLOTWIDGET INFORMATION: When saving plotmethods: 3 possible ones: Bevier, Line and Spline\n";
	for(int i=0;i<maxfori;i++)
		{
		Exercise *ex = exerciseList.at(i);
		///Number Of Points To Plot	
		name="<NumberOf";
		name.append(ex->getName());
		name.append("PointsToPlot> !");
		out<<name<<ex->getNbOfPointsToPlot()<<"! \n";/*
		if(getnumberofpoints(exercise->getName(i))==0){out <<name<<0<<"! \n";}
		else {out <<name<<exercise->getExercise(i)->getNbOfPointsToPlot()<<"! \n";}*/
		///Plot Method (bevier, splines, lines)
		name="<PlotMethodFor";
		name.append(ex->getName());
		name.append("> !");
		QStringList temp = ex->getPlotMethod();
		QString writeString="";
		for(int k=0;k<temp.size();k++){
			writeString.append(temp.at(k));
			writeString.append("!");
			}
		out<<name<<writeString<<"\n";
		}
	

	///DATA-POINTS
	///seperate forlus => to seperate sections in the file
	out << "EXERCISE DATA POINTS: !DATE!WEIGHT!REPETITIONS! \n";
	
	for(int i=0;i<maxfori;i++)///exercise->getNbOfExercises() == hashesOfExercises->size()
	{
	Exercise *ex = exerciseList.at(i);
	name="<";
	name.append(ex->getName());
	name.append("> !");
	QList<PowerTrainingMeasurement*> list= ex->getMeasurements();
	for(int j=0;j<list.size();j++){
		out<<name<<list.at(j)->getDate().getQString()<<"!"<<list.at(j)->getWeight()<<"!"<<list.at(j)->getRepetitions()<<"! \n";
		}/*
	QHashIterator<QString, int> ia(*hashesOfExercises->at(i));
		while(ia.hasNext())
		{
		ia.next();ia.next(); ///two times because we store weight AND repetitions
		values = hashesOfExercises->at(i)->values(ia.key());
		out<<name<<ia.key()<<"!"<<values.at(1)<<"!"<<values.at(0)<<"! \n";
		}*/
	}


	///TRAININGS
	out<< "TRAINGS:  !DATE!STARTTIME!ENDTIME!TITLE!EXPLAINATION!_SCHEDULENAME_EXERCISE1_EXERCISE2_..._! \n";
	name="<Training> !";
	QMapIterator<StringDate, Training*> i(*trainingList);
 	while (i.hasNext()) {
     	i.next();
	Training *myTraining=i.value();
     	out<<name<<myTraining->toString()<<endl;
	}


	///TRAININGSCHEDULES
	out<< "TRAINGSCHEDULES:  !NAME!EXPLANATION!Rotation_Iteration_Performance_Repetitions!Rotation_Iteration_Performance_Repetitions!...! \n";
	name="<TrainingSchedule> !";
	QMapIterator<QString,TrainingSchedule*> iter(*this->trainingScheduleList);
 	while (iter.hasNext()) {
     	iter.next();
     	out << name<<iter.value()->toString()<< endl;
 	}


	///EXERCISETAGS && TRAININGTAGS
	out<< "TAGS: !tagname!tagname!....!\n";
	name="<ExerciseTag> !";
	if(exercise->getPossibleExerciseTagList().size()>0){out<<name;}
	for(int i=0;i< exercise->getPossibleExerciseTagList().size();i++){
	out<<exercise->getPossibleExerciseTagList().at(i)<<QString("!");
	}
	if(exercise->getPossibleExerciseTagList().size()>0){out<<endl;}
	


	///SCHEDULE OCCURRENCES
	out<<"SCHEDULEOCCURECE: !date!name!_exercises_seperated_by_!_weights_seperated_by_!_repetitions_seperated_by_!\n";
	name="<ScheduleOccurrence> !";
	QMapIterator<QString,QList<ScheduleOccurrence>* > iter2(*this->scheduleOccurrenceList);
	while(iter2.hasNext()){
		iter2.next();
		QList<ScheduleOccurrence> *list = iter2.value();
		for(int i=0;i<list->size();i++){
			out<<name<<list->at(i).toString();
			}
		}
}///(if getSaveEnable())

}

// int ConfigFileHandlerPowerTraining::getDefaultValueForRepetitions()
// {
// return defaultValueForRepetitions;
// }


// int ConfigFileHandlerPowerTraining::getage()
// {
// return this->age;
// }
// 
// int ConfigFileHandlerPowerTraining::getweight()
// {
// return this->weight;
// }
// 
// QString ConfigFileHandlerPowerTraining::getsex()
// {
// return this->sex;
// }



// QString ConfigFileHandlerPowerTraining::getnormal()
// {
// return this->normal;
// }
// 
// QString ConfigFileHandlerPowerTraining::getmaxrepetitions()
// {
// return this->maxrepetitions;
// }
// 
// QString ConfigFileHandlerPowerTraining::getmaxpower()
// {
// return this->maxpower;
// }


/**
 * returns the number of points to be used to plot the data curve
 * @return  the number of points to be used to plot the data curve
 */
// int ConfigFileHandlerPowerTraining::getnumberofpointstoplot(QString exercisename)
// {
// return exer
// int i = exercise->getindex(exercisename);
// if(pointsToPlotOfExercise->size()>i+1){
// 	return pointsToPlotOfExercise->at(i);
// 	}
// return 0;
// }


/**
 * We can only append one datapoint a day. We need to know if we are overwriting a value or appending a new one
 * @param date QData format
 * @param exercisename QString name of the exercise as stored in Exercises
 * @return boolean, true when data on date <data> was already stored
 */
bool ConfigFileHandlerPowerTraining::isdatealreadystored(QString exercisename, QDate date)
{
if(!(exercise->isAlreadyStored(exercisename))){
return false;
}
///exercise exists
return exercise->getExercise(exercisename)->hasMeasurement(date);
/*
bool returnbool = false;


QString datestring = StringDate(date).getQString();
QHashIterator<QString, int> ia(*hashesOfExercises->at(exercise->getindex(exercisename)));
 while (ia.hasNext()) {
     ia.next();
     if(ia.key()==datestring){returnbool = true;}
 	}
return returnbool;*/
}


/**
 * sets the profile to <profilename>
 * reload the data from the configfile
 * @param profilename a QString representing the profilename
 */
void ConfigFileHandlerPowerTraining::setprofilename(QString profilename)
{
this->profilename=profilename;
///when loading a new profile we need to remove the exercises of the old profile from the ordered lists
clearalldatahashes();
// this->listdates->clear();
// this->listweights->clear();
// this->listrepetitions->clear();
// this->listnames->clear();
///end remove the data from odered lists
loaddata(profilename);
}

///FROM THIS POINT IT HANDLES ABOUT THE DATAPOINTS AND NOT THE PROFILE SETTINGS


/**
 * @param exercisename
*		name of the exercise as in Exercise
 * @param weight
*	how much weight did you use
 * @param  quantity
*	how many times did you repeat the exercise.(use default value, or a value close tot the default one)
 * @param date 
*	when did you do the exercise
* @post This function will append the new data, increase the number of points to be plotted, (the latter 
* funciton call wil make sure the data is saved 
* 
*If already a measurement exists on the date, the measurement is overridden and the nb points to plot is NOT increased
 */
void ConfigFileHandlerPowerTraining::appenddata(QString exercisename, int weight,int quantity, QDate date)
{
if(exercise->isAlreadyStored(exercisename)){
///exercise exists
Exercise *ex = exercise->getExercise(exercisename);
PowerTrainingMeasurement *mes = new PowerTrainingMeasurement(weight,quantity,StringDate(date),ex);
ex->linkMeasurement(mes);
}

}




/**
*This slot deletes Training with index  'index' in the getTrainings() QList
*/
void ConfigFileHandlerPowerTraining::deleteTraining(QDate date){
Training *temp = trainingList->value(StringDate(date));
trainingList->remove(StringDate(date));
delete temp;
savedata();
}


/**
 * returns the progress in % of the last <numberoftrainings> (or less)
 * @param numberoftrainings 
 * @return 
 */
float ConfigFileHandlerPowerTraining::getprogress(int numberoftrainings)
{
///sorting doesn' t take long, the bottlenech is the forlus
//sortallexercises(); /// we sort once in the entire process.
//float normalizedValues[numberoftrainings];
float totalProgess=0; ///sum of all progresses of all exercises
int numberOfEmptyExercises=0; ///don't count in exercises where we didn't fill in any or only 1 datapoint
int nbExercises=exercise->getNbOfExercises();
for(int i=0; i<nbExercises;i++) ///For every exercise
{
	int index = getExercise()->getIndexes().at(i);
	if(exercise->getExercise(index)->getMeasurements().size()<2){numberOfEmptyExercises++;}
	else{totalProgess+=getprogress(numberoftrainings,exercise->getName(index));}
}
if(nbExercises == numberOfEmptyExercises) {return 0;} ///we don't have any datapoints
float devideby = nbExercises-numberOfEmptyExercises;
float result = (totalProgess/devideby);
int trimmedresulttimeshundred = (int)(result*100);
float trimmedfloat = trimmedresulttimeshundred;
result = trimmedfloat/100;
return (float) result;
}

/**
 * Returns the % progress of one exercise for the last <numberoftrainings> (or less)
 * @param numberoftrainings 
 * @param exercisename 
 * @return 
 */
float ConfigFileHandlerPowerTraining::getprogress(int numberoftrainings, QString exercisename)
{
if(exercise->isAlreadyStored(exercisename)){
	///exercise exists
	QList<PowerTrainingMeasurement*> list = exercise->getExercise(exercisename)->getMeasurements();
	int size=list.size();
	if(numberoftrainings>size){numberoftrainings=size;} 
	if(numberoftrainings%2!=0){numberoftrainings--;} 
	if(numberoftrainings<=0){return 0;}
	///numberoftrainings is now even and legal
	float sumOfValues1 = 0; ///first n values summed (most recent)
	float sumOfValues2 = 0; ///last n values summed (oldest)
	float result =0; /// procentual progress of sumOfValues2 compared to sumOfValues1
	
	int index= list.size()-1;
	int endindex1 =list.size()-(numberoftrainings/2); ///smallest index used for list 1
	int endindex2 =list.size()-numberoftrainings; ///smallest index used for list 2
		
	while(index>=endindex1){
		///use the numberoftrainings most recent values/measurements
		sumOfValues1 += list.at(index)->getNormalisedWeight();
		index--;
		}
	
	while(index>=endindex2){
		///use the numberoftrainings most recent values/measurements
		sumOfValues2 += list.at(index)->getNormalisedWeight();
		index--;
		}
	
	if(sumOfValues1+sumOfValues2 == 0) {
		return 0;
		}
	result = ((sumOfValues1-sumOfValues2)/(sumOfValues2+sumOfValues1))*100;
	int trimmedresulttimeshundred = (int)(result*100);
	float trimmedfloat = trimmedresulttimeshundred;
	result = trimmedfloat/100;
	return (float) result;

}
return (float)0;

/*
//if(withsorting){sortallexercises();} ///we sort here once, but never again in this method
for(int i=getweights(false).size()-1;i!=-1;i--) ///we gaan van nieuwe data naar oude data. per oefening na elkaar
	{
	if(getnames(false).at(i)==exercisename){
		int nbValue = 0;
		while(nbValue<numberoftrainings)
		{
		normalizedValues[nbValue]=normalize(getrepetitions(false).at(i-nbValue),getweights(false).at(i-nbValue));
		nbValue++;
		}///we have all the data now, we now calculate the progress

		int maxfora=(int)((numberoftrainings/2));
		for(int a =0;a<maxfora;a++)
		{
		sumOfValues1+=normalizedValues[a];
		}

		int minfora=(int)(numberoftrainings/2);
		for(int a =minfora;a<numberoftrainings;a++)
		{
		sumOfValues2+=normalizedValues[a];
		}
		
		if(sumOfValues1+sumOfValues2 == 0) {
			return 0;
			}
		result = ((sumOfValues1-sumOfValues2)/(sumOfValues2+sumOfValues1))*100;
		int trimmedresulttimeshundred = (int)(result*100);
		float trimmedfloat = trimmedresulttimeshundred;
		result = trimmedfloat/100;

		return (float) result;
	}
	}	
///NOTE: the list made by sortallexercises is ordered per exercise from old to new, The data from one exercise 
///is one block. But the blocks of exercisedata are NOT ordered alphabeticly.
return (float)0;
*/
}


/**
 * returns getlatestweight(exercise->getExercise(exercisename).getIndex())
 */
int ConfigFileHandlerPowerTraining::getlatestweight(QString exercisename)
{
if(exercise->isAlreadyStored(exercisename)){
	int a = exercise->getExercise(exercisename)->getMeasurements().size()-1;
	if(a<0){
		return -1;
		}
	return exercise->getExercise(exercisename)->getMeasurements().at(a)->getNormalisedWeight();
	}
else{
	return -1;
	}


//QTextStream cout(stdout, QIODevice::WriteOnly);
//float ricco = -0.035714285; ///linear approach: I plotted '%change in weight' in function of '%change in repetitions'
// int nbOfPoints = exercise->getExercise(exercisename)->getMeasurements().size();
// if(nbOfPoints==0){return 0;}
//if(withsorting){sortallexercises();}
// int maxValue= getweights(false).size();
// for(int i=0;i<maxValue;i++) ///van voor naar achter, want data is van oud naar nieuw
// {
// if(getnames(false).at(i)==exercisename) {
// 				int index=i+nbOfPoints-1;
// 				float result = normalize(getrepetitions(false).at(index),getweights(false).at(index));
// 				int resultint= (int) (result+0.40);
// 				return resultint;
// 				}
// }
// return 0;
}

/**
* OBSOLETE!
 * This method normalizes the weight you used to the weight you would have used when you did the default number
 * of repetitions
 * @param repetitions 
 * @param weight 
 * @return 
 */
// float ConfigFileHandlerPowerTraining::normalize(int repetitions, int weight)
// {
// float ricco = NORMALIZE_FACTOR; ///linear approach: I plotted '%change in weight' in function of '%change in repetitions'
// float norm = getDefaultValueForRepetitions();
// float tussenresultaat=(repetitions-norm)*(ricco);
// float result = weight - (tussenresultaat*weight);
// return result;
// }



/**
*OBSOLETE
 * @param weightused weight you used
 * @param repsdone the number of reps you did
 * @param nbReps the number of reps you want to know the weight of
 */
// float ConfigFileHandlerPowerTraining::normalize(float weightused,float repsdone, int nbReps)
// {
// float ricco = NORMALIZE_FACTOR; ///linear approach: I plotted '%change in weight' in function of '%change in repetitions'
// float norm = nbReps;
// float tussenresultaat=(repsdone-norm)*(ricco);
// float result = weightused - (tussenresultaat*weightused);
// return result;
// }

/**
 * same as the other getlatestweight but accesed with indexes
 * @return normalised weight of most recent measurement of exercise with index index
 * If weight can not be found -1 is returned 
 */
int ConfigFileHandlerPowerTraining::getlatestweight(int index)
{
if(exercise->contains(index)){
	int a = exercise->getExercise(index)->getMeasurements().size()-1;
	if(a<0){
		return -1;
		}
	return exercise->getExercise(index)->getMeasurements().at(a)->getNormalisedWeight();
	}
else{
	return -1;
	}
}




// int ConfigFileHandlerPowerTraining::getday(QString date)
// {
// QStringList list = date.split(".");
// return list.at(0).toInt();
// }
// 
// int ConfigFileHandlerPowerTraining::getmonth(QString date)
// {
// QStringList list = date.split(".");
// return list.at(1).toInt();
// }
// 
// int ConfigFileHandlerPowerTraining::getyear(QString date)
// {
// QStringList list = date.split(".");
// return list.at(2).toInt();
// }

/**
 * returns the number of datapoints for <exercisename> in the configfile
 * @return integer number of datapoints
 */
// int ConfigFileHandlerPowerTraining::exercise->getExercise(i)->getMeasurements().size()(QString exercisename)
// {
// int temp = exercise->getindex(exercisename);
// addQMultiHash();
// if(hashesOfExercises->at(temp)->isEmpty()){return 0;}
// 
// return ((hashesOfExercises->at(temp)->size())/2);
// ///we append weight AND repetitions, they both count => #points = size/2
// }

/**
 * getvector returns a vector with the data in order
 * @return exerciseHandler->getExercise(exercisename)->getVector()
 */
QVector<QPointF> ConfigFileHandlerPowerTraining::getvector(QString exercisename)
{
return exercise->getExercise(exercisename)->getVector();

// QMultiHash<QString,int> *hash = hashesOfExercises->at(exercise->getindex(exercisename));
// int nb =  hash->size();
// nb=nb/2;
// return getvector(hash, nb);
}



/**
 * getvector returns a vector with the data in order
 * @return 
 */
// QVector<QPointF> ConfigFileHandlerPowerTraining::getvector(QString exercisename, int numberofpoints)
// {
// return getvector(hashesOfExercises->at(exercise->getindex(exercisename)), numberofpoints);
// }
 

/**
 * This method makes makes a vector with points in order
 * @param numberofpoints how many points need to be plotted?
 * @return QVector<QPointF>
 */
// QVector<QPointF> ConfigFileHandlerPowerTraining::getvector(QMultiHash<QString, int> *hash, int numberofpoints)
// {
// ///TODO reverse order of elements!
// 
// QVector<QPointF> data;
// int minday=360000;
// int previousmin=0;
// //int norm = getDefaultValueForRepetitions();
// QPointF pointf;
// for(int i=0; i<hash->size();i=i+2)///i+2 because we store weight AND repetitions
// {
// 	QHashIterator<QString, int> ic(*hash);
// 	minday=360000;
//  	while (ic.hasNext()) 
// 	{
// 		ic.next();ic.next();///we store weight AND repetitions
// 		QList<int> values = hash->values(ic.key());
// 		int day=getdaysfrom1jan2000(ic.key());
// 		
// 		if((minday>day) && day>previousmin)
// 		{
// 		float repetitions = values.at(0);
// 		float weight = values.at(1);
// 		minday=day;pointf.setX(day);pointf.setY(normalize(repetitions,weight));}
// 		///we used normalized values => to default repetitions
//  	}	
// 	previousmin=pointf.x();
// 	data.append(pointf); 	
// }
// ///now we cut some data at the beginning, so our vector has the right size.
// int howmanytoremove = data.size()-numberofpoints;
// if(howmanytoremove > 0) { data=cutnpoints(howmanytoremove,data);}
// /**
// *now we make the first date not the number of days till 2000 but just 0 for readabilety
// *Today becomes 0 and yesterday -1 ...
// */
// 	///today in number of days till 1jan2000
// 	int today = getdaysfrom1jan2000((StringDate(QDate::currentDate()).getQString())); 
//  	for(int a=0;a<data.size();a++)
//  	{
// 	const double newvalueforx=data.at(a).x()-today;
// 	const QPointF newpointf(newvalueforx, data.at(a).y());
//  	data.replace(a,newpointf);
//  	}
// 
// return data;
// }

/**
 * This method removes the first n points of the QVector...we don't need to display very old data
 * @param n integer: how many need to be removed
 * @param vector Startvector
 * @return new shorter vector
 */
// QVector<QPointF> ConfigFileHandlerPowerTraining::cutnpoints(int n, QVector<QPointF> vector)
// {
// if(n<vector.size()){
// for(int i=0; i<n;i++){vector.remove(0);}
// }
// return vector;
// }



/**
 * This method removes all data from the exercise stored in <hash> from
 * listdates, listnames,listrepetions, listweights
 * but it doesn't remove other exercises.This way you can update only the date from one exercice.
 * @param hash 
 */
// void ConfigFileHandlerPowerTraining::removeFromOrderedLists(QMultiHash<QString, int> hash)
// {
// 	QString name;
// 	for (int i=0; i<hashesOfExercises->size(); i++)
// 	{
// 		if(hash== *hashesOfExercises->at(i)){name=exercise->getName(i);}
// 	}
// 	QList<int> indexestoremove;
// 	for(int i=0;i<this->listnames->size();i++)
// 	{
// 	if(this->listnames->at(i)==name){
// 				indexestoremove.append(i);
// 				}
// 	}
// 	for(int i=indexestoremove.size()-1;i>=0;i--) ///MUST BE DONE FROM i=...->i=O not the other way
// 	{
// 		this->listdates->removeAt(indexestoremove.at(i));
// 		this->listweights->removeAt(indexestoremove.at(i));
// 		this->listrepetitions->removeAt(indexestoremove.at(i));
// 		this->listnames->removeAt(indexestoremove.at(i));
// 	}
// 	
// 	// 	if(this->listdates.size()!=this->listweights.size()){cout <<"niet gelijke size"<<endl;}
// // 	cout << "ConfigFileHandlerPowerTraining::size names" << listnames->size() <<endl;
// // 	cout << "ConfigFileHandlerPowerTraining::size dates" << listdates->size() <<endl;
// // 	cout << "ConfigFileHandlerPowerTraining::size weight" << listweights->size() <<endl;
// // 	cout << "ConfigFileHandlerPowerTraining::size rep" << listrepetitions->size() <<endl;
// 
// // 	this->listnames.clear();
// // 	this->listweights.clear();
// // 	this->listrepetitions.clear();
// // 	this->listdates.clear();
// }


/**
 * This method sorts all the data from the config file from old to new in 4 list
 * listdates, listnames,listrepetions, listweights (all in the same order)
 * @param hash 
 */
// void ConfigFileHandlerPowerTraining::sortdatainQLists(QMultiHash<QString, int> hash)
// {
// removeFromOrderedLists(hash);
// 	QString name;
// 	for (int i=0; i<hashesOfExercises->size(); i++)
// 	{
// 		if(hash==*hashesOfExercises->at(i)){name=exercise->getName(i);}
// 	}
// int minday=360000;
// int previousmin=0;
// // this->listdates.clear();
// // this->listweights.clear();
// // this->listrepetitions.clear();
// // this->listdates.clear();
// QString datetemp;
// int weightstemp;
// int repetitionstemp;
// for(int i=0; i<hash.size();i=i+2)///i+2 because we store weight AND repetitions
// {
// 	QHashIterator<QString, int> ic(hash);
// 	minday=360000;
//  	while (ic.hasNext())  ///we zoeken het minimum in de elementen niet kleiner dan het vorige minimum
// 	{
// 		ic.next();ic.next();///we store weight AND repetitions
// 		QList<int> values = hash.values(ic.key());
// 		int day=getdaysfrom1jan2000(ic.key());
// 		
// 		if((minday>day) && day>previousmin)
// 		{
// 		minday=day;
// 		datetemp = ic.key();
// 		weightstemp = values.at(1);
// 		repetitionstemp = values.at(0);
// 		}	
// 	}
// 	previousmin=minday;
// ///SORTED by DATE and then by EXERCISE
// // 	this->listdates->insert(i,datetemp);
// // 	this->listrepetitions->insert(i, repetitionstemp);
// // 	this->listweights->insert(i,weightstemp);
// // 	this->listnames->insert(i,name);
// ///SORTED by EXERCISE and then by DATE
// 	this->listdates->append(datetemp);
// 	this->listrepetitions->append(repetitionstemp);
// 	this->listweights->append(weightstemp);
// 	this->listnames->append(name);
// 
// 
// 	//cout <<"weightstemp: " <<weightstemp <<endl;
// 	//cout <<"minday: "<<minday<<" weight "<<weightstemp<<endl;
// }
// //cout << "size: " << this->listdates.size()<<endl;
// }


/**
 * Sort all the exercises by exercise and then by date using sortdatainQLists
 */
// void ConfigFileHandlerPowerTraining::sortallexercises()
// {
// for (int i=0; i<hashesOfExercises->size(); i++)
// 	{	
// 		sortdatainQLists(*hashesOfExercises->at(i));
// 	}
// }


/**
 * This method return all the dates of all the datapoints from old to most recent
 * @return Ordered list of dates by exercise and then by date
 */
// QList<QString> ConfigFileHandlerPowerTraining::()
// {
// sortallexercises();
// return *this->listdates;
// }

/**
 * This method return all the weights used of all the datapoints from old to most recent
 * @return Ordered list of dates by exercise and then bydate
 */
// QList<int> ConfigFileHandlerPowerTraining::getweights(bool withsorting)
// {
// if(withsorting){sortallexercises();}
// return *this->listweights;
// }

/**
*Returns a list with all the Planned Trainings ordered in ascending order!
*/
QList<Training*> ConfigFileHandlerPowerTraining::getTrainings(){
return this->trainingList->values();
}


/**
*Returns a list with all the Training Schedules
*/
QList<TrainingSchedule*> ConfigFileHandlerPowerTraining::getTrainingSchedules(){
return this->trainingScheduleList->values();
}

/**
*Returns the Training Schedule with the given name 
*If none exists it returns 0
*/
TrainingSchedule* ConfigFileHandlerPowerTraining::getTrainingSchedule(QString name){
for(int i=0;i<getTrainingSchedules().size();i++){
	if(getTrainingSchedules().at(i)->getName() == name){
		return getTrainingSchedules().at(i);
		}
	}
return 0;
}

/**
*Returns all schedule Occurrences with the given date
* date == "dd.MM.yyyy" as QString
*If the map contains no item with key=date, the function returns a default-constructed value.
*Use containsScheduleOccurrences(QString date) to check!
*/
QList<ScheduleOccurrence>* ConfigFileHandlerPowerTraining::getScheduleOccurrences(QString date){
return scheduleOccurrenceList->value(date);
}




/**
*Returns true if one or more scheduleOccurrences exist on the given date
*date== "dd.MM.yyyy" as QString
*/
bool ConfigFileHandlerPowerTraining::containsScheduleOccurrences(QString date){
return scheduleOccurrenceList->contains(date);
}

/**
*Returns all schedule Occurrences as a QMap (date="dd.MM.yyyy" as QString as key)
*/
QMap<QString, QList<ScheduleOccurrence>* > *ConfigFileHandlerPowerTraining::getScheduleOccurrenceList(){
return scheduleOccurrenceList;
}



/**
 * This method return all the repetitions of all the datapoints from old to most recent
 * @return Ordered list of repetitions by exercise and then by date
 */
// QList<int> ConfigFileHandlerPowerTraining::getrepetitions(bool withsorting)
// {
// if(withsorting){sortallexercises();}
// return *this->listrepetitions;
// }

/**
 * This method return all the names of all the datapoints from old to most recent
 * @return Ordered list of names by exercise and then by date
 */
// QList<QString> ConfigFileHandlerPowerTraining::getnames(bool withsorting)
// {
// if(withsorting){sortallexercises();}
// return *this->listnames;
// }
