#ifndef	_T_TEST_TRAITS_H
#define	_T_TEST_TRAITS_H

// First thing we always do is include the ANTLR3 generated files, which
// will automatically include the antlr3 runtime header files.
// The compiler must use -I (or set the project settings in VS2005)
// to locate the antlr3 runtime files and -I. to find this file
#include <antlr3.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <fstream>
#include <iostream>
#include <sstream>

// Forward declaration for Lexer&Parser class(es)
namespace Antlr3Test {
	class PLSQLLexer;
	class PLSQLParser;

	typedef antlr3::Traits<PLSQLLexer, PLSQLParser> PLSQLTraits;
	typedef PLSQLTraits PLSQLLexerTraits;
	typedef PLSQLTraits PLSQLParserTraits;
	typedef PLSQLTraits PLSQLParser_PLSQLKeysTraits;
	typedef PLSQLTraits PLSQLParser_PLSQLCommonsTraits;
	typedef PLSQLTraits PLSQLParser_PLSQL_DMLParserTraits;
	typedef PLSQLTraits PLSQLParser_SQLPLUSParserTraits;
	typedef PLSQLTraits PLSQLParser_PLSQL_DMLParser_PLSQLKeysTraits;
	typedef PLSQLTraits PLSQLParser_PLSQL_DMLParser_PLSQLCommonsTraits;

	//template<class StringType>
	inline bool equalsIgnoreCase(PLSQLTraits::StringType const& s1, const char* s2)
	{
		// return !strcasecmp(s1.c_str(), s2);
		// StringType s1U(s1);
		// std::transform(s1U.begin(), s1U.end(), s1U.begin(), ::toupper);
		// return s1U == s2;
		PLSQLTraits::StringType ST2(s2);
		return boost::iequals(s1, ST2);
	}

  	template<class CommonTokenType>
	inline bool isTableAlias(CommonTokenType *LT1, CommonTokenType *LT2) {
		static const std::string wPARTITION("PARTITION");
		static const std::string wBY("BY");
		static const std::string wCROSS("CROSS");
		static const std::string wNATURAL("NATURAL");
		static const std::string wINNER("INNER");
		static const std::string wJOIN("JOIN");
		static const std::string wFULL("FULL");
		static const std::string wLEFT("LEFT");
		static const std::string wRIGHT("RIGHT");
		static const std::string wOUTER("OUTER");

		PLSQLTraits::StringType lt1 = LT1->getText();
		PLSQLTraits::StringType lt2 = "";
		//std::transform(lt1.begin(), lt1.end(), lt1.begin(), ::toupper);
        
		if ( LT2 && LT2->getText() != ""){
			lt2 = LT2->getText();
			std::transform(lt2.begin(), lt2.end(), lt2.begin(), ::toupper); 
		}
		
		if ( (boost::iequals(lt1, wPARTITION) && boost::iequals(lt2, wBY))
		     || boost::iequals(lt1, wCROSS)
		     || boost::iequals(lt1, wNATURAL)
		     || boost::iequals(lt1, wINNER)
		     || boost::iequals(lt1, wJOIN)
		     || ( ( boost::iequals(lt1, wFULL) || boost::iequals(lt1, wLEFT) || boost::iequals(lt1, wRIGHT) ) && ( boost::iequals(lt2, wOUTER) || boost::iequals(lt2, wJOIN) ) )
		     )
		{
			return false;
		}
		return true;
	}

  	template<class StringType>
	inline bool isStandardPredictionFunction(StringType const& originalFunctionName) {
		static const std::string wPREDICTION("PREDICTION");
		static const std::string wPREDICTION_BOUNDS("PREDICTION_BOUNDS");
		static const std::string wPREDICTION_COST("PREDICTION_COST");
		static const std::string wPREDICTION_DETAILS("PREDICTION_DETAILS");
		static const std::string wPREDICTION_PROBABILITY("PREDICTION_PROBABILITY");
		static const std::string wPREDICTION_SET("PREDICTION_SET");		
		// StringType  functionName = originalFunctionName;
		// std::transform(functionName.begin(), functionName.end(), functionName.begin(), ::toupper);
		
		if ( boost::iequals(originalFunctionName, wPREDICTION)
		     || boost::iequals(originalFunctionName, wPREDICTION_BOUNDS)
		     || boost::iequals(originalFunctionName, wPREDICTION_COST)
		     || boost::iequals(originalFunctionName, wPREDICTION_DETAILS)
		     || boost::iequals(originalFunctionName, wPREDICTION_PROBABILITY)
		     || boost::iequals(originalFunctionName, wPREDICTION_SET)
			)
		{
			return true;
		}
		return false;
	}

