/*
 * StringDiff.h
 *
 *  Created on: Apr 4, 2017
 *      Author: Tomas Pecka
 */

#ifndef STRING_DIFF_H_
#define STRING_DIFF_H_

#include <compare/DiffAux.h>
#include <compare/StringCompare.h>

#include <alib/utility>
#include <alib/vector>
#include <ostream>

#include "string/CyclicString.h"
#include "string/LinearString.h"

namespace compare {

class StringDiff {
private:
	template < class SymbolType >
	static void printDiff ( const string::LinearString < SymbolType > & a, const string::LinearString < SymbolType > & b, std::ostream & out );

	template < class SymbolType >
	static void printDiff ( const string::CyclicString < SymbolType > & a, const string::CyclicString < SymbolType > & b, std::ostream & out );

public:
	template<class T>
	static void diff(const T & a, const T & b, std::ostream & out );

	template < class T >
	static std::string diff ( const T & a, const T & b );
};

template < class SymbolType >
void StringDiff::printDiff ( const string::CyclicString < SymbolType > &, const string::CyclicString < SymbolType > &, std::ostream & ) {
	throw "NYI";
}

template < class SymbolType >
void StringDiff::printDiff ( const string::LinearString < SymbolType > & a, const string::LinearString < SymbolType > & b, std::ostream & out ) {
	out << "StringsComparer" << std::endl;

	if ( a.getAlphabet ( ) != b.getAlphabet ( ) ) {
		out << "Alphabet" << std::endl;

		DiffAux::setDiff ( out, a.getAlphabet ( ), b.getAlphabet ( ) );
	}

	if ( a.getContent ( ) != b.getContent ( ) ) {
		out << "Content" << std::endl;

		DiffAux::vectorDiff ( out, a.getContent ( ), b.getContent ( ) );
	}
}

template < class T >
void StringDiff::diff ( const T & a, const T & b, std::ostream & out ) {
	if ( !StringCompare::compare ( a, b ) ) {
		StringDiff::printDiff ( a, b, out );
	}
}

template < class T >
std::string StringDiff::diff ( const T & a, const T & b ) {
	std::stringstream ss;
	diff ( a, b, ss );
	return ss.str ( );
}

} /* namespace compare */

#endif /* STRING_DIFF_H_ */
