/*
    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 GHSOM_HIERARCHICAL_SOM_H
#define GHSOM_HIERARCHICAL_SOM_H

#include "SOMNet.h"

namespace clustering
{
	namespace som
	{
		typedef boost::shared_ptr<std::vector<size_t> > ClusterVectorPtr;

		//TODO: redesing to GHSOM (currently do not use it is not in CMakeLists)
		class HierarchicalSOM
		{
		public:
			HierarchicalSOM(boost::shared_ptr<Matrices::SuperMatrix> matrix,
				boost::shared_ptr<smartcomparator::simfunctions::LocalSimilarityFunction> simfun, double t1, double t2,
				int neurons = 3, int epoch = 5);


			void Start();
			void TestSOMHierarchies();

			static double CountMapMeanMQE(std::vector< std::vector<double> > &map_desc);

			~HierarchicalSOM();


			ClusteringBase::ClusterSetPtr GetClusters();
			ClusteringBase::LinkSetPtr GetLinks();

			ClusterVectorPtr GetClustersIndices(bool firstLayerOnly);
			std::multimap<size_t, boost::shared_ptr<CSOMNet> > GetMaps();

		private:

			double CountMQE0();

			void BuildHierarchy(boost::shared_ptr<CSOMNet> net, size_t layerNo, std::string name);

			std::pair<size_t, size_t> FindNeuron(size_t neuronId, int layerNo);

			/**
			Zwraca true jezeli siec powinna zostac zwiekszona
			*/
			bool ExpandFurther(CSOMNet &net, double MQEm);
			/**
			Zwraca true jezeli dla danego neuronu na pozycji [row,column] w mapie
			powinno sie zbudowac podmapę
			*/
			bool GoDeeper(CSOMNet &net, CSOMNeuron& neuron, size_t currlayer);

			/// macierz dokumenty x terminy
			boost::shared_ptr<Matrices::SuperMatrix> m_Matrix;
			/// funkcja podobieństwa wg ktorej ma byc liczone dopasowanie wag poszczegolnych neuronow do danych wejsciowych
			boost::shared_ptr<smartcomparator::simfunctions::LocalSimilarityFunction> m_pSimFunction;

			/// maksymalna liczba wątków
			size_t m_cThreads;
			/// początkowa wielkość sieci w pierwszej warstwie
			size_t m_stInitialNeurons;
			/// liczba epok do treningu
			size_t m_cEpoch;
			/// wartość mqe_0 (dopasowanie dla warstwy 0)
			double m_dMQE0;
			/// numner_warstwy -> sieci
			std::multimap<size_t, boost::shared_ptr<CSOMNet> > m_Maps;


			/**
			Tworzy grupy w formacie do zapisu do xml
			*/
			void CreateClustersFromSOM();
			/**
			Tworzy połączenia między grupami w formacie do zapisu do xml
			*/
			void CreateLinksFromSOM();

			ClusteringBase::ClusterSetPtr m_pClusterSet;
			ClusteringBase::LinkSetPtr m_pLinkSet;

			/**
			  * Horizontal expansion threshold
			  */
			double _t1;

			/**
			  * Vertical expansion threshold
			  */
			double _t2;
		};
	}//namespace SOM
}//namespace Clustering

#endif //GHSOM_HIERARCHICAL_SOM_H

