/*
 * BorderArrayNaive.h
 *
 *  Created on: 5. 11. 2014
 *      Author: Jan Travnicek
 */

#pragma once

#include <alib/vector>

#include <global/GlobalData.h>

#include "SubtreeJumpTable.h"

#include <tree/ranked/PrefixRankedBarNonlinearPattern.h>
#include <tree/ranked/PrefixRankedBarPattern.h>
#include <tree/ranked/PrefixRankedNonlinearPattern.h>
#include <tree/ranked/PrefixRankedPattern.h>

namespace tree {

namespace properties {

/**
 * Computation of BCS table for BMH from MI(E+\eps)-EVY course 2014
 * To get rid of zeros in BCS table we ignore last haystack character
 */
class BorderArrayNaive {
	template < class SymbolType >
	static bool matches ( const tree::PrefixRankedBarNonlinearPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset );

	template < class SymbolType >
	static bool matches ( const tree::PrefixRankedBarPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset );

	template < class SymbolType >
	static bool matches ( const tree::PrefixRankedNonlinearPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset );

	template < class SymbolType >
	static bool matches ( const tree::PrefixRankedPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset );

public:
	/**
	 * Search for pattern in linear string.
	 * @return set set of occurences
	 */
	template < class SymbolType >
	static ext::vector < size_t > construct ( const tree::PrefixRankedBarNonlinearPattern < SymbolType > & pattern );

	/**
	 * Search for pattern in linear string.
	 * @return set set of occurences
	 */
	template < class SymbolType >
	static ext::vector < size_t > construct ( const tree::PrefixRankedBarPattern < SymbolType > & pattern );

	/**
	 * Search for pattern in linear string.
	 * @return set set of occurences
	 */
	template < class SymbolType >
	static ext::vector < size_t > construct ( const tree::PrefixRankedNonlinearPattern < SymbolType > & pattern );

