/***************************************************************************
 * File	    : TOEFL Section3.java (C) Copyright 1999                       *
 * Date     : 1999.7.14                                                    *
 * Author   : Ryo UMETSU                                                   *
 * Email    : u-ryo@sipeb.aoyama.ac.jp                                     *
 ***************************************************************************/

import java.applet.*;
import java.awt.*;
import java.text.*;
import java.net.*;
import java.io.*;
import java.util.*;

public class Section3 extends Applet {
    private Font f;
    private Selection selection;
    private Passages passages;
    private Panel panel = new Panel();
    private CardLayout card = new CardLayout();

    public void init() {
        setLayout(card);
        add("selection", panel);
        panel.setLayout(new BorderLayout());
        selection = new Selection(this);
        panel.add("Center", selection);
        String param = getParameter("fontSize");
        f = new Font("TimesRoman", Font.PLAIN,
                     (param == null ? 20 : Integer.parseInt(param)));
 
        for (int j=0; j<2; j++)
            for (int i=0;;i++) {
                param = getParameter((j==0 ? "course" : "passage") +i);
                if (param != null)
                    selection.addItem(j, param);
                else
                    break;
        }
        card.show(this, "selection");
    }
    public void selectCourse(String fileName, boolean course) {
        passages = new Passages(f, fileName, getCodeBase().toString(),
                                         course, this);
        Panel pan = new Panel();
        pan.setLayout(new BorderLayout());
        pan.add("Center", passages);
        add("passage", pan);
        card.show(this, "passage");
        repaint();
    }
    public void back() {
        if (passages != null) {
            remove(passages);
            passages = null;
            card.show(this, "selection");
        }
    }
}

class Selection extends Panel {
    private CheckboxGroup select = new CheckboxGroup();
    private Choice courseChoice[] = new Choice[2];
    private Section3 section3;
    private Checkbox course[] = new Checkbox[2];

    public Selection(Section3 sec) {
        Panel pan[] = new Panel[7];
        for (int i=0; i<pan.length; i++)
            pan[i] = new Panel();
        section3 = sec;
        Color bg = new Color(240, 255, 246);
        setBackground(bg);
        setLayout(new GridLayout(3, 1));

        add("Center", pan[0]);
        pan[0].setLayout(new GridLayout(2, 1));
        pan[0].add("Center", pan[3]);
        pan[0].add("Center", pan[4]);
        setFont(new Font("TimesRoman", Font.BOLD, 24));
        Label toefl, section;
        pan[3].add("South", toefl = new Label("TOEFL"));
        pan[4].add("Center", section = new Label("SECTION 3"));
        toefl.setForeground(new Color(255, 100, 100));
        section.setForeground(new Color(100, 255, 100));

        add("Center", pan[1]);
        pan[1].setLayout(new GridLayout(2, 1));
        pan[1].add("Center", pan[5]);
        pan[1].add("Center", pan[6]);
        String temp[] = { "Full Course(55 min)",
                          "1 Passage Course(7-10 min)" };
        for (int i=0; i<2; i++) {
        pan[5+i].add(course[i] =
                   new Checkbox(temp[i], select, false));
        pan[5+i].add(courseChoice[i] = new Choice());
        course[i].setBackground(bg);
        courseChoice[i].setBackground(bg);
        }

        add("Center", pan[2]);
        pan[2].add(new Button("Start!!"));
    }
    public void addItem(int num, String param) {
        courseChoice[num].addItem(param);
    }
    public boolean action(Event evt, Object obj) {
        if (evt.target instanceof Button)
            if (select.getCurrent() != null)
                if (select.getCurrent().getLabel().
                    substring(0, 11).equals("Full Course"))
                    section3.selectCourse(courseChoice[0].getSelectedItem(),
                                          true);
                else if (select.getCurrent().getLabel().
                         substring(0, 16).equals("1 Passage Course"))
                    section3.selectCourse(courseChoice[1].getSelectedItem(),
                                          false);
                else;
            else;
        else if (evt.target instanceof Choice)
            if (evt.target.equals(courseChoice[0]))
                select.setCurrent(course[0]);
            else
                select.setCurrent(course[1]);
        return true;
    }
    public boolean handleEvent(Event evt) {
        return super.handleEvent(evt);
    }
}

