#include <stdio.h>
#include <string.h>

#define _UNOFFICIAL

#define MSEC 1000

#define LED_OFF   fputs("7,1\n", f_led)
#define LED_ON    fputs("7,2\n", f_led)
#define LED_BLINK fputs("7,3\n", f_led)

#define T_DIT 60000/(50*wpm) * MSEC

#define DAH	3
/* Time between... */
#define SIGN	1
#define LETTER	DAH
#define WORD	7

#define NO_PAUSE -1

#define O_NORMAL	0
#define O_VERBOSE	1
#define O_ONOFF		2

char* morsecode[] = {
			/* '.' is a dit, '-' is a dah, everything else is a pause of one dit */

			/* letters */
			"A" ".-",
			"B" "-...",
			"C" "-.-.",
			"D" "-..",
			"E" ".",
			"F" "..-.",
			"G" "--.",
			"H" "....",
			"I" "..",
			"J" ".---",
			"K" "-.-",
			"L" ".-..",
			"M" "--",
			"N" "-.",
			"O" "---",
			"P" ".--.",
			"Q" "--.-",
			"R" ".-.",
			"S" "...",
			"T" "-",
			"U" "..-",
			"V" "...-",
			"W" ".--",
			"X" "-..-",
			"Y" "-.--",
			"Z" "--..",

			/* numbers */
			"0" "-----",
			"1" ".----",
			"2" "..---",
			"3" "...--",
			"4" "....-",
			"5" ".....",
			"6" "-....",
			"7" "--...",
			"8" "---..",
			"9" "----.",

			/* punctuation */
			"." ".-.-.-",
			"," "--..--",
			"?" "..--..",
			"\'" ".----.",
			"/" "-..-.",
			"&" ". ...",
			":" "---...",
			";" "-.-.-.",
			"=" "-...-",
			"-" "-....-",
			"$" "...-..-",
			"\"" ".-..-.",
			"@" ".--.-.",
#ifdef _UNOFFICIAL
			"!" "-.-.--",
			"(" "-.--.",
			")" "-.--.-",
#else
			"(" "-.--.-",
			")" "-.--.-",
#endif

			/* custom */
			"#" "|-",
			"*" "|.",
};

int morse(char s[]);
void strmorse(char s[]);

FILE* f_led;
int format;
int wpm = 20;

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

	if (argc < 2) {
		printf("Usage: %s [0|1 (format)] [words-per-minute] string\n", argv[0]);
		return -1;
	}
	
	if (argc > 2 && isdigit(*argv[1]) && (format = atoi(argv[1])) >= O_NORMAL && format <= O_ONOFF) {
		i = 2;

		if (argc > 3 && isdigit(*argv[2])) {
			wpm = atoi(argv[2]);
			i++;
		}
	} else {
		format = O_NORMAL;
		i = 1;
	}

	f_led = fopen("/var/led", "w");
	setvbuf(f_led, NULL, _IONBF, BUFSIZ);
	setvbuf(stdout, NULL, _IONBF, BUFSIZ);

	strmorse(argv[i]);

	return 0;
}

int morse(char s[])
{
	int i, n;

	for (i = 1; s[i] != '\0'; i++) {
		switch (s[i]) {
			case '.':
				LED_ON;
				if (format == O_ONOFF)
					putchar('=');
				else
					putchar('.');

				usleep(T_DIT);
				break;
			case '-':
				LED_ON;
				if (format == O_ONOFF)
					for (n = 0; n < DAH; n++) {
						putchar('=');
						usleep(T_DIT);
					}
				else {
					putchar('-');
					usleep(DAH*T_DIT);
				}
				break;
			default:
				if (format == O_ONOFF)
					putchar('.');
				else
					putchar(' ');
				usleep(T_DIT);
		}

		LED_OFF;
		if (s[i+1] != '\0') {
			if (format == O_ONOFF)
				putchar('.');
			usleep(SIGN*T_DIT);
		} else
			break;
	}
	
	return i;
}
	

void strmorse(char s[])
{
	int c, i, j, n;

	if (format == O_VERBOSE)
		printf("%s\n", s);

	for (i = 0; s[i] != '\0'; i++) {
		if (format == O_VERBOSE)
			printf("\t'%c' ", s[i]);

		if (!isblank(s[i])) {
			c = toupper(s[i]);
		
			/* find the morse code */
			for (j = sizeof(morsecode)/sizeof(char*)-1; j >= 0 && morsecode[j][0] != c; j--)
				;

			if (j >= 0) {
				morse(morsecode[j]);
				if (s[i+1] != '\0') {
					if (format == O_ONOFF)
						for (n = 0; n < LETTER; n++) {
							putchar('.');
							usleep(T_DIT);
						}
					else {
						if (format == O_NORMAL)
							putchar(' ');
						usleep(LETTER*T_DIT);
					}
				}
				if (format == O_VERBOSE)
					putchar('\n');
			} else
				puts("unknown character");
		} else {
			if (format == O_NORMAL)
				printf("/ ");
			else {
				for (n = 0; n < WORD-LETTER; n++) {
					if (format == O_ONOFF)
						putchar('.');
					else
						putchar(' ');
					usleep(T_DIT);
				}
				if (format == O_VERBOSE)
					putchar('\n');
			}
		}
	}

	if (format != O_VERBOSE)
		putchar('\n');
}

