#include <unistd.h>
#include <ctype.h>
#include <stdio.h>

struct opt_t {
	int cur, start, delta;
	char dir, nlreset, verbose;
} opt;

extern char *optarg;
extern int optind, opterr, optopt;

void fasthelp (void)
{
	fprintf (stderr, "rot [-hlr] [-s start] [-d delta]\n\n");
	fprintf (stderr, "  -h: fasthelp\n");
	fprintf (stderr, "  -s: start rot (domyślnie 13)\n");
	fprintf (stderr, "  -d: delta rot (domyślnie 0)\n");
	fprintf (stderr, "  -l: left dir\n");
	fprintf (stderr, "  -r: newline reset\n");
	fprintf (stderr, "\nhttp://www.gophi.rulez.pl/\n");
}

void parse_opt (int ac, char **av)
{
	char done = 0;

	opt.delta = 0;
	opt.dir = 'r';
	opt.start = 13;
	opt.nlreset = 0;
	opt.verbose = 0;

	while (!done)
		switch (getopt(ac, av, "hrlvs:d:")) {
			case 'h':
				fasthelp();
				exit (0);
			case 'r':
				opt.nlreset = 1;
				break;
			case 'l':
				opt.dir = 'l';
				break;
			case 'v':
				opt.verbose = 1;
				break;
			case 's':
				opt.start = atoi(optarg);
				break;
			case 'd':
				opt.delta = atoi(optarg);
				break;
			case -1:
				done = 1;
				break;
			case '?':
			case ':':
				exit (1);
		}

	opt.start %= 26;
	opt.delta %= 26;
	opt.cur = opt.start;

	if (opt.verbose) {
		fprintf (stderr, "opt.start => %d\n", opt.start);
		fprintf (stderr, "opt.delta => %d\n", opt.delta);
		fprintf (stderr, "opt.dir   => %c\n", opt.dir);
		fprintf (stderr, "opt.reset => %d\n", opt.nlreset);
	}
}

char rotate_char (char ch)
{
	int i;

	if (tolower(ch) < 'a' || tolower(ch) > 'z')
		return ch;

	for (i = 0; i < opt.cur; i++) {
		if (opt.dir == 'r') {
			if (ch == 'z')
				ch = 'a';
			else if (ch == 'Z')
				ch = 'A';
			else
				ch++;
		} else {
			if (ch == 'a')
				ch = 'z';
			else if (ch == 'A')
				ch = 'z';
			else
				ch--;
		}
	}

	return ch;
}

void update_opt (char ch)
{
	if (ch == 0x0D)
		return;
	else if (ch == 0x0A && opt.nlreset)
		opt.cur = opt.start;
	else {
		opt.cur += opt.delta;
		opt.cur %= 26;
	}
}

void parse_char (char ch)
{
	ch = rotate_char(ch);
	update_opt (ch);

	putchar (ch);
}

void parse_text (char *ptr)
{
	while (*ptr)
		parse_char (*ptr++);
}

void parse (char **ptr)
{
	if (ptr) {
		while (*ptr)
			parse_text (*ptr++);
	} else {
		char buf[1024];

		while (!0) {
			fgets (buf, sizeof(buf), stdin);
			if (feof(stdin))
				break;
			else
				parse_text (buf);
		}
	}
}

int main (int ac, char **av)
{
	parse_opt (ac, av);

	if (av[optind])
		parse (av + optind);
	else
		parse (NULL);
}
