#include <iostream>
#include <iterator>
#include <string>
#include <list>
#include <map>
#include <algorithm>
#include "float.h"
#include "networks/wiredbas/WiredBasSpecificaion.h"
#include "networks/wiredbas/WiredBasPlatformInstance.h"
#include "networks/wiredbas/WiredBasImplementation.h"
#include "networks/graph/RealWeightedGraph.h"
#include "platforms/wiredbas/BusPlatform.h"
#include "platforms/wiredbas/NetworkPlatform.h"
#include "io/bas/HmetisInterface.h"
#include "io/bas/PatohInterface.h"
#include "algorithms/graph/Tsp.h"

#ifndef PARTITIONGENERATOR_H_
#define PARTITIONGENERATOR_H_

namespace cosi {

namespace algorithms {

namespace wiredbas {

class PartitionGenerator {
public:
	PartitionGenerator(cosi::commstruct::wiredbas::Specification* pSpec,
			cosi::platforms::wiredbas::BusPlatform* pPlt);
	PartitionGenerator(cosi::commstruct::wiredbas::Specification* pSpec,
				cosi::platforms::wiredbas::NetworkPlatform* pPlt);
	virtual ~PartitionGenerator();

	void Run();

	std::list< cosi::commstruct::wiredbas::Implementation* > GetChains();
	std::set<int> GetRouters();

	void SetBandwidthWeight(double W);
	void SetLatencyWeight(double W);
	void SetDistanceWeight(double W);

private:
	//INPUTS
	cosi::commstruct::wiredbas::Specification* mSpecification;
	cosi::platforms::wiredbas::BusPlatform* mPlt;
	cosi::platforms::wiredbas::NetworkPlatform* mNetPlt;
	//OUTPUTS
	std::list< cosi::commstruct::wiredbas::Implementation* > mChains;
	std::map<int,Position> mRouters;
	//PARAMTERS
	double mBandwidthWeight;
	double mLatencyWeight;
	double mDistanceWeight;

	//PRIVATE METHODS
	cosi::commstruct::graph::RealWeightedGraph* GenerateWeightedGraph();

	std::list<cosi::commstruct::wiredbas::Implementation* > GenerateChains(
			std::vector<std::set<int> > Partitions);

	std::list<cosi::commstruct::wiredbas::Implementation* > GenerateNets(
				std::vector<std::set<int> > Partitions);

	std::list<cosi::commstruct::wiredbas::Implementation* > GenerateTrees(
			std::vector<std::set<int> > Partitions);

	double ComputeAverageBandwidth(int U, int V);

	std::list<int> GenerateChain(std::set<int> Nodes, int RouterId);


	cosi::commstruct::graph::U_RealWeightedGraph* GenerateTree(std::set<int> Nodes, int RouterId);

	std::list<int> GenerateShortestChain(std::set<int> Nodes, int RouterId);

	cosi::commstruct::wiredbas::Implementation* GenerateBusInstance(
			std::list<int> Chain, int RouterId);

	cosi::commstruct::wiredbas::Implementation* GenerateNetInstance(
			std::set<int> Nodes, int RouterId);

	cosi::commstruct::wiredbas::Implementation* GenerateBusInstance(
			cosi::commstruct::graph::U_RealWeightedGraph* G, int RouterId);

	bool CheckLatency(cosi::commstruct::wiredbas::Implementation* pBus);

	bool CheckNetLatency(cosi::commstruct::wiredbas::Implementation* pNet);

	bool mBusBased ;

};

}

}

}

#endif /*PARTITIONGENERATOR_H_*/
