// File:            ReadWords.cpp
// ---------------------------------------------------------------------
//          Author: Russell Lowke,  lowke@fas.harvard.edu
//              TF: Francis Crick
//            Date: 8/1/2002
//      Assignment: Unit 7 Hard Supp programming exercises
//         Version: 1
//
//     Description: program that takes a text file containing one word per line and
//					sorts those worfds in alphabetical order by:
//					a) Read words from the file into 26 arrays
//					b) sort each array by an algorithm from sort.hpp
//					c) Write sorted arrays to an output file.
// 

// include header
#include "ReadWords.h"

const int MAXSTRLEN = 30;
const int MAXLIST   = 1000;
const int LETTER_AZ = 27;

typedef char* wordList[MAXLIST];


//
// BubbleSort - perform bubble sort on the specified string
//
void BSort(char* arr[], int num_objects)
{
	char temp[MAXSTRLEN];
	num_objects--;
	
    for (int i = 1; i <= num_objects; i++) {
		for (int j = num_objects; j >= i; j--) {
			
	    	if ( strcmp( arr[j], arr[j-1] ) < 0 ) {
				
				// swap
				strcpy(temp, arr[j - 1]);
				strcpy(arr[j - 1], arr[j]);
				strcpy(arr[j], temp);
	
			}
		}
	}
}


//
//   ReadWords class
//   analyzes files, counting number of small, large, and medium words
//
class ReadWords
{
	private :
	
		char *  pFileName;						// name of file being read
	  ifstream  pInStream;						// in stream for file
	  
	  wordList  letterLists[LETTER_AZ];
	  int		wCount[LETTER_AZ];
		
      public:
       
		        ReadWords(char *filename); 		// constructor
		        ~ReadWords();					// destructor
       	int     readFile(int letterNum);		// open and read
		void    printData();					// display
		void    clearMemory();
		void    sortArrays();
		int     openFile();						// generic open
		int     closeFile();					// generic close
		void    writeFile(char * fileName);
};


//
//  constructor for FilePairs class
//
ReadWords :: ReadWords (char * fileName)
{
	// empty pWords list
	for (int i = 0; i < MAXLIST; i++) {
		for(int j = 0; j < LETTER_AZ; j++) {
			letterLists[j][i] == NULL;
		}
	}
	
	for (int i = 0; i < LETTER_AZ; i++) {
		wCount[i] = 0;
	}
	
	pFileName = fileName;
}

//
//  destructor for ReadWords class
//  
ReadWords :: ~ReadWords()
{
}

//
//  open file stuff
int ReadWords :: openFile()
{
	// open file		
	pInStream.open(pFileName);
	
	// ensure file exists
	if (pInStream == NULL) {					// file not found
	
		cout << pFileName << " -- Input file not found!\n";
		return -1;								// readFile failed
		
	} else {									// file OK
	
		pInStream.unsetf(ios::skipws);			// unset skip whitespace	
		
		return 0;								// readFile worked
	}
}


int ReadWords :: closeFile()
{
	pInStream.close();
	return 0;									// closeFile worked
}

//
// write sorted word data to a file
// 
void ReadWords :: writeFile(char * fileName)
{
	ofstream outFile;
	outFile.open(fileName);
	
	for (int binNum = 0; binNum < LETTER_AZ; binNum++) {
		int counter = 0;
		while(letterLists[binNum][counter]) {
			outFile << letterLists[binNum][counter] << endl;
			counter++;
		}
	}
	
	outFile.close();
}


//
//  read file [pFileName]
//
int ReadWords :: readFile(int letterNum = 0)
{
	char c;	
	int wordLength = 0;
	int wordCount  = 0;
	int binNum     = 0;
	
	char* str = new char[MAXSTRLEN];
	
	while (! pInStream.eof() ) {
	
		pInStream >> c;						// read file
		
		// convert to lowercase
		c = tolower(c);
		
		// new word if space or EOF
		if ( isspace(c) || pInStream.eof() ) {
			
			// finish word
			str[wordLength] = '\0';
			
			// save word
			binNum = (int) (str[letterNum] - 'a');
			if (binNum > -1 && binNum < LETTER_AZ) {
				letterLists[binNum][wCount[binNum]] = str;
			}
			
			// new word
			wCount[binNum]++;
			str = new char[MAXSTRLEN];
			wordLength = 0;					// reset wordLength
			
		} else if ( (c >= 'a' && c <= 'z') ) {
			str[wordLength] = c;			// add char
			wordLength++;
		}
	}
		
	return 0;									// readFile worked
}


//
//  Print data for ReadWords 
//
void ReadWords :: printData()
{
	for (int binNum = 0; binNum < LETTER_AZ; binNum++) {
		int counter = 0;
		while(letterLists[binNum][counter]) {
			cout << letterLists[binNum][counter] << endl;
			counter++;
		}
	}
}

//
//  sort each letter array! (bubble sort)
//
void ReadWords :: sortArrays()
{
	int nWords;
	
	for (int binNum = 0; binNum < LETTER_AZ; binNum++) {
		nWords = wCount[binNum];
		BSort(letterLists[binNum], nWords);
	}
}


//
//  Print data for ReadWords 
//
void ReadWords :: clearMemory()
{
	for (int binNum = 0; binNum < LETTER_AZ; binNum++) {
		int counter = 0;
		while(letterLists[binNum][counter]) {
			delete [] letterLists[binNum][counter];
			counter++;
		}
	}
}


//
// prints the array
//
void pntArray(char* arr[], int n)
{
	cout << "{ ";
	for (int i = 0; i < n; i++) {
		cout << arr[i] << " ";
	}
	cout << "}" << endl;
}


void main()
{
	char fileName[MAXSTR];
	
	getString("Name of your file: ", fileName, MAXSTR);
	ReadWords robot( fileName );				// construct ReadWords object
	if ( robot.openFile() == -1 ) {
		 exit(1);								// file not found
	}
	robot.readFile(0);							// read file in
	robot.closeFile();							// close it
	
	robot.sortArrays();							// sort it
		
	robot.writeFile("sortedWords.txt");			// save it out
	robot.clearMemory();						// clear memory
	
	exit(0);
}