/*
    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 ARCH2HAL_ARCHITECT_H
#define ARCH2HAL_ARCHITECT_H
#include "arch_headers.h"
#include "LexicalUnit.h"

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

	};


	class Architect
	{
	public:
		/**
		  * Constructor
		  */
		Architect();
		/**
		  * Function initializing output matrix along with lexical units for computing
		  */
		void Initalize();
		/**
		  * Function starting processing of given corpus
		  */
		void Start(int corpusNo);
		/**
		  * Function retrieving result matrix
		  */
		Matrices::CRSMatrixPtr getMatrix();
		/**
		  * Function returning corpus size counted as number of tokens processed
		  */
		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* TransformSenetenceOnCurrentPosiotion ( Corpus::CSentence* old, Triplets &t, size_t
																  &removedBeforeCurrentPos, LexicalUnits::LexicalUnitPtr lu );
		/**
		  * Function processing given corpus
		  */
		void ProcessBinaryCorpus(int corpusNo);
		/**
		  * Function processing corpus sentence by sentence
		  */
		void ProcessBinaryCorpusBySentence(int corpusNo);
		/**
		  * Function processing corpus token by token (window case)
		  */
		void ProcessBinaryCorpusByToken(int corpusNo);
		/**
		  * Function processing given sentence
		  */
		void ProcessSentence ( Corpus::CSentence* sentence );
		/**
		  * Function flattening document - putting all it's tokens to a single vector
		  */
		std::vector<Corpus::CToken*> FlattenDocument(std::vector< boost::shared_ptr<Corpus::CSentence> > * pSentences);

		/**
		  * 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 running proper function for counting coocurrences (based on switch)
		  */
		void CountCoocurrences( Corpus::CSentence * &sentence, std::map<size_t, size_t>  &relevantRows,
								std::map<size_t, size_t> &relevantColumns );
		/**
		  * Function counting coocurrences in sentence case
		  */
		void CountCoocurrencesEveryWithEvery( Corpus::CSentence * &sentence, std::map<size_t, size_t>  &relevantRows,
											  std::map<size_t, size_t> &relevantColumns );
		/**
		  * Function counting coocurrences in window case
		  */
		void CountCoocurrencesForWindowCenter( Corpus::CSentence * &sentence, std::map<size_t, size_t>  &relevantRows,
											   std::map<size_t, size_t> &relevantColumns );
		/**
		  * Function counting coocurrences in hal case (not implemented yet)
		  */
		void CountCoocurrencesForHALWindow( Corpus::CSentence * &sentence, std::map<size_t, size_t>  &relevantRows,
											std::map<size_t, size_t> &relevantColumns );

		Matrices::CRSMatrixPtr 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;

		double (*m_pDistFunct)(size_t, size_t, size_t);
		int corpusSize;
	};

	double DistanceOne(size_t, size_t, size_t);
	double DistanceLog(size_t dist, size_t winLeft, size_t winRight);
	double DistanceLen(size_t dist, size_t winLeft, size_t winRight);
	double DistanceRevLog(size_t dist, size_t winLeft, size_t winRight);
}//namespace architect

#endif //ARCH2_ARCHITECT_H

