
/****************************************************************************
 * 				 Project 2
 *  			   
 *  			 Course : CMSC 443
 *			   Date : April 17, 1995
 * 	     	     
 *****************************************************************************
    This project is an interactive rectangle processing tool which can help us
 to decryp the transposition cipher. In this project, I created a menu to let
 user select the operations. It can counts total characters, vowels, display
 ciphertext, suggestion rectangle size, and swap or unswap two columns.
 here is assumed your input file is called "p2_infile" and the output file
 will be called "p2_outfile"
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define  ROW     256
#define  COLUMN  256

FILE  *InFile,  *OutFile;

char  VowelSet[10]={ 'a', 'A', 'e', 'E', 'i', 'I', 'o', 'O', 'u', 'U' };

typedef struct pair
{
   int  row;		/* store the row of selected rectangle */
   int  column;     	/* store the column of selected rectangle */
}Pair;
		     
int main()
{
   int   TotalChar=0,		    /* total char in ciphertext */
         TotalVowel=0;		    /* total vowels in ciphertext */
   int   Vowel[COLUMN];		    /* store number of vowels in each row */
   char  cipher[ROW][COLUMN];       /* store original ciphertext */
   char  Rectangle[ROW][COLUMN];    /* store cipher into rectangle */
   Pair  SizeSelection[COLUMN];     /* store selections of rectangle size */
   Pair  R_size;		    /* store size of selected rectangle */
   int   InputLine=0,	            /* total line of input cipher */
         flag=1, select, NumPair, col1, col2,
         i, j;
   int   ReadInCipher( FILE *, char [ROW][COLUMN], int *, int * );
   void  Display( char [ROW][COLUMN], int );
   int   ShowRectangleSize( int , Pair * );
   void  MakeRectangle( char [ROW][COLUMN], char [ROW][COLUMN], int [],
		        Pair, int );
   void  Swap( char [ROW][COLUMN], int, int, Pair );
   void  SaveRectangle( char [ROW][COLUMN], Pair );

   if ((InFile = fopen("p2_infile", "r")) == NULL)
   {
      printf("Couldn't open indata file.\n");
      exit(1);
   }
   else if ((OutFile = fopen("p2_outfile", "w")) == NULL)
   {
      printf("Couldn't open outdata file.\n");
      exit(1);
   }

   /* read in cipher from input file */
   InputLine = ReadInCipher( InFile, cipher, &TotalVowel, &TotalChar );
   /* process possible rectangle size */
   NumPair = ShowRectangleSize( TotalChar, SizeSelection );
   R_size.row = R_size.column = 0;
   while(flag)
   {
      printf("\n\t*********************************************************\n");
      printf("\t*                                 		        *\n");
      printf("\t*       (1) Count total characters in ciphertext        *\n");
      printf("\t*       (2) Display ciphertext			        *\n");
      printf("\t*       (3) Suggest the possible rectangle size         *\n");
      printf("\t*       (4) Count vowel		                        *\n");
      printf("\t*       (5) permute two columns	                        *\n");
      printf("\t*       (6) Undo swap		                        *\n");
      printf("\t*       (7) Restore orginal rectangle cipher            *\n");
      printf("\t*       (8) Save rectangle to file                      *\n");
      printf("\t*       (9) Exit 		                        *\n");
      printf("\t*                             			        *\n");
      printf("\t*********************************************************\n");
      printf("\n\nPlease select one operation < ");
      while( (select = getc( stdin )) < '1' || select > '9' ) 
      {
          if( select == '\n' );
          else
          {
              printf("\n** Your selection was not accepted.\n");
              printf("--> Please enter your selection again between 1 to 9 < ");
	  }
      }

      switch(select)
      {
          case '1' :	/* Count total characters in ciphertext */
    	     printf("\n\t***  TotalChar = %d  ***\n", TotalChar);
             break;

          case '2' :	/* Display ciphertext */
	     Display( cipher, InputLine );
             break;

          case '3' :	/* Suggest the possible rectangle size */
	     /* show possible rectangle size */
  	     for( i=0; i<NumPair; i++ )
       		printf("\t<%2d> ( %3d, %3d )\n", i+1,
 		       SizeSelection[i].row, SizeSelection[i].column );

	     printf("\n-->Please input one size for rectangle < ");
  	     while( (select = getc(stdin)) < '1' || select > NumPair+48 ) 
      	     {
          	if( select == '\n' );
          	else
          	{
              	   printf("\n** Your selection was not accepted.\n");
                   printf("\n-->Please enter selection again between 1 to %d < ",
					NumPair);
	  	}
             }

   	     R_size = SizeSelection[select-49];
	     /* make a rectangle with user selected size */
   	     MakeRectangle( cipher, Rectangle, Vowel, R_size, InputLine );
             break;

          case '4' :	/* Count vowel  */
    	     printf("\n\t***  TotalVowel = %d ***\n", TotalVowel);
             break;

          case '5' :	/* permute two columns */
             if( !R_size.row && !R_size.column )
	  	printf("\n\t???  Please select rectangle size first!!!\n");
             else
             {
 	        /* get two swap column */
                col1 = col2 = 0;
                while(1)
 		{
                   printf("\n\t* Please enter 2 columns between 0 and %d for swapping. *\n",
		                     R_size.column);
                   printf("--> Please enter 1st column for swapping < ");

  		 /* check for valid input column */
                   while(!isdigit(col1=getc(stdin)))
                   {
          	      if( col1 == '\n' );
          	      else
         	      {
              	         printf("\n** Your selection was not accepted.\n");
                         printf("\n-->Please enter between 0 and %d < ",
				  R_size.column);
	  	      }
		   }
		   ungetc(col1, stdin);
                   scanf("%d", &col1);

  		 /* check for valid input column */
                   printf("--> Please enter 2nd column for swapping < ");
                   while(!isdigit(col2=getc(stdin)))
                   {
          	      if( col2 == '\n' );
          	      else
         	      {
              	         printf("\n** Your selection was not accepted.\n");
                         printf("\n-->Please enter between 0 and %d < ",
				  R_size.column);
	  	      }
		   }
		   ungetc(col2, stdin);
                   scanf("%d", &col2);

  		 /* check for valid input column */
                   if((col1<0 || col1 >= SizeSelection[select-49].column)
		      ||(col2<0 || col2 >= SizeSelection[select-49].column))
                   {
                       printf("\n** Your selection was not accepted.\n");
                       printf("\n-->Please enter 2 columns between 0 and %d for swapping < ",
				  R_size.column);
                   }
 		   else  break;
                }
                printf("\n\t**  Swapping column %d and %d  **\n",col1,col2);
                Swap( Rectangle, col1, col2, R_size );      /* process swap */
	     }
             break;

          case '6' :	/* Undo swap */
             Swap( Rectangle, col2, col1, R_size );	     
             break;

          case '7' :	/* Restore orginal rectangle cipher */
   	     MakeRectangle( cipher, Rectangle, Vowel, R_size, InputLine );
             break;

          case '8' :	/* Save rectangle to file */
             if( !R_size.row && !R_size.column )
	  	printf("\n\t???  Please select rectangle size first!!!\n");
             else
             {
	        SaveRectangle( Rectangle, R_size );
                printf("\n\t*****  Save to file completed.  *****\n");
	     }
             break;

          case '9' :	/* Exit */
 	     flag = 0;
             break;
      }
   }

   printf("\n\t*** Thank you! Bye! ***\n");
   close( InFile );
   close( OutFile );
   return 0;
}