	/**
	 * Search for pattern in linear string.
	 * @return set set of occurences
	 */
	template < class SymbolType >
	static ext::vector < size_t > construct ( const tree::PrefixRankedPattern < SymbolType > & pattern );

};

template < class SymbolType >
bool BorderArrayNaive::matches ( const tree::PrefixRankedBarNonlinearPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset ) {
	unsigned i = 0;

	while ( offset < stop && i < pattern.getContent ( ).size ( ) )
		if ( pattern.getContent ( )[i] == pattern.getContent ( )[offset] ) {
			i++;
			offset++;
		} else if ( ( pattern.getContent ( )[i] == pattern.getSubtreeWildcard ( ) ) || ( pattern.getNonlinearVariables ( ).count ( pattern.getContent ( ) [ i ] ) )
			 || ( pattern.getContent ( )[offset] == pattern.getSubtreeWildcard ( ) ) || ( pattern.getNonlinearVariables ( ).count ( pattern.getContent ( ) [ offset ] ) ) ) {
			i = subtreeJumpTable[i];
			offset = subtreeJumpTable[offset];
		} else {
			return false;
		}

	return true;
}

template < class SymbolType >
ext::vector < size_t > BorderArrayNaive::construct ( const tree::PrefixRankedBarNonlinearPattern < SymbolType > & pattern ) {
	ext::vector < int > patternSubtreeJumpTable = SubtreeJumpTable::compute ( pattern );
	ext::vector < size_t > res;

	for ( size_t i = 0; i <= pattern.getContent ( ).size ( ); i++ )
		res.push_back ( 0 );

	res[0] = -1;

	for ( size_t i = 1; i <= pattern.getContent ( ).size ( ); i++ ) {
		size_t min = i;

		for ( size_t j = 1; j < i; j++ )
			if ( matches ( pattern, patternSubtreeJumpTable, i, j ) ) {
				min = j;
				break;
			}

		res[i] = i - min;
	}

/*	if ( common::GlobalData::verbose )
		common::Streams::log << res << std::endl;*/

	return res;
}

template < class SymbolType >
bool BorderArrayNaive::matches ( const tree::PrefixRankedBarPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset ) {
	unsigned i = 0;

	while ( offset < stop && i < pattern.getContent ( ).size ( ) )
		if ( pattern.getContent ( )[i] == pattern.getContent ( )[offset] ) {
			i++;
			offset++;
		} else if ( ( pattern.getContent ( )[i] == pattern.getSubtreeWildcard ( ) ) || ( pattern.getContent ( )[offset] == pattern.getSubtreeWildcard ( ) ) ) {
			i = subtreeJumpTable[i];
			offset = subtreeJumpTable[offset];
		} else {
			return false;
		}

	return true;
}

template < class SymbolType >
ext::vector < size_t > BorderArrayNaive::construct ( const tree::PrefixRankedBarPattern < SymbolType > & pattern ) {
	ext::vector < int > patternSubtreeJumpTable = SubtreeJumpTable::compute ( pattern );
	ext::vector < size_t > res;

	for ( size_t i = 0; i <= pattern.getContent ( ).size ( ); i++ )
		res.push_back ( 0 );

	res[0] = -1;

	for ( size_t i = 1; i <= pattern.getContent ( ).size ( ); i++ ) {
		size_t min = i;

		for ( size_t j = 1; j < i; j++ )
			if ( matches ( pattern, patternSubtreeJumpTable, i, j ) ) {
				min = j;
				break;
			}

		res[i] = i - min;
	}

/*	if ( common::GlobalData::verbose )
		common::Streams::log << res << std::endl;*/

	return res;
}

template < class SymbolType >
bool BorderArrayNaive::matches ( const tree::PrefixRankedNonlinearPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset ) {
	size_t i = 0;

	while ( offset < stop && i < pattern.getContent ( ).size ( ) )
		if ( pattern.getContent ( )[i] == pattern.getContent ( )[offset] ) {
			i++;
			offset++;
		} else if ( ( pattern.getContent ( )[i] == pattern.getSubtreeWildcard ( ) ) || ( pattern.getNonlinearVariables ( ).count ( pattern.getContent ( ) [ i ] ) )
			 || ( pattern.getContent ( )[offset] == pattern.getSubtreeWildcard ( ) ) || ( pattern.getNonlinearVariables ( ).count ( pattern.getContent ( ) [ offset ] ) ) ) {
			i = subtreeJumpTable[i];
			offset = subtreeJumpTable[offset];
		} else {
			return false;
		}

	return true;
}

template < class SymbolType >
ext::vector < size_t > BorderArrayNaive::construct ( const tree::PrefixRankedNonlinearPattern < SymbolType > & pattern ) {
	ext::vector < int > patternSubtreeJumpTable = SubtreeJumpTable::compute ( pattern );
	ext::vector < size_t > res;

	for ( size_t i = 0; i <= pattern.getContent ( ).size ( ); i++ )
		res.push_back ( 0 );

	res[0] = -1;

	for ( size_t i = 1; i <= pattern.getContent ( ).size ( ); i++ ) {
		size_t min = i;

		for ( size_t j = 1; j < i; j++ )
			if ( matches ( pattern, patternSubtreeJumpTable, i, j ) ) {
				min = j;
				break;
			}

		res[i] = i - min;
	}

	if ( common::GlobalData::verbose )
		common::Streams::log << res << std::endl;

	return res;
}

template < class SymbolType >
bool BorderArrayNaive::matches ( const tree::PrefixRankedPattern < SymbolType > & pattern, const ext::vector < int > & subtreeJumpTable, int stop, int offset ) {
	size_t i = 0;

	while ( offset < stop && i < pattern.getContent ( ).size ( ) )
		if ( pattern.getContent ( )[i] == pattern.getContent ( )[offset] ) {
			i++;
			offset++;
		} else if ( ( pattern.getContent ( )[i] == pattern.getSubtreeWildcard ( ) ) || ( pattern.getContent ( )[offset] == pattern.getSubtreeWildcard ( ) ) ) {
			i = subtreeJumpTable[i];
			offset = subtreeJumpTable[offset];
		} else {
			return false;
		}

	return true;
}

template < class SymbolType >
ext::vector < size_t > BorderArrayNaive::construct ( const tree::PrefixRankedPattern < SymbolType > & pattern ) {
	ext::vector < int > patternSubtreeJumpTable = SubtreeJumpTable::compute ( pattern );
	ext::vector < size_t > res;

	for ( size_t i = 0; i <= pattern.getContent ( ).size ( ); i++ )
		res.push_back ( 0 );

	res[0] = -1;

	for ( size_t i = 1; i <= pattern.getContent ( ).size ( ); i++ ) {
		size_t min = i;

		for ( size_t j = 1; j < i; j++ )
			if ( matches ( pattern, patternSubtreeJumpTable, i, j ) ) {
				min = j;
				break;
			}

		res[i] = i - min;
	}

	if ( common::GlobalData::verbose )
		common::Streams::log << res << std::endl;

	return res;
}

} /* namespace properties */

} /* namespace tree */

