/** @file context.h
 *
 *	Declaration of module designed to ease storage of N-grams context.
 *
 *	(C) Ceslav Przywara 2008, MFF UK Prague
 *
 */

#ifndef _CONTEXT_H
#define _CONTEXT_H

#include <vector>

// Some base datatypes.
#include "config.h"

namespace ace {

/**	Definition of type used for context frequency counter.
 */
typedef unsigned int context_frequency_t;

#if defined(_MSC_VER) || defined(__GNUC__)
// Save default pack value.
#pragma pack(push)
// Pack following structure data on 2 bytes data boundary.
#pragma pack(2)
#endif

/** Part of context is smallest unit used for context tracing functionality.
 *	It holds data for any word founded within context (in general):
 *	1. word lemma
 *	2. word morphologic tag
 *	3. word frequency
 */
class PartOfContext {
	/**
	 */
	static const context_frequency_t _max_frequency;
	/**
	 */
	static const context_frequency_t _narrow_flag_bitmask;
	/** Word frequency.
	 */
	context_frequency_t _frequency; // 4 bytes
	/** Word lemma and tag altogether.
	 */
	TaggedLemma _tagged_lemma; // 4 bytes	
public:
	/** Constructor needs to know lemma and morphologic tag.
	 *	It also set frequency counter to 1.
	 *	@param lemma Word lemma.
	 *	@param tag Word morphologic tag.
	 *	@param narrow If true -> part of narrow context, if false -> part of wide one.
	 */
	PartOfContext(string_index_t lemma, tag_index_t tag, bool narrow = false):  _frequency(1), _tagged_lemma(lemma, tag) {
		if ( narrow ) {
			_frequency |= _narrow_flag_bitmask;
		}
	}
	/** Two contexts are equal if they are binded to the same lemma and tag.
	 *	@param rhs Part of context to compare.
	 *	@return True, if given context is equal to self.
	 */
	inline bool operator==(const PartOfContext& rhs) const {
		return (lemma() == rhs.lemma()) && (tag() == rhs.tag())
			&& (
				((_frequency ^ rhs._frequency) // If MSB is the same, would be zero now...
					& _narrow_flag_bitmask) // ...all non MSB bits will now be zero too.
					== 0); // So.
	}
	/** @return Frequency of given part of context.
	 */
	inline context_frequency_t frequency(void) const { return _frequency & _max_frequency; }
	/** Increment frequency counter.
	 *	@throw context_part_frequency_index_overflow In case of frequency counter overflow.
	 */
	void inc(void);
	/** @return True, if given word is part of narrow context.
	 */
	inline bool is_part_of_narrow(void) const { return (_frequency & _narrow_flag_bitmask) > 0; }
	/** @return True, if given word is part of wide context.
	 */
	inline bool is_part_of_wide(void) const { return (_frequency & _narrow_flag_bitmask) == 0; }
	/** @return Word lemma of given part of context.
	 */
	inline string_index_t lemma(void) const { return _tagged_lemma.lemma(); }
	/** @return Morphologic tag of given part of context.
	 */
	inline tag_index_t tag(void) const { return _tagged_lemma.tag(); }
};

#if defined(_MSC_VER) || defined(__GNUC__)
// Restore default pack value.
#pragma pack(pop)
#endif

/** Full context is made out from parts of context.
 */
typedef std::vector<PartOfContext> context_t;

} // namespace ace

#endif
