package lectures.exceptions;
import util.annotations.WebDocuments;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * EXCEPTIONS IN PROGRAMS INVOLVING MULTIPE METHODS
 * The previous example involved one method, which both performed 
 * error-prone operations and handled the errors. 
 * 
 * It did not involve recovering from errors. 
 * 
 * Much of exception handling is about cooperative error handling/recovery 
 * in multi-method programs.
 * 
 * This is an example of a multi-method program, but it does not involve cooperative
 * multi-method processing or much error recovery. Each method processes the
 * exceptions thrown when it does its job. Is this the best strategy?
 * 
 * Look at the program and follow the instructions after main.
 * 
 *
 */
@WebDocuments({"Lectures/Exceptions.pptx", "Lectures/Exceptions.pdf", "Videos/Exceptions.avi"})
public class LinesReaderAndPrinter {
    
    /*
     * BufferedReader is an alternative to Scanner that better suits our purpose
     * as it throws an important Java exception, IOException, that we will study here.
     * The readLine() method of the class takes the place of the Scanner nextLine() method.
     * 
     */
    static BufferedReader input = new BufferedReader(
            new InputStreamReader(System.in));
    
    /**
     * Delegates work to two methods, each of which can result in errors.    
     */
    public static void main (String args[])  {
        try {
        /* 
         * set break point below
         */
        echoLines(numberOfInputLines(args));
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Catch block in main executed");      
        }
    } 
    
    /**
     * Reads from the console the number of lines specified in the argument
     * and echoes each of them to the console. 
     * 
     * Possible error: the user may not enter the expected number of lines. 
     * For instance, the expected number is 2 and the user entered one and
     * then entered the EOF (End-of-File) character to close the console input.
     * 
     * This method can be called from main or some other method. So it does
     * not know the context - that its argument is specified by the end
     * user as a main argument.
     */
    public static void echoLines (int numberOfInputLines) {
        try {
            for (int inputNum = 0; inputNum < numberOfInputLines; inputNum++) {
                System.out.println("Please enter the line to be echoed");
                System.out.println(input.readLine());
            }
        } catch (IOException e) { 
         // User entered the EOF (End of File) marker to close input 
         // before the read was executed
           
         System.out.println("Did not input " + numberOfInputLines 
                 +  " input strings before input was closed. ");
        }
    }
    
    /**
     * Determines the number of lines to be echoed by converting the 
     * zeroth main argument into an int.
     * 
     * Possible error: The user does not enter the main argument, as in the previous
     * example.
     * 
     * Another error: The user does not specify a String that can be converted into an int.
     * We will ignore this error.
     * 
     * Like the previous method, it can be called from main or some other method.
     * So it does also does not know the context - that its result will be used
     * in an interactive session by an end-user to echo lines. 
     *  
     * Is returning 0 the best error "recovery" strategy?
     * 
     * Can you think of a better one, if the method had context and knew 
     * what main was doing?
     *
     */
    public static int numberOfInputLines(String[] args) {
        try {
            return Integer.parseInt(args[0]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Did not enter an argument");         
            return  0; 
         }
    }
}
/*
 * EXCEPTIONS IN PROGRAMS INVOLVING MULTIPE METHODS
 * 
 * Set the breakpoint in main.
 * 
 * Debug-run the program with no argument, and use step into, step return and step over to
 * follow the program execution.
 * 
 * (T/F) LinesReaderAndPrinter with no argument executes (one or more statements in) a try 
 * block of numberOfInputLines.
 * 
 * (T/F) LinesReaderAndPrinter with no argument executes a catch block of numberOfInputLines. 
 * 
 *  
 * (T/F) LinesReaderAndPrinter with no argument executes (one or more statements in) a catch
 *  block of main.
 * 
 * (T/F) If method p calls method q, and the execution of q results in an exception 
 * of type E that is handled by a catch block of q, then control transfers to a 
 * catch block of q that can handle an exception of type E.
 * 
 * (T/F) LinesReaderAndPrinter with no argument executes (one or more statements in) a try 
 * block of echoLines.
 * 
 * (T/F) LinesReaderAndPrinter with no argument executes a catch block of echoLines. 
 * 
 * (T/F) LinesReaderAndPrinter with no argument prompts the user for input.
 * 
 * Now debug-run the program with an argument of 2 and follow the program
 * execution. Respond to the prompt in the console.
 * 
 * (T/F) LinesReaderAndPrinter with an argument of 2 executes (one or more statements in) a try 
 * block of numberOfInputLines.
 * 
 * (T/F) LinesReaderAndPrinter with an argument of 2 executes a catch 
 * block of numberOfInputLines. 
 * 
 * (T/F) LinesReaderAndPrinter with an argument of 2 executes (one or more statements in) a try 
 * block of echoLines.
 * 
 * (T/F) LinesReaderAndPrinter with an argument of 2 executes a catch 
 * block of echoLines.
 * 
 * 
 * 
 * In this example, is the operation that first detects an error the right one to
 * (completely) handle it? 
 * 
 * If not what do you need from Java to separate detection 
 * and handling and to provide error handling involving multiple methods?
 * 
 
 * 
 * Go to {@link LinesReaderAndPrinterPropagatingExceptions}
 *
 */