#include "PPGraphCut.h"

#include "objrec/segmentation/RegionGraph.h"

using namespace std;
using namespace NICE;
using namespace OBJREC;

void PPGraphCut::setClassNo(int _classno)
{
	classno = _classno;

	coocurence = new double[classno*classno];
	
	for(int i = 0; i < classno*classno; i++)
	{
		coocurence[i] = 0.0;
	}

}

PPGraphCut::PPGraphCut()
{
	conf = new Config();
	Init();
}

PPGraphCut::PPGraphCut(const Config *_conf):conf(_conf)
{
	Init();
}

void PPGraphCut::Init()
{
	std::string section = "PostProcess";
}

PPGraphCut::~PPGraphCut()
{
	
}

void PPGraphCut::optimizeImage(RegionGraph &regions, vector<vector<double> > & probabilities)
{
	vector<Node*> nodes;
	regions.get(nodes);

	GCoptimizationGeneralGraph graphcut(nodes.size(), classno);

	graphcut.setSmoothCost(coocurence);
	
	map<pair<int,int>, int> pairs;
	
	for(int i = 0; i < (int) nodes.size(); i++)
	{
		vector<Node*> nbs;
		nodes[i]->getNeighbors(nbs);
		int pos1 = nodes[i]->getNumber();
		for(int j = 0; j < (int)nbs.size(); j++)
		{
			int pos2 = nbs[j]->getNumber();
			pair<int,int> p(std::min(pos1,pos2),std::max(pos1,pos2));
			map<pair<int,int>, int>::iterator iter = pairs.find(p);
			if(iter == pairs.end())
			{
				pairs.insert(make_pair(p,1));
				graphcut.setNeighbors(pos1, pos2,1.0);
			}
		}
		for(int l = 0; l < classno; l++)
		{
			double val = probabilities[i][l];
			if(val <= 0.0)
				val = 1e-10;
			val = -log(val);
			graphcut.setDataCost(pos1, l, val);
		}
		graphcut.setLabel(pos1, nodes[i]->getLabel());
	}

	graphcut.swap(20);

	//MRF::EnergyVal E_smooth = graphcut->smoothnessEnergy();

	//MRF::EnergyVal E_data   = graphcut->dataEnergy();

	for (int i = 0; i < (int)nodes.size(); i++ )
	{
		regions[i]->setLabel(graphcut.whatLabel(i));
	}
}

void PPGraphCut::optimizeImage(Examples &regions, NICE::Matrix &mask, GenericImage<double> & probabilities)
{
	RegionGraph g;
	g.computeGraph(regions, mask);

	vector<vector<double> > probs;
	
	for(int p = 0; p < (int)regions.size(); p++)
	{
		vector<double> pr;
		for(int l = 0; l < classno; l++)
		{
			pr.push_back(probabilities.get(regions[p].second.x, regions[p].second.y, l));
		}
		probs.push_back(pr);
	}

	optimizeImage(g, probs);
}

void PPGraphCut::trainImage(RegionGraph &g)
{
	vector<Node*> nodes;
	g.get(nodes);

	for(int i = 0; i < (int) nodes.size(); i++)
	{
		vector<Node*> nbs;
		nodes[i]->getNeighbors(nbs);
		for(int j = 0; j < (int)nbs.size(); j++)
		{
			//if(nodes[i]->getLabel() != nbs[j]->getLabel())
			coocurence[nodes[i]->getLabel()*classno+nbs[j]->getLabel()]+=1.0;
		}
	}
}

void PPGraphCut::trainImage(Examples &regions, NICE::Matrix &mask)
{
	// coocurence Matrix bestimmen
	RegionGraph g;
	g.computeGraph(regions, mask);
	trainImage(g);
}
		
void PPGraphCut::finishPP(ClassNames &cn)
{
	for(int i = 0; i < classno; i++)
	{
		for(int j = 0; j < classno; j++)
		{
			cout << coocurence[classno*i+j] << " ";
		}
		cout << endl;
	}
	cout << endl;
	
	double weight = conf->gD( "PPGC", "weight", 0.01 );
	double maxv =  -numeric_limits<double>::max();
	for(int i = 0; i < classno; i++)
	{
		for(int j = 0; j < classno; j++)
		{
			if(j == i)
				coocurence[classno*i+j] = 0.0;
			else
				maxv = std::max(maxv, coocurence[classno*i+j]);
		}
	}
	
	maxv+=1+1e-10;
	
	for(int i = 0; i < classno; i++)
	{
		for(int j = 0; j < classno; j++)
		{
			if(j == i)
				coocurence[classno*i+j] = 0.0;
			else
				coocurence[classno*i+j] = -weight*(log(( coocurence[classno*i+j]+1.0)/maxv));
		}
	}
	for(int i = 0; i < classno; i++)
	{
		for(int j = 0; j < classno; j++)
		{
			cout << coocurence[classno*i+j] << " ";
		}
		cout << endl;
	}
	//GetChar();
}

void PPGraphCut::restore (istream & is, int format)
{
	
}
		
void PPGraphCut::store (ostream & os, int format) const
{
	
}

void PPGraphCut::clear()
{
	
}