/*****************************  READINCIPHER  ******************************
    This function reads in ciphertext from input file. It also counts the
 total number of characters and vowels in the ciphertext. 
 ***************************************************************************/
int  ReadInCipher( FILE *InFile, char cipher[ROW][COLUMN], int *TotalVowel,
				 int *TotalChar )
{
   char  temp;
   int   i=0, j=0, end;
   int   t;

   while( fscanf( InFile, "%c", &temp ) != EOF )
   {
       cipher[i][j++] = temp;    /* read in ciphertext */
       if( temp == '\n' )
       {
 	   i++;
	   j = 0;
       }
       else if( isalpha(temp) || ispunct(temp) )
       {
	   for( t=0; t<10; t++)
		if( temp == VowelSet[t] )   /* check for vowel */
		    (*TotalVowel)++; 
	   (*TotalChar)++;
       }
   }
   end = i;
   return end;
}

/******************************  DISPLAY  **********************************
    This function just prints the orginal ciphertext.
 ***************************************************************************/
void  Display( char cipher[ROW][COLUMN], int end )
{
   int i, j;

   printf("\t***  Input Ciphertext  ***\n\n");
   for( i=0; i<end; i++ )
   {
	for( j=0; j<COLUMN; j++)
	{
           if(cipher[i][j] == '\n')
		  break;
           printf("%c", cipher[i][j]);
	}
        printf("\n");
   }
}