class Passages extends Panel implements Runnable {
    private CardLayout card = new CardLayout();
    private Panel panel[] = new Panel[3];
    private Passage passage[];
    private Thread runner;
    private Date startTime;
    private int limitTime;
    private TextField dispLimit;
    private Label dispTime;
    private Button stopButton;
    private Label result;
    private int numOfQuestions;
    private CheckboxGroup passageNo;
    private Section3 section3;
    private Comments commentsDialog;

    public Passages(Font f, String fileName, String codeBase,
                    boolean course, Section3 sectionThree) {
        section3 = sectionThree;
        setFont(f);
        setLayout(new BorderLayout());
        add("North", panel[0] = new Panel());
        panel[0].add("Center", panel[1] = new Panel());
        Color bg = new Color(100, 232, 200);
        Color red = new Color(255, 50, 50);
        panel[0].setBackground(bg);

        panel[1].setBackground(bg);
        panel[1].add(new Label("Limit Time", Label.RIGHT));
        panel[1].add(dispLimit = new TextField("55", 2));
        panel[1].add(dispTime = new Label("00:00"));
        panel[1].add(stopButton = new Button("Stop Timer"));
        panel[1].add(new Button("Answer"));
        panel[1].add(result = new Label("Score 00(00/50)"));
        dispTime.setForeground(red);
        result.setForeground(red);
        panel[1].add(new Button("QUIT!"));

        passage = new Passage[(course ? 5 : 1)];
        if (course) {
            panel[0].setLayout(new GridLayout(2, 1));
            Panel pan = new Panel();
            passageNo = new CheckboxGroup();
            panel[0].add("Center", pan);
            pan.add(new Label("Passage No.", Label.RIGHT));
            Color pbg = new Color(255, 242, 238);
            pan.setBackground(pbg);
            Checkbox c[] = new Checkbox[passage.length];
            for (int i=0; i<passage.length; i++) {
                pan.add(c[i] =
                        new Checkbox(Integer.toString(i+1), passageNo,
                                     (i==0 ? true : false)));
                c[i].setBackground(pbg);
            }
        }
        add("Center", panel[2] = new Panel());
        panel[2].setBackground(Color.white);
        panel[2].setLayout(card);
        for (int i=0; i<passage.length; i++) {
            passage[i] = new Passage(f, fileName, codeBase,
                                     course, i+1, this);
            panel[2].add(Integer.toString(i+1), passage[i]);
        }
        limitTime = (course ? 55 : passage[0].getNumOfQuestions());
        dispLimit.setText(Integer.toString(limitTime));
        result.setText("Score 00(00/" +
                       (course ? "50" :
                        Integer.toString(passage[0].getNumOfQuestions()))
                       + ")");
        card.show(panel[2], "1");

        startTime = new Date();
        if (runner == null); {
            runner = new Thread(this);
            runner.start();
        }
    }
    public boolean action(Event evt, Object obj) {
        if (evt.target instanceof Checkbox) {
            card.show(panel[2], passageNo.getCurrent().getLabel());
            setComments();
            repaint();
        } else if (evt.target instanceof Button) {
            if (obj.equals("Stop Timer")) {
                if (commentsDialog == null) {
                    stop();
                    //answerButton.setEnabled(true);
                    stopButton.setLabel("Restart");
                }
            } else if (obj.equals("Restart")) {
                if (commentsDialog == null) {
                    stopButton.setLabel("Stop Timer");
                    runner = new Thread(this);
                    runner.start();
                    startTime = new Date();
                    //answerButton.setEnabled(false);
                }
            } else if (obj.equals("Answer")) {
                if (commentsDialog == null) {
                    if (runner == null) {
                        calcScore();
                        //stopButton.setEnabled(false);
                    } else {
                        Warning warn;
                        warn = new Warning();
                    }
                } else
                    if (!commentsDialog.isShowing())
                        commentsDialog.show();
            } else if (obj.equals("QUIT!")) {
                stop();
                if (commentsDialog != null) {
                    commentsDialog.dispose();
                    commentsDialog = null;
                }
                section3.back();
            }
        }
        return true;
    }
    public void stop() {
        if (runner != null) {
            //stopButton.setEnabled(false);
            runner.stop();
            runner = null;
        }
    }
    private void calcScore() {
        int score = 0;
        int numOfQ = 0;
        for (int i=0; i<passage.length; i++) {
            passage[i].stop();
            score += passage[i].getResult();
            numOfQ += passage[i].getNumOfQuestions();
        }
        String RESULT;
        if (passage.length == 5) {
            int conversion[] =
            { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39,
              40, 41, 41, 42, 43, 43, 44, 44, 45, 46, 46, 47, 48, 48, 49,
              49, 50, 50, 51, 52, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60,
              61, 62, 63, 64, 66, 68 };
            RESULT = "Score" + conversion[score] + "(" + score +
                "/" + numOfQ + ")";
        } else
            RESULT = "Result " + score + "/" + numOfQ;
        result.setText(RESULT);
        commentsDialog = new Comments("Your score is "
                                      + score + "/" + numOfQ,
                                      getComments());
    }
    public void run() {
        while(true){
            Date nowTime = new Date();
            try {
                limitTime = Integer.parseInt(dispLimit.getText());
            } catch (Exception e) { }
            int time = (int)(startTime.getTime() - nowTime.getTime()) / 1000
                + limitTime * 60;
            DecimalFormat df = new DecimalFormat("00");
            dispTime.setText(df.format(time / 60) + ":" +
                             df.format(time % 60));
            if (nowTime.getTime() >= startTime.getTime()+limitTime*60000) {
                calcScore();
                stop();
            }
            try { Thread.sleep(1000); }
            catch (InterruptedException e) { }
        }
    }
    public String getComments() {
        int i;
        if (passageNo != null)
            i = Integer.parseInt(passageNo.getCurrent().getLabel());
        else
            i = 1;
        return passage[i - 1].getComments();
    }
    public void setComments() {
        if (commentsDialog != null)
            commentsDialog.changeComments(getComments());
    }
}

