#ifndef CLUSTERINGPSOREADY_H_INCLUDED
#define CLUSTERINGPSOREADY_H_INCLUDED

/*************************************************************************
* Project: Library of Evolutionary Algoriths
*************************************************************************
* Author: Changhe Li & Ming Yang
* Email: changhe.lw@google.com Or yangming0702@gmail.com
* Language: C++
*************************************************************************
*  This file is part of EAlib. This library 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, or (at your option) any later version.
*************************************************************************/
// Created: 11 Oct. 2011
// Last modified:



#include "../../Clustering/ClusterPopulation.h"
#include "../../../PerformanceMeasure/PopulationInforDOP.h"
template<typename T, typename U>
class ClusteringReadyMethod: public virtual ClusterPopulation<T,U>{

public:
    ClusteringReadyMethod(){
        strcpy(this->ma_name,"CPSOR");
        this->m_algPar<<"Global population size: "<<Global::g_gPopsize<<"; sub-population size: "<<Global::g_subSize<<"; Overlap degree:"<<Global::g_overlapDegree<<";"<<"; Diversity degree:"<<Global::g_diversityDegree<<";";
    }

    ~ClusteringReadyMethod(){

    }


    void newSubswarms(ClusterPopulation<T,U> & cradle){

        cradle.clst.initialize(cradle.mp_pop,cradle.m_popsize);
        cradle.clst.roughClustering();

        for(int k=0;k< cradle.clst.m_number;k++){
            //cout<<"pop "<<k<<" size "<<cradle.clst.mp_group[k].m_number<<endl;
            ClusterPopulation<T,U> *s=new ClusterPopulation<T,U>(cradle.clst.mp_group[k]);

            if(gIsTerminate()) return ;

            ClusterPopulation<T,U>::addPopulation(*s);

            int *id=new int[ cradle.clst.mp_group[k].m_number];
            for(int j=0;j< cradle.clst.mp_group[k].m_number;j++) id[j]= cradle.clst.mp_group[k].mp_member[j].m_id;
            cradle.deleteIndividual(id, cradle.clst.mp_group[k].m_number);

            delete [] id;
            id=0;
        }
		cradle.clst.freeMemory();
#ifdef EALIB
		PopulationInforDOP::getPopInfor()->input(Global::gp_problem->getEvaluations(),Population<U>::ms_gNumIndis,this->ms_popNum,ClusterPopulation<T,U>::computePeaksFound(), dynamic_cast<DynamicContinuous*>(Global::gp_problem)->getNumofVisablePeaks());
#endif
    }




    int evolve(){

        while(!gIsTerminate()){
			#ifdef DEMON_EALIB
			if(ClusterPopulation<T,U>::ms_popNum>0) Buffer<U>::updateBuffer(ClusterPopulation<T,U>::msp_subPop);
#endif
            //cout<<Global::g_runIdx+1<<" "<<Global::gp_problem->getEvaluations()<<endl;
            for(int k=0;k<ClusterPopulation<T,U>::ms_popNum;k++){
                dynamic_cast<T*>(ClusterPopulation<T,U>::msp_subPop[k])->evolve();
                if(gIsTerminate()) return 0;

            }

            if(Population<U>::ms_gNumIndis>=Global::g_gPopsize*Global::g_diversityDegree){
                while(ClusterPopulation<T,U>::checkOverlapping());

                for(int k=0;k<ClusterPopulation<T,U>::ms_popNum;k++)dynamic_cast<ClusterPopulation<T,U> *>(ClusterPopulation<T,U>::msp_subPop[k])->checkOverCrowd();

                //convergence check
                for(int k=0;k<ClusterPopulation<T,U>::ms_popNum;k++){
                    if(dynamic_cast<ClusterPopulation<T,U> *>(ClusterPopulation<T,U>::msp_subPop[k])->isConverged()){
                        ClusterPopulation<T,U>::deletePopulation(k);
                        k--;
                    }
                }
            }
             #ifdef EALIB
			PopulationInforDOP::getPopInfor()->input(Global::gp_problem->getEvaluations(),Population<U>::ms_gNumIndis,ClusterPopulation<T,U>::ms_popNum,ClusterPopulation<T,U>::computePeaksFound(), dynamic_cast<DynamicContinuous*>(Global::gp_problem)->getNumofVisablePeaks());
#endif

            if(Population<U>::ms_gNumIndis<Global::g_gPopsize*Global::g_diversityDegree){
				if(dynamic_cast<DynamicProblem * >(Global::gp_problem)->predictChange(Global::g_gPopsize-Population<U>::ms_gNumIndis)){
                    cout<<"mode=false, i.e., fitness evaluations not counted as it will causes environmental change"<<endl;
                    ClusterPopulation<T,U> cradle(Global::g_gPopsize-Population<U>::ms_gNumIndis,false);
                    newSubswarms(cradle);
                }else{
                    ClusterPopulation<T,U> cradle(Global::g_gPopsize-Population<U>::ms_gNumIndis,true);
                    newSubswarms(cradle);
                }
            }

         }

        return 0;
    }

    int run(){

        ClusterPopulation<T,U>  cradle(Global::g_gPopsize);
        newSubswarms(cradle);

        evolve();
		#ifdef DEMON_EALIB
		if(ClusterPopulation<T,U>::ms_popNum>0) Buffer<U>::updateBuffer(ClusterPopulation<T,U>::msp_subPop);
#endif
        for(int j=0;j<ClusterPopulation<T,U>::ms_popNum;j++){
            delete ClusterPopulation<T,U>::msp_subPop[j];
            ClusterPopulation<T,U>::msp_subPop[j]=0;
        }
        ClusterPopulation<T,U>::ms_popNum=0;
        ClusterPopulation<T,U>::msp_subPop.clear();
        Population<U>::ms_gNumIndis=0;
            return 0;

    }





};




#endif // CLUSTERINGPSOREADY_H_INCLUDED
