/*  
	Names:		Maria Hristova, Ananya Misra, Megan Rutter
	Date:		May 2002
	Project:	Identifying and Correcting Common Java Programming Errors and Misconceptions for
				Introductory Computer Science Students
*/ 

#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include <string.h>
#include <vector.h>
using namespace std;

struct characterEntry 
{
	//line is the character's line number in the original code (including comments)
	char character;
	int line;
};

struct wordEntry
{
	string word;
	int line;
};

struct varkind									// MR
{
	string var;
	string kind; 
};

struct param									// MR
{
	string method;
	string paramname;
	string paramtype;
	int location;
};


char fileName[30];
vector<characterEntry> file;
vector<wordEntry> words;
string keywords[50];							// MR 
string methodNames[50][2];						// MH 
int numberMethods = 0;							// MH 
vector<varkind> variables;  					// MR 
vector<param> parameters;						// MR 

void setUpKeywords();							// MR 
void openFile();
void checkBeforeTokenize();
void tokenizeByWord();
bool isPunctuation(char);
string charToString(char);
void checkForKeywords();						// MR 
void checkMethodHeader(); 						// MR 
void specialStructures(); 						// AM 
int ifChecks(int); 								// AM 
int whileChecks(int); 							// AM 
int forChecks(int); 							// AM 
void collectMethodNames();						// MH 
void booleans();								// AM 
bool nextExpressionComparison(int);			  	// AM
void checkMethodCall();  						// MR 
void collectVariables();  						// MR 
void collectMethodDefinitionParameterTypes(); 	// MR 
void checkMethodCallParameterTypes(); 		 	// MR 
void checkParameters(); 						// MR 
bool isString(int, bool); 						// AM 
void dotEquals();								// AM 
void nonVoidMethodAsStatement();				// MH 
bool isAMethod(string);							// MH 
string returnMethodType(string);				// MH 
void nonVoidMethodWithoutReturn();				// MH 
void interfaceWithoutAllMethods();				// MH 
void incompatibleReturnTypeInvocation();		// MH
bool isAVariable(string);						// MH
string returnVariableType(string);				// MH 

void main()
{
	setUpKeywords();
	openFile();
    checkBeforeTokenize();
    characterEntry x;
    x.character = '\n'; 
    x.line = 0;
    file.push_back(x);
    tokenizeByWord();
    checkForKeywords();  
    specialStructures();  
    checkMethodHeader(); 
    collectMethodNames();	 
	booleans(); 
	checkMethodCall();  
	collectVariables();  
	checkParameters();
	dotEquals(); 
	nonVoidMethodAsStatement();
	nonVoidMethodWithoutReturn();  
	interfaceWithoutAllMethods();
	incompatibleReturnTypeInvocation();
	
	//extra part to prevent Windows application
	//from closing automatically
	char ender;
	cout << "Enter e (or anything else) to exit: ";
	cin >> ender;
}


// stores all of the keywords in an array (see checkForKeywords)
void setUpKeywords()
{
	keywords[0] = "abstract";
	keywords[1] = "boolean";
	keywords[2] = "break";
	keywords[3] = "byte";
	keywords[4] = "case";
	keywords[5] = "catch";
	keywords[6] = "char";
	keywords[7] = "class";
	keywords[8] = "const";
	keywords[9] = "continue";
	keywords[10] = "default";
	keywords[11] = "do";
	keywords[12] = "double";
	keywords[13] = "else";
	keywords[14] = "extends";
	keywords[15] = "false";
	keywords[16] = "final";
	keywords[17] = "finally";
	keywords[18] = "float";
	keywords[19] = "for";
	keywords[20] = "goto";
	keywords[21] = "if";
	keywords[22] = "implements";
	keywords[23] = "import";
	keywords[24] = "instanceof";
	keywords[25] = "int";
	keywords[26] = "interface";
	keywords[27] = "long";
	keywords[28] = "native";
	keywords[29] = "new";
	keywords[30] = "null";
	keywords[31] = "package";
	keywords[32] = "private";
	keywords[33] = "protected";
	keywords[34] = "public";
	keywords[35] = "return";
	keywords[36] = "short";
	keywords[37] = "static";
	keywords[38] = "super";
	keywords[39] = "switch";
	keywords[40] = "synchronized";
	keywords[41] = "this";
	keywords[42] = "throw";
	keywords[43] = "throws";
	keywords[44] = "transient";
	keywords[45] = "true";
	keywords[46] = "try";
	keywords[47] = "void";
	keywords[48] = "volatile";
	keywords[49] = "while";
}


//stores each character and its line number in a vector of characterEntries called "file"
//and removes all comments in the code
void openFile()
{
	ifstream fileIn;

	cout << "Please enter the name of the file: ";
	cin >> fileName;

	fileIn.open(fileName, ios::in);

    if (!fileIn)
    {
        cout << "Error in opening file. Quitting..." << endl;
        exit(1);
    }

	char c, b, one, two;
	int i = 0;
	int lineNumber = 1;
	
	//looks through file one character at a time
    while (( c = fileIn.get()) != EOF)
    {
        //checks for a /
        if (c == '/')
        {
        	b = fileIn.get();
        	//checks for next / (for // comments)
        	if (b == '/')
        	{
        		while (fileIn.get() != '\n'){
        		int fake = 49;
        		}
        		characterEntry w;
        		w.character = '\n';
        		w.line = lineNumber;
        		file.push_back(w);
        		lineNumber++;
        	}//end of if b == /
        	
        	//checks for a * (for /* ... */ comments)
        	else if (b == '*')
        	{
        		//it already has /* it checks for the following */
        		//two characters at a time
        		one = fileIn.get();
        		two = fileIn.get();
        		while (true)
        		{
        		    if (one =='\n')
        		    {
        		    	lineNumber++;
        		    }
        		    else if (one == '*')
        		    {
        		        if (two == '/')
        		        //success
        		        	break;
        		    }
        		    //failure, checks next pair
        		    one = two;
        		    two = fileIn.get();
        		}
        	}//end of if b == *
        	else
        	{
        		//if the character is a / (with no * or / following)
        		// a / is stored in the vector as well as the character following
        		characterEntry x;
        		x.character = c;
        		x.line = lineNumber;
        		file.push_back(x); 
        		i++;
        		characterEntry y;
        		y.character = b;
        		y.line = lineNumber;
        		file.push_back(y);
        		i++;
        		if (b == '\n')
        		{
        			lineNumber++;
        		}
        		
        	}//end of else (b not * or /)
        }//end of if c == /       	
        else
        {
        	//if the character is not a / it is stored in the vector
        	characterEntry z;
        	z.character = c;
        	z.line = lineNumber;
        	file.push_back(z);
        	i++;
        	if(c == '\n')
        	{
        		lineNumber++;
        	}
        }//end of else (c not /)
    }//end of while (cin file)
}//end of openFile


