import java.io.*;
import java.util.*;

public class JohnnyAppleseed {
	private static final int EXIT_FAILURE = 1;
	private static final int EXIT_SUCCESS = 0;
        private static final int[] TEXTURE_CHOICES = { 32, 64, 128, 256, 512, 1024, 2048 };
        private static final String DEFAULT_INPUT_FILE = "world.tiles";
        private static final String DEFAULT_OUTPUT_FILE = "overlay.add.txt";
        
	int numToReplace = -1;
	int textureId = -1;
        int width = -1;
        int height = -1;
        BufferedReader mapInput = null;
        BufferedWriter output = null;

	private void printQuestionMarks( int counter ) {
		for ( int i = 0; i < counter; i++ ) {
			if ( i % 2 == 0 ) {
				System.out.print( "?" );
			} else {
				System.out.print( "!" );
			}
		}
		System.out.println();
	}
        
        private void printTextureSizeChoices() {
            for ( int i = 0; i < TEXTURE_CHOICES.length; i++ ) {
                System.out.println( "" + i + ". " + getTextureSize( i ) );
            }      
        }
        
        private int getTextureSize( int textureChoice ) {
            int textureSize = -1;
            
            if ( textureChoice < 0 || textureChoice >= TEXTURE_CHOICES.length ) {
                System.err.println( "Invalid texture choice" );
                System.exit( EXIT_FAILURE );
            }
            
            return TEXTURE_CHOICES[ textureChoice ];
        }
        
        public JohnnyAppleseed() {
            getInputFromUser();
            parseAndWrite();
        }

        public void getInputFromUser() {
		// texture_id x y width height
		BufferedReader input = new BufferedReader( new InputStreamReader( System.in ) );
		String line = null;
		int counter = 1;
		boolean done = false;

		System.out.println( "Welcome to Johnny Appleseed!" );
		System.out.println( "#####" );
	
		do {
                        System.out.println();
			System.out.print( "What number should I find and replace" );
			printQuestionMarks( counter );
			try {
				line = input.readLine();
				numToReplace = Integer.parseInt( line );
				if ( numToReplace >= 100 && numToReplace <= 999 ) {
					done = true;
				} else {
					System.err.println( "Invalid Texture ID: 100 <= texture_id <= 999" );
				}
			} catch ( NumberFormatException ex ) {
				System.err.println( "Your number isn't a number" );
			} catch ( Exception e ) {
				System.err.println( "Error reading from console!" );
				System.exit( EXIT_FAILURE );
			}
			counter++;
		} while ( !done || ( line == null || line.equals( "" ) ) );		
		done = false;
		counter = 1;
		System.out.println( "Replace this: " + numToReplace );
		System.out.println( "#####" );
		
		do {
                        System.out.println();
			System.out.print( "What texture do you want to replace with" );
			printQuestionMarks( counter );
			try {
				line = input.readLine();
				textureId = Integer.parseInt( line );
				if ( textureId >= 100 && textureId <= 999 ) {
					done = true;
				} else {
					System.err.println( "Invalid Texture ID: 100 <= texture_id <= 999" );
				}
			} catch ( NumberFormatException ex ) {
				System.err.println( "Your number isn't a number" );
			} catch ( Exception e ) {
				System.err.println( "Error reading from console!" );
				System.exit( EXIT_FAILURE );
			}
			counter++;
		} while ( !done || ( line == null || line.equals( "" ) ) );		
		done = false;
		counter = 1;
		System.out.println( "New Texture ID: " + textureId );
		System.out.println( "#####" );
                
                do {
                        System.out.println();
			System.out.print( "What is the width of that texture?" );
			printQuestionMarks( counter );
                        
                        System.out.println();
                        printTextureSizeChoices();
                        System.out.println();
                        
			try {
				line = input.readLine();
				width = Integer.parseInt( line );
				if ( width >= 0 && width < TEXTURE_CHOICES.length ) {
					done = true;
				} else {
					System.err.println( "Invalid Texture Size Choice" );
				}
			} catch ( NumberFormatException ex ) {
				System.err.println( "Your number isn't a number" );
			} catch ( Exception e ) {
				System.err.println( "Error reading from console!" );
				System.exit( EXIT_FAILURE );
			}
			counter++;
		} while ( !done || ( line == null || line.equals( "" ) ) );		
		done = false;
		counter = 1;
		System.out.println( "Texture Width: " + width );
		System.out.println( "#####" );
                
                do {
                        System.out.println();
			System.out.print( "What is the height of that texture?" );
			printQuestionMarks( counter );
                        
                        System.out.println();
                        printTextureSizeChoices();
                        System.out.println();
                        
			try {
				line = input.readLine();
				height = Integer.parseInt( line );
				if ( height >= 0 && height < TEXTURE_CHOICES.length ) {
					done = true;
				} else {
					System.err.println( "Invalid Texture Size Choice" );
				}
			} catch ( NumberFormatException ex ) {
				System.err.println( "Your number isn't a number" );
			} catch ( Exception e ) {
				System.err.println( "Error reading from console!" );
				System.exit( EXIT_FAILURE );
			}
			counter++;
		} while ( !done || ( line == null || line.equals( "" ) ) );		
		done = false;
		counter = 1;
		System.out.println( "Texture Height: " + width );

                // Open the file...If we can't, ask for a name until we can
                try {
                    mapInput = new BufferedReader( new FileReader( DEFAULT_INPUT_FILE ) );
                } catch ( Exception e ) {
                    System.err.println( "Error opening input file " + DEFAULT_INPUT_FILE );
                    System.exit( EXIT_FAILURE );
                }
                
                try {
                    output = new BufferedWriter( new FileWriter( DEFAULT_OUTPUT_FILE ) );
                } catch ( Exception ex ) {
                    System.err.println( "Error opening output file " + DEFAULT_OUTPUT_FILE );
                    System.exit( EXIT_FAILURE );
                }
                
                // close link to console. done reading in
                try {
                    input.close();
                } catch ( Exception e ) {
                    // Do nothing...Doesn't matter if we've already read stuff in
                }
	}
        
