/*************************************************************************
* 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: 21 September 2011
// Last modified:
#include <fstream>
#include "PopulationInforDOP.h"
#include "../ToolnDef/Global.h"

PopulationInforDOP * PopulationInforDOP::msp_infor=0;

PopulationInforDOP::PopulationInforDOP():m_avgOptsFound(0), m_avgVisablePeaks(0), m_avgSurvivedPops(0),m_avgInitialRadius(0),m_outputProgFlag(false)
{
    //ctor
     mpv_infor=new vector<PopInfor> [Global::g_numRuns];
}

PopulationInforDOP::~PopulationInforDOP()
{
    //dtor
    for(int i=0;i<Global::g_numRuns;i++) mpv_infor[i].clear();

    delete [] mpv_infor;
}

void PopulationInforDOP::setFileName(stringstream &rName){
    m_fileName.str(rName.str());
}
void PopulationInforDOP::setOutProgFlag(bool rflag){
			m_outputProgFlag=rflag;
}
PopulationInforDOP * PopulationInforDOP::getPopInfor(){
    if(PopulationInforDOP::msp_infor) return PopulationInforDOP::msp_infor;
    else{
        Throw(Runtime_error("the instance has not been initialized"));
        exit(0);
    }

}
void PopulationInforDOP::initialize(){
    PopulationInforDOP::msp_infor=new PopulationInforDOP();

}
void PopulationInforDOP::deletePerformPopInforDOP(){
    delete  PopulationInforDOP::msp_infor;
}
void PopulationInforDOP::input(int fes, int numIndis,int numPops,int numOptsFound,int numVisablePeaks,float initialRadius,float curRadius,float largestRadius,float smallestRadius){
    PopInfor infor;
    infor.m_fes=fes;infor.m_numIndis=numIndis;infor.m_numOptsFound=numOptsFound;infor.m_numPops=numPops;infor.m_numVisablePeaks=numVisablePeaks;
    infor.m_avgInitialRadius=initialRadius;infor.m_avgCurRadius=curRadius;infor.m_largestRadius=largestRadius;infor.m_smallestRadius=smallestRadius;
    mpv_infor[Global::g_runIdx].push_back(infor);

}
void PopulationInforDOP::output(){
    /** method to output average results
        example of data format with each input in 3 runs (fes, number of populations), where change fre=10, total fes=50
                    0 10,  0 10,  0 10
                    1 9,   2 9,   1 8
                    3 7,   5 6,   2 7
                    6 2,   7 3,   4 5
                    10 10, 8 1,   6 3
                    12 9,  11 10, 9 1
                    15 6,  13 8,  10 10
                    ...    ...    ...
                     .      .      .
                    49 2   49 1   49 6
    **/
    unsigned int *idx=new unsigned int[Global::g_numRuns];
    for(int i=0;i<Global::g_numRuns;i++) idx[i]=0;

    int smallestFes;

    stringstream oss;
    ofstream out;

    oss<<"Result//"<<m_fileName.str()<<"PopInfor.txt";
    out.open(oss.str().c_str());


    while(1){
		int idxSmallest=0;
		while(idx[idxSmallest]>=mpv_infor[idxSmallest].size()&&idxSmallest<Global::g_numRuns) idxSmallest++;
		if(idxSmallest==Global::g_numRuns) 	 break;
		/// find the idex of data with smallest fes
         for(int i=0;i<Global::g_numRuns;i++) {
			 if(idx[i]>=mpv_infor[i].size()) continue;
            if(mpv_infor[i][idx[i]].m_fes<mpv_infor[idxSmallest][idx[idxSmallest]].m_fes) {
                idxSmallest=i;
            }
        }

        smallestFes=mpv_infor[idxSmallest][idx[idxSmallest]].m_fes;
        float numIndis=0, numPops=0, numOptsFound=0, numVisablePeaks=0,initialRadius=0,curRadius=0,largestRadius=0,smallestRadius=0;
        // sum all the results with smallest idex and the previous results if current index is not the smallest
        for(int i=0;i<Global::g_numRuns;i++){
            if(idx[i]<mpv_infor[i].size()&&mpv_infor[i][idx[i]].m_fes==smallestFes){
                numIndis+=mpv_infor[i][idx[i]].m_numIndis;
                numPops+=mpv_infor[i][idx[i]].m_numPops;
                numOptsFound+=mpv_infor[i][idx[i]].m_numOptsFound;
                numVisablePeaks+=mpv_infor[i][idx[i]].m_numVisablePeaks;
                initialRadius+=mpv_infor[i][idx[i]].m_avgInitialRadius;
                curRadius+=mpv_infor[i][idx[i]].m_avgCurRadius;
                largestRadius+=mpv_infor[i][idx[i]].m_largestRadius;
                smallestRadius+=mpv_infor[i][idx[i]].m_smallestRadius;
                idx[i]++;

            }else{
				numIndis+=mpv_infor[i][idx[i]-1].m_numIndis;
				numPops+=mpv_infor[i][idx[i]-1].m_numPops;
				numOptsFound+=mpv_infor[i][idx[i]-1].m_numOptsFound;
				numVisablePeaks+=mpv_infor[i][idx[i]-1].m_numVisablePeaks;
				initialRadius+=mpv_infor[i][idx[i]-1].m_avgInitialRadius;
                curRadius+=mpv_infor[i][idx[i]-1].m_avgCurRadius;
                largestRadius+=mpv_infor[i][idx[i]-1].m_largestRadius;
                smallestRadius+=mpv_infor[i][idx[i]-1].m_smallestRadius;
            }
        }
		bool flag=true;
		for(int i=0;i<Global::g_numRuns;i++){
			if(idx[i]<1){ flag=false; break;}
			if(idx[i]<mpv_infor[i].size())		flag=flag&&(mpv_infor[i][idx[i]].m_fes/Global::g_changeFre!=mpv_infor[i][idx[i]-1].m_fes/Global::g_changeFre);
		}
		if(flag){
            m_avgOptsFound+=numOptsFound;
            m_avgVisablePeaks+=numVisablePeaks;
            m_avgSurvivedPops+=numPops;
            m_avgInitialRadius+=initialRadius;
		}

        numIndis/=Global::g_numRuns;
        numPops/=Global::g_numRuns;
        numOptsFound/=Global::g_numRuns;
        numVisablePeaks/=Global::g_numRuns;
        initialRadius/=Global::g_numRuns;
        curRadius/=Global::g_numRuns;
        smallestRadius/=Global::g_numRuns;
        largestRadius/=Global::g_numRuns;
        if(m_outputProgFlag)
        out<<smallestFes<<" "<<numIndis<<" "<<numPops<<" "<<numOptsFound<<" "<<numVisablePeaks<<" "<<initialRadius<<" "<<curRadius<<" "<<smallestRadius<<" "<<largestRadius<<endl;
    }

    out<<endl;
    out<<"OptsFound: "<<m_avgOptsFound/(Global::g_numRuns*(Global::g_tEvals/Global::g_changeFre));
    out<<" SurvivedPops: "<<m_avgSurvivedPops/(Global::g_numRuns*(Global::g_tEvals/Global::g_changeFre));
    out<<" VisablePeaks: "<<m_avgVisablePeaks/(Global::g_numRuns*(Global::g_tEvals/Global::g_changeFre));
    out<<" initialRadius: "<<m_avgInitialRadius/(Global::g_numRuns*(Global::g_tEvals/Global::g_changeFre))<<endl;
    out.close();
    delete [] idx;
}