//checks matching and counting, spaces after periods, and =< or =>
void checkBeforeTokenize()
{
	//check Parentheses
	
	int parenC = 0;
	int parenO = 0;
	
	for(int i = 0; i <= file.size() - 1; i++)
	{
		if (file[i].character == '(')
		{
			parenC++;
		}
		else if (file[i].character == ')')
		{
			parenC--;
			//any time that we get a negative value for paren we know there is an extra )
			if (parenC < 0)
			{
				cout << "line " << file[i].line << ": You have an extra ')'." << endl;
				parenC++;
				
			}
		}
		else if (file[i].character == ';')
		{
			if (parenC < 0)
			{
				cout << "line " << file[i].line << ": You have an extra ')'." << endl;
			}
			parenC = 0;
		}
	}
	// check if there are extra ( and find which ones they are in the most general case
	for(int i = file.size() - 1; i >= 0; i--)
	{
		if (file[i].character == ')')
		{
			parenO--;
		}
		else if (file[i].character == '(')
		{
			parenO++;
			//if paren is negative, there is an extra )
			if (parenO > 0)
			{
				cout << "line " << file[i].line << ": You have an extra '('." << endl;
				parenO--;
			}
		}
		else if (file[i].character == ';')
		{
			if (parenO > 0)
			{
				cout << "line " << file[i].line << ": You have an extra '('." << endl;
			}
			parenO = 0;
		}
	}
		
	
	//check Brackets
	int bracketC = 0;
	int bracketO = 0;
	
	for(int i = 0; i <= file.size() - 1; i++)
	{
		if (file[i].character == '{')
		{
			bracketC++;
		}
		else if (file[i].character == '}')
		{
			bracketC--;
			if (bracketC < 0)
			{
				cout << "line " << file[i].line << ": You have an extra '}'." << endl;
				bracketC++;
			}
		}
	}
	
	for(int i = file.size() - 1; i >= 0; i--)
	{
		if (file[i].character == '}')
		{
			bracketO--;
		}
		else if (file[i].character == '{')
		{
			bracketO++;
			if (bracketO > 0)
			{
				cout << "line " << file[i].line << ": You have an extra '{'." << endl;
				bracketO--;
			}
		}
	}
	
	//check Square Brackets
	int sbracketC = 0;
	int sbracketO = 0;
	
	for(int i = 0; i <= file.size() - 1; i++)
	{
		if (file[i].character == '[')
		{
			sbracketC++;
		}
		else if (file[i].character == ']')
		{
			sbracketC--;
			if (sbracketC < 0)
			{
				cout << "line " << file[i].line << ": You have an extra ']'." << endl;
				sbracketC++;
			}
		}
		else if (file[i].character == ';')
		{
			if (sbracketC < 0)
			{
				cout << "line " << file[i].line << ": You have an extra ']'." << endl;
				
			}
			sbracketC = 0;
		}
	}
	
	for(int i = file.size() - 1; i >= 0; i--)
	{
		if (file[i].character == ']')
		{
			sbracketO--;
		}
		else if (file[i].character == '[')
		{
			sbracketO++;
			if (sbracketO > 0)
			{
				cout << "line " << file[i].line << ": You have an extra '['." << endl;
				sbracketO--;
			}
		}
		else if (file[i].character == ';')
		{
			if (sbracketO > 0)
			{
				cout << "line " << file[i].line << ": You have an extra '['." << endl;	
			}
			sbracketO = 0;
		}
	}
	
	//check Single Quotation Marks
	int squote = 0;
	int lastIndexS = 0;
	
	for(int i = 0; i <= file.size() - 1; i++)
	{
		if (file[i].character == '\'')
		{
			squote++;
			lastIndexS = i;
		}
	}
	//check to see if we have an extra '
	if ((squote%2) != 0)
	{
		cout << "line " << file[lastIndexS].line << ": You have an extra single quotation mark." << endl;	
	}
	
	//check Double Quotation Marks
	int dquote = 0;
	int lastIndexD = 0;
	
	for(int i = 0; i <= file.size() - 1; i++)
	{
		if (file[i].character == '"')
		{
			dquote++;
			lastIndexD = i;
		}
	}
	
	//check to see if we have an extra "
	if ((dquote%2) != 0)
	{
		cout << "line " << file[lastIndexD].line << ": You have an extra double quotation mark." << endl;	
	}
	
	// MR 
	//check =< and =>
	for (int j = 0; j < file.size() - 2; j++)
	{
		if((file[j].character == '=') && ((file[j+1].character == '<') || (file[j+1].character == '>')))
		{
			cout << "line " << file[j].line << ": The = should come after the " << file[j+1].character << "." << endl;
		}
	}
	
	// MR
	//check for incorrect space after a period when calling a specific method (object.method)
	for (int k = 0; k < file.size() - 2; k++)
	{
		if((file[k].character == '.') && (file[k+1].character == ' '))
		{
			cout << "line " << file[k].line << ": There shouldn't be a space after the period." << endl;
		}
	}

}//end checkBeforeTokenize


//takes a vector of characterEntries and deletes the whitespace (blanks, tabs, end of lines, etc.)
//stores the resulting strings in a new vector of wordEntries called "words".
void tokenizeByWord()
{
	string x;
	for (int i = 0; i < file.size(); i++)
	{
		if (isPunctuation(file[i].character)) 
		{
			wordEntry a;
        	a.word = x;
        	a.line = file[i-1].line;
        	if (a.word != "")
        	{
        		words.push_back(a);
        		x = "";
        	}
        	
        	wordEntry c;
        	c.word = file[i].character;
        	c.line = file[i].line;
        	if (c.word != "")
        	{
        		words.push_back(c);
        		x = "";
        	}
		}
		else if (file[i].character == '\n' || file[i].character == ' ' || file[i].character == '\t')
		{
			wordEntry b;
        	b.word = x;
        	b.line = file[i-1].line;
        	if (b.word != "")
        	{
        		words.push_back(b);
        		x = "";
        	}
		}
		else //file[i] is a character
		{
			x.append(charToString(file[i].character)); 
		}
	}
}


// returns true if the character is a punctuation mark
bool isPunctuation(char x)
{
	if (x == '(' || x == ')' || x == '-' || x == '+' || x == '=' || x == '*' ||
	    x == '/' || x == '<' || x == '>' || x == '{' || x == '}' || x == '[' ||
	    x == ']' || x == '|' || x == '&' || x == ',' || x == '.' || x == '?' ||
	    x == '^' || x == ';' || x == ':' || x == '\'' || x == '"' || x == '~' ||
	    x == '%' || x == '!' || x == '`')
	{
	    return true;
	}  
	else 
		return false;	                       
}


// converts a character to a string
string charToString(char x)
{
	char f[1];
	f[0] = x;
	
	string g;
	g = f[0];
	
	return g;
}


//returns an error if any variable or method has a keyword for its name
void checkForKeywords()
{
	for (int i = 0; i < words.size() - 1; i++)
	{
		if ((words[i].word == "byte") || (words[i].word == "short") || (words[i].word == "int") || 
			(words[i].word == "long") || (words[i].word == "float") || (words[i].word == "double") ||
			(words[i].word == "char") || (words[i].word == "boolean") || (words[i].word == "string"))
		{
			for (int j = 0; j < 50; j++)
			{
				if (words[i + 1].word == keywords[j])
				{
					cout << "line " << words[i].line << ": " << words[i + 1].word << " is a keyword." << endl;
				} 
			}
		} 
	}
}


//returns an error if there's a semicolon at the end of a method header
void checkMethodHeader()
{
	for (int k = 0; k < words.size() - 7; k++)
	{
		if ((words[k].word == "byte") || (words[k].word == "short") || (words[k].word == "int") || 
			(words[k].word == "long") || (words[k].word == "float") || (words[k].word == "double") ||
			(words[k].word == "char") || (words[k].word == "boolean") || (words[k].word == "string") ||
			(words[k].word == "void"))
		{
			if (words[k+2].word == "(")
			{	
				for (int l = k + 3; l < words.size() - 5; l++)
				{
				if (words[l].word == ")")
					{
						if ((words[l+1].word == ";") && (words[l+2].word == "{"))
						{
							cout << "line " << words[l+1].line << ": Method Headers should not be followed by a semicolon." << endl;
						}
						l = words.size() - 5;
					}
				}
			}
		}
	} 
}


//returns an error if there are no parentheses after a method call
void checkMethodCall()
{
	for (int i = 0; i < words.size(); i++)
	{
		for (int j = 0; j < 50; j++)
		{
			if ((words[i].word == methodNames[j][1]) 
			&&  
			((words[i-1].word != "byte") && (words[i-1].word != "short") && (words[i-1].word != "int") && 
			(words[i-1].word != "long") && (words[i-1].word != "float") && (words[i-1].word != "double") &&
			(words[i-1].word != "char") && (words[i-1].word != "boolean") && (words[i-1].word != "string")))
			{
				if(words[i+1].word != "(")
				{
					cout << "line " << words[i].line << ": Method calls should be followed by parentheses." << endl;
				}
			} 
		}	
	}	
}


