#include "String_Utilities.h"

// Author: Steve Talbot

/*
 * utility functions ..
 */

bool setBoolean( int intVersion ){

	bool returnBoolean = false;

	if( intVersion > 0 ){

		returnBoolean = true;

	}

	return returnBoolean;

}


bool isEven( int number ){

	int result = ( number % 2 );

	if ( result > 0 ) {

		return false;

	} else {

		return true;

	}

} // end "isEven( int number )" ..


bool isOdd( int number ){

	int result = ( number % 2 );

	if ( result > 0 ) {

		return true;

	} else {

		return false;

	}

} // end "isOdd( int number )" ..


bool isInteger( char* value ){

	// DEBUGGING ..
	//cout << "value: " << value << endl;

	string stringValue = value;

	bool isDigit = false;

	int startIndex = 0;

	if ( ( (char&)stringValue.at( 0 ) == '-' ) ||
	     ( (char&)stringValue.at( 0 ) == '+' ) ){

		startIndex = 1;

	}

	for(int i=startIndex; i < stringValue.size(); i++){

		isDigit = setBoolean( isdigit( stringValue.at( i ) ) );

		if ( !isDigit ) {

			// if there are any chars that are not digits,
			// this string is not an integer ..
			isDigit = false;
			break;

		}

	}

	return isDigit;

}  // end "isInteger( char* value )" ..


bool isFloat( char* value ){

	string stringValue = value;

	bool isFloat = false;

	bool isPunct = false;

	int periodCounter = 0;

	int startIndex = 0;

	if ( ( (char&)stringValue.at( 0 ) == '-' ) ||
	     ( (char&)stringValue.at( 0 ) == '+' ) ){

		startIndex = 1;

	}

	for(int i=startIndex; i < stringValue.size(); i++){

		isFloat = setBoolean( isdigit( stringValue.at( i ) ) );

		if ( !isFloat ) {

			isPunct = setBoolean( ispunct( stringValue.at( i ) ) );

			if ( isPunct ) {

				if ( stringValue.at( i ) == '.' ){

					isFloat = true;
					periodCounter++;

				} else {

					// punctuation marks besides a "." indicate that
					// this string is not a float ..
					isFloat = false;
					break;

				}

			} else {

				// if there are any chars that are not digits (excluding a single period),
				// this string is not a float ..
				isFloat = false;
				break;

			}

		}

		if ( periodCounter > 1 ){

			// there should be at most a single ".",
			// if there is more, its not a float, so don't bother checking the rest of the string ..
			isFloat = false;
			break;

		}


	} // end "for()" ..


	if ( periodCounter == 0 ){

		// there should be at least a single ".",
		// if there is none, its not a float ..
		isFloat = false;

	}


	return isFloat;


}  // end "isFloat( char* value )" ..


bool isAlphabetic( char* value ){

	string stringValue = value;

	bool isAlpha = true;

	bool isAlphabetic = true;

	for(int i=0; i < stringValue.size(); i++){

		isAlpha = setBoolean( isalpha( stringValue.at( i ) ) );

		if ( !isAlpha ) {

			// if there are any characters in the string that are
			// non-alphabetic, set the flag and quit the loop ..
			isAlphabetic = false;
			break;

		}

	}

	return isAlphabetic;

}  // end "isAlphabetic( char* value )" ..


bool isNumeric( char* value ){

	string stringValue = value;

	bool isDigit = false;

	bool isPunct = false;

	bool isNumeric = true;

	int periodCounter = 0;

	int startIndex = 0;

	if ( ( (char&)stringValue.at( 0 ) == '-' ) ||
	     ( (char&)stringValue.at( 0 ) == '+' ) ){

		startIndex = 1;

	}

	for(int i=startIndex; i < stringValue.size(); i++){

		isDigit = setBoolean( isdigit( stringValue.at( i ) ) );

		isPunct = setBoolean( ispunct( stringValue.at( i ) ) );

		if ( isPunct ){

			// found some kind of punction .. looking for "periods" ..

			if ( stringValue.at( i ) == '.' ){

				periodCounter++;

			} else {

				// found non-"period" punction .. this is an error ..
				isNumeric = false;
				break;

			}

		}

		if ( periodCounter > 1 ){

			// there should be at most a single ".",
			// if there is more, its not alphanumeric,
			// so don't bother checking the rest of the string ..
			isNumeric = false;
			break;

		}

		if ( !isDigit ) {

			// if there are any chars that are not either digits or alphabetic,
			// this string is not alphanumeric ..
			isNumeric = false;
			break;

		}

	}

	return isNumeric;

}  // end "isNumeric( char* value )" ..