class Passage extends Panel {
    private URL theURL;
    private String data[];
    private TextArea sentences;
    private int numOfQuestions;
    private CardLayout qCard;
    private CheckboxGroup q = new CheckboxGroup();
    private Checkbox qNo[];
    private String answers[][]; // [identityNum][0:number 1:right 2:answered]
    private Panel pan[] = new Panel[4];
    private Question question[];
    private Passages passages;

    public Passage(Font f, String fileName, String codeBase,
                   boolean course, int num, Passages pass) {
        setFont(f);
        passages = pass;
        if (course)
            fileName = codeBase + "section3-" + fileName + "-" + num;
        else
            fileName = codeBase + fileName;
        readFile(fileName + ".dat");

        setLayout(new GridLayout(2, 1));
        for (int i=0; i<pan.length; i++)
            pan[i] = new Panel();
        add("Center", pan[0]); // Passage TextArea
        add("Center", pan[1]);
        pan[1].setLayout(new BorderLayout());
        pan[1].add("North", pan[2]); // Question Choice
        pan[1].add("Center", pan[3]); // Question Area
        setBackground(Color.white);
        Color bg = new Color(232, 200, 100);
        pan[2].setBackground(bg);
        if (numOfQuestions > 10)
            pan[2].add(new Label("No.", Label.RIGHT));
        else
            pan[2].add(new Label("Question No.", Label.RIGHT));
        pan[3].setLayout(qCard = new CardLayout());

        analysis(bg);
        drawPassage(f);
        pan[0].setLayout(new BorderLayout());
        pan[0].add("Center", sentences);

        question = new Question[numOfQuestions];
        for (int i=0; i<numOfQuestions; i++) {
            question[i] = new Question(data, answers[i], answers[i][0], f);
            pan[3].add(answers[i][0], question[i]);
        }
    }
    public int getNumOfQuestions() {
        return numOfQuestions;
    }
    private void readFile(String fileName) {
        try {
            theURL = new URL(fileName);
        } catch (Exception e) {
            System.out.println("Unable to open URL");
        }
        DataInputStream ds = null;
        InputStream conn = null;
        try {
            conn = theURL.openStream();
            ds = new DataInputStream(new BufferedInputStream(conn));
        } catch (IOException e) {
            System.out.println(e);
        }
        String s;
        Vector vect = new Vector();
        try {
            while ((s = ds.readLine()) != null)
                vect.addElement(new String(s));
        } catch (IOException e) {
            System.out.println("Exception caught reading file.");
        }
        data = new String[vect.size()];
        int flag = 0;
        for (int i=0; i<vect.size(); i++) {
            data[i] = String.valueOf(vect.elementAt(i));
            if (data[i].length() >= 4 &&
                data[i].substring(0, 4).equals("----"))
                flag++;
            if (flag == 2 &&
                (data[i].indexOf(". ") == 1 || data[i].indexOf(". ") == 2))
                numOfQuestions++;
        }
    }
    private void analysis(Color bg) {
        int flag = 0;
        int count = 0;
        boolean check = true;
        answers = new String[numOfQuestions][3];
        qNo = new Checkbox[numOfQuestions];
        for (int i=0; i<data.length; i++) {
            if (data[i].length() > 4 &&
                data[i].substring(0, 4).equals("----"))
                flag++;
            if ((data[i].indexOf(". ") == 1 ||
                 data[i].indexOf(". ") == 2) &&
                !Character.isLetter(data[i].charAt(0)) &&
                !Character.isLetter(data[i].charAt(1)) &&
                flag == 2) {
                answers[count][0] =
                    data[i].substring(0, data[i].indexOf(". "));
                answers[count][1] =
                    data[i].substring(data[i].indexOf(". ") + 2);
                answers[count][2] = "";
                pan[2].add(qNo[count] =
                           new Checkbox(answers[count][0], q, false));
                qNo[count++].setBackground(bg);
            }
        }
        q.setCurrent(qNo[0]);
        qCard.show(pan[3], q.getCurrent().getLabel());
    }
    private void drawPassage(Font f) {
        FontMetrics fm = getFontMetrics(f);
        String text = "";
        for (int i=0; i<data.length; i++) {
            if (data[i].length() > 4 &&
                data[i].substring(0, 4).equals("----"))
                break;
            String indent = "        ";
            if (i == 4)
                indent = "5      ";
            else if (i > 5 && (i+1) % 5 == 0)
                indent = (i+1) + "    ";
            text += indent + data[i] + "\n";
        }
        sentences = new TextArea(text);
        sentences.setEditable(false);
    }
    public boolean action(Event evt, Object obj) {
        if (evt.target instanceof Checkbox) {
            qCard.show(pan[3], q.getCurrent().getLabel());
            passages.setComments();
            repaint();
        }
        return true;
    }
    public void stop() {
        for (int i=0; i<numOfQuestions; i++)
            question[i].stop();
    }
    public int getResult() {
        int score = 0;
        for (int i=0; i<numOfQuestions; i++)
            if (question[i].getResult())
                score++;
        return score;
    }
    public String getComments() {
        for (int i=0; i<qNo.length; i++)
            if (q.getCurrent() == qNo[i])
                return question[i].getComments();
        return null;
    }
}

