/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
any later version.

    This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. 

    See the LICENSE and COPYING files for more details.
*/

#ifndef CLUSTERINGBASE_CLUSTER_H
#define CLUSTERINGBASE_CLUSTER_H

#include <boost/shared_ptr.hpp>
#include <fstream>
#include <vector>
#include <set>
#include <map>
#include "matrices_all.h"

namespace ClusteringBase
{
	typedef std::set<size_t> IdSet;

	class Cluster
	{
	public:
		/**
		Przyznaje id - używane w wypadku, gdy metoda działa bezpośrednio na Cluster 
		(lub pochodnych), lub gdy id są nieistotne z punktu widzenia algorytmu grupowania
		(np. nie trzeba znać id, żeby utworzyć połączenie w wypadku grupowania płaskiego)
		*/
		Cluster();
		/**
		Po użyciu tego c-tora nie powinno się korzystać z c-tora bezparametrowego. 
		Użytkownik zarządza id grup.
		*/
		Cluster(size_t id);

		virtual ~Cluster();
		size_t GetID() const;

		/**
		Compares id's
		*/
		virtual bool operator < (Cluster &c) const;

		void AddPoint(size_t pointID);

		IdSet& GetPointsID();

		std::vector<boost::shared_ptr<Cluster> >& GetChildren();
		boost::shared_ptr<Cluster> GetParent();
		void SetParent(boost::shared_ptr<Cluster> parent);

	private:
		size_t m_ID;
		static size_t m_LastID;

		IdSet *m_pDataPointsID;
		std::vector<boost::shared_ptr<Cluster> > m_vChildren;
		boost::shared_ptr<Cluster> m_pParent;

		Cluster(const Cluster&);// no implementation
		Cluster& operator=(const Cluster&); // no implementation
	};

	
	typedef boost::shared_ptr<Cluster> ClusterPtr;

	struct lessClusterPtr
	{
		bool operator()(const ClusterPtr c1, const ClusterPtr c2) const;
		
	};

	typedef std::set<ClusterPtr, lessClusterPtr> ClusterSet;
	typedef boost::shared_ptr<ClusterSet> ClusterSetPtr;
	typedef std::pair<size_t, ClusterPtr> IdClusterPtrPair;
	typedef std::map<size_t, ClusterPtr> ClusterMap;
	typedef boost::shared_ptr<ClusterMap> ClusterMapPtr;

	ClusterPtr MergeClusters(ClusterPtr c1, ClusterPtr c2);

	void WriteClusters(ClusterSetPtr clusterset, const std::string &filename);
	bool IsFlat(ClusterSetPtr clusterset);
	void GetRoots(ClusterSetPtr clusterset, ClusterSet &roots);
	void GetLeafs(ClusterSetPtr clusterset, ClusterSet &leafs);

	void ToParentArray(ClusterSetPtr pClusters, Matrices::SuperMatrixPtr pMatrix,  std::vector<int> &parray);
	void SaveParentArray(std::vector<int> &parray, const std::string &filename);
	void CreateParray(ClusterSetPtr clusters, std::vector<int> &parray);

}

#endif //CLUSTERINGBASE_CLUSTER_H

