/*File Name: Environment.cpp
  Author: Betti Österholz ; Date: 10.09.2003
  System: C++

  
  Copyright (C) 2004  Betti Österholz

  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, June 1991, 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 "Environment.h"
#include <time.h>                      // define time()
#include <limits.h>//datatype limits

void printTime()
//prints the actual time
{
time_t now =time(NULL);
tm z=*(localtime(&now));//to get the actual time and date
cout<<(z.tm_mday)<<"."<<(z.tm_mon+1)<<"."<<(z.tm_year+1900)<<"   ";
cout<<(z.tm_hour)<<":"<<(z.tm_min)<<":"<<(z.tm_sec%60);
}

void printLicens()
//prints the licens
{
cout<<endl<<"fib-GA, Copyright (C) 2004 Betti Österholz"<<endl;
cout<<"fib-GA comes with ABSOLUTELY NO WARRANTY;"<<endl;
cout<<"This is free software, and you are welcome"<<endl;
cout<<"to redistribute it under certain conditions"<<endl;
cout<<endl<<"You should have received a copy of the"<<endl;
cout<<"GNU General Public License along with this program;"<<endl;
cout<<"if not, write to the Free Software Foundation, Inc.,"<<endl;
cout<<"59 Temple Place, Suite 330, Boston, MA  02111-1307  US"<<endl<<endl;
}

Environment::Environment():GoodnessSum(0.0), BadnessSum(0.0), BestGoodness(0.0), LastId(0), rg(TRandomMersenne((long int)time(0))),printPrimitivDocu(0)
//standart constructor
//initializes the object with standard values
{
printLicens();
cout<<"start time : ";
printTime();
cout<<endl;
Original.load("standart.bmp");
unsigned long* tsize=Original.getSize();
MaxTimeNeed=tsize[0]*tsize[1]*tsize[2]*tsize[3]*30;
delete tsize;
WorstImmortal=0;
if ((ParameterV.getDocumentParameter(4))&&(ParameterV.getDocumentParameter(8)))
{
	ofstream *stream;
	stream=new ofstream(ParameterV.getNamesParameter(4),std::ios::app);//append the best object to best object file
	(*stream)<<endl<<"Pictur : ;" <<ParameterV.getNamesParameter(0)<<endl;
	(*stream)<<endl<<"LastIndiviual ;best Goodness ;average Goodness ;"<<endl<<"0";
	delete stream;
}
}

Environment::Environment(Parameter parm):ParameterV(parm), GoodnessSum(0.0), BadnessSum(0.0),
						BestGoodness(0.0), LastId(0), rg(TRandomMersenne((long int)time(0))),printPrimitivDocu(0)
//special constructor
//set the parameters to the values given by the parameter object
//pre: the parameter for the new Enviroment object
{
printLicens();
cout<<"start time : ";
printTime();
cout<<"load : \""<<(ParameterV.getNamesParameter(0))<<"\""<<((ParameterV.getNamesParameter(0))[0]!=' ')<<endl;
if ((ParameterV.getNamesParameter(0))[0]!=' ')
{
	Original.load(ParameterV.getNamesParameter(0));
}else{
	Original.load("standart.bmp");
}
unsigned long* tsize=Original.getSize();
MaxTimeNeed=tsize[0]*tsize[1]*tsize[2]*tsize[3]*30;
delete tsize;
WorstImmortal=0;
if (ParameterV.getOperationsParameter(0)>=ParameterV.getInitParameter(0))
{
	ParameterV.setInitParameter(0,(unsigned int)(ParameterV.getOperationsParameter(0))+1);
}
if ((ParameterV.getDocumentParameter(4))&&(ParameterV.getDocumentParameter(8)))
{
	ofstream *stream;
	stream=new ofstream(ParameterV.getNamesParameter(4),std::ios::app);//append the best object to best object file
	(*stream)<<endl<<"Pictur : ;" <<ParameterV.getNamesParameter(0)<<endl;
	(*stream)<<endl<<"LastIndiviual ;best Goodness ;average Goodness ;"<<endl<<"0";
	delete stream;
}
}

Environment::~Environment()
//standard destructor
{
printLicens();
cout<<"end time :";
printTime();
cout<<endl<<"Best Individual : "<<BestGoodness<<endl;
while (!IndividualList.empty())//delete all Individuals
{
	delete (*IndividualList.end());//delete last Individual
	IndividualList.erase(IndividualList.end());//delet last Individual pointer from the IndividualList
}
}

void Environment::start()
//the method to start the genetic algorithm
{
init();
while (!reachTerminalCondition())
{
	makeNewIndividual();
	eraseIndividual();
}
}

void Environment::init()
//this method initialisizes the Individuals
{
//random point init
for (unsigned long i=0;i<(ParameterV.getInitParameter(1));i++)
{//make a new random point and insert it as an individal into the IndividualList
	Color col=Color(Original.getNumberOfColorComponents());
	for (unsigned int a=1;a<=Original.getNumberOfColorComponents();a++)
		//set the color vector components to random values
		//the color components determine the color
		{col.setValueToValue(a,(int)(getRandom(Original.getDepthOfComponent(a))));}
	Position pos=Position(Original.getNumberOfPositionComponents());
	for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
		//set the position vector components to random values
		//the position components determine the position in the picture
		{pos.setValueToValue(a,(int)(getRandom((Original.getSize()[a-1]))));}
	PicturObject* obj=new Point(pos,col);
	insertObject(obj);
}
//init with point objects of the orginal picture
for (unsigned long i=0;i<(ParameterV.getInitParameter(2));i++)
{
	Position pos=Position(Original.getNumberOfPositionComponents());
	unsigned long posn[4]={0,0,0,0};
	for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
	{
		//set the position vector components to random values
		//the position components determine the position in the picture
		posn[a-1]=(unsigned long)(getRandom((Original.getSize()[a-1])));
		pos.setValueToValue(a,(int)posn[a-1]);
	}
	//get the color of the original picture at this position
	Color *col=Original.getColorFrom(posn);
	PicturObject* obj=new Point(pos,*col);
	insertObject(obj);
}
//init correct PicturObjects, the positions of the points in the conc objects are random generated
for (unsigned long i=0;i<(ParameterV.getInitParameter(3));i++)
{
	unsigned long posn[4]={0,0,0,0};
	unsigned long* sz;
	sz=Original.getSize();
	Position pos=Position(Original.getNumberOfPositionComponents());
	Color *col;
	col=Original.getColorFrom(posn);
	PicturObject* gobj=new Point(pos,*col);//create one object that will be the first point of the whole picture
	PicturObject* obj;
	for (posn[0]=0;posn[0]<sz[0];posn[0]++){
	for (posn[1]=0;posn[1]<sz[1];posn[1]++){
	for (posn[2]=0;posn[2]<sz[2];posn[2]++){
	for (posn[3]=0;posn[3]<sz[3];posn[3]++){
		for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
		{
			pos.setValueToValue(a,(int)posn[a-1]);
		}
		col=Original.getColorFrom(posn);
		obj=new Point(pos,*col);
		//insert the point in the copy of the Picturobject
		if (!(gobj->insertObjectInObject(((unsigned int)(getRandom(gobj->getNumberOfObjects()))), obj, (((int)(getRandom(2)))==1))))
			{gobj=new Conc(gobj,obj);}

	}}}}
	insertObject(gobj);
	delete sz;
}
//load objects from a file
if (ParameterV.getInitParameter(4))//if objects should be loaded
	{load(ParameterV.getNamesParameter(3),ParameterV.getInitParameter(4));}//load them
//init correct PicturObjects, the positions of the points in the conc objects are random generated
for (unsigned long i=0;i<(ParameterV.getInitParameter(5));i++)
{
	unsigned long posn[4]={0,0,0,0};
	unsigned long* sz;
	sz=Original.getSize();
	Position pos=Position(Original.getNumberOfPositionComponents());
	Color *col;
	col=Original.getColorFrom(posn);
	PicturObject* gobj=new Point(pos,*col);//create one object that will be the first point of the whole picture
	PicturObject* obj;
	for (posn[0]=0;posn[0]<sz[0];posn[0]++){
	for (posn[1]=0;posn[1]<sz[1];posn[1]++){
	for (posn[2]=0;posn[2]<sz[2];posn[2]++){
	for (posn[3]=0;posn[3]<sz[3];posn[3]++){
		for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
		{
			pos.setValueToValue(a,(int)posn[a-1]);
		}
		col=Original.getColorFrom(posn);
		obj=new Point(pos,*col);
		//insert the point in the copy of the Picturobject
		if (((int)(getRandom(2)))==1)
			{gobj=new Conc(gobj,obj);}
		else{gobj=new Conc(obj,gobj);}

	}}}}
	insertObject(gobj);
	delete sz;
}


//free for more

}

bool Environment::reachTerminalCondition() const
//returns if the terminal condition is reached
//post: true if the terminal condition is reached
{
bool b=false;
b=b||(LastId>=ParameterV.getTerminalConditionParameter(0));
b=b||(BestGoodness>=ParameterV.getTerminalConditionParameter(1));

//free for more

return b;
}

void Environment::load(const char* file,const unsigned int num)
//load n PicturObjects from the file <file> into this object
//if no n objects exists in the file, load as much as exists
{
//open file
FILE *in;
if ((in= fopen( file, "r" ))!=NULL)
{
	stringstream *strstr;
	char c;
	bool b=true;
	unsigned int brk;
	Point socket;
	//read objects
	for (unsigned int i=1;i<=num;i++)
	{
		//get first symbols
		strstr=new stringstream;
		c=' ';
		b=true;
		while (b)
		{
			c = (char)(fgetc( in));
			if ((c=='p')||(c=='c')||(c=='f')){b=false;}
			if (feof(in)){b=false;}
		}
		(*strstr)<<c;
		//read til '('
		while (c!='(')
		{
			c = (char)(fgetc( in));
			(*strstr)<<c;
			if (feof(in)){break;}
		}
		brk=1;//for the first braket read
		//read till all brakets are closed
		while (brk)
		{
			c = (char)(fgetc(in));
			(*strstr)<<c;
			if (c=='('){brk++;}
			if (c==')'){brk--;}
			if (feof(in)){break;}
		}
		if (feof(in)){delete strstr;break;}
		else{
			PicturObject* obj=socket.restoreElementTyp(*strstr);
			list<double*> varl;
			obj->restore(*strstr,varl);
			if (obj) {insertObject(obj);}
		}
		delete strstr;
	}
	fclose(in);
}
}

void Environment::makeNewIndividual()
//generates a new Individual with the genetic operations and puts it to
//the Individuals in the IndividualList
{
double rand=getRandom(1);//generates random value between 0 and 1
Individual* idv=selectIndividual();
if (idv)
{
	PicturObject* sobj=(idv->getObject())->copy();
	PicturObject* obj=0;

	while (rand>0){
		if ((rand<=ParameterV.getOperationsParameter(10))){
			//if rand is lower or equal than the probability of this operation, select this operation
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation0"<<endl<<flush;}
			//the "if (ParameterV.getDocumentParameter(i)){...}" are just for documentation/debugging
			obj=Operation0(sobj);}
		rand-=ParameterV.getOperationsParameter(10);
			//p1<rand<=(p2+p1)  equals ->  0<rand-p1<=p2
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(11)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation1"<<endl<<flush;}
			obj=Operation1(sobj);}
		rand-=ParameterV.getOperationsParameter(11);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(12)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation2"<<endl<<flush;}
			obj=Operation2(sobj);}
		rand-=ParameterV.getOperationsParameter(12);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(13)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation3"<<endl<<flush;}
			obj=Operation3(sobj);}
		rand-=ParameterV.getOperationsParameter(13);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(14)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation4"<<endl<<flush;}
			obj=Operation4(sobj);}
		rand-=ParameterV.getOperationsParameter(14);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(15)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation5"<<endl<<flush;}
			obj=Operation5(sobj);}
		rand-=ParameterV.getOperationsParameter(15);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(16)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation6"<<endl<<flush;}
			obj=Operation6(sobj);}
		rand-=ParameterV.getOperationsParameter(16);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(17)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation7"<<endl<<flush;}
			obj=Operation7(sobj);}
		rand-=ParameterV.getOperationsParameter(17);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(18)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation8"<<endl<<flush;}
			obj=Operation8(sobj);}
		rand-=ParameterV.getOperationsParameter(18);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(19)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation9"<<endl<<flush;}
			obj=Operation9(sobj);}
		rand-=ParameterV.getOperationsParameter(19);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(20)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation10"<<endl<<flush;}
			obj=Operation10(sobj);}
		rand-=ParameterV.getOperationsParameter(20);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(21)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation11"<<endl<<flush;}
			obj=Operation11(sobj);}
		rand-=ParameterV.getOperationsParameter(21);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(22)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation12"<<endl<<flush;}
			obj=Operation12(sobj);}
		rand-=ParameterV.getOperationsParameter(22);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(23)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation13"<<endl<<flush;}
			obj=Operation13(sobj);}
		rand-=ParameterV.getOperationsParameter(23);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(24)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation14"<<endl<<flush;}
			obj=Operation14(sobj);}
		rand-=ParameterV.getOperationsParameter(24);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(25)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation15"<<endl<<flush;}
			obj=Operation15(sobj);}
		rand-=ParameterV.getOperationsParameter(25);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(26)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation16"<<endl<<flush;}
			obj=Operation16(sobj);}
		rand-=ParameterV.getOperationsParameter(26);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(27)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation17"<<endl<<flush;}
			obj=Operation17(sobj);}
		rand-=ParameterV.getOperationsParameter(27);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(28)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation18"<<endl<<flush;}
			obj=Operation18(sobj);}
		rand-=ParameterV.getOperationsParameter(28);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(29)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation19"<<endl<<flush;}
			obj=Operation19(sobj);}
		rand-=ParameterV.getOperationsParameter(29);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(30)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation20"<<endl<<flush;}
			obj=Operation20(sobj);}
		rand-=ParameterV.getOperationsParameter(30);
		if (rand<=0){break;}
		if (rand<=ParameterV.getOperationsParameter(31)){
			if (ParameterV.getDocumentParameter(1)) {cout<<"Operation21"<<endl<<flush;}
			obj=Operation21(sobj);}
		rand-=ParameterV.getOperationsParameter(31);

		//and so on
	}


	if (obj){insertObject(obj);}
}
//last operation = 19
}

void Environment::eraseIndividual()
//erase Individuals from the IndividualList until it has the right size
{
if (ParameterV.getDocumentParameter(2)) {
	cout<<"erase individual  best good : "<<BestGoodness<<" noi: "<<getNumberOfIndividuals()<<" >? "<<ParameterV.getInitParameter(0)<<endl<<flush;
}
while ((getNumberOfIndividuals())>(ParameterV.getInitParameter(0)))
{
	//select randomly an Individual
	double rand=getRandom(BadnessSum);
	if (!IndividualList.empty())//if the IndividualList is not empty
	{
		list<Individual*>::iterator i;
		for (i=IndividualList.begin();i!=IndividualList.end();i++)
		{
			rand=rand-1/((*i)->getGoodness());
			if (rand<=0) {break;}
		}
		//erase Individual if it is not immortal
		if (!((*i)->getImmortal()))//if the Individual is not Immortal
		{
			GoodnessSum=GoodnessSum-((*i)->getGoodness());
			BadnessSum=BadnessSum-1/((*i)->getGoodness());
			if (ParameterV.getDocumentParameter(2)) {
				stringstream strstr;
				unsigned int i1=0;
				((*i)->getObject())->store(i1,strstr);
				cout<<" idv : "<<strstr.str()<<endl<<flush;
				cout<<" idv ident : "<<((*i)->getIdentifier())<<endl<<flush;
			}
			delete (*i);//delete Individual
			IndividualList.erase(i);//delete Individual pointer from the IndividualList
		}
	}
}

//free for more

}

bool Environment::insertIndividual(Individual* idv)
//insert a Individual to the IndividualList, if it is not equal(Value)
//to an Individual in the IndividualList
{
if (ParameterV.getDocumentParameter(0))
{
	cout<<"insertIndividual  "<<(idv->getIdentifier())<<" good: "<<(idv->getGoodness())<<flush;
	stringstream strstr;
	unsigned int i1=0;
	(idv->getObject())->store(i1,strstr);
	cout<<" idv : "<<strstr.str()<<endl<<flush;
}
if (ParameterV.getDocumentParameter(4)) {
	printPrimitivDocu++;
	if (printPrimitivDocu>=ParameterV.getInitParameter(20))
	{
		printPrimitivDocu=0;
		if (ParameterV.getDocumentParameter(8)) {
			ofstream *stream;
			stream=new ofstream(ParameterV.getNamesParameter(4),std::ios::app);//append the best object to best object file
			(*stream)<<";"<<BestGoodness<<";"<<(GoodnessSum/(IndividualList.size()))<<";"<<endl<<LastId;
			delete stream;
		}
		if (ParameterV.getDocumentParameter(7)) {
			cout<<"best goodness : "<<BestGoodness<<" average goodness : "<<(GoodnessSum/(IndividualList.size()))<<endl;
		}
		cout<<"last individual : "<<LastId<<endl;
	}
}
bool b=false;
if (!IndividualList.empty())//if the IndividualList is not empty
{
	for (list<Individual*>::iterator i=IndividualList.begin();i!=IndividualList.end();i++)
	{
		b=b||((*i)->getObject())->equalValue(idv->getObject());
		if (b) {break;}
	}
}
if (!b)
{//insert if there exists no equal Individual
	IndividualList.insert(IndividualList.end(),idv);
	GoodnessSum=GoodnessSum+(idv->getGoodness());
	BadnessSum=BadnessSum+1/(idv->getGoodness());
	if ((idv->getGoodness())>BestGoodness)//if the best Individual is changed
	{
		BestGoodness=(idv->getGoodness());
		//store the picture
		PicturMatrix tmpm=PicturMatrix(Original,false);
		if (((idv->getObject())->getTimeNeed(MaxTimeNeed))<=MaxTimeNeed)
		{
			(idv->getObject())->makeMatrix(&tmpm);
			tmpm.store(ParameterV.getNamesParameter(1));
		}
		//store the fib individual with his data
		stringstream tstrstr;
		unsigned int i=0;
		(idv->getObject())->store(i,tstrstr);
		ofstream *stream;
		if (ParameterV.getDocumentParameter(6))
			{stream=new ofstream(ParameterV.getNamesParameter(2),std::ios::app);}//append the best object to best object file
		else	{stream=new ofstream(ParameterV.getNamesParameter(2),std::ios::out);}//overwrite best object fiile
		(*stream)<<tstrstr.str()<<";goodness : "<<(idv->getGoodness())<<" distance to original : "<<(Original.distanceTo(tmpm));
		(*stream)<<" time need : "<<((idv->getObject())->getTimeNeed(MaxTimeNeed))<<" greatness : "<<((idv->getObject())->getGreatness())<<" idv : "<<(idv->getIdentifier())<<endl<<flush;
		delete stream;
	}
	if ((ParameterV.getOperationsParameter(0))>=1)//if there should be immortal individauals
	{
	if ((idv->getGoodness())>WorstImmortal)
		//if the worst immortal goodness is not as good as the goodnes of the
		//inserted object, delete the worst one from the ImmortalList and
		//insert the inserted object into the ImmortalList
	{
		idv->setImmortal(true);
		if (ImmortalList.empty())//if the ImmortalList is empty
		{
			ImmortalList.insert(ImmortalList.end(),idv);//just insert the Individual pointer
		}else{
			std::list<Individual*>::iterator itr;
			for (itr=ImmortalList.begin();itr!=ImmortalList.end();itr++)
			{
				if((idv->getGoodness())<=((*itr)->getGoodness()))
				{//insert the Individual on the position, so that the goodness
				//of the Immortal Individauals are in the correct order
					ImmortalList.insert(itr,idv);
					break;
				}
			}
			if(itr==ImmortalList.end())
				{ImmortalList.insert(itr,idv);}//if the Individual was the best
			while ((ImmortalList.size())>(ParameterV.getOperationsParameter(0)))
			{
				(*(ImmortalList.begin()))->setImmortal(false);
				ImmortalList.erase(ImmortalList.begin());
			}//try to restrict the ImmortalGoodness list to the right size
		}
		WorstImmortal=(*(ImmortalList.begin()))->getGoodness();
	}
	}
}

//free for more


return !b;
}

bool Environment::insertObject(PicturObject* obj)
//insert an Individual in the IndividualList, if no equal (Value)
//Individual is in the IndividualList
//the new Individual is created from the given object obj
//if the created Individual could not be inserted, the given object is destroyed
//pre: the PicturObject obj to create the new Inividual from
//post: a new Individual with the given object in the individual list
//  if no equal individual already exists in it
{
LastId++;
Individual* idv=new Individual(obj,getGoodness(obj),LastId);
if (!insertIndividual(idv))
{
	LastId--;
	delete idv;
	return false;
}
return true;
}

double Environment::getRandom(long double max) const
//to get a random number from 0 to max, there are (ULONG_MAX) random numbers
//pre: the maximum for the random number
//post: a random number from 0 to max
{
return (((const_cast<TRandomMersenne*>(&rg))->BRandom())*max/(ULONG_MAX));//random generator
}

double Environment::getGoodness(PicturObject* obj)
//returns the Goodness of the given PicturObject to the orginal PicturMatrix
//post: a double value for the Goodness of the given PicturObject to the
//  orginal PicturMatrix
{
if (ParameterV.getDocumentParameter(5))
{
	stringstream strstr;
	unsigned int i1=0;
	obj->store(i1,strstr);
	cout<<"goodness of : "<<strstr.str()<<endl<<flush;
}
unsigned long ttime=(obj->getTimeNeed(MaxTimeNeed));
if (ttime<=MaxTimeNeed)//if it is not too time-consuming
{
	PicturMatrix tmpm=PicturMatrix(Original,false);
	obj->makeMatrix(&tmpm);
	unsigned long tdist=Original.distanceTo(tmpm);
	if (ParameterV.getDocumentParameter(5))
	{
		cout<<" dist : "<<tdist<<" time need : "<<ttime<<" greatness : "<<(obj->getGreatness())<<endl<<flush;
	}
	if (ParameterV.getDocumentParameter(3))
	{
		cout<<endl<<"Distance : "<<tdist<<endl<<flush;
	}
	return (1000000.0/((ParameterV.getTerminalConditionParameter(11))*tdist
		+(ParameterV.getTerminalConditionParameter(12))*(obj->getGreatness())
		+(ParameterV.getTerminalConditionParameter(13))*ttime));
}//else
return (0.0000000001);//don't evaluate the matrix if it takes too long

//free for more

}

bool Environment::setParameter(Parameter parm)
//set the parameters to the given parameters parm
//pre: the parameters to set the variable ParameterV of this object to
//post: true if the parameters are set, else false
{
ParameterV=parm;
return true;
}

Parameter Environment::getParameter() const
//retuns the parameters of this object
//post: the parameters of this object
{return ParameterV;}

unsigned long Environment::getNumberOfIndividuals() const
//returns the number of Individuals in the IndividualList
//post: the number of Individuals in the IndividualList
{return IndividualList.size();}

Individual* Environment::selectIndividual()
//select an Individual from the IndividualList
//post: an Individual from the IndividualList
{
if (!IndividualList.empty())//if the IndividualList is not empty
{
	double rand=getRandom(GoodnessSum);
	list<Individual*>::iterator i;
	list<Individual*>* tmvl=const_cast<list<Individual*>* >(&IndividualList);
	for (i=tmvl->begin();i!=tmvl->end();i++)
	{
		rand=rand-((*i)->getGoodness());
		if (rand<=0) {return (*i);}
	}
	return (*i);
}
return 0;

//free for more

}



PicturObject* Environment::Operation0(PicturObject* obj1)
//insert a new random Point on a random position in a selected
//PicturObject that overlaps the selected object
{
//create a random point
Color col=Color(Original.getNumberOfColorComponents());
for (unsigned int a=1;a<=Original.getNumberOfColorComponents();a++)
{
	col.setValueToValue(a,(int)(getRandom(Original.getDepthOfComponent(a))));
}
Position pos=Position(Original.getNumberOfPositionComponents());
for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
{
	pos.setValueToValue(a,(int)(getRandom((Original.getSize())[a-1])));
}
PicturObject* obj=new Point(pos,col);
//insert the random point in the copy of the PicturObject of the selcted Individual
//select the place to insert
unsigned int wher=(unsigned int)(getRandom(obj1->getNumberOfObjects()+1));
if (!(obj1->insertObjectInObject(wher,obj,true)))
	{obj1=new Conc(obj,obj1);}
return obj1;
}


PicturObject* Environment::Operation1(PicturObject* obj1)
//insert a new random Point on a random position in a selected
//PicturObject that is overlaped by the selected object
{
//creat a random point
Color col=Color(Original.getNumberOfColorComponents());
for (unsigned int a=1;a<=Original.getNumberOfColorComponents();a++)
{
	col.setValueToValue(a,(int)(getRandom(Original.getDepthOfComponent(a))));
}
Position pos=Position(Original.getNumberOfPositionComponents());
for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
{
	pos.setValueToValue(a,(int)(getRandom((Original.getSize())[a-1])));
}
PicturObject* obj=new Point(pos,col);
//insert the random point in the copy of the PicturObject of the selcted Individual
//select the place to insert
unsigned int wher=(unsigned int)(getRandom(obj1->getNumberOfObjects()+1));
if (!(obj1->insertObjectInObject(wher,obj,false)))
	{obj1=new Conc(obj1,obj);}
return obj1;
}


PicturObject* Environment::selectPartObject(PicturObject* obj)
//select a part-object from the given PicturObject obj
//pre: a PicturObject to select a part-object from
//post: the copy of the selected a part-object from the given PicturObject obj
{
PicturObject* tmpo;
double pgood[obj->getNumberOfObjectPoints()+1];//goodness of the part-objects
long double goods=0;//goodness sum of the part-objects
double tgood; //temporary goodness
//evaluate part-goodnesses
tgood=getGoodness(obj);//whole object
pgood[0]=tgood;
goods=goods+tgood;
for (unsigned int i=1;i<=(obj->getNumberOfObjectPoints());i++)
{
	tmpo=obj->copy(i);
	if (tmpo)
	{
		tgood=getGoodness(tmpo);
		tmpo->deleteObject();
		delete tmpo;
		pgood[i]=tgood;
		goods=goods+tgood;
	}
}
//select PicturObject
long double rnd=getRandom(goods);
for (unsigned int i=0;i<=(obj->getNumberOfObjectPoints());i++)
{
	if (rnd<=pgood[i])
	{
		if (i) {return obj->copy(i);}//return part-object
			{return obj->copy();}//return whole object
	}
	rnd=rnd-pgood[i];
}
return 0;
}


PicturObject* Environment::Operation2(PicturObject* obj2)
//insert a random part-object of a selected PicturObject on a random
//position in another selected PicturObject that overlaps the selected part-object
{
Individual* idv2=selectIndividual();
if (idv2)
{
	//get random part-object
	PicturObject* obj1=selectPartObject(idv2->getObject());
	if (obj1)
	{
		stringstream strstr1;
		unsigned int i1=0;
		obj1->store(i1,strstr1);
		//insert the random part-object into the copy of the PicturObject of the selected Individual
		//select the place to insert
		unsigned int wher=(unsigned int)(getRandom(obj2->getNumberOfObjects()+1));
		if (!(obj2->insertObjectInObject(wher,obj1,true)))
			{obj2=new Conc(obj1,obj2);}
		return obj2;
	}
}
obj2->deleteObject();
delete obj2;
return 0;
}

PicturObject* Environment::Operation3(PicturObject* obj2)
//insert a random part-object of a selected PicturObject on a random
//position in another selected PicturObject that does not overlap the selected part-object
{
Individual* idv2=selectIndividual();
if (idv2)
{
	//get random part-object
	PicturObject* obj1=selectPartObject(idv2->getObject());
	if (obj1)
	{
		//insert the random part-object in the copy of the PicturObject of the selcted Individual
		//select the place to insert
		unsigned int wher=(unsigned int)(getRandom(obj2->getNumberOfObjects()+1));
		if (!(obj2->insertObjectInObject(wher,obj1,false)))
			{obj2=new Conc(obj2,obj1);}
		return obj2;
	}
}
obj2->deleteObject();
delete obj2;
return 0;
}

PicturObject* Environment::Operation4(PicturObject* obj)
//delete a part-object of the copy of a selected individual
{
list<Vector*> tlist;
Function Socket=Function(obj,tlist);//needed if the first element in obj is a conc
Socket.removeObject((unsigned int)(getRandom(obj->getNumberOfObjectPoints()+1)));
//to do: better choose a good (good to remove=bad goodness) one

obj=Socket.getNext();
return obj;
}

PicturObject* Environment::Operation5(PicturObject* obj)
//change a value of the copy of a selected Individual
{
unsigned int wich=(unsigned int)(getRandom(obj->getNumberOfValue()+1));
int dist=(unsigned int)(getRandom(40))-20;
obj->changeValueAbout(wich,dist);
return obj;
}

PicturObject* Environment::Operation6(PicturObject* obj)
//change a variable of the copy of a selected Individual
{
unsigned int wich=(unsigned int)(getRandom((obj->getNumberOfVariable())+1));//wich variable to change
list<double*> varl=obj->getAllDefinedVariableOverVariable(wich);
if (varl.empty())//if no variables above the object are defined
{
	obj->deleteObject();
	delete obj;
	return 0;
}
list<double*>::iterator i=varl.begin();
unsigned int select=(unsigned int)getRandom(varl.size()+1);
for (unsigned int a=0;a<select;a++){i++;}
if (i==varl.end()){i=varl.begin();}//to be sure i is a variable
obj->setVariableToVariable(wich,(*i));
return obj;
}

PicturObject* Environment::Operation7(PicturObject* obj)
//insert a variable, at a position where a value stands, that is defined
//above the object, in which the Vector, where the variable is inserted, is contained
{
unsigned int wich=(unsigned int)(getRandom(obj->getNumberOfValue()+1));//which value to change
list<double*> varl=obj->getAllDefinedVariableOverValue(wich);
if (varl.empty())//if no variables are defined above the object
{
	obj->deleteObject();
	delete obj;
	return 0;
}
list<double*>::iterator i=varl.begin();
unsigned int select=(unsigned int)getRandom(varl.size()+1);
for (unsigned int a=0;a<select;a++){i++;}
if (i==varl.end()){i=varl.begin();}//to be sure i is a variable
obj->setValueToVariable(wich,(*i));
return obj;
}

PicturObject* Environment::Operation8(PicturObject* obj)
//insert a new value on a position where a variable stands, that is generated
//randomly
{
unsigned int wich=(unsigned int)(getRandom(obj->getNumberOfVariable()+1));//which variable to change
obj->setVariableToValue(wich,(int)getRandom(50));
return obj;
}

PicturObject* Environment::Operation9(PicturObject* obj)
//insert a new Function element on the root position and insert the
//variable, that the new Function element defines, at a random position
{
unsigned int wich=(unsigned int)(getRandom(obj->getNumberOfValue()+1));//which value to change
int val=obj->getValue(wich);
//generate UnderFunction list
UnderFunction *fkt=new UnderFunction();
if (getRandom(2)<1.0)//choose randomly one of two possibilities
{
	fkt->setValueToValue(1,val);
	fkt->setValueToValue(2,1);
	fkt->setValueToValue(3,(int)(getRandom(5)-2));
}else{
	fkt->setValueToValue(1,1);
	fkt->setValueToValue(2,val);
	fkt->setValueToValue(3,1);
}
list<Vector*> vl;
vl.insert(vl.end(),fkt);
//generate Function object
obj=new Function(obj,vl);
//insert the defined variable of the new Function object
double* var=obj->getDefinedVariableFrom(obj->getNumberOfMovePoints());
	//get the defined variable of the new Function object
if (var){obj->setValueToVariable(wich,var);}
else{
	obj->deleteObject();
	delete obj;
	return 0;
}
return obj;
}

PicturObject* Environment::Operation10(PicturObject* obj)
//insert a new Area element at the root position and insert the
//variable, that the new Area element defines, at a random position
{
unsigned int wich=(unsigned int)(getRandom(obj->getNumberOfValue()+1));//which value to change
int val=obj->getValue(wich);
//generate UnderArea list
UnderArea *area=new UnderArea();
if (getRandom(2)<1.0)//choose randomly one of two possibilities
{
	area->setValueToValue(1,val);
	area->setValueToValue(2,val);
}else{
	area->setValueToValue(1,val-(int)getRandom(5));
	area->setValueToValue(2,val+(int)getRandom(5));
}
list<Vector*> vl;
vl.insert(vl.begin(),area);
//generate Area object
obj=new Area(obj,vl);
//insert the defined variable of the new Area object
double* var=obj->getDefinedVariableFrom(obj->getNumberOfMovePoints());
//get the defined variable of the new Area object
if (var){obj->setValueToVariable(wich,var);}
else{
	obj->deleteObject();
	delete obj;
	return 0;
}
return obj;
}


PicturObject* Environment::Operation11(PicturObject* obj)
//deletes from 10 Area or Function elements at a random position the
//elements that can be deleted (the variable they define are not required below anymore)
{
list<Vector*> tlist;
Function Socket=Function(obj,tlist);//else you can not remove the first object
for (int i=0;i<10;i++)
{
	Socket.removeElement((unsigned int)(getRandom(Socket.getNumberOfMovePoints())));
		//delete a random move-point
}
return Socket.getNext();
}


PicturObject* Environment::Operation12(PicturObject* obj)
//insert a Function vector in a Function vector list of a randomly chosen Function element
{
//generate new UnderFunction
UnderFunction *fkt=new UnderFunction();
fkt->setValueToValue(1,(int)(getRandom(21)-10));
fkt->setValueToValue(2,(int)getRandom(10));
fkt->setValueToValue(3,(int)(getRandom(5)-2));
if (obj->insertFunctionVector((unsigned int)getRandom(obj->getNumberOfFunctions()+1),fkt))
	{return obj;}
else{delete fkt;}
obj->deleteObject();
delete obj;
return 0;
}

PicturObject* Environment::Operation13(PicturObject* obj)
//insert an Area vector in an Area vector list of a randomly chosen Area element
{
//generate new UnderArea
UnderArea *area=new UnderArea();
int middle=(int)getRandom(100);
area->setValueToValue(1,middle-(int)getRandom(5));
area->setValueToValue(2,middle+(int)getRandom(5));
if (obj->insertAreaVector((unsigned int)getRandom(obj->getNumberOfArea()+1),area))
	{return obj;}
else{delete area;}
obj->deleteObject();
delete obj;
return 0;
}

PicturObject* Environment::Operation14(PicturObject* obj)
//remove a randomly chosen list vector
{
obj->removeListVector((unsigned int)getRandom(obj->getNumberOfListVectors()+1));
return obj;
}

PicturObject* Environment::Operation15(PicturObject* obj)
//move a randomly chosen element of a randomly chosen Individual a random number of steps
{
list<Vector*> tlist;
Function Socket=Function(obj,tlist);//else it is not possible to move the first object
Socket.moveElement(((unsigned int)getRandom(obj->getNumberOfMovePoints()+1)),((int)getRandom(30)-10));
return Socket.getNext();
}

PicturObject* Environment::Operation16(PicturObject* obj)
//flip the objects of a randomly chosen Conc object
{
obj->flipObjects((unsigned int)getRandom(obj->getNumberOfConc()+1));
return obj;
}

PicturObject* Environment::Operation17(PicturObject* obj1)
//insert a random Point from the original into a selected PicturObject
//that overlaps the selected object
{
//get a random point from the original
Position pos=Position(Original.getNumberOfPositionComponents());
unsigned long posn[4]={0,0,0,0};
for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
{
	posn[a-1]=(unsigned long)(getRandom((Original.getSize()[a-1])));
	pos.setValueToValue(a,(int)posn[a-1]);
}
Color *col=Original.getColorFrom(posn);
PicturObject* obj=new Point(pos,*col);
//insert the random point into the copy of the Picturobject of the selected Individual
//select the place to insert
unsigned int wher=(unsigned int)(getRandom(obj1->getNumberOfObjects()+1));
if (!(obj1->insertObjectInObject(wher,obj,true)))
	{obj1=new Conc(obj,obj1);}
return obj1;
}

PicturObject* Environment::Operation18(PicturObject* obj1)
//insert a random Point from the original picture in a selected
//PicturObject that does not overlap the selected object
{
//get a random point from original
Position pos=Position(Original.getNumberOfPositionComponents());
unsigned long posn[4]={0,0,0,0};
for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
{
	posn[a-1]=(unsigned long)(getRandom((Original.getSize()[a-1])));
	pos.setValueToValue(a,(int)posn[a-1]);
}
Color *col=Original.getColorFrom(posn);
PicturObject* obj=new Point(pos,*col);
//insert the random point into the copy of the Picturobject of the selected Individual
//select the place to insert
unsigned int wher=(unsigned int)(getRandom(obj1->getNumberOfObjects()+1));
if (!(obj1->insertObjectInObject(wher,obj,false)))
	{obj1=new Conc(obj1,obj);}
return obj1;
}


PicturObject* Environment::Operation19(PicturObject* obj)
//deletes a random ListObject which may not be needed
//replaces the defined variable of this object with the value that is
//defined by the Listobject
//if the chosen ListObject has just values in its list vectors and the
//values stand for one (Area) evaluted value defined by the function of the
//ListObject, the list vector element is deleted and the variable it defines, is
//replaced by the value
//try deleting 10 chosen ListObjects, until one is deleted
{
unsigned int wich;//which element to delete
bool delet=false;
PicturObject* lobj;
list<Vector*> tlist;
Function Socket1=Function(obj,tlist);
double sum=0.0;
for (int i=0;i<10;i++)
{
	wich=(unsigned int)getRandom(Socket1.getNumberOfMovePoints());
	lobj=Socket1.getObjectFrom(Socket1.movePointToObjectPoint(wich));
	if (lobj)
	{
		list<Vector*>* tmvl=((ListObject*)lobj)->getVectorList();
		if (tmvl->empty())
		{
			delet=true;
			break;
		}
		bool allv=true;
		if(lobj->classnameOf()=="Function")
		{
			for (std::list<Vector*>::iterator i=tmvl->begin();i!=tmvl->end();i++)
			{//tests if all vectors have just values inside
				allv=allv&&(((*i)->getNumberOfValue())==3);
			}
			if (allv)//if all vectors contain only values
			{//evaluate the value of this Function object
				double *a,*b,*c;
				for (std::list<Vector*>::iterator i=tmvl->begin();i!=tmvl->end();i++)
				{
					//evaluate the defined variable for area elements below this object
					a=((*i)->getComponentPointer(1));
					b=((*i)->getComponentPointer(2));
					c=((*i)->getComponentPointer(3));
					if ((*b)>0){sum=sum+(*a)*exp((*c)*log(*b));}
				}
				delet=true;
				break;
			}
		}
		if(lobj->classnameOf()=="Area")
		{
			for (std::list<Vector*>::iterator i=tmvl->begin();i!=tmvl->end();i++)
			{//tests if all vectors contain only values
				allv=allv&&(((*i)->getNumberOfValue())==2);
				}
			if (allv)//if all vectors contain only values
			{//evaluate the value of this Area object
				sum=((*(tmvl->begin()))->getValue(1));
				for (std::list<Vector*>::iterator i=tmvl->begin();i!=tmvl->end();i++)
				{
					allv==allv&&(((*i)->getValue(1))==((*i)->getValue(2))==(int)sum);
				}
				if (allv)
				{
					delet=true;
					break;
				}
			}
		}
	}
}
if (delet)
{
	//if the element can be deleted
	Function Socket2=Function(obj,tlist);//else it is not possible to remove the first object
	lobj=Socket2.getObjectFrom(Socket2.movePointToObjectPoint(wich));
	double* var;
	var=lobj->getDefinedVariableFrom(wich);
	lobj->setVariableToValue(var,(int)sum);
	Socket2.removeElement(wich);//delete a random move point
	return Socket2.getNext();
}
obj->deleteObject();
delete obj;
return 0;
}


PicturObject* Environment::Operation20(PicturObject* obj)
//insert a slanting line, uses a Area and a Function object for this
{
unsigned int wich=(unsigned int)(getRandom(obj->getNumberOfValue()+1));//which value to change
int val=obj->getValue(wich);
//generate the values for (var*a1^(-1)+a2*var^1)
int a1=(int)(getRandom(20)+1);
int a2=(int)((getRandom(20)-10)*(getRandom(10))/10);
if (a1&&int(1.0/a1+a2)) {val=(int)(val/(1.0/a1+a2));}//evaluate the value for the area object
//generate UnderArea list
UnderArea *area=new UnderArea();
area->setValueToValue(1,val-(int)getRandom(5));
area->setValueToValue(2,val+(int)getRandom(5));
list<Vector*> vl;
vl.insert(vl.begin(),area);
//generate Area object
PicturObject* obj2=new Area(0,vl);
//get the defined variable of the area object
double* var=obj2->getDefinedVariableFrom(obj2->getNumberOfMovePoints());
//generate UnderFunction list
UnderFunction *fkt=new UnderFunction();
fkt->setValueToValue(2,a1);
fkt->setValueToValue(3,(-1));
fkt->setValueToVariable(1,var);
list<Vector*> vl2;
vl2.insert(vl2.end(),fkt);
fkt=new UnderFunction();
fkt->setValueToValue(1,a2);
fkt->setValueToValue(3,1);
fkt->setValueToVariable(2,var);
vl2.insert(vl2.end(),fkt);//the list is {(var;a1;-1),(a2;var;1)}=var*a1^b1+a2*var^1
//generate Function object
obj=new Function(obj,vl2);
//insert the defined variable of the new Function object
double* var1=obj->getDefinedVariableFrom(obj->getNumberOfMovePoints());
	//get the defined variable of the new Function object
//insert Area objekt above the new Function object
obj2->insertObject(obj);
obj=obj2;
//insert the defined variable of the Function object on the right place
if (var){
	obj->setValueToVariable(wich,var1);
	if (int(getRandom(1.5))){obj->setValueToVariable((wich-int(getRandom(1.7))),var);}
		//a smaler possibility to set a near value to the variable defined by the new Area
}else{
	obj->deleteObject();
	delete obj;
	return 0;
}
return obj;
}




PicturObject* Environment::Operation21(PicturObject* obj)
//insert a slanting line, uses a Area and a Function object for this
{


Position pos=Position(Original.getNumberOfPositionComponents());
unsigned long posn[4]={0,0,0,0};
for (unsigned int a=1;a<=Original.getNumberOfPositionComponents();a++)
{
	posn[a-1]=(unsigned long)(getRandom((Original.getSize()[a-1])));
	pos.setValueToValue(a,(int)posn[a-1]);
}
Color *col=Original.getColorFrom(posn);
PicturObject* pobj=new Point(pos,*col);




int val=pobj->getValue(1);
//generate the values for (var*a1^(-1)+a2*var^1)
int a1=(int)(getRandom(20)+1);
int a2=(int)((getRandom(20)-10)*(getRandom(10))/10);
if (a1&&int(1.0/a1+a2)) {val=(int)(val/(1.0/a1+a2));}//evaluate the value for the area object
//generate UnderArea list
UnderArea *area=new UnderArea();
area->setValueToValue(1,val-(int)getRandom(5));
area->setValueToValue(2,val+(int)getRandom(5));
list<Vector*> vl;
vl.insert(vl.begin(),area);
//generate Area object
PicturObject* obj2=new Area(0,vl);
//get the defined variable of the area object
double* var=obj2->getDefinedVariableFrom(obj2->getNumberOfMovePoints());
//generate UnderFunction list
UnderFunction *fkt=new UnderFunction();
fkt->setValueToValue(2,a1);
fkt->setValueToValue(3,(-1));
fkt->setValueToVariable(1,var);
list<Vector*> vl2;
vl2.insert(vl2.end(),fkt);
fkt=new UnderFunction();
fkt->setValueToValue(1,a2);
fkt->setValueToValue(3,1);
fkt->setValueToVariable(2,var);
vl2.insert(vl2.end(),fkt);//the list is {(var;a1;-1),(a2;var;1)}=var*a1^b1+a2*var^1
//generate Function object
pobj=new Function(pobj,vl2);
//insert the defined variable of the new Function object
double* var1=pobj->getDefinedVariableFrom(pobj->getNumberOfMovePoints());
	//get the defined variable of the new Function object
//insert Area objekt above the new Function object
obj2->insertObject(pobj);
pobj=obj2;
//insert the defined variable of the Function object on the right place
if (var){

	if (int(getRandom(2))){
		pobj->setValueToVariable(1,var1);
		pobj->setValueToVariable(2,var);
	}else{
		pobj->setValueToVariable(2,var1);
		pobj->setValueToVariable(1,var);
	}
	//insert the random point into the copy of the Picturobject of the selected Individual
	//select the place to insert
	unsigned int wher=(unsigned int)(getRandom(obj->getNumberOfObjects()+1));
	if (!(obj->insertObjectInObject(wher,pobj,int(getRandom(2)))))
		{obj=new Conc(pobj,obj);}
}else{
	obj->deleteObject();
	delete obj;
	return 0;
}
return obj;
}










