/*
    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.
*/

//#define JOSKIPI_OPERATOR_TEST
#ifndef ARCH2_ARCHITECT_H
#define ARCH2_ARCHITECT_H

#include "arch_headers.h"
#include "LexicalUnit.h"
#include "UnigramDictionary.h"

#include <mpi.h>




namespace me_architect
{
	struct Triplets
	{
		size_t lexId;
		size_t headId;
		std::set<size_t> constituents;

	};

	class Architect
	{
	public:
		/**
          * Empty constructor
          */
		Architect();

		/**
          * Function starting work. Initializes instance and starts work with corpus
          */
		void Start();

		/**
          * Function retrieving results matrix
          * \returns Results matrix
          */
		Matrices::CCSMatrixPtr getMatrix();

		/**
          * \returns Size of all corpuses being worked on
          */
		int getCorpusSize();
	private:
		/**
          * Function transforming multiword expressions in sentence to single occurences
          * \param old Sentence to be processed
          * \param t Triplet with lexical unit ID
          * \param removedBeforeCurrentPos Number of removed units before current position. After we remove units,
          *                                                                         we have to adjust position in file
          * \param lu Lexical unit for transformation
          * \returns
          */
		Corpus::CSentence* TransformSentenceOnCurrentPosition(
				Corpus::CSentence* old, Triplets &t, size_t
				&removedBeforeCurrentPos, LexicalUnits::LexicalUnitPtr lu);


		/**
          * Function processing corpuses
          */
		void ProcessBinaryCorpus();

		/**
          * Function processing sentence
          * \param sentence Sentence to be processed
          */
		void ProcessSentence(Corpus::CSentence* sentence);

		/**
          * Function initializing instance. Cleaning all previous data and filling it with current
          */
		void Initalize();


		/**
          * Function checking if column operator should be run in current sentence
          * \param sentence Sentence processed
          * \param relevantRows Output with relevant matrix rows
          * \param relevantColumns Output with relevan matrix columns
          */
		void CheckSentence(Corpus::CSentence * &sentence,
				   std::map<size_t, size_t> &relevantRows,
				   std::map<size_t, size_t> &relevantColumns);

		/**
          * Function checking which lexical units can possibly occure in current sentence
          * \param sentence Sentence to be checked
          * \param relevantLUs Target set for possibly relevant lexical units
          */
		void FindAllOccurrences(Corpus::CSentence *sentence,
					std::set<size_t> &relevantLUs);

		/**
          * Function finds all positions where column operator should be run
          * \param sentence Sentence checked
          * \param relevantLUs Output with lexical units
          * \param foundLUs Output with triplets
          */
		void FindAllPotentialForPosition(Corpus::CSentence *sentence,
						 std::set<size_t> & relevantLUs, std::vector< Triplets> &foundLUs);

		/**
          * Function checking for each relevant lexical unit and inserting it to maps for further processing
          * \param pos Position in sentence
          * \param relevantRows Output with relevant rows
          * \param relevantColumns Output with relevant columns
          * \param t Output triplet
          * \param foundLUs Output with found lexical units
          * \param lu Chosen lexical unit
          * \returns Whether lexical unit was chosen or not
          */
		bool ChooseLU(int pos, std::map<size_t, size_t> &relevantRows,
			      std::map<size_t, size_t> &relevantColumns, Triplets &t,
			      std::vector< Triplets> &foundLUs, LexicalUnits::LexicalUnitPtr &lu);



		/**
          * Function checking which operators should be run on sentence, running it and inserting new value to matrix if needed
          * \param sentence Sentence being processed
          * \param relevantRows Previously chosen relevant rows
          * \param relevantColumns Previously chosen relevant columns
          */
		void CheckConditions(Corpus::CSentence * &sentence,
				     std::map<size_t, size_t> &relevantRows,
				     std::map<size_t, size_t> &relevantColumns);

		Matrices::CCSMatrixPtr m_pMatrix;
		std::map<size_t, size_t> m_mUnit2Row;
		std::map<size_t, size_t> m_mUnit2Column;
		std::multimap<int, size_t> m_mBase2PotentialUnit;

		size_t m_stTokenCount;
		size_t m_stLexicalUnitCount;
		int corpusSize;

	};
}//namespace architect

#endif //ARCH2_ARCHITECT_H
