
import java.util.ArrayList;
import java.io.*;
import java.util.Scanner;
import java.util.InputMismatchException;

/**
 * A Quizzer reads in a file of questions and answers and 
 * poses each to the user to answer using the console.
 * 
 * @author Zach Tomaszewski
 * @version Nov 21, 2007
 */
public class Quizzer {

  /** The file that contains the questions and answers */
  protected String filename;
  /** Holds the questions, once read in */
  protected Question[] questions;
  
  
  /**
   * Creates a new Quizzer that will read its questions
   * from the given file.
   */
  public Quizzer(String filename) {
    this.filename = filename;
  }
  
  
  /**
   * Returns the name of the question file associated with this Quizzer
   */
  public String getFilename() {
    return this.filename;
  }
  
  /**
   * Runs this Quizzer, using the console to display questions and retrieve
   * answers from the user.
   * 
   * @throws IOException  If this Quizzer's file cannot be opened to be read
   * @throws QuizzerFileException  If there is a problem with this Quizzer's 
   *                               file format
   * 
   * @see #loadQuestions()                              
   */
  public void run() throws IOException, QuizzerFileException{
    //first, load questions.  If problem, end here with exception
    this.loadQuestions();
    
    Scanner input = new Scanner(System.in);

    //loop through questions
    for (Question nextQ : this.questions) {
      //print question
      System.out.println(nextQ);
      
      //loop until valid response received 
      boolean validInput = false;
      while (!validInput) {
        try {
          System.out.print("Answer: ");
          int answer = input.nextInt(); //on invalid input, jump to catch
          input.nextLine(); //clear out input stream
          
          //on invalid range, isCorrect throws exception, caught below
          boolean userIsCorrect = nextQ.isCorrect(answer - 1); 
          if (userIsCorrect) {
            System.out.println("Correct!");
          }else {
            System.out.print("Incorrect.  ");
            System.out.println("The correct answer is: " + 
                (nextQ.getCorrect() + 1));
          }
          validInput = true;
          System.out.println();

        }catch (IndexOutOfBoundsException ioobe) {
          //user's entered integer not is range of valid answers
          System.out.println("That is not one of the numbered options. " +
              "Please try again.");
        }catch (InputMismatchException ime) {
          //user entered non-integer
          System.out.println("Please enter one of the numbers listed above.");
          input.nextLine(); //clear dirty input stream
        }
      }//end while      
    }//end for  
  }
  
  /**
   * Return a String containing all the question-and-answers held by
   * this Quizzer.
   */
  public String toString() {
    String result = "";
    for (int i = 0; i < this.questions.length; i++) {
      result += questions[i].toString() + "\n";
    }
    return result;
  }
  
  
  /**
   * Reads in the question-and-answer file associated with this Quizzer.
   * <p>
   * The file format is as follows:
   * <ul>
   * <li>It must begin with a question--one more more lines of text.
   * <li>Each question must be followed by a block of one or more
   * answers.  Each answer can be only a single line, and must begin
   * with a * against the left margin.
   * <li>One of the answers in an answer block must begin with **, 
   * which marks that this is the correct answer.  
   * If more than one answer is so marked, only the last one marked 
   * is remembered as correct by loadQuestions.
   * </ul>
   * <p>
   * Here's an example question and answer block:
   * <pre>
   * Assume: x + 3 = 5
   * What is the value of x?
   * *x = 8
   * ** x = 2
   * *x = 5
   * *x = 3
   * </pre>
   * <p>
   * White space can separate question-and-answer blocks.
   * 
   * @throws IOException           If the file cannot be found or read
   * @throws QuizzerFileException  If the file is not formatted properly
   */
  protected void loadQuestions() throws IOException, QuizzerFileException {

    //an temporary expandable data structure for all the questions
    ArrayList<Question> fileQuestions = new ArrayList<Question>();
    
    //open the file to read in questions
    BufferedReader filein = new BufferedReader(new FileReader(this.filename));
       
    //read the first line
    String line = filein.readLine();    
    if (line == null) {
      throw new QuizzerFileException("No contents found in file.");
    }
    
    //keep reading lines until whole file is processed
    while (line != null) {
      String fileQ = "";  //file question
      while (line != null && !line.startsWith("*")) {
        //read in all lines of question
        fileQ += line + "\n";
        line = filein.readLine();
      }
      fileQ = fileQ.trim();  //remove any trailing whitespace form question
      
      //got all of question; now get answers
      if (line == null) {
        //ended question without finding matching answer block
        throw new QuizzerFileException("Question with no answers.");
      }
      ArrayList<String> fileAs = new ArrayList<String>();
      int fileCorrect = -1;
      while (line != null && line.startsWith("*")) {
        line = line.replaceFirst("\\* ", ""); //trim off "* "
        if (line.startsWith("*")) {
          //if still starts with a *, then marked as correct answer
          fileCorrect = fileAs.size();
          line = line.replaceFirst("\\*", "");
        }
        fileAs.add(line);
        line = filein.readLine();
      }
      
      if (fileCorrect == -1) { 
        //this batch of questions had no correct answer noted
        throw new QuizzerFileException("Answer block had no correct answer marked.");
      }
            
      //can now add question-and-answers to question list
      fileQuestions.add(new Question(fileQ, 
                                     fileAs.toArray(new String[0]), 
                                     fileCorrect));
      
      //ignore any empty lines after question/answer block
      while (line != null && line.trim().equals("")) {
        line = filein.readLine();
      }
    }
    
    //read all of file, so finally convert ArrayList to normal array
    this.questions = fileQuestions.toArray(new Question[0]);    
  }
  
  
  /**
   * Runs a sample Quizzer using "questions.txt"
   */
  public static void main(String[] args) {
    Quizzer q = new Quizzer("questions.txt");
    try {
      q.run();
      System.out.println("Quiz complete. Thanks for playing!");
    }catch (IOException ioe) {
      System.out.println("Error: Could not open " + q.getFilename());
    }catch (QuizzerFileException qfe) {
      System.out.println("Error: Problem with " + q.getFilename());
      System.out.println("-- " + qfe.getMessage());
    }
  }
  
}


