#include<iostream>
#include<string>
#include <cstdlib>
#include<cctype>
#include<stdexcept>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
	
/* This is the function from the text for generating a randon integer
 * between 0 and one less than the value passed as a parameter. The 
 * function returns the random value. 
 *
 * The function performs by dividing the range between 0 and RAND_MAX into 
 * n buckets of size bucket_size=RAND_MAX/n (integer division). The function 
 * generates a random value by calling rand() from cstdlib and dividing it by 
 * bucket_size. If the result is >=n, the function discards the value and
 * tries again. This discard process allows the function to avoid the range 
 * between n*bucket_size and RAND_MAX,  that will generally not have 
 * the right number of values (bucket_size) in it.
 */   		
int nrand(int n)
{
	if(n<=0 ||n>RAND_MAX)
		throw domain_error("Argument to nrand is out of range");
	const int bucket_size=RAND_MAX/n;
	int r; 
	do r = rand()/bucket_size;
	while (r>=n);
	return r;
}
/* This function just loads a vector<char> with the uppercase letters A-Z, 
 * then returns the vector.
 */  
vector<char> alphabet()
{
	vector<char> ret;
	for(int i=0; i<26; i++)
		ret.push_back('A'+i);
	return ret;
}

/* The shuffle function takes a vector as its parameter and returns 
 * a randomly shuffled version of the vector.
 *
 * It is a implemented here with a function template. The class T represents any
 * data type to which swap applies. We will see more about templates in 
 * chapter 8. When the compiler encounters a call to a function implemented 
 * with a template, the compiler creates a version of the function for the 
 * type/s provided as parameters.
 */ 
template <class T>		
vector<T> shuffle(vector<T> v)//Returns a shuffled version of v.
{
	typedef typename vector<T>::size_type v_size;
	/* For each index, exchange the value at that index with a random
	 * value from earlier in the vector.
	 */
	for(v_size i=1; i<v.size(); i++)
	{
		int replacement=nrand(i+1);
		swap(v[i], v[replacement]);
	}
	return v;
}
/* This displays the elements a of vector separated by spaces. */
 template <class T>
 void show(const vector<T> v)
{
	typedef typename vector<T>::size_type v_size;
	for(v_size i=0; i<v.size(); i++)
		cout<<v[i]<<" ";
}
/* The main function creates and displays a random substitution cipher.
 * It enciphers and deciphers a line of text supplied by the user.
 */
int main()
{
	srand(time(NULL));//Seed the random number sequence.
	vector<char> a=alphabet();
	vector<char> s=shuffle(a);
	map<char, char> cipher, decipher;
	for(vector<char>::size_type i=0; i<26; i++)
	{
		cipher[a[i]]=s[i];/*Map each letter to the 
				    letter shuffled to that 
				    position.
				    */
		decipher[s[i]]=a[i];/*Create the inverse map.*/
	}
	show(a);
	cout<<endl;
	show(s);
	cout<<endl;
	cout<<"Enter a line to encode: " ;
	string plain_text, cipher_text;
	getline(cin, plain_text);
	/* Use the map 'cipher' to encode plain_text one character at
	 * a time.
	 */
	for(string::size_type i=0; i!=plain_text.size();i++)
		if(isalpha(plain_text[i]))
			cipher_text += cipher[toupper(plain_text[i])];
		else
			cipher_text+= plain_text[i];
		
	cout<<endl<<cipher_text;
	plain_text="";
	
	/* Decode using the map 'decipher'.
	 */
	for(string::size_type i=0; i!=cipher_text.size();i++)
		if(isalpha(cipher_text[i]))
			plain_text += decipher[toupper(cipher_text[i])];
		else
			plain_text+= cipher_text[i];
	cout<<endl<<plain_text;
	//system("clear"); clears the screen 
	return 0;
}