bool isAlphanumeric( char* value ){

	string stringValue = value;

	bool isDigit = false;

	bool isAlpha = false;

	bool isPunct = false;

	bool isAlphanumeric = true;

	int periodCounter = 0;

	int startIndex = 0;

	if ( ( (char&)stringValue.at( 0 ) == '-' ) ||
	     ( (char&)stringValue.at( 0 ) == '+' ) ){

		startIndex = 1;

	}

	for(int i=startIndex; i < stringValue.size(); i++){

		isDigit = setBoolean( isdigit( stringValue.at( i ) ) );

		isAlpha = setBoolean( isalpha( stringValue.at( i ) ) );

		isPunct = setBoolean( ispunct( stringValue.at( i ) ) );

		if ( isPunct ){

			if ( stringValue.at( i ) == '.' ){

				periodCounter++;

			} else {

				// found non-"period" punction .. this is an error ..
				isAlphanumeric = false;
				break;

			}

		}

		if ( periodCounter > 1 ){

			// there should be at most a single ".",
			// if there is more, its not alphanumeric,
			// so don't bother checking the rest of the string ..
			isAlphanumeric = false;
			break;

		}

		//if ( !isDigit && !isAlpha && !isPunct ) {
		if ( !isDigit && !isAlpha ) {

			// if there are any chars that are not either digits or alphabetic,
			// this string is not alphanumeric ..
			isAlphanumeric = false;
			break;

		}

	}

	return isAlphanumeric;

}  // end "isAlphanumeric( char* value )" ..


int strToInt( string stringValue ) {

	int returnInteger = 0;

	// make sure that the string to convert is an integer ..
	if ( isInteger( (char*) stringValue.c_str() ) ){

		returnInteger = atoi( stringValue.c_str() );

	} else {

		// return value "-1" indicates that the input was not an integer;
		// if "stringValue" was equal to -1, then user should understand
		// that the return value in this case does not indicate failure ..

		return -1;

	}

	return returnInteger;

} // end "strToInt( string stringValue )" ..


float strToFloat( string stringValue ) {

	float returnFloat = 0;

	// make sure that the string to convert is an integer ..
	if ( isFloat( (char*) stringValue.c_str() ) ){

		returnFloat = (float) atof( stringValue.c_str() );

	} else {

		// return value "-1" indicates that the input was not a float;
		// if "stringValue" was equal to -1, then user should understand
		// that the return value in this case does not indicate failure ..

		return -1;

	}

	return returnFloat;

} // end "strToFloat( string stringValue )" ..


double strToDouble( string stringValue ) {

	double returnDouble = 0;

	// make sure that the string to convert is an integer ..
	if ( isFloat( (char*) stringValue.c_str() ) ){

		returnDouble = (double) atof( stringValue.c_str() );

	} else {

		// return value "-1" indicates that the input was not a double;
		// if "stringValue" was equal to -1, then user should understand
		// that the return value in this case does not indicate failure ..

		return -1;

	}

	return returnDouble;

} // end "strToDouble( string stringValue )" ..


string intToStr( int integerValue ) {

	// these don't seem to work:
	//char* cstring = ((char*) integerValue);
	//string returnString = reinterpret_cast<string>( &integerValue );
	//string returnString = static_cast<char*>( integerValue );
	//string returnString( ((char*)integerValue) );
	//char* returnString = sprintf("%d", integerValue);

	// this works ..
	ostringstream ost;

	ost << integerValue;

	string returnString = ost.str();

	return returnString;

}  // end "intToStr( int integerValue )" ..


