// FILE HEADER COMMENT

import java.io.*;

// CLASS HEADER COMMENT
class Encoder {

 	private static BufferedReader stdin = new BufferedReader
 		(new InputStreamReader (System.in));	

	private static final int MAX_INT = 2147483647;
	private static final int NUM_DIGITS = 10;
	private static final int NUM_LETTERS = 26;


	// main method--runs the encoder
    public static void main (String[] args) throws IOException {

		// get integer to shift letters and digits
		int shiftValue = readInt( "Enter # of shifts" , 0, MAX_INT );

		String srcFileName; // name of the source file
		File srcFile;       // File object associated with source file
		File dstFile;       // File object associated with destination file

		// get source file and create destination file
		boolean repeat = false;
		do {
			srcFileName = readString( "Enter source file name", -1 );
			srcFile = new File( srcFileName );
			dstFile = new File( srcFileName + ".enc" );
			dstFile.createNewFile();

			if( !srcFile.exists() ) {
				System.out.println( "ERROR--Source File does not exists" );
				repeat = true;
			}
			else if( !srcFile.isFile() || !srcFile.canRead() ){
				System.out.println( "ERROR--File not readable" );
				repeat = true;
			}
			else if( !dstFile.canWrite() ) {
				System.out.println( "ERROR--Can't write to " + srcFileName + ".enc" );
				repeat = true;
			}
			else {
				repeat = false;
			}
		}
		while( repeat );

		// object for file input and file output
		BufferedReader inFile = new BufferedReader( new FileReader( srcFile ) );
		PrintWriter outFile = new PrintWriter( new BufferedWriter
											   ( new FileWriter( dstFile ) ) );

		// read each line from source file, encode it,
		// and write it to destination file
		while( inFile.ready() ) {

			String line = inFile.readLine();
			outFile.println( encodeString( line, shiftValue ) );

		}

		// close files
		inFile.close();
		outFile.close();
		
    }//end of main method


	
	/**
	 * encodeString
	 *
	 * Encodes a String by shifting digits and letters by shiftValue.
	 * Digits are only shifted amongst digits, and letters are only
	 * shifted amongst letters.  All other characters remain unchanged.
	 * @param str the string to be encoded
	 * @param shiftValue the number of positions to shift characters
	 * @return the encoded String
	 **/
	public static String encodeString( String str , int shiftValue) {

		StringBuffer newStr = new StringBuffer( "" );

		for( int i = 0; i < str.length(); i++ ) {

			char nextChar = str.charAt( i );
			
			// shift if digit
			if( isNumber( nextChar ) ) {
				nextChar += (shiftValue % NUM_DIGITS);
				if( nextChar > '9' ) {
					nextChar = (char)(nextChar % '9' + '0' - 1);
				}
			}
			
			// shift if lower-case letter
			else if ( isLowerLetter( nextChar ) ) {
				nextChar += (shiftValue % NUM_LETTERS);
				if( nextChar > 'z' ) {
					nextChar = (char)(nextChar % 'z' + 'a' - 1);
				}
			}
			
			// shift if upper-case letter
			else if ( isUpperLetter( nextChar ) ) {
				nextChar += (shiftValue % NUM_LETTERS);
				if( nextChar > 'Z' ) {
					nextChar = (char)(nextChar % 'Z' + 'A' - 1);
				}
			}
			
			// append nextChar to newLine
			newStr.append( nextChar );
			
		}
		return( newStr.toString() );
	}


	public static boolean isNumber( char c ) {

		return( c >= '0' && c <= '9' );

	}

	public static boolean isLowerLetter( char c ) {

		return( c >= 'a' && c <= 'z' );

	}

	public static boolean isUpperLetter( char c ) {
		
		return( c >= 'A' && c <= 'Z' );

	}

	/**
	 * readString
	 *
	 * reads a String of characters from user input (up to maxStrSize
	 * characters, but at least 1 character), and returns the String.
	 * Note, if maxStrSize has a length < 0, then there is no upper
	 * limit to the String size.
	 * @param prompt the prompt to tell the user what to enter
	 * @param maxStrSize the maximum # characters that the user can enter
	 * @return the String entered by the user
	 **/
	public static String readString( String prompt, int maxStrSize )
	throws IOException {

		String str = "";
		boolean repeat = true;

		do {
			System.out.print( prompt + ": " );
			str = stdin.readLine( );
			if( str.length( ) == 0 ) {
				System.out.println( "You must enter a string of at least " +
									"one character in length." );
				repeat = true;
			}
			else if( maxStrSize > 0 && str.length( ) > maxStrSize ) {				
				System.out.println( "The string entered must be no more " +
									"than " + maxStrSize + " characters " +
									"in length." );
				repeat = true;
			}
			else {
				repeat = false;
			}
		}
		while( repeat );
		return( str );
	}



	/**
	 * readInt
	 *
	 * reads an integer from the user in a specified range
	 * @param prompt the prompt to tell the user what to enter
	 * @param min the minimum allowable integer that a user can enter
	 * @param max the maximum allowable integer that a user can enter
	 * @return the integer entered by the user
	 **/
	public static int readInt( String prompt, int min, int max )
	throws IOException {

		int val = 0;              // integer to be returned
		boolean repeat = false;   // flag for loop repeating
		
		do {
			System.out.print( prompt + ": " );
			try {
				val = Integer.parseInt( stdin.readLine() );
				if( val < min || val > max ) {
					System.out.println( "The integer entered must be " +
										"between " + min + " and " + max +
										"." );
					repeat = true;
				}
				else {
					repeat = false;
				}
			}
			catch( NumberFormatException e ) {
				System.out.println( "You must enter an integer." );
				repeat = true;
			}
		}
		while( repeat );

		return( val );
	}												
}





