PROGRAM CodeMaker;
{Programmer:	Gregory A. Perkins
				CS 65
		Due:	4 December 1996}
		
{This program gives the user a menu of choices which include encryption,
	decryption, and quit.  The program will either encrypt or decrypt a
	one line message entered by the user, and display the result.  The
	program also makes use of an interactive loop to allow the user to
	do as many operations as desired.}
	
{Declarations module}
VAR Key1, Key2, Key3, Operation : INTEGER;
VAR Continue : BOOLEAN;
TYPE Message = ARRAY[1..80] OF CHAR;
VAR Plain, Crypt : Message;

PROCEDURE Encrypt(Shift : INTEGER; VAR Code : CHAR);
VAR NumCode : INTEGER;
BEGIN
	NumCode := ORD(Code);
	IF (NumCode + Shift <= 126) THEN
		NumCode := NumCode + Shift
	ELSE
		NumCode := NumCode + Shift - 95;
	Code := CHR(NumCode);
END;

PROCEDURE Decrypt(Shift : INTEGER; VAR Code : CHAR);
VAR NumCode : INTEGER;
BEGIN
	NumCode := ORD(Code);
	IF (NumCode - Shift >= 32) THEN
		NumCode := NumCode - Shift
	ELSE
		NumCode := NumCode - Shift + 95;
	Code := CHR(NumCode);
END;

PROCEDURE Encryption(K1, K2, K3 : INTEGER; PlainText : Message; VAR CipherText : Message);
{Accepts the three keys/offsets(K1,K2,K3) to a polyaphabetic code and a message written
	in PlainText and encrypts the message storing it in CipherText}
VAR Count, K, Index : INTEGER;
VAR Letter : CHAR;	
	BEGIN
		WRITELN;
		WRITELN('Enter your message on one line and terminate with a tilde (~).');
		WRITELN('The program will display the encrypted text when you');
		WRITELN('press the ENTER key.');

		{Input module}
		Count := 0;
		READ(Letter);  {letter must be initialized}

		WHILE (ORD(Letter) <> 126) DO
			BEGIN
				Count := Count + 1;
				PlainText[Count] := Letter;
				READ(Letter);
			END;
			
		READLN;  {clears the 'READ' queue}
		
		{Main loop : encryption module}
		FOR Index := 1 TO Count DO
			BEGIN
				K := Index MOD 3;
				Letter := PlainText[Index];
		
				CASE K OF
					0 : Encrypt(K1, Letter);
					1 : Encrypt(K2, Letter);
					2 : Encrypt(K3, Letter);
				END;  {case}
		
				CipherText[Index] := Letter;
			END;
	
		{Output module}
		WRITELN;
		WRITELN('The encrypted text is: ');

		FOR Index := 1 TO Count DO
			BEGIN
				Letter := CipherText[Index];
				WRITE(Letter);
			END;
		WRITELN;  {advance to next line}
	END;
	
PROCEDURE Decryption(K1, K2, K3 : INTEGER; CipherText : Message; VAR PlainText : Message);
{Accepts the three keys/offsets(K1,K2,K3) to a polyaphabetic code and a coded message
	(CipherText) and decodes the message storing it in PlainText}
VAR Count, K, Index : INTEGER;
VAR Letter : CHAR;	
	BEGIN
		WRITELN;
		WRITELN('Enter the encrypted message on one line and terminate');
		WRITELN('with a tilde (~). The program will display the decrypted');
		WRITELN('text when you press the ENTER key.');

		{Input module}
		Count := 0;
		READ(Letter);  {letter must be initialized}

		WHILE (ORD(Letter) <> 126) DO
			BEGIN
				Count := Count + 1;
				CipherText[Count] := Letter;
				READ(Letter);
			END;
			
		READLN;  {clears the 'READ' queue}
		
		{Main loop : encryption module}
		FOR Index := 1 TO Count DO
			BEGIN
				K := Index MOD 3;
				Letter := CipherText[Index];
		
				CASE K OF
					0 : Decrypt(K1, Letter);
					1 : Decrypt(K2, Letter);
					2 : Decrypt(K3, Letter);
				END;  {case}
		
				PlainText[Index] := Letter;
			END;
	
		{Output module}
		WRITELN;
		WRITELN('The decrypted text is: ');

		FOR Index := 1 TO Count DO
			BEGIN
				Letter := PlainText[Index];
				WRITE(Letter);
			END;
		WRITELN;  {advance to next line}
	END;
	

BEGIN  {program}

Continue := TRUE;
WHILE Continue DO  {interactive loop}
	BEGIN
		{Prompt module}
		REPEAT
			WRITELN;
			WRITELN('1 = Encryption');
			WRITELN('2 = Decryption');
			WRITELN('3 = QUIT');
			WRITE('ENTER the number of the operation you would like to perform : ');
			READLN(Operation);
			IF ((Operation < 1) OR (Operation > 3)) THEN
				WRITELN('**********  I N V A L I D   C H O I C E  **********');
		UNTIL ((Operation >= 1) AND (Operation <= 3));

			
		IF ((Operation = 1) OR (Operation = 2)) THEN
			BEGIN
				WRITELN;
				WRITELN('Enter the three encoding/decoding keys.');
				WRITE('Numbers from 1 - 94 separated by spaces(Ex. 6 2 38) : ');
				READLN(Key1, Key2, Key3);
			END;
			
		{Execution module}
		CASE Operation OF
			1 : Encryption(Key1, Key2, Key3, Plain, Crypt);
			2 : Decryption(Key1, Key2, Key3, Crypt, Plain);
			3 : Continue := FALSE;
		END;
				
	END;  {interactive loop}
	
END.  {program}