//stores the variables and their types in a vector of varkinds called "variables"
void collectVariables()
{
	for (int i = 0; i < words.size() - 4; i++)
	{
		if (((words[i].word == "byte") || (words[i].word == "short") || (words[i].word == "int") || 
			(words[i].word == "long") || (words[i].word == "float") || (words[i].word == "double") ||
			(words[i].word == "char") || (words[i].word == "boolean") || (words[i].word == "String") || 
			(words[i].word == "string")) && 
			((words[i+2].word == "=") || (words[i+2].word == ",") || (words[i+2].word == ";")) && 
			(words[i-1].word != "(") && (words[i-1].word != ","))
			
		{
			varkind x;
			x.var = words[i + 1].word;
        	x.kind = words[i].word;
        	variables.push_back(x);
		}
		
		if (((words[i].word == "byte") || (words[i].word == "short") || (words[i].word == "int") || 
			(words[i].word == "long") || (words[i].word == "float") || (words[i].word == "double") ||
			(words[i].word == "char") || (words[i].word == "boolean") || (words[i].word == "String") || 
			(words[i].word == "string")) && 
			((words[i+2].word == ",") || (words[i+4].word == ",")) && (words[i-1].word != "(") && 
			((words[i+3].word != "byte") && (words[i+3].word != "short") && (words[i+3].word != "int") && 
			 (words[i+3].word != "long") && (words[i+3].word != "float") && (words[i+3].word != "double") &&
			 (words[i+3].word != "char") && (words[i+3].word != "boolean") && (words[i+3].word != "String") && 
			 (words[i+3].word != "string")))
		{
			int j = i + 2;
			while (words[j].word != ";")
			{
				if(words[j].word == ",")
				{
					varkind x;
					x.var = words[j+1].word;
        			x.kind = words[i].word;
        			variables.push_back(x);
				}
				j++;
			}
		}
		
		
	}
}


// collects methods definition parameter types and stores them in a vector of params called "parameters"
void collectMethodDefinitionParameterTypes()
{
	for (int k = 0; k < words.size() - 7; k++)
	{
		if ((words[k].word == "byte") || (words[k].word == "short") || (words[k].word == "int") || 
			(words[k].word == "long") || (words[k].word == "float") || (words[k].word == "double") ||
			(words[k].word == "char") || (words[k].word == "boolean") || (words[k].word == "string") ||
			(words[k].word == "void"))
		{
			for (int j = 0; j < 50; j++)
			{
				if (words[k+1].word == methodNames[j][1])
				{
					if (words[k+2].word == "(")
					{
						int counter = 1;
						int m = k + 3;
						while (words[m].word != ")")
						{
							param x;
							if ((words[m].word == "byte") || (words[m].word == "short") || (words[m].word == "int") || 
								(words[m].word == "long") || (words[m].word == "float") || (words[m].word == "double") ||
								(words[m].word == "char") || (words[m].word == "boolean") || (words[m].word == "string") ||
								(words[m].word == "void"))
							{
								x.method = words[k+1].word;
								x.paramname = words[m+1].word;
								x. paramtype = words[m].word;
								x.location = counter;
								parameters.push_back(x);
								counter++;
							}
							m++;
						}
					}
				}
			}
		}
	} 
}


// returns an error if the method call parameter types don't match the method definition parameter types
void checkMethodCallParameterTypes()
{
	for (int i = 0; i < words.size(); i++)
	{
		for (int k = 0; k < 50; k++)
		{
			if ((words[i].word == methodNames[k][1]) 
			&&  
			((words[i-1].word != "byte") && (words[i-1].word != "short") && (words[i-1].word != "int") && 
			(words[i-1].word != "long") && (words[i-1].word != "float") && (words[i-1].word != "double") &&
			(words[i-1].word != "char") && (words[i-1].word != "boolean") && (words[i-1].word != "string") &&
			(words[i-1].word != "void")))
			{
				if(words[i+1].word == "(")
				{
					int counter = 1;
					int m = i + 2;
					while (words[m].word != ")")
					{	
						for(int n = 0; n < variables.size(); n++)
				 		{
							if(words[m].word == variables[n].var)
							{	
								bool match = false;
								for(int p = 0; p < parameters.size(); p++)
								{	
									if((parameters[p].method == methodNames[k][1]) 
									    && (parameters[p].paramtype == variables[n].kind)
									    && (parameters[p].location == counter))
										{
											match = true;
											counter++;
										}		
								}
								if(match == false)
								{
									cout <<"line " << words[m].line;
									cout << " : Parameter type in method call does not match method definition" << endl;
									counter++;
								}									
							}
						}
						m++;
					}
				}
			} 
		}	
	}	
}


//calls collectMethodDefinitionParameterTypes and checkMethodCallParameterTypes
void checkParameters()
{
	collectMethodDefinitionParameterTypes();
	checkMethodCallParameterTypes(); 
}


// goes through 'words' and looks for "if", "while" and "for" to pass on to appropriate function
// also looks for possibe use of "==" instead of "=" outside these special structures
void specialStructures()
{
	int closingParenIndex = 0;
	
	for( int i = 0; i < words.size()-1; i++) 
	{
		if( words[i].word == "if" )
		{ 	// found an "if"...pass index in 'words' to ifChecks
			closingParenIndex = ifChecks(i);
		}
		else if( words[i].word == "while" )
		{	// found a "while"...pass index in 'words' to whileChecks
			closingParenIndex = whileChecks(i);
		}
		else if( words[i].word == "for" )
		{	// found a "for"... pass index in 'words' to forChecks
			closingParenIndex = forChecks(i);
		}
		else if( words[i].word == "=" )
		{	// found an "="...
			// if it in the "if", "while" or "for" clause, ignore. Otherwise...
			// it probably should be an assignment (=)
			
			if( i > closingParenIndex && words[i+1].word == "=" )
			{	// there is an "==" outside the special structure parentheses
				cout << "\nline " << words[i].line << ": \"==\" is a comparison operator and does not"
					 << " change the value of\n\tthe left hand side." << endl
					 << "\tTo change the value, use \"=\"." << endl;	
			}
		}	
	} 
} 


// carries out "if" tests and returns the index of the ")" in "if( ... )"
int ifChecks( int index ) 
{	
	// ensure words[index].word is an "if"
	if( words[index].word != "if" )
		return index; 
	
	// Now words[index].word is an "if"
	// first check index is not too close to end of words array 
	if( index + 3 >= words.size() - 1 )
		return index;
	
	// next check that the next token is a "("
	if( words[index + 1].word != "(" )
	{
		cout << "\nline " << words[index + 1].line << ": The \"if\" should be followed by a '('."
			 << endl << "\tformat: \"if(<condition>) {<statements>}\"" << endl;
	}
	
	// look for "=" inside if(...)
	int i = index + 2; // next token after the (
	int parenCount = 1; // parenCount counts ()...parenCount==0 => end of "if" condition
	while ( parenCount > 0 && i < words.size()-2 ) // 2nd condition just for safety
	{
		if( words[i].word == "(" )
			parenCount++;
		else if( words[i].word == ")" )
			parenCount--;
		
		else if( words[i].word == ";" ) // ';' should not be in an 'if' condition
			cout << "\nline " << words[i].line << ": Possible unbalanced parentheses in \"if\" condition"
				 << "\n\tformat: \"if(<condition>) {<statements>}\"" << endl;
					
		else if( words[i].word == "=" ) // check if next is also an = (so the operator is ==)
		{								// also check that previous symbol is not >, <, !, since 
										// these can be valid & safe prefixes to an "=" sign.
			if( words[i-1].word != ">" && words[i-1].word != "<" 
				&& words[i-1].word != "!" && words[i+1].word != "=" ) 
			{ // possible problem
				cout << "\nline " << words[i].line << ": \"=\" is an assignment operator and changes the value of"
					 << endl << "\tthe left hand side." << endl
					 << "\tTo compare without changing values, use \"==\"." << endl;
			}
			i++; 
		}	
		
		i++; // next token	
	} 
	
	// now parenCount = 0 so i must be the index of the token after ')'
	// check if this is a ';'
	if( words[i].word == ";" )
	{
		cout << "\nline " << words[i].line << ": The ';' after the \"if\" condition " 
			 << "means that if the condition is true," 
			 << endl << "\tthe program will do nothing. " << endl
			 << "\tTo carry out an instruction if the condition is true, remove this ';'." 
			 << endl << "\t(To carry out multiple instructions, place them within a block:" << endl
			 << "\t\t{statement1; statement2;...;})." << endl;
	}
	
	return i-1;		// index of ')'
}


