/*
 * ExactCompare.h
 *
 *  Created on: Oct 14, 2014
 *	  Author: Radomir Polach
 */

#ifndef EXACT_COMPARE_H_
#define EXACT_COMPARE_H_

#include <string/LinearString.h>
#include <string/CyclicString.h>

namespace string {

namespace naive {

/**
 * Implements exact comparison of string contents.
 *
 */
class ExactCompare {
public:
	/**
	 * Implementation of exact comparison of strings.
	 *
	 * \tparam SymbolType the of symbols in the string
	 *
	 * \param u the first string to compare
	 * \param v the second string to compare
	 *
	 * \return negative value if u compares smaller than v, positive value if u compares bigger than v, zero if u and v are equal
	 */
	template < class SymbolType >
	static int compare(const string::LinearString < SymbolType >& u, const string::LinearString < SymbolType >& v);

	/**
	 * Implementation of exact comparison of strings. The algorithm also handles rotated strings.
	 *
	 * \tparam SymbolType the of symbols in the string
	 *
	 * \param u the first string to compare
	 * \param v the second string to compare
	 *
	 * \return negative value if u compares smaller than v, positive value if u compares bigger than v, zero if u and v are equal
	 */
	template < class SymbolType >
	static int compare(const string::CyclicString < SymbolType >& u, const string::CyclicString < SymbolType >& v);
};

template < class SymbolType >
int ExactCompare::compare ( const string::LinearString < SymbolType > & u, const string::LinearString < SymbolType > & v ) {
	int n = ( int ) u.getContent ( ).size ( );
	int m = ( int ) v.getContent ( ).size ( );
	int k = 0;

	while ( k < n && k < m && u.getContent ( )[k] == v.getContent ( )[k] ) k++;

	if ( ( k == m ) && ( k == n ) )
		return 0;
	else if ( k == m )
		return -1;
	else if ( k == n )
		return 1;
	else if ( u.getContent ( )[k] < v.getContent ( )[k] )
		return -1;
	else
		return 1;
}

template < class SymbolType >
int ExactCompare::compare ( const string::CyclicString < SymbolType > & u, const string::CyclicString < SymbolType > & v ) {
	int n = ( int ) u.getContent ( ).size ( );
	int m = ( int ) v.getContent ( ).size ( );
	int i = -1;
	int j = -1;
	int k;

	bool last = false;

	while ( i < n - 1 && j < m - 1 ) {
		k = 1;

		while ( k <= n && u.getContent ( )[( i + k ) % n] == v.getContent ( )[( j + k ) % m] ) k++;

		if ( k > n ) return 0;

		last = u.getContent ( )[( i + k ) % n] > v.getContent ( )[( j + k ) % m];

		if ( last )
			i += k;
		else
			j += k;
	}

	return last ? 1 : -1;
}

} /* namespace naive */

} /* namespace string */

#endif /* EXACT_COMPARE_H_ */
