#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>

using namespace std;

//Struct wordItem
struct wordItem {
	string word;
	int count = 0;
};

//function prototypes
wordItem* doubleArray(wordItem*, int*);			//does array doubling
void getStopWords(char *ignoreWordFileName, string ignoreWords[]); //reads the stop words from ignoreWordFileName and store them in the ignoreWords array
bool isStopWord(string word, string ignoreWords[]);						//returns whether the word is in the ignorewords array
void addWord(wordItem*, string, int*, int*);	//adds word to wordItemList or increments word count
void arraySort(wordItem list[], int length);						//sorts the list array by word frequency
int getTotalNumberNonStopWords(wordItem list[], int length);			//finds total number of words in list
void printTopN(wordItem wordItemList[], int topN);                  //prints out the first topN words of the sorted array

//Main function
int main(int argc, char** argv) {

	int topN = atoi(argv[1]);

	char* ignoreWordFileName = argv[3];
	int ignoreWordLength = 50;
	string* ignoreWords = new string[ignoreWordLength];
	getStopWords(ignoreWordFileName, ignoreWords);

	char* filename = argv[2];
	ifstream file;
	file.open(filename);
	if (file.fail()) {
		cout << "Error opening file!" << endl;
		return 1;
	}

	string word;
	int length = 100;
	wordItem* wordItemList = new wordItem[length];
	int currentsize = 0;

	int arrayDoubled = 0;

	while (getline(file, word, ' ')) {
		//resizing array
		if (currentsize >= length) {
			wordItemList = doubleArray(wordItemList, &length);
			arrayDoubled++;
		}
		word.erase(std::remove(word.begin(), word.end(), '\n'), word.end());
		if (isStopWord(word, ignoreWords) || word == "") {
			continue;
		}
		addWord(wordItemList, word, &currentsize, &length);
	}

	arraySort(wordItemList, currentsize);
	int totalWords = getTotalNumberNonStopWords(wordItemList, currentsize);

	/*output*/
	//topN most frequent words
	printTopN(wordItemList, topN);
	//Array doubled
	cout << "Array doubled: " << arrayDoubled << endl;
	cout << "#" << endl;
	//Unique non-common words
	cout << "Unique non-common words: " << currentsize << endl;
	cout << "#" << endl;
	//Total non-common words
	cout << "Total non-common words: " << totalWords << endl;

	return 0;
}
//end of main function

//get stop words from file and store in array
void getStopWords(char *ignoreWordFileName, string ignoreWords[]){
    ifstream file;
	file.open(ignoreWordFileName);
	if (file.fail()) {
		cout << "Error opening file!" << endl;
		return;
	}
	string word;
	int numWords = 0;
	while (getline(file, ignoreWords[numWords])) {
        numWords++;
	}
	file.close();
    return;
}

//Array doubling
wordItem* doubleArray(wordItem* a, int* length) {
	wordItem* temp = new wordItem[2 * (*length)];

	for (int i = 0; i < *length; ++i) {
		temp[i].word = a[i].word;
		temp[i].count = a[i].count;
	}
	(*length) *= 2;
	delete[] a;

	return temp;
}

//check whether word is in the array
bool isStopWord(string word, string ignoreWords[]) {
	for (int i = 0; i < 50; ++i) {
		if (ignoreWords[i] == word) {
			return true;
		}
	}
	return false;
}

//Add word to list or increment wordItem count
void addWord(wordItem* wordItemList, string word, int* currentsize, int* length) {
	for (int i = 0; i < *currentsize; ++i) {
		if (wordItemList[i].word == word) {
			wordItemList[i].count++;
			return;
		}
	}
	//word is not in the wordItemList
	wordItemList[*currentsize].word = word;
	wordItemList[*currentsize].count = 1;
	(*currentsize)++;
	return;
}

//Sort list by word frequency
void arraySort(wordItem list[], int length) {

	for (int i = 0; i < length - 1; ++i) {
		for (int j = 0; j < length - i - 1; ++j) {
			if (list[j].count < list[j + 1].count) {
				int count = list[j].count;
				string word = list[j].word;
				list[j].count = list[j + 1].count;
				list[j].word = list[j + 1].word;
				list[j + 1].count = count;
				list[j + 1].word = word;
			}
		}
	}

	return;
}

//find total number of words in the list
int getTotalNumberNonStopWords(wordItem list[], int length) {
	int total = 0;
	for (int i = 0; i < length; ++i) {
		total += list[i].count;
	}
	return total;
}

//print topN list
void printTopN(wordItem wordItemList[], int topN){
    for (int i = 0; i < topN; ++i) {
		cout << wordItemList[i].count << " - " << wordItemList[i].word << endl;
	}
	cout << "#" << endl;
}