	template<class StringType>     
	inline bool enablesWithinOrOverClause(StringType const& originalFunctionName) {
		static const std::string wCUME_DIST("CUME_DIST");
		static const std::string wDENSE_RANK("DENSE_RANK");
		static const std::string wLISTAGG("LISTAGG");
		static const std::string wPERCENT_RANK("PERCENT_RANK");
		static const std::string wPERCENTILE_CONT("PERCENTILE_CONT");
		static const std::string wPERCENTILE_DISC("PERCENTILE_DISC");
		static const std::string wRANK("RANK");		
		// StringType functionName = originalFunctionName;
		// std::transform(functionName.begin(), functionName.end(), functionName.begin(), ::toupper);
		
		if ( boost::iequals(originalFunctionName, wCUME_DIST)
		     || boost::iequals(originalFunctionName, wDENSE_RANK)
		     || boost::iequals(originalFunctionName, wLISTAGG)
		     || boost::iequals(originalFunctionName, wPERCENT_RANK)
		     || boost::iequals(originalFunctionName, wPERCENTILE_CONT)
		     || boost::iequals(originalFunctionName, wPERCENTILE_DISC)
		     || boost::iequals(originalFunctionName, wRANK)
			)
		{
			return true;
		}
		return false;
	}

	template<class StringType>          
	inline bool enablesUsingClause(StringType const& originalFunctionName) {
		static const std::string wCLUSTER("CLUSTER_");
		static const std::string wFEATURE("FEATURE_");		
		// StringType functionName = originalFunctionName;
		// std::transform(functionName.begin(), functionName.end(), functionName.begin(), ::toupper);
		
		if ( boost::algorithm::istarts_with(originalFunctionName, wCLUSTER)
		     || boost::algorithm::istarts_with(originalFunctionName, wFEATURE)
			)
		{
			return true;
		}
		return false;
	}

	//template<class StringType>     
	inline bool enablesOverClause(PLSQLTraits::StringType const& originalFunctionName) {
		static const std::string wREGR("REGR_");
		static const std::string wSTDDEV("STDDEV");
		static const std::string wVAR("VAR_");
		static const std::string wCOVAR("COVAR_");		
		static const std::string wAVG("AVG");
		static const std::string wCORR("CORR");
		static const std::string wLAG("LAG");
		static const std::string wLEAD("LEAD");
		static const std::string wMAX ("MAX");
		static const std::string wMEDIAN("MEDIAN");
		static const std::string wMIN("MIN");
		static const std::string wNTILE("NTILE");
		static const std::string wRATIO_TO_REPORT("RATIO_TO_REPORT");
		static const std::string wROW_NUMBER("ROW_NUMBER");
		static const std::string wSUM("SUM");
		static const std::string wVARIANCE("VARIANCE");       
		// StringType functionName = originalFunctionName;
		// std::transform(functionName.begin(), functionName.end(), functionName.begin(), ::toupper);		
		
		if ( boost::iequals(originalFunctionName, wAVG)
		     || boost::iequals(originalFunctionName, wCORR)
		     || boost::iequals(originalFunctionName, wLAG)
		     || boost::iequals(originalFunctionName, wLEAD)
		     || boost::iequals(originalFunctionName, wMAX)
		     || boost::iequals(originalFunctionName, wMEDIAN)
		     || boost::iequals(originalFunctionName, wMIN)
		     || boost::iequals(originalFunctionName, wNTILE)
		     || boost::iequals(originalFunctionName, wRATIO_TO_REPORT)
		     || boost::iequals(originalFunctionName, wROW_NUMBER)
		     || boost::iequals(originalFunctionName, wSUM)
		     || boost::iequals(originalFunctionName, wVARIANCE)
		     || boost::algorithm::istarts_with(originalFunctionName, wREGR)
		     || boost::algorithm::istarts_with(originalFunctionName, wSTDDEV)
		     || boost::algorithm::istarts_with(originalFunctionName, wVAR)
		     || boost::algorithm::istarts_with(originalFunctionName, wCOVAR)
			)
		{
			return true;
		}
		return false;
	}

	inline std::string slurp(std::string const& fileName)
	{
		std::ifstream ifs(fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
		//std::ifstream::pos_type fileSize = ifs.tellg();
		ifs.seekg(0, std::ios::beg);
		std::stringstream sstr;
		sstr << ifs.rdbuf();
		return sstr.str();
	}
};

#endif