/***************************  SHOWRECTANGLESIZE  ***************************
   This function takes the totalchar as its argument and makes all possible
 size of rectangle. This function returns total number of factors of
 TotalChar as the index of table SizeSelection.
 ***************************************************************************/
int  ShowRectangleSize( int TotalChar, Pair SizeSelection[] )
{
   int   Factor[COLUMN];            /* store factors of total input char */
   int   Factoring( int [], int );  /* find the factors of TotalChar */
   int   total_factor,		    /* store how many factors */
	 i;

   for( i=0; i<COLUMN; i++ )        /* initialize the SizeSeldction table */
   {
	SizeSelection[i].row = 0;
	SizeSelection[i].column = 0;
   }

   total_factor = Factoring( Factor, TotalChar );  /* find factors */
   
   for( i=0; i<total_factor; i++ )           /* assign value to SizeSelection */
   {
	SizeSelection[i].row = Factor[i];
	SizeSelection[i].column = TotalChar/Factor[i];
   }

   return  total_factor;
}

/*******************************  FACTORING  *******************************
   This function factor out the factors of TotalChar. It takes the TotalChar
 and the Factor table as its parameters, and returns the total factors. This
 function takes a number from 2 to half totalchar. If this number can divide
 TotalChar, it is a factor of TotalChar.
 ***************************************************************************/
int  Factoring( int Factor[], int TotalChar )
{
    int  t=2;       /* if t divides TotalChar, it is a factor of TotalChar */
    int  i, p=0;
    while( t < TotalChar/2 )
    {
	if(!( TotalChar % t ))
	    Factor[p++] = t;
	t++;
    }

    return p;
}

/****************************  MAKERECTANGLE  ******************************
   This function makes the input cipher as a rectangle. We pass the original
 cipher and the size of rectangle(R_size) as its arguments. It also counts
 the vowel of each row in new rectangle.
 ***************************************************************************/
void  MakeRectangle( char cipher[ROW][COLUMN], char Rectangle[ROW][COLUMN],
		     int Vowel[ROW], Pair R_size, int InputLine )
{
   int r=R_size.row,           /* row of rectangle */
       c=R_size.column;        /* column of rectangle */
   int i, j, a=0, b=0;

 /* assigns the data into the rectangle, and makes the vowel of each row as 0 */
   Vowel[a] = 0;              
   for( i=0; i<InputLine; i++ )
       for( j=0; j<COLUMN; j++ )
       {
           if(cipher[i][j] == '\n')      break;
           if( b >= c )
	   {
	      a++;
   	      Vowel[a] = 0;              
              b = 0;
	   }
	   Rectangle[a][b++] = cipher[i][j];
       }

 /* print out the content of rectangle */
   printf("\n\tRectangle size is (%d, %d)\n", r, c);
   for( a=0; a<r; a++ )
   {
       printf("\n\t");
       for( b=0; b<c; b++ )
       {
	   for( i=0; i< 10; i++ )   /* count vowel of each row */
	       if( Rectangle[a][b] == VowelSet[i] )
		   Vowel[a]++;
	   printf("%c", Rectangle[a][b]);
	   
       }
       printf("\tVowel = %d", Vowel[a]);
   }       	
   printf("\n");
}

/*********************************  SWAP  **********************************
   This function swap two columns of rectangle. We pass two columns we want
 to swap; this function will permute the columns and show the result.
 ***************************************************************************/
void  Swap( char Rectangle[ROW][COLUMN], int c1, int c2, Pair R_size )
{
    int  i, j;
    char p;

    for( i=0; i<R_size.row; i++ )      /* swap tow columns */
    {
	p = Rectangle[i][c1];
	Rectangle[i][c1] = Rectangle[i][c2];
	Rectangle[i][c2] = p;
    }

    for( i=0; i<R_size.row; i++ )      /* display result */
    {
       printf("\n\t");
       for( j=0; j<R_size.column; j++ )
	   printf("%c", Rectangle[i][j]);
    }
    printf("\n");
}

/***************************** SAVERECTANGLE   *****************************
   This function takes the retangle which want to write to output file
 as the argument and writes to output file.
 ***************************************************************************/
void  SaveRectangle( char Rectangle[ROW][COLUMN], Pair R_size )
{
   int  i, j;

   fprintf( OutFile, "Size is (%3d, %3d)\n\n", R_size.row, R_size.column );
   for( i=0; i<R_size.row; i++ )
   {
        fprintf( OutFile, "\t\n");
	for( j=0; j<R_size.column; j++ )
	   fprintf(OutFile, "%c", Rectangle[i][j]);
   }
}


