#include	<iostream>
#include	<string>
#include	<map>
#include	<fstream>
#include	<stdexcept>
#include	<iomanip>

using std::string;		using std::map;
using std::ifstream;		using std::invalid_argument;
using std::cerr;		using std::cout;
using std::endl;		using std::setw;

const string dictionary_file = "/usr/share/dict/words";

string
lowercase(const string &str)
{
	// This could be better done using transform().
	string	ret;
	string::const_iterator	it;
	for (it = str.begin(); it != str.end(); it++) 
		ret += tolower(*it);
	return ret;
}

map<string, bool>
read_dictionary()
{
	ifstream in(dictionary_file.c_str());
	map<string, bool> dictionary;

	if (! in)
		throw invalid_argument("Invalid: \"" + dictionary_file + "\"");

	string word;
	while (in >> word)
		dictionary[lowercase(word)] = true;

	return dictionary;
}

bool non_alpha(char c)
{
	return !isalpha(c);
}

void
remove_non_alphas(string &word)
{
	word.erase(remove_if(word.begin(), word.end(), non_alpha), word.end());
}

map<string, int>
spell_check_file(const char *file, const map<string, bool> &dictionary)
{
	ifstream in(file);

	if (! in)
		throw invalid_argument("Invalid file \"" + string(file) + "\"");

	string word;
	map<string, int> misspellings;
	while (in >> word) {
		remove_non_alphas(word);
		if (word.empty())
			continue;
		if (dictionary.find(lowercase(word)) == dictionary.end())
			misspellings[word] ++;
	}
	return misspellings;
}

int
main(int argc, char **argv)
{
	if (argc != 2) {
		cerr << "Must specify a file name" << endl;
		return 1;
	}

	try {
		map<string, bool> dict = read_dictionary();
		map<string, int> misspellings = spell_check_file(argv[1], dict);
		map<string, int>::const_iterator it;
		for (it = misspellings.begin(); it != misspellings.end(); it++) {
			cout << setw(15) << it->first
			     << " was misspelled "
			     << it->second
			     << " time" << (it->second == 1 ? "" : "s")
			     << endl;
		}
	} catch (invalid_argument e) {
		cerr << e.what() << endl;
		return 1;
	}

	return 0;
}
