/* rotx.cc
   Sun May 22 15:18:35 CEST 2005, jochem@vorm.net 
   See http://vorm.net/foucaultspendulum */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <iterator>
#include <vector>
#include <map>

using namespace std;

string shift_word(string word, int shift) {

    unsigned char tmp[4096];

    int size = word.size()+1;
    memcpy(tmp, word.c_str(), size);
    for (int j=0; j < size; ++j) {
        if ((tmp[j] >= 'a' and tmp[j] <= 'z')) {
            tmp[j] += (unsigned char) shift;
            if (tmp[j] > 'z') --tmp[j] -= 'z'-'a';
            if (tmp[j] < 'a') ++tmp[j] += 'z'-'a';
        }
    }
    return string(reinterpret_cast<char *>(tmp));
}

void grow(vector<string> &in, multimap<string,short> &all, short shift) {

    string word;
    for (vector<string>::iterator i = in.begin(); i != in.end(); ++i) {
        word = shift_word(*i, shift);
        all.insert(make_pair(word, shift));
    }
}

void print_dups(multimap<string,short> &all) {

    string prev;
    string orig;
    string last_printed;
    multimap<string,short>::iterator i;
    for (i = all.begin(); i != all.end(); ++i) {
        if (i->second == 0) {
            prev = i->first;
        } else if (i->first == prev) {
            if (i->first != last_printed) {
                orig = shift_word(i->first, -i->second);
                cout << setw(2) << i->second << " " << orig << " " << i->first
                     << endl;
                last_printed = i->first;
            }
        }
    }
}

void strtolower(string *in) {

    char tmp[4096];
    int s = (*in).size()+1;
    memcpy(tmp,(*in).c_str(),s);
    for (int i=0; i < s; i++)
        tmp[i] = tolower(tmp[i]);
    (*in) = tmp;
}

int main (int argc, char* argv[]) {

    string filename;
    string word;
    vector<string> wordlist;
    multimap<string,short> memhog;

    if (argc == 2)  {
        // Set filename
        filename = argv[1];
        if (filename == "-") {
            filename = "/dev/stdin";
        }

        // Read wordlist
        ifstream fh(filename.c_str());
        while (fh >> word) {
            if (word.length() > 2)
                if (word.find("'",0)  == string::npos) {
                    strtolower(&word);
                    wordlist.push_back(word);
                }
        }
        fh.close();

        // Loop through alphabet (half, problem is symmetric) add to memhog
        for (short i=0; i < 14; i++) {
            grow(wordlist, memhog, i);
        }

        // Print matches
        print_dups(memhog);
    } else {
        cerr << "Syntax: rotx wordfile.txt" << endl;
    }
    return 0;
}