// carries out "while" tests and returns index of the ")" in "while( ... )"
int whileChecks( int index ) 
{	
	// make sure words[index].word is a "while"
	if( words[index].word != "while" )
		return index;
	
	// Now words[index].word is a "while"
	// first check that index is not too close to end of words array
	if( index + 3 >= words.size()-1 || index - 2 < 0 )
		return index;
	
	// next check that the next token is a "("
	if( words[index + 1].word != "(" )
	{
		cout << "\nline " << words[index + 1].line << ": The \"while\" should be followed by a '('."
			 << endl << "\tformat: \"while(<condition>) {<statements>}\""
			 << endl << "\t or: \"do {<statements>} while(<condition>);\"" << endl;
	}
	
	// look for "=" inside while(...) 
	int i = index + 2; // next token after the (
	int parenCount = 1; // parenCount counts ()...parenCount==0 => end of "while" condition
	while (parenCount > 0 && i < words.size()-2) // 2nd condition for safety
	{
		if( words[i].word == "(" )
			parenCount++;
		else if( words[i].word == ")" )
			parenCount--;
			
		else if( words[i].word == ";" ) // ';' should not be in 'while' condition, usually
			cout << "\nline " << words[i].line << ": Possible unbalanced parentheses in \"while\" condition."
				 << "\n\tformat: while(<condition>) {<statements>}\""
				 << "\n\t or: \"do {<statements>} while(<condition>);\"" << endl;
			
		else if( words[i].word == "=" ) // check if next is also an = (so the operator is ==)
		{								
			if( words[i-1].word != "<" && words[i-1].word != ">" 
				&& words[i-1].word != "!" && words[i+1].word != "=" ) 
			{ // possible problem
				cout << "\nline " << words[i].line << ": \"=\" is an assignment operator and changes the value of"
					 << endl << "\tthe left hand side." << endl
					 << "\tTo compare without changing values, use \"==\"." << endl;
			}
			i++; 
		} 
		
		i++; // next token	
	} 
	
	// now parenCount = 0 so i must be the index of the token after ')'
	// check if this is a ';'
	if( words[i].word == ";" )
	{
		// make sure it's not a "do-while"
		
		// case 1: do stmt; while ( condition );
		if( words[index-1].word == ";" ) // words[index-1].word is the token before "while"
		{ // look for the token before a possible "do" -- a ";" or a "}" or a "{"...
			int j = index - 2; 
			while( words[j].word != ";" && words[j].word != "}" && words[j].word != "{" && j > 0 )
			{	// check previous token
				j--;
			}
			
			// now words[j].word is one of the above statement separators
			// so check if next is "do" and if not, cout error message
			if ( words[j+1].word != "do" )
			{
				cout << "\nline " << words[i].line << ": The ';' after the \"while\" condition" 
			 		 << " means if the condition\n\tis true, the program will do nothing." << endl
			 		 << "\tTo carry out an instruction if the condition is true, remove this ';'." 
			 		 << endl << "\t(To carry out multiple instructions, place them within a block:" << endl
			 		 << "\t\t{statement1; statement2;...;})." << endl;
			}
		} // end of case 1
		
		// case 2: do {stmt;...stmt;} while( condition );
		else if( words[index-1].word == "}" )
		{
			int bracketCount = 1; 
			// bracketCount == 0 => the counter has crossed '{' for original '}'
			int j = index - 2;
			while( bracketCount > 0 && j > 0 ) // 2nd cond. for safety
			{
				if( words[j].word == "}" )
					bracketCount++;
				else if( words[j].word == "{" )
					bracketCount--;
				j--; 	
			}
			
			// now words[j+1].word is the "{" that made bracketCount equal 0
			// check if words[j].word is "do", and if not, cout error message
			if( words[j].word != "do" )
			{
				cout << "\nline " << words[i].line << ": The ';' after the \"while\" condition" 
			 		 << " means if the condition\n\tis true, the program will do nothing." << endl 
			 		 << "\tTo carry out an instruction if the condition is true, remove this ';'." 
			 		 << endl << "\t(To carry out multiple instructions, place them within a block:" << endl
			 		 << "\t\t{statement1; statement2;...;})." << endl;
			}
		} // end of case 2	
		
		// case 3: not a possible "do"...
		else
		{ // simple while loop, cout error message
			cout << "\nline " << words[i].line << ": The ';' after the \"while\" condition" 
			 	 << " means if the condition\n\tis true, the program will do nothing." << endl
			 	 << "\tTo carry out an instruction if the condition is true, remove this ';'." 
			 	 << endl << "\t(To carry out multiple instructions, place them within a block:" << endl
			 	 << "\t\t{statement1; statement2;...;})." << endl;
		} // end of case 3	
	} // end of if( words[i].word == ";" )
	
	return i-1; 	// index of ')' in "while( ... )"
}


// carries out "for" tests and returns index of ")" in "for ( ... ; ... ; ... )"
int forChecks( int index )
{	
	// make sure words[index].word is a "for"
	if( words[index].word != "for" )
		return index; 
	
	// Now words[index].word is a "for"
	// first check that index is not too close to the end
	if( index + 3 >= words.size() - 1 )
		return index;
	
	// next check that the next token is a "("
	if( words[index + 1].word != "(" )
	{
		cout << "\nline " << words[index + 1].line << ": The \"for\" should be followed by a '('."
			 << endl << "\tformat: \"for(<initialization>; <condition>; <update>) {<statements>}\"" << endl;
	}
	
	// special parentheses checking for "for" loops
	int i = index + 2; // next token after the (
	int parenCount = 1; // parenCount counts ()...parenCount==0 => end of "for" loop condition
	int semiCount = 0; // semiCount counts ;'s used as separators
	
	while( true )
	{
		if( words[i].word == "(" )
			parenCount++;
		else if( words[i].word == ")" )
			parenCount--;
		else if( words[i].word == ";" )
			semiCount++;
		
		// == with semiCount != 1 or = with semiCount == 1 => problem
		else if( words[i].word == "=" )
		{
			if( words[i+1].word == "=" ) // it is an "=="
			{	// possible error if semiCount != 1
				if( semiCount == 0 ) // initialization clause of "for" loop
					cout << "\nline " << words[i+1].line << ": The first or initialization clause"
						 << " of a \"for\" loop usually\n\thas an assignment operator (=)." << endl
						 << "\tAre you sure you want \"==\" and not \"=\"?" << endl;
				else if( semiCount == 2 ) // update clause
					cout << "\nline " << words[i+1].line << ": The third or update clause"
						 << " of a \"for\" loop usually\n\thas an assignment operator (=)." << endl
						 << "\tAre you sure you want \"==\" and not \"=\"?" << endl;
			}
			
			else // words[i+1].word != "="
			{    // possible error if semiCount == 1 (the test/condition clause of the loop)
				 // but also make sure operator is not >=, <=, != or ==
				if( semiCount == 1 && words[i-1].word != ">" && words[i-1].word != "<"
				   && words[i-1].word != "!" && words[i-1].word != "=" )
					cout << "\nline " << words[i+1].line << ": The second or condition clause"
					     << " of a \"for\" loop usually\n\thas a comparison operator (==)." << endl
						 <<	"\t\"=\" is an assignment operator"
						 << " and changes the value of" << endl << "\tthe left hand side." << endl
						 << "\tTo compare without changing values, use \"==\"." << endl;
			}
		} 
			
		
		// lack of closing ) -> if semiCount = 3 and parens are not balanced
		if( semiCount > 2 && parenCount > 0 )
			cout << "\nline " << words[index].line << ": Possible unbalanced parentheses after \"for\"."
				 << endl << "\tformat: \"for(<initialization>; <condition>; <update>) {<statements>}\"" << endl;
		
		// wrong separators -> if parenCount is balanced w/ semiCount < 2
		if( parenCount == 0 && semiCount < 2 )
			cout << "\nline " << words[index].line << ": Possible missing semi-colon within \"for\" parentheses."
				 << endl << "\tformat: \"for(<initialization>; <condition>; <update>) {<statements>}\"" << endl;
		
		// possible unwanted ; -> parenCount == 0 and next token is ;
		if( parenCount == 0 && words[i+1].word == ";" )
			cout << "\nline " << words[i+1].line << ": The ';' after the \"for\" criteria " 
			 	 << "means that for the duration of the" 
			 	 << endl << "\tloop, the program will do nothing. " << endl
			 << "\tTo repeat an instruction via the \"for\" loop, remove this ';'." 
			 << endl << "\t(To carry out multiple instructions, place them within a block:" << endl
			 << "\t\t{statement1; statement2;...;})." << endl;
		
		// break out of this while loop when parenCount == 0 or semiCount > 2
		// (i.e. when we've most probably finished checking the "for" syntax)
		if( parenCount == 0 || semiCount > 2 || i == words.size()-1 )
			break;
		
		// move on to next token
		i++;	
	} 
	
	return i; 		// index of ')' in "for ( ... ; ... ; ... )"
} 