string floatToStr( float floatValue ) {

	// these don't seem to work:
	//char* cstring = ((char*) floatValue);
	//string returnString = reinterpret_cast<string>( &floatValue );
	//string returnString = static_cast<char*>( floatValue );
	//string returnString( ((char*)floatValue) );
	//char* returnString = sprintf("%f", floatValue);

	// this works ..
	ostringstream ost;

	ost << floatValue;

	string returnString = ost.str();

	return returnString;

} // end "floatToStr( float floatValue )" ..


string doubleToStr( double doubleValue ) {

	// these don't seem to work:
	//char* cstring = ((char*) floatValue);
	//string returnString = reinterpret_cast<string>( &floatValue );
	//string returnString = static_cast<char*>( floatValue );
	//string returnString( ((char*)floatValue) );
	//char* returnString = sprintf("%f", floatValue);

	// this works ..
	ostringstream ost;

	ost << doubleValue;

	string returnString = ost.str();

	return returnString;

} // end "doubleToStr( float doubleValue )" ..


void printStr( string str ) {

	for(int i=0; i<str.size(); i++){

		cout << str.at(i);

	}


} // end "printString( string str )" ..

string stringToUpper( std::string str ){

	string upperString;

	char charInStringToUpper;

	for(int i=0; i<str.size(); i++){

		charInStringToUpper = toupper( str.at(i) );

		upperString += charInStringToUpper;

	}

	return upperString;

} // end "printString( string str )" ..


string stringToLower( std::string str ){

	string lowerString;

	char charInStringToLower;

	for(int i=0; i<str.size(); i++){

		charInStringToLower = tolower( str.at(i) );

		lowerString += charInStringToLower;

	}

	return lowerString;

} // end "printString( string str )" ..


void updateMaxStringLength( string newTestString, int& maxStringLength ){

	// if "newTestString > maxStringLength",
	// update "maxStringLength" to be equal to the new length ..

	int newTestStringlength = newTestString.size();

	if ( newTestStringlength > maxStringLength ) {

		maxStringLength = newTestStringlength;

	}

} // end "updateMaxStringLength()" ..


vector<char*> getInputStringTokens( string inputString, const char* delimiters ){

	char* inputStringToken;

	vector<char*> tokens;

	int tokenCounter = 0;

	inputStringToken = strtok( (char*) inputString.c_str(), delimiters );

	tokens.push_back( inputStringToken );

	tokenCounter++;

	do {

		inputStringToken = strtok( NULL, delimiters  );

		if ( inputStringToken != NULL ) {

			tokens.push_back( inputStringToken );

			tokenCounter++;

		}

	} while( inputStringToken != NULL );


	// DEBUGGING ..
	//for(int i=0; i<tokens.size(); i++){
		//cout << tokens[i] << endl;
	//}


	return tokens;


} // end "getInputStringTokens( string inputString )" ..


float getDivisionRemainderFraction( float numerator, float denominator ){

	// return the fraction portion of "dividend_float" ..
	string dividend = "";

	float dividend_float = ( numerator / denominator );

	dividend = floatToStr( dividend_float );

	// check whether the division operation has a remainder ..
	bool dividendIsFloat = isFloat( ( (char*) dividend.c_str() ) );

	float fraction = 0.0;

	if ( ( dividendIsFloat ) &&
	     ( denominator != 0 ) ) {

		// if the division operation is a float, it has a remainder,
		// so parse out the "remainder" portion of the number ..

		vector<char*> tokens = getInputStringTokens( dividend, "." );

		// "tokens" should have 2 numbers: first number is the integer,
		// second number is the remainder ..
		// "pop_back()" should get the second number ..

		string wholeIntegerString = tokens[0];

		int wholeInteger = strToInt( wholeIntegerString );

		if ( wholeInteger == 0 ) {

			// this occurs when numerator < denominator ..

			return 0.0;

		} else {

			// this occurs when numerator > denominator ..

			string fractionString = ".";

			fractionString += tokens[ ( tokens.size() - 1 ) ];

			fraction = strToFloat( fractionString );

			return fraction;

		}


	} else {

		// if its an integer, "numerator" is a multiple of "denominator"
		// so the remainder should be zero ..

		fraction = 0.0;

		return fraction;


	} // end "if ( dividendIsFloat )" ..


} // end "getDivisionFractionRemainder( int numerator, int denominator )" ..
