#ifdef _CH_
#pragma package <opencv>
#endif

#ifndef _EiC
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
#endif

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>

#include "training.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

training::training()
{
	numpositives=0;
	numnegatives=0;

	featureNumber=0;	//the number of the feature used in the featurelist vector in main
	featoffsetX=0;	//specifics of the feature used in this training
	featoffsetY=0;
	featScaleX=0;
	featScaleY=0;
	theta=0;	//threshold theta
	s=0;	//sign
	falsepos=0;	//number of false positives in the threshold finding procedure.
	missed=0;		//number of missed (false negatives)
	alpha=0;	//weight of the weak classifier.
	ce=0;
	vectorsEmpty = false;
	nm=0;
	pm=0;
}

training::~training() {
	if (!vectorsEmpty) {
		for (int di=0; di<trainRecs.size(); ++di){			
			trainingRecord *e = (trainingRecord*) trainRecs[di];
			delete e;
		}
		trainRecs.clear();
		for (di=0; di<unsortedtrainRecs.size(); ++di){			
			trainingRecord *e = (trainingRecord*) unsortedtrainRecs[di];
			delete e;
		}
		unsortedtrainRecs.clear();
	}
}

void training::freeVectors() {
	for (int di=0; di<trainRecs.size(); ++di){			
		trainingRecord *e = (trainingRecord*) trainRecs[di];
		delete e;
	}
	trainRecs.clear();
	for (di=0; di<unsortedtrainRecs.size(); ++di){			
		trainingRecord *e = (trainingRecord*) unsortedtrainRecs[di];
		delete e;
	}
	unsortedtrainRecs.clear();
	vectorsEmpty=true;
}

training::training(training *m) {
	
	numpositives=m->numpositives;
	numnegatives=m->numnegatives;
	nm=m->nm;
	pm=m->pm;

	featureNumber=m->featureNumber;
	featoffsetX=m->featoffsetX;
	featoffsetY=m->featoffsetY;
	featScaleX=m->featScaleX;
	featScaleY=m->featScaleY;
	theta=m->theta;
	s=m->s;	//sign
	falsepos=m->falsepos;	//number of false positives in the threshold finding procedure.
	missed=m->missed;		//number of missed (false negatives)
	alpha=m->alpha;	//weight of the weak classifier.
	ce=m->ce;		//combined error
}

void training::settraining(int featno, int offX, int offY, int scaX, int scaY){
	featureNumber=(short)featno;	
	featoffsetX=offX;	
	featoffsetY=offY;
	featScaleX=scaX;
	featScaleY=scaY;
}

void training::addRec(int sign1, int featVal) {
	struct trainingRecord *rec = new struct trainingRecord(sign1,featVal);
	trainRecs.push_back(rec);
	struct trainingRecord *rec1 = new struct trainingRecord(sign1,featVal);
	unsortedtrainRecs.push_back(rec1);
	if (sign1>0)
		numpositives++;
	else
		numnegatives++;
}

std::vector<trainingRecord*>& training::getTrainRecs() {
	return trainRecs;
}

std::vector<trainingRecord*>& training::getUnsortedTrainRecs() {
	return unsortedtrainRecs;
}

void training::findWeakClassifier() {
	int sp=0;
	int sn=0;
	int missclassified=0;
	s=1;
	if (numnegatives<numpositives) {
		missclassified=numnegatives;
		falsepos=numnegatives;
		theta=trainRecs[trainRecs.size()-1]->featValue+1;
	} else {
		missclassified=numpositives;
		missed=numpositives;
		theta=trainRecs[0]->featValue-1;
	}

	int total=numpositives+numnegatives;
	for (int j=0; j<total-1; j++) {
		if (trainRecs[j]->sign==1) {
			sp++;
		} else {
			sn++;
		}
		if (sp + numnegatives - sn < missclassified) {
			missclassified=sp + numnegatives - sn;
			s=-1;
			theta=((float)trainRecs[j]->featValue + (float)trainRecs[j+1]->featValue)/2.0;
			//try
			falsepos=numnegatives-sn;
			missed=sp;
		}
		if (sn + numpositives - sp < missclassified) {
			missclassified = sn + numpositives - sp;
			s=1;
			theta=((float)trainRecs[j]->featValue + (float)trainRecs[j+1]->featValue)/2.0;
			//try
			falsepos=sn;
			missed=numpositives-sp;
		}
		if ((s==1)&&(trainRecs[j]->sign==-1)&&((float)trainRecs[j]->featValue==theta)) {		//see ../oldfuzzyboosts/theta problem.txt for details
			missclassified++;
			falsepos++;
		}
		if ((s==-1)&&(trainRecs[j]->sign==1)&&((float)trainRecs[j]->featValue==theta)) {
			missclassified++;
			missed++;
		}
	}

	if (s>0) {
		pm=trainRecs[0]->featValue;
		nm=trainRecs[trainRecs.size()-1]->featValue;
	} else {
		nm=trainRecs[0]->featValue;
		pm=trainRecs[trainRecs.size()-1]->featValue;
	}

	float e=(float)missclassified/(float)(total);
	if (e==0) 
		alpha=1;
	else {
		float beta=e/(1-e);
		alpha=-log10(beta);
		if (alpha>1)
			alpha=1.0;
	}

	//fing ce (combined error)
	ce=((float)missed+(float)falsepos)/(float)total;
	//ce=e;
}

void training::sortRecs() {
	sortRecs(trainRecs, 0, trainRecs.size()-1);
}

void training::sortRecs(std::vector<trainingRecord*>& set, int fst, int lst) {
		int     splitpt;
        int     isplit(std::vector<trainingRecord*>& set, int f, int l);

        if (fst < lst) {
                splitpt = isplit(set, fst, lst);
                sortRecs(set, fst, splitpt - 1);
                sortRecs(set, splitpt +1, lst);
        }
}

void iswap(std::vector<trainingRecord*>& set, int p, int q) {
        int tempVal;
		short tempSign;

        tempVal = set[p]->getVal();
		tempSign= set[p]->getSign();
        set[p]->sign = set[q]->sign;
		set[p]->featValue = set[q]->getVal();
        set[q]->featValue = tempVal;
		set[q]->sign = tempSign;
}

int isplit(std::vector<trainingRecord*>& set, int f, int l) {
        int    x;
        int    u, sp;
        void  iswap(std::vector<trainingRecord*>& set, int p, int q);

        x  = set[f]->getVal();
        sp = f;
        for (u = f + 1; u <= l; ++u){
                if( set[u]->getVal() < x){
                        ++sp;
                        iswap(set, u, sp);
                }
        }

        iswap(set, f, sp);
        return(sp);
}

#ifdef _EiC
main(1,"training.cpp");
#endif