// other syntax errors relating to booleans
void booleans() 
{ 
// && and ||-- if the next expression has a comparison operator
//  (before a ';' or ')'), ignore, otherwise warn.
	for( int i = 0; i <= words.size()-3; i++ ) 	
	{
		if( words[i].word == "&" && words[i+1].word == "&" )
		{
			if( !nextExpressionComparison( i+2 ) )
				cout << "\nLine: " << words[i].line << " \"&&\" is a short-cut evaluator. If the left hand side"
					 << "\n\texpression is false, the right side will not be evaluated."
					 << endl << "\tIf the right side directly changes the program"
					 << endl << "\tand so must always be evaluated, use \"&\" instead of \"&&\"." << endl;
		}
		else if( words[i].word == "|" && words[i+1].word == "|" )
		{
			if( !nextExpressionComparison( i+2 ) )
				cout << "\nLine: " << words[i].line << " \"||\" is a short-cut evaluator. If the left hand side"
					 << "\n\texpression is true, the right side will not be evaluated."
					 << endl << "\tIf the right side directly changes the program"
					 << endl << "\tand so must always be evaluated, use \"|\" instead of \"||\"." << endl;
		}	
	}
}


// true if there is a comparison operator (>, <, >=, <=, !=, ==, .equals) before the next ';' or ')'.
bool nextExpressionComparison(int indexPassed)
{	
	for( int index = indexPassed; 
		 words[index].word != ")" && words[index].word != ";" && index < words.size() - 1;
		 index++ )
	{
		if( words[index].word == ">" || words[index].word == "<" || words[index].word == "!" )
			return true;
		if( words[index].word == "=" && words[index+1].word == "=" )
			return true;
		if( words[index].word == "." && words[index+1].word == "equals" )
			return true;
	}
	
	return false;
}


// collects method names and return types and stores them in a two-dimensional array called "methodNames" 
void collectMethodNames(){

	for (int i = 0; i < words.size() - 5; i++)
	{
		// the method begin with either public, private or protected keyword
		if ((words[i].word == "public") || (words[i].word == "private") || (words[i].word == "protected"))
		{
			// the method is PPP static or abstract
			if ((words[i+1].word == "static") || (words[i+1].word == "abstract"))
			{ 
				// the method has a return type of one of the following
				if ((words[i+2].word == "byte") || (words[i+2].word == "short") || (words[i+2].word == "int") || 
					(words[i+2].word == "long") || (words[i+2].word == "float") || (words[i+2].word == "double") ||
					(words[i+2].word == "char") || (words[i+2].word == "boolean") || (words[i+2].word == "String") || (words[i+2].word == "void"))
				{
					if (words[i+4].word == "(")
					{
						methodNames[numberMethods][1] = words[i+3].word;
						methodNames[numberMethods][0] = words[i+2].word;
						numberMethods++;
						i = i + 4;
					}
				}
			}
			// the method is PPP return_type name
			if ((words[i+1].word == "byte") || (words[i+1].word == "short") || (words[i+1].word == "int") || 
				(words[i+1].word == "long") || (words[i+1].word == "float") || (words[i+1].word == "double") ||
				(words[i+1].word == "char") || (words[i+1].word == "boolean") || (words[i+1].word == "String") || (words[i+1].word == "void"))
			{
				if (words[i+3].word == "(")
				{
						methodNames[numberMethods][1] = words[i+2].word;
						methodNames[numberMethods][0] = words[i+1].word;
						numberMethods++;
						i = i + 3;
				}
			}	
		}
		// the method is of type SA return_type name
		else if (((words[i].word == "static") || (words[i].word == "abstract")) && ((words[i-1].word != "public") || (words[i-1].word != "private") || (words[i-1].word != "protected")))
		{
			if ((words[i+1].word == "byte") || (words[i+1].word == "short") || (words[i+1].word == "int") || 
				(words[i+1].word == "long") || (words[i+1].word == "float") || (words[i+1].word == "double") ||
				(words[i+1].word == "char") || (words[i+1].word == "boolean") || (words[i+1].word == "String") || (words[i+1].word == "void"))
			{
				if (words[i+3].word == "(")
				{
						methodNames[numberMethods][1] = words[i+2].word;
						methodNames[numberMethods][0] = words[i+1].word;
						numberMethods++;
						i = i + 3;
				}
			}	
		}
		// the method is of type return_type name
		else if (((words[i].word == "byte") || (words[i].word == "short") || (words[i].word == "int") || 
			(words[i].word == "long") || (words[i].word == "float") || (words[i].word == "double") ||
			(words[i].word == "char") || (words[i].word == "boolean") || (words[i].word == "String") || (words[i].word == "void"))
			&& (((words[i-1].word != "static") || (words[i-1].word != "abstract")) 
				&& ((words[i-1].word != "public") || (words[i-1].word != "private") || (words[i-1].word != "protected"))))
		{
			if (words[i+2].word == "(")
			{
				methodNames[numberMethods][1] = words[i+1].word;
				methodNames[numberMethods][0] = words[i].word;
				numberMethods++;
				i = i + 2;
			}
		}
	}
}