class Question extends Panel {
    private String data[];
    private String answers[];
    private CheckboxGroup q;
    private Checkbox alt[];
    private Font f;
    private String question[];
    private boolean stop = false;
    private String comments[];
    private double yy = 1.2;

    public Question(String d[], String ans[],
                    String questionLabel, Font ff) {
        setFont(ff);
        data = d;
        f = ff;
        answers = ans;
        q = new CheckboxGroup();
        alt = new Checkbox[4];
        String temp[] = { "A", "B", "C", "D" };
        for (int i=0; i<temp.length; i++) {
            add(alt[i] = new Checkbox(temp[i], q, false));
            alt[i].setBackground(Color.white);
        }
        setLayout(null);
        int from[] = {0, 0};
        int to[] = {0, 0};
        int flag = 0;
        for (int i=0; i<data.length; i++) {
            if (data[i].length() >= 4 &&
                data[i].substring(0, 4).equals("----"))
                flag++;
            if (data[i].length() > 5 &&
                ((data[i].substring(0, 1).equals(questionLabel) &&
                  data[i].substring(1, 3).equals(". ")) ||
                 (data[i].substring(0, 2).equals(questionLabel) &&
                  data[i].substring(2, 4).equals(". "))))
                if (flag == 1)
                    from[0] = i;

                else if (flag == 3)
                    from[1] = i;

            if (flag == 1 && from[0] != 0 && to[0] == 0 &&
                data[i].equals(""))
                to[0] = i;

            if (flag == 3 && from[1] != 0 && to[1] == 0 &&
                data[i].equals(""))
                to[1] = i;

        }
        question = new String[to[0] - from[0]];
        comments = new String[to[1] - from[1]];
        int count = 0;
        for (int i=from[0]; i<to[0]; i++)
            question[count++] = data[i];

        count = 0;
        for (int i=from[1]; i<to[1]; i++) {
            comments[count++] = data[i];
        }

    }
    public void stop() {
        stop = true;
        if (q.getCurrent() != null)
            answers[2] = q.getCurrent().getLabel();
        else
            answers[2] = "";
        repaint();
    }
    public boolean getResult() {
        if (answers[1].equals(answers[2]))
            return true;
        return false;
    }
    public void paint(Graphics g) {
        //setFont(f);
        FontMetrics fm = getFontMetrics(f);
        int x = 0;
        int y = fm.getHeight();
        int count = 0;
        double temp = yy;
        yy = draw(g, fm, x, y, count, yy);
        if (yy < temp)
            repaint();

        Checkbox current = q.getCurrent();
        for (int i=0; i<alt.length; i++)
            q.setCurrent(alt[i]);
        q.setCurrent(current);
    }
    private double draw(Graphics g, FontMetrics fm, int x,
                        int y, int count, double yy) {
        for (int i=0; i<question.length; i++) {
            StringTokenizer tokens =
                new StringTokenizer(question[i]);
            while (tokens.hasMoreTokens()) {
                String s = tokens.nextToken();
                x += fm.stringWidth(s) + fm.stringWidth(" ");
                if (s.length() == 3 &&
                    s.charAt(0) == '(' && s.charAt(2) == ')') {
                    if (!stop) {
                        Dimension d = alt[count].preferredSize();
                        alt[count++].reshape(10,
                                             y + (int)(fm.getHeight() * 0.2),
                                             d.width, d.height);
                        y += (int)(fm.getHeight() * yy);
                    } else if (stop) {
                        if (alt[count] != null)
                            remove(alt[count++]);
                        if (answers[1].equals(s.substring(1, 2))) {
                            g.setColor(Color.red);
                            if (answers[1].equals(answers[2]))
                                g.drawOval(20, y, fm.stringWidth("OO"),
                                           fm.getHeight()+10);
                        }
                        if (answers[2].equals(s.substring(1, 2)))
                            g.setColor(Color.blue);
                        y += (int)(fm.getHeight() * yy);
                        g.drawString(s.substring(1, 2), 30, y);
                        g.setColor(Color.black);
                    }
                    x = 20;
                    continue;
                } else if (x > this.size().width - 70) {
                    x = 40;
                    y += (int)(fm.getHeight() * yy);
                } else
                    x -= fm.stringWidth(s);
                g.drawString(s, x + 40, y);
                x += fm.stringWidth(s);
            }
        }
        if (y > this.size().height)
            return yy * 0.95;
        else
            return yy;
    }
    public String getComments() {
        String string = "";
        for (int i=0; i<comments.length; i++) {
            string += comments[i] + "\n";
            System.out.println(comments[i]);
        }
        System.out.println("================================================");
        byte by[] = string.getBytes();
        try {
            String result = new String(by, "JIS");
            return result;
        } catch (Exception e) {
            System.out.println(e);
        }
    return null;
    }
}
class Comments extends Frame {
    private Panel pan[] = new Panel[3];
    private TextArea textArea;

