#include	<iostream>
#include	<algorithm>
#include	<vector>
#include	<fstream>
#include	<cctype>
#include	<stdexcept>

using std::vector;
using std::string;
using std::ifstream;
using std::endl;
using std::cerr;
using std::cout;
using std::invalid_argument;
using std::transform;

void read_words(const char *file, vector<string> &words)
{
	ifstream in(file);

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

	string word;
	while (in >> word)
		words.push_back(word);
}

bool no_uppercase_chars(const string &str)
{
	return find_if(str.begin(), str.end(), isupper) == str.end();
}

bool not_ends_in_x(const string &str)
{
	return *(str.end() - 1) != 'x';
}

bool short_string(const string &str)
{
	return str.size() < 8;
}

string to_uppercase(const string &str)
{
	// A better way to do this would be to use transform() ...
 	string	ret;
 	string::const_iterator	it;
 	for (it = str.begin(); it != str.end(); it++) 
 		ret += toupper(*it);
 	return ret;
}

void show_words(const vector<string> &words)
{
	vector<string>::const_iterator it;
	for (it = words.begin(); it != words.end(); it++) 
		cout << *it << endl;
}

int
main()
{
	vector<string> standard;
	vector<string> custom;

	try {
		read_words("/usr/share/dict/words", standard);
		read_words("custom", custom);
	} catch (invalid_argument e) {
		cerr << e.what() << endl;
		return -1;
	}

	// Create a new vector which consists of all the strings
	// in 'standard' and all the strings in 'custom'.
	//
	vector<string> words(standard);

	copy(custom.begin(), custom.end(), back_inserter(words));
	// or equivalently...
	//       words.insert(words.end(), custom.begin(), custom.end());

	// Remove all those strings from 'words' that do not end with
	// the letter 'x'.
	//
	words.erase(remove_if(words.begin(), words.end(), not_ends_in_x),
		    words.end());

	// or equivalently...
	// 	vector<string>::iterator start_erase;
	// 	start_erase = remove_if(words.begin(), words.end(),
	// 			        not_ends_in_x);
	// 	words.erase(start_erase, words.end());

	// Create a new vector 'capitalized' that will contain all those
	// strings in 'words' that contain at least one capitalized letter.
	// Note that vector 'words' is unmodified.
	//
	vector<string> capitalized;
	remove_copy_if(words.begin(), words.end(), back_inserter(capitalized),
			no_uppercase_chars);

	// Finally create a new vector 'capitalized' which contains all the
	// strings of 'words', but capitalized.  Note that we are doing
	// the transformation `in place'.  We could have sent the
	// output to another vector using a back_inserter().
	//
	transform(capitalized.begin(), capitalized.end(),
		  capitalized.begin(), to_uppercase);

	// Partition the 'capitalized' vector into short strings and
	// long strings.
	//
	vector<string>::iterator boundary =
		stable_partition(capitalized.begin(), capitalized.end(),
				 short_string);

	// Store the long words in its own vector and remove them
	// from the capitalized vector.
	//
	vector<string> long_words(boundary, capitalized.end());
	capitalized.erase(boundary, capitalized.end());

	// Show both vectors.
	//
	cout << "Short words ending in 'x'" << endl;
	show_words(capitalized);
	cout << endl << "Long words ending in 'x'" << endl;
	show_words(long_words);
}