// returns true if the argument is probably a string
bool isString( int tokenIndex, bool lhs )	
{	
	// lhs is true if the argument passed is to the left of the ==, false otherwise
	
	bool isMethod = false; // is the argument a method call
	bool isVariable = false; // is the argument a variable
	
	if( lhs )
	{
		if( words[tokenIndex].word == "\"" ) // of the form "...." == _____
			return true;
		if( words[tokenIndex].word == ")" )
		{
			int paren = 1;
			int i = tokenIndex - 1;
			while ( i > 0 )
			{
				if( words[i].word == ")" )
					paren++;
				else if( words[i].word == "(" )
					paren--;
				
				if( paren == 0 ) // () balanced--check previous token to see if the whole is a method that returns a string
				{
					for( int j = 0; j < 50; j++ ) // 50 = size of methodNames
					{
						if( methodNames[j][1] == words[i-1].word ) // there is a method by that name
						{
							if( methodNames[j][0] == "String" )
								return true;
							else // method but not returning a string
								isMethod = true;
						}	
					}
					
					// not yet returned implies that it was not a method returning a string
					// it could still be a method returning something else
					if( isMethod )
						return false; 
					
					else // not any type of method, but an expression ending with ). Check expression inside (...) in same way
						return isString( tokenIndex-1, lhs );
				} // end of if ( paren == 0 )	
				
				i--;
			} 		
		} 
		
		// or the token might be a variable. 
		for( int k = 0; k < variables.size(); k++ )
		{
			if( variables[k].var == words[tokenIndex].word ) // is a variable name
			{
				if( variables[k].kind == "String" )
					return true;
				else // variable but not string
					isVariable = true;
			} 
		} 
		
		// still here implies that it was not a string variable
		// it could still be a variable of some other type and thus not a string
		if( isVariable )
			return false;
	
	} // end of if( lhs )	
	
	if( !lhs ) 
	{
		if( words[tokenIndex].word == "\"" )
			return true;
		
		if( words[tokenIndex].word == "(" ) // have no use for ( in ____ == (....) so get rid of it
		{
			if( tokenIndex < words.size() - 1 )
				return isString( tokenIndex+1, lhs );
			else // last tokens in words array are == (
				return false;
		}
			
		// check if method returning string
		for( int j = 0; j < 50; j++ )
		{
			if( methodNames[j][1] == words[tokenIndex].word ) // there is a method by that name
			{
				if( methodNames[j][0] == "String" ) // the method returns a string
					return true;
				else // a method with the right name but not returning a string
					isMethod = true;
			}
		}
		
		if( isMethod ) // is a method that returns something other than a string
			return false;
		
		// check if string variable
		for( int j = 0; j < variables.size(); j++ )
		{
			if( variables[j].var == words[tokenIndex].word ) // there is a variable by that name
			{
				if( variables[j].kind == "String" ) // it is a string variable
					return true;
				else // a variable with the right name but not of type string
					isVariable = true;
			}
		} 
		
		if( isVariable ) // is a variable of type other than string
			return false;
				
	} 

	return false;
} 


// returns error if both arguments of a == are Strings
void dotEquals() 
{ 
	for( int i = 1; i < words.size() - 3; i++ )
	{
		if( words[i].word == "=" && words[i+1].word == "=" ) // there is a ==
		{ 
			if( isString( i-1, true )  && isString( i+2, false ) ) // both arguments of the == are strings
				cout << "Line " << words[i].line << ": To compare the contents of two Strings, use \".equals\"." << endl
					 << "\tformat: \"(<string1>).equals(<string2>)\"" << endl;
		}
	}		
}


// returns error if a non void method is used as a statement
void nonVoidMethodAsStatement(){

	for (int i = 2; i < words.size(); i++)
	{
		if((words[i].word == "(") && (isAMethod(words[i-1].word) == true) && (words[i-2].word != "byte") 
			&& (words[i-2].word != "short") && (words[i-2].word != "int") && (words[i-2].word != "long") 
			&& (words[i-2].word != "float") && (words[i-2].word != "double") &&	(words[i-2].word != "char") 
			&& (words[i-2].word != "boolean") && (words[i-2].word != "String") && (words[i-2].word != "void")
			&& (words[i-2].word != "new"))
			{
			string methodType = returnMethodType(words[i-1].word); 
			if ((methodType != "void") && (words[i-2].word != "="))
			{
				cout << "line " << words[i-1].line << ": The method " << words[i-1].word << " is not a void method and can not be called" 
					 <<	"\n\tas a statement.";
				cout << "  Consider using a variable of the  same type as the " 
					 <<	"\n\tmethod where the return value can be stored." << endl;
				bool found = false;
				
				for (int j = i - 2 ; j > 0; j--)
				{
					if ((words[j].word == "+") || (words[j].word != "-") || (words[j].word != "*") || 
						(words[j].word != "/") || (words[j].word != "(") || (words[j].word != "return"))
					
						found = false;
						
					if (words[j].word == "=")
					{
						found = true;
						break;
					}
				}
				if (found == false)
				{
					cout << "line " << words[i-1].line << ": The method " << words[i-1].word << " is not a void method and can not be called" 
						 << "\n\tas a statement. ";
					cout << "Consider using a variable of the  same type as the " 
						 << "\n\tmethod where the return value can be stored." << endl;
				}
			}
		}
	}
}


// checks if a given string is the name of a method
bool isAMethod(string methodName){

bool compResult = false;

	for (int i = 0; i < numberMethods; i++)
	{
		if (methodName == methodNames[i][1])
		{
			compResult = true;
			break;
		}	
	}		
	
	return compResult;
}


// returns the type associated with every method
string returnMethodType(string methodName){

string methodType;

	for (int i = 0; i < numberMethods; i++)
	{
		if (methodName == methodNames[i][1])
		{
			methodType = methodNames[i][0];
		}
	}
	return methodType;
}


// returns error if a non void method does not have a return statement
void nonVoidMethodWithoutReturn(){

int counter = 0;
bool outcome = false;

	for (int i = 2; i < words.size() ; i++)
	{
		if((words[i].word == "(") && (isAMethod(words[i-1].word) == true) && (returnMethodType(words[i-1].word) != "void")
			&& ((words[i-2].word == "byte") || (words[i-2].word == "short") || (words[i-2].word == "int") 
				|| (words[i-2].word == "long") || (words[i-2].word == "float") || (words[i-2].word == "double") 
				||	(words[i-2].word == "char") || (words[i-2].word == "boolean") || (words[i-2].word == "String")))
		{
			for (int j = i + 1; j < words.size(); j++)
			{
				if (words[j].word == "{")
					counter++;
				if (words[j].word == "}")
				{
					counter--;
					if (counter == 0)
					{
						if ((words[j-1].word == ";") || (words[j-1].word == "}"))
						{
						int stopPoint = 0;
						int p;
						
							for (p = j - 2; p > 0; p--)
							{
								if (((words[p].word == ";") || (words[p].word == "}")) && (words[p+1].word != "return"))
								{
									stopPoint = p;
									break;
								}
							}
							for (int k = j - 2; k >= p; k--)
							{
								if (((words[k].word == ";") || (words[k].word == "}")) && (words[k+1].word != "return"))
								{
									cout << "The method " << words[i-1].word << " is a non-void method missing a return statement" << endl;
									cout << "Consider adding a return statement or changing the type of the method to 'void.'" << endl;
									break;
								} 
								if (((words[k].word == ";") || (words[k].word == "}")) && (words[k+1].word == "return"))
								{	
									break;
								}						
							}
							
						}
					break;
					}
				}				
			}
		}
	}
}