    public Comments(String score, String comments) {
        super(score);
        setFont(new Font("Courier", Font.PLAIN, 18));
        setLayout(new BorderLayout());
        for (int i=0; i<pan.length; i++) {
            pan[i] = new Panel();
        }
        add("Center", textArea =
                   new TextArea(comments));
        textArea.setEditable(false);
        add("South", pan[0]);
        pan[0].setLayout(new GridLayout(2, 1));
        pan[0].add(new Label("(If you can't read the comments, see the java console)", Label.CENTER));
        pan[0].add(pan[2]);
        pan[2].add(new Button("OK"));
        resize(650, 350);
        show();
    }
    public void changeComments(String comments) {
        textArea.setText("");
        textArea.setText(comments);
    }
    public boolean action(Event evt, Object arg) {
        if (evt.id == Event.WINDOW_DESTROY)
            dispose();
        else if (evt.target instanceof Button)
            dispose();
        return true;
    }
}
class Warning extends Frame {
    private Panel pan[] = new Panel[2];

    public Warning() {
        super("Warning");
        setFont(new Font("Courier", Font.PLAIN, 18));
        setLayout(new GridLayout(2, 1));
        for (int i=0; i<pan.length; i++) {
            pan[i] = new Panel();
        }
        add(pan[0]);
        pan[0].add(new Label("Please stop the timer, first!",
                             Label.CENTER));
        add(pan[1]);
        pan[1].add(new Button("OK"));
        resize(350, 150);
        show();
    }
    public boolean action(Event evt, Object arg) {
        if (evt.id ==Event.WINDOW_DESTROY)
            dispose();
        else if (evt.target instanceof Button)
            dispose();
        return true;
    }
}
