/*
    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 PARALLEL_SIM
#define PARALLEL_SIM
//Messages
const int EXIT_CODE=-15000;
const int GIVE_ME_ROW=-15001;
const int SENDING_RESULTS=-15002;
const int ALL_OK=-15003;

#include "Config.h"
#include "MatrixSaverInterface.h"
#include "MatrixSaverSuperMatrix.h"
#include "MatrixSaverTextFile.h"
#include "MatrixSaverDenseMatrix.h"
#include <mpi.h>
#include "../mpi_handler/mpi_handler.h"

namespace parallel
{
	namespace similarity
	{

		class ParallelMaster
		{
		public:
			/**
			  * Constructor
			  */
			ParallelMaster();
			~ParallelMaster();
			/**
			  * Function initializing all local variables
			  */
			void Init(MPI_Status stat);
			/**
			  Function starting parallel master
			  */
			void Start();
		private:

			/**
			  * Function Loading words to be processed
			  */
			void LoadWordsList(Matrices::SuperMatrixPtr matrix);
			/**
			  * Function printing ETA
			  */
			void printETA();
			/**
			  * Function responsible for giving node a task
			  */
			void receivedRowRequest(int nodeNum);
			/**
			  * Function responsible for receiving results from slaves
			  */
			void receivingResults(int nodeNum);

			MPI_Status stat;
			bool isSimetrical;
			int totalNumOfRows;
			int numOfComputedRows;
			int numOfNodes;
			MatrixSaverInterface* resultsMatrix;
			int numOfRowsToCompute;
			bool *isResult;
			boost::posix_time::ptime start;
			boost::posix_time::time_duration total_time;
			MPI_Handler mpiHandler;
			int rowIterator;

		};
		class ParallelSlave
		{
		public:
			/**
			  * Constructor
			  */
			ParallelSlave(int myRank);
			~ParallelSlave();
			/**
			  * Function initializing all local variables
			  */
			void Init(MPI_Status stat);
			/**
			  Function starting parallel slave for similarity computation
			  */
			void Start();
		private:
			/**
			  * Function responsible for sending results to master node
			  */
			void sendResults(int numOfResults);
			/**
			  * Function responsible for computing given row
			  */
			int Compute();
			int myRank;
			smartcomparator::compare::CompareFunctionPtr pCmp;
			bool isSimetrical;
			int numOfAllRows;
			MPI_Status stat;
			double *results;
			int *resultsIndex;
			int currentRowNum;
			MPI_Handler mpiHandler;
		};

		/**
 * Main function. Initializes MPI, takes care of everything concerning computation.
 * \param ac Input argument count
 * \param av Input arguments
 */
		void runParallelSimilarityFunction(int ac, char **av);

	}
}
#endif // PARALLEL_SIM