void interfaceWithoutAllMethods(){

// boolean variables for all the interfaces
bool ActionListener = false;
bool AdjustmentListener = false;
bool ComponentListener = false;
bool ContainerListener = false;
bool FocusListener = false;
bool ItemListener = false;
bool KeyListener = false;
bool MouseListener = false;
bool MouseMotionListener = false;
bool TextListener = false;
bool WindowListener = false;

// boolen avariables for all of the methods for each interface
bool actionPerformed = false;
bool adjustmentValueChanged = false;
bool componentHidden = false;
bool componentMoved = false;
bool componentResized = false;
bool componentShown = false;
bool componentAdded = false;	// for container listener
bool componentRemoved = false;	// for container listener
bool focusGained = false;
bool focusLost = false;
bool itemStateChanged = false;
bool keyPressed = false;
bool keyReleased = false;
bool keyTyped = false;
bool mouseClicked = false;
bool mouseEntered = false;
bool mouseExited = false;
bool mousePressed = false;
bool mouseReleased = false;
bool mouseMoved = false;
bool mouseDragged = false;
bool textValueChanged = false;
bool windowActivated = false;
bool windowClosed = false;
bool windowClosing = false;
bool windowDeactivated = false;
bool windowDeiconified = false;
bool windowIconified = false;
bool windowOpened = false;

// boolean variables for all of the adapters
bool ComponentAdapter = false;
bool ContainerAdapter = false;
bool FocusAdapter = false;
bool KeyAdapter = false;
bool MouseAdapter = false;
bool MouseMotionAdapter = false;
bool WindowAdapter = false;

	for (int i = 0; i < words.size() - 1 ; i++)
	{
		if (words[i].word == "implements")
		{
			for (int k = i + 1; k < words.size() - 1; k++)
			{
			//while (words[k].word != "{")
			//{
				if (words[k].word == "ActionListener")
				{
					ActionListener = true;
					for (int j = i + 2; j < words.size() - 2; j++)
					{
						
						// if you find it switch the boolean variable and break out of the loop
						if ((words[j].word == "actionPerformed") && (words[j+1].word == "("))
						{
							cout << "i am in" << endl;
							actionPerformed = true;
							break;
						} 
					}
				}
				if (words[k].word == "AdjustmentListener")
				{
					AdjustmentListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "adjustmentValueChanged") && (words[j+1].word == "("))
						{
							adjustmentValueChanged = true;
							break;
						} 
					}
				}
				if (words[k].word == "ComponentListener")
				{
					ComponentListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "componentHidden") && (words[j+1].word == "("))
						{
							componentHidden = true;
						} 
						if ((words[j].word == "componentMoved") && (words[j+1].word == "("))
						{
							componentMoved = true;
						} 
						if ((words[j].word == "componentResized") && (words[j+1].word == "("))
						{
							componentResized = true;
						} 
						if ((words[j].word == "componentShown") && (words[j+1].word == "("))
						{
							componentShown = true;
						} 
					}
				}
				if (words[k].word == "ContainerListener")
				{
					ContainerListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "componentAdded") && (words[j+1].word == "("))
						{
							componentAdded = true;
						} 
						if ((words[j].word == "componentRemoved") && (words[j+1].word == "("))
						{
							componentRemoved = true;
						} 
					}
				}
				if (words[k].word == "FocusListener")
				{
					FocusListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "focusGained") && (words[j+1].word == "("))
						{
							focusGained = true;
						} 
						if ((words[j].word == "focusLost") && (words[j+1].word == "("))
						{
							focusLost = true;
						} 
					}
				}
				if (words[k].word == "ItemListener")
				{
					ItemListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "itemStateChanged") && (words[j+1].word == "("))
						{
							itemStateChanged = true;
							break;
						} 
					}
				}
				if (words[k].word == "KeyListener")
				{
					KeyListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "keyPressed") && (words[j+1].word == "("))
						{
							keyPressed = true;
						} 
						if ((words[j].word == "keyReleased") && (words[j+1].word == "("))
						{
							keyReleased = true;
						} 
						if ((words[j].word == "keyTyped") && (words[j+1].word == "("))
						{
							keyTyped = true;
						} 
					}
				}
				if (words[k].word == "MouseListener")
				{
					MouseListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "mouseClicked") && (words[j+1].word == "("))
						{
							mouseClicked = true;
						} 
						if ((words[j].word == "mouseEntered") && (words[j+1].word == "("))
						{
							mouseEntered = true;
						} 
						if ((words[j].word == "mouseExited") && (words[j+1].word == "("))
						{
							mouseExited = true;
						} 
						if ((words[j].word == "mousePressed") && (words[j+1].word == "("))
						{
							mousePressed = true;
						} 
						if ((words[j].word == "mouseReleased") && (words[j+1].word == "("))
						{
							mouseReleased = true;
						} 
					}
				}
				if (words[k].word == "MouseMotionListener")
				{
					MouseMotionListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "mouseMoved") && (words[j+1].word == "("))
						{
							mouseMoved = true;
						} 
						if ((words[j].word == "mouseDragged") && (words[j+1].word == "("))
						{
							mouseDragged = true;
						} 
					}
				}
				if (words[k].word == "TextListener")
				{
					TextListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "textValueChanged") && (words[j+1].word == "("))
						{
							textValueChanged = true;
							break;
						}	 
					}
				}
				if (words[k].word == "WindowListener")
				{
					WindowListener = true;
					for (int j = i + 2; j < words.size() - 1; j++)
					{
						if ((words[j].word == "windowActivated") && (words[j+1].word == "("))
						{
							windowActivated = true;
						} 
						if ((words[j].word == "windowClosed") && (words[j+1].word == "("))
						{
							windowClosed = true;
						} 
						if ((words[j].word == "windowClosing") && (words[j+1].word == "("))
						{
							windowClosing = true;
						} 
						if ((words[j].word == "windowDeactivated") && (words[j+1].word == "("))
						{
							windowDeactivated = true;
						} 
						if ((words[j].word == "windowDeiconified") && (words[j+1].word == "("))
						{
							windowDeiconified = true;
						} 
						if ((words[j].word == "windowIconified") && (words[j+1].word == "("))
						{
							windowIconified = true;
						} 
						if ((words[j].word == "windowOpened") && (words[j+1].word == "("))
						{
							windowOpened = true;
						} 
					}
				}
			//}
			}
		}
	}
	// consider when there is an adapter implemented
	for (int i = 0; i < words.size() - 1 ; i++)
	{
		if (words[i].word == "extends") 
		{
			for (int j = i + 1; j < words.size() - 1; j++)
			{
				if (words[j].word == "ComponentAdapter")
				{
					ComponentAdapter = true;
				}
				if (words[j].word == "ContainerAdapter") 
				{
					ContainerAdapter = true;
				}
				if (words[j].word == "FocusAdapter") 				
				{
						FocusAdapter = true;
				}
				if (words[j].word == "KeyAdapter") 
				{
					KeyAdapter = true;
				}
				if (words[j].word == "MouseAdapter") 
				{
					MouseAdapter = true;
				}
				if (words[j].word == "MouseMotionAdapter") 				
				{
					MouseMotionAdapter = true;
				}
				if (words[j].word == "WindowAdapter") 
				{
					WindowAdapter = true;
				}
			}
		}
	}
	// ActionListener
	if ((actionPerformed == false) && (ActionListener == true))
	{
		cout << "This applet implements the ActionListener interface which requires the "
			 << "actionPerformed method even if it is empty. Consider inserting it in your code." << endl;
	}
	if ((actionPerformed == true) && (ActionListener == false))
	{
		cout << "This applet includes the actionPerformed method which requires implementing " 
			 <<  "the ActionListener interface. Consider inserting it in your code." << endl;
	}
	// AdjustmentListener
	if ((adjustmentValueChanged == false) && (AdjustmentListener == true))
	{
		cout << "This applet implements the AdjustmentListener interface which requires the "
			 << "adjustmentValueChanged method even if it is empty. Consider inserting it in your code." << endl;
	}
	if ((adjustmentValueChanged == true) && (AdjustmentListener == false))
	{
		cout << "This applet includes the adjustmentValueChanged method which requires implementing " 
			 <<  "the AdjustmentListener interface. Consider inserting it in your code." << endl;
	}
	// ComponentListener
	if ((ComponentListener == true) && (ComponentAdapter == false))
	{
		if (componentHidden == false)
		{
			cout << "This applet implements the AdjustmentListener interface which requires the " << endl;
			cout << "componentHidden method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (componentMoved == false)
		{
			cout << "This applet implements the AdjustmentListener interface which requires the " << endl;
			cout << "componentMoved method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (componentResized == false)
		{
			cout << "This applet implements the AdjustmentListener interface which requires the " << endl;
			cout << "componentResized method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (componentShown == false)
		{
			cout << "This applet implements the AdjustmentListener interface which requires the " << endl;
			cout << "componentShown method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	if ((ComponentListener == false) && (ComponentAdapter == true))
	{
		cout << "This applet includes the ComponentAdapter which requires implementing " 
			 <<  "the ComponentListener interface. Consider inserting it in your code." << endl;
	}
	// ContainerListener
	if ((ContainerListener == true) && (ContainerAdapter == false))
	{
		if (componentAdded == false)
		{
			cout << "This applet implements the ContainerListener interface which requires the " << endl;
			cout << "componentAdded method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (componentRemoved == false)
		{
			cout << "This applet implements the ContainerListener interface which requires the " << endl;
			cout << "componentRemoved method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	//IT STARTS HERE!!!!
	if ((ContainerListener == false) && (ContainerAdapter == true))
	{
		cout << "This applet includes the ContainerAdapter which requires implementing " 
			 <<  "the ContainerListener interface. Consider inserting it in your code." << endl;
	}
	// FocusListener
	if ((FocusListener == true) && (FocusAdapter == false))
	{
		if (focusGained == false)
		{
			cout << "This applet implements the FocusListener interface which requires the " << endl;
			cout << "focusGained method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (focusLost == false)
		{
			cout << "This applet implements the FocusListener interface which requires the " << endl;
			cout << "focusLost method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	if ((FocusListener == false) && (FocusAdapter == true))
	{
		cout << "This applet includes the FocusAdapter which requires implementing " 
			 <<  "the FocusListener interface. Consider inserting it in your code." << endl;
	}
	// ItemListener
	if ((itemStateChanged == false) && (ItemListener == true))
	{
		cout << "This applet implements the ItemListener interface which requires the "
			 << "itemStateChanged method even if it is empty. Consider inserting it in your code." << endl;
	}
	if ((itemStateChanged == true) && (ItemListener == false))
	{
		cout << "This applet includes the itemStateChanged method which requires implementing " 
			 <<  "the ItemListener interface. Consider inserting it in your code." << endl;
	}
	// KeyListener
	if ((KeyListener == true) && (KeyAdapter == false))
	{
		if (keyPressed == false)
		{
			cout << "This applet implements the KeyListener interface which requires the " << endl;
			cout << "keyPressed method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (keyReleased == false)
		{
			cout << "This applet implements the KeyListener interface which requires the " << endl;
			cout << "keyReleased method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (keyTyped== false)
		{
			cout << "This applet implements the KeyListener interface which requires the " << endl;
			cout << "keyTyped method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	if ((KeyListener == false) && (KeyAdapter == true))
	{
		cout << "This applet includes the KeyAdapter which requires implementing " 
			 <<  "the KeyListener interface. Consider inserting it in your code." << endl;
	}
	// MouseListener
	if ((MouseListener == true) && (MouseAdapter == false))
	{
		if (mouseClicked == false)
		{
			cout << "This applet implements the MouseListener interface which requires the " << endl;
			cout << "mouseClicked method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (mouseEntered == false)
		{
			cout << "This applet implements the MouseListener interface which requires the " << endl;
			cout << "mouseEntered method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (mouseExited == false)
		{
			cout << "This applet implements the MouseListener interface which requires the " << endl;
			cout << "mouseExited method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (mousePressed == false)
		{
			cout << "This applet implements the MouseListener interface which requires the " << endl;
			cout << "mousePressed method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (mouseReleased == false)
		{
			cout << "This applet implements the MouseListener interface which requires the " << endl;
			cout << "mouseReleased method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	if ((MouseListener == false) && (MouseAdapter == true))
	{
		cout << "This applet includes the MouseAdapter which requires implementing " 
			 <<  "the MouseListener interface. Consider inserting it in your code." << endl;
	}
	// MouseMotionAdapter
	if ((MouseMotionListener == true) && (MouseMotionAdapter == false))
	{
		if (mouseMoved == false)
		{
			cout << "This applet implements the MouseMotionListener interface which requires the " << endl;
			cout << "mouseMoved method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (mouseDragged == false)
		{
			cout << "This applet implements the MouseMotionListener interface which requires the " << endl;
			cout << "mouseDragged method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	if ((MouseMotionListener == false) && (MouseMotionAdapter == true))
	{
		cout << "This applet includes the MouseMotionAdapter which requires implementing " 
			 <<  "the MouseMotionListener interface. Consider inserting it in your code." << endl;
	}
	// TextListener
	if ((textValueChanged == false) && (TextListener == true))
	{
		cout << "This applet implements the TextListener interface which requires the "
			 << "textValueChanged method even if it is empty. Consider inserting it in your code." << endl;
	}
	if ((textValueChanged == true) && (TextListener == false))
	{
		cout << "This applet includes the textValueChanged method which requires implementing " 
			 <<  "the TextListener interface. Consider inserting it in your code." << endl;
	}
	// WindowListener
	if ((WindowListener == true) && (WindowAdapter == false))
	{
		if (windowActivated == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowActivated method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (windowClosed == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowClosed method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (windowClosing == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowClosing method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (windowDeactivated == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowDeactivated method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (windowDeiconified == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowDeiconified method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (windowIconified == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowIconified method even if it is empty.Consider inserting it in your code." << endl;
		}
		if (windowOpened == false)
		{
			cout << "This applet implements the WindowListener interface which requires the " << endl;
			cout << "windowOpened method even if it is empty.Consider inserting it in your code." << endl;
		}
	}
	if ((WindowListener == false) && (WindowAdapter == true))
	{
		cout << "This applet includes the WindowAdapter which requires implementing " 
			 <<  "the WindowListener interface. Consider inserting it in your code." << endl;
	}
}

void incompatibleReturnTypeInvocation(){

	for (int i = 4; i < words.size(); i++)
	{
		if((words[i].word == "(") && (isAMethod(words[i-1].word) == true)
			&& (words[i-2].word != "byte") && (words[i-2].word != "short") && (words[i-2].word != "int") 
			&& (words[i-2].word != "long") && (words[i-2].word != "float") && (words[i-2].word != "double") 
			&& (words[i-2].word != "boolean") && (words[i-2].word != "String") && (words[i-2].word != "void")
			&& (words[i-2].word != "new"))
		{
			if (((words[i-2].word == "=") || (words[i-2].word == ">") || (words[i-2].word == "<")) 
				&& (words[i-3].word != "=") && (words[i-3].word != "!") && (words[i-3].word != ">") 
				&& (words[i-3].word != "<") && (isAVariable(words[i-3].word) == true))
			{
				if (returnVariableType(words[i-3].word) != returnMethodType(words[i-1].word))
				{
					cout << "The type of method "<< words[i-1].word << " is not compatible with the type of the variable "
						 << words[i-3].word << ". Consider changing either type to match the other." << endl;	
				}
			}
			if ((words[i-2].word == "=") && ((words[i-3].word == "=") || (words[i-3].word == "!") 
				|| (words[i-3].word == ">") || (words[i-3].word == "<")))
			{
				if (isAVariable(words[i-4].word) == true)
				{
					if (returnVariableType(words[i-4].word) != returnMethodType(words[i-1].word))
					{
						cout << "The type of method "<< words[i-1].word << " is not compatible with the type of the variable "
						 	 << words[i-4].word << ". Consider changing either type to match the other." << endl;	
					}
				}
				int stopPoint;
				// a method is being compared to another method
				if (words[i-4].word == ")")
				{
					for (int j = i - 4; j > 0; j--)
					{
						if (words[j].word == "(")
						{
							stopPoint = j;
							break;
						}
					}
					
					if (isAMethod(words[stopPoint-1].word) == true)
					{	
						if (returnMethodType(words[stopPoint-1].word) != returnMethodType(words[i-1].word))
						{
							cout << "The type of method "<< words[i-1].word << " is not compatible with the type of method "
						 	 	 << words[stopPoint-1].word << ". Consider changing both types to be the same." << endl;	
						}
					}
				} 
			}
		}
	}
}

bool isAVariable(string variableName){

bool compResult = false;

	for (int i = 0; i < variables.size(); i++)
	{
		if (variableName == variables[i].var)
		{
			compResult = true;
			break;
		}	
	}		
	
	return compResult;
}

string returnVariableType(string variableName){

string variableType;

	for (int i = 0; i < variables.size(); i++)
	{
		if (variableName == variables[i].var)
		{
			variableType = variables[i].kind;
			break;
		}	
	}		
	return variableType;
}