        public void parseAndWrite() {
            try {
                String line = mapInput.readLine();
                int width = -1;
                int height = -1;
            
                // get the width and the height ( the first line of the file )
                try {
                    if ( line == null ) {
                        throw new Exception( "" );
                    } else {
                        width = Integer.parseInt( line.substring( 0, line.indexOf( " " ) ) );
                        height = Integer.parseInt( line.substring( line.indexOf( " " ) + 1 ) );
                    }
                } catch ( Exception e ) {
                    System.err.println( "Error reading map file.  Invalid width or height" );
                    mapInput.close();
                    output.close();
                    System.exit( EXIT_FAILURE );
                }
            
                //loop over checking for the number we're looking for
                line = mapInput.readLine();
                // loop over lines
                for ( int i = 0; i < height; i++ ) {
                    StringTokenizer stringTok = new StringTokenizer( line );
                    // loop over the numbers in the line
                    for ( int j = 0; j < width; j++ ) {
                        if ( stringTok.hasMoreTokens() ) {
                            String nextNumber = stringTok.nextToken();
                            int number = -1;
                            try {
                                number = Integer.parseInt( nextNumber );
                            } catch ( NumberFormatException e ) {
                                System.err.println( "Error reading map file.  " 
                                            + nextNumber + " is not a number at [ " 
                                            + j + ", " + i + " ]" );
                                System.exit( EXIT_FAILURE );
                            }
                        
                            // Check if this is the number we're looking for
                            if ( number == numToReplace ) {
                                // It is.  Print out another overlay to our file.  Otherwise, do nothing.
                                output.write( "" + textureId 
                                        + " " + j 
                                        + " " + i 
                                        + " " + TEXTURE_CHOICES[ this.width ] 
                                        + " " + TEXTURE_CHOICES[ this.height ] );
                                output.write( "\n" );
                            }
                        } else {
                            System.err.println( "Error reading map file.  Expecting token at [ " 
                                    + j + ", " + i + " ]" );
                            System.exit( EXIT_FAILURE );
                        }
                    }
                    line = mapInput.readLine();
                }
            
                output.close();
                mapInput.close();
            } catch ( Exception e ) {
                System.err.println( "Error reading, writing, or closing.  Please try again\n" );
            }
        }
        
        public static void main( String[] args ) {
            new JohnnyAppleseed();
        }
}

