001    /*
002     *  PAVLOV -- Multiple Choice Study System
003     *  Copyright (C) 2000 - 2004 T.J. Willis
004     *
005     *  This program is free software; you can redistribute it and/or
006     *  modify it under the terms of the GNU General Public License
007     *  as published by the Free Software Foundation; either version 2
008     *  of the License, or (at your option) any later version.
009     *
010     *  This program is distributed in the hope that it will be useful,
011     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
012     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     *  GNU General Public License for more details.
014     *
015     *  You should have received a copy of the GNU General Public License
016     *  along with this program; if not, write to the Free Software
017     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
018     *
019     *  $Header: /cvsroot/pavlov/net/sourceforge/pavlov/controllers/QuizController.java,v 1.7 2004/06/27 08:16:25 tj_willis Exp $
020     */
021    package net.sourceforge.pavlov.controllers;
022    
023    import java.awt.*;
024    import java.io.*;
025    import java.net.URL;
026    import java.net.URLDecoder;
027    import java.net.URLEncoder;
028    import java.util.*;
029    import javax.swing.*;
030    import javax.swing.border.*;
031    import javax.swing.event.*;
032    import java.lang.StringBuffer;
033    
034    import net.sourceforge.pavlov.event.*;
035    import net.sourceforge.pavlov.library.*;
036    import net.sourceforge.pavlov.main.Quiz;
037    import net.sourceforge.pavlov.main.standalone.ResourceBroker;
038    import net.sourceforge.pavlov.user.*;
039    import net.sourceforge.sillyview.*;
040    import org.apache.log4j.*;
041    
042    /**
043     *  <code>QuizController</code> is a controller that presents the user with
044     *  questions and gives various sorts of feedback.
045     *
046     *@author     <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a>
047     *@created    Feb 10, 2004
048     *@since      1.1
049     *@version    $Revision: 1.7 $
050     */
051    public final class QuizController extends Widget
052                     implements QuestionChangedListener
053    {
054    
055            /**
056             *  Token used to communicate with velocity model.
057             */
058            public final static String ANSWER_EVENT = "__ANSWER_EVENT";
059            /**
060             *  Token used to communicate with velocity model.
061             */
062            public final static String ANSWER_MODE = "__ANSWER_MODE";
063            /**
064             *  Token used to communicate with velocity model.
065             */
066            public final static String RIGHT = "__RIGHT";
067            /**
068             *  Token used to communicate with velocity model.
069             */
070            public final static String WRONG = "__WRONG";
071    
072            /**
073             *  Token used to communicate with velocity model.
074             */
075            public final static String BOOK_NAME = "BOOK_NAME";
076            /**
077             *  Token used to communicate with velocity model.
078             */
079            public final static String CHAPTER_NAME = "CHAPTER_NAME";
080    
081            /**
082             *  Token used to communicate with velocity model.
083             */
084            public final static String QUESTION_TEXT = "QUESTION_TEXT";
085            /**
086             *  Token used to communicate with velocity model.
087             */
088            public final static String QUESTION_IMAGE = "QUESTION_IMAGE";
089            /**
090             *  Token used to communicate with velocity model.
091             */
092            public final static String ANSWER_A = "A_ANSWER";
093            /**
094             *  Token used to communicate with velocity model.
095             */
096            public final static String ANSWER_B = "B_ANSWER";
097            /**
098             *  Token used to communicate with velocity model.
099             */
100            public final static String ANSWER_C = "C_ANSWER";
101            /**
102             *  Token used to communicate with velocity model.
103             */
104            public final static String ANSWER_D = "D_ANSWER";
105            /**
106             *  Token used to communicate with velocity model.
107             */
108            public final static String HREF_A = "A_BUTTON";
109            /**
110             *  Token used to communicate with velocity model.
111             */
112            public final static String HREF_B = "B_BUTTON";
113            /**
114             *  Token used to communicate with velocity model.
115             */
116            public final static String HREF_C = "C_BUTTON";
117            /**
118             *  Token used to communicate with velocity model.
119             */
120            public final static String HREF_D = "D_BUTTON";
121            /**
122             *  Token used to communicate with velocity model.
123             */
124            public final static String URL_PREFIX = "URL_PREFIX";
125    
126            private ResourceBroker rb;
127            /**
128             *  Description of the Field
129             */
130            public final static int LOCAL_FILES = 0;
131            /**
132             *  Description of the Field
133             */
134            public final static int REMOTE_FILES = 1;
135    
136            /**
137             *  Description of the Field
138             */
139            protected int fileLocations = LOCAL_FILES;
140            /**
141             *  Description of the Field
142             */
143            protected QuestionHistory s1;
144            /**
145             *  Description of the Field
146             */
147            protected QuizStatus s2;
148            /**
149             *  Description of the Field
150             */
151            protected ChapterCoverage s3;
152    
153            private static Category cat
154                             = Category.getInstance(QuizController.class.getName());
155    
156            /**
157             *  Describe variable <code>quiz</code> here.
158             */
159            protected Quiz quiz;
160    
161    
162            /**
163             *  Creates a new <code>QuizFrame</code> instance.
164             *
165             *@param  q  a <code>Quiz</code> value
166             *@param  v  a <code>WidgetView</code> value
167             */
168            public QuizController(Quiz q, WidgetView v)
169            {
170                    super(v);
171                    cat.setLevel(Level.WARN);
172                    rb = ResourceBroker.getInstance();
173                    if(q==null) return;
174    
175    
176                    ChapterReference ref = null;
177                    setQuiz(q);
178                    ref = q.getChapterReference();
179                    
180                    // Set up the title
181                    StringBuffer bf = new StringBuffer();
182                    bf.append(rb.getString(rb.PAVLOV_QUIZ));
183                    bf.append(": ");
184                    bf.append(ref.getBookName());
185                    bf.append(" : ");
186                    bf.append(ref.getChapterName());
187                    
188                    view.setToken(JPanelView.TITLE,bf.toString());
189                    
190                    // Set up BaseURL
191                    //FIXME: try to get rid of this block
192                    try {
193                            File f = new File("resources/views/");
194                            view.setToken("BASE_URL", f.toURL());
195                    }
196                    catch (Exception e) {
197                            cat.error("Setting base_url", e);
198                    }
199            }
200    
201    
202            /**
203             *  Set the Quiz value.
204             *
205             *@param  newQuiz  The new Quiz value.
206             */
207            public void setQuiz(Quiz newQuiz)
208            {
209                    this.quiz = newQuiz;
210                    if(quiz==null) return;
211    
212                    s1 = new QuestionHistory(view);
213                    s2 = new QuizStatus(view);
214                    s3 = new ChapterCoverage(view, quiz.getChapterData());
215    
216                    quiz.addQuestionChangedListener(this);
217                    quiz.addAnswerListener(s3);
218                    quiz.addQuestionChangedListener(s1);
219                    quiz.addAnswerListener(s2);
220            }
221    
222    
223            /**
224             *  Get the Quiz value.
225             *
226             *@return    the Quiz value.
227             */
228            public Quiz getQuiz()
229            {
230                    return quiz;
231            }
232    
233    
234            /**
235             *  Description of the Method
236             *
237             *@param  q   Description of the Parameter
238             *@param  qd  Description of the Parameter
239             */
240            public void questionChanged(Question q, QuestionData qd)
241            {
242                    _presentQuestion(q);
243            }
244    
245    
246            /**
247             *  Sets the template attribute of the QuizController object
248             *
249             *@param  tmp      The new template value
250             *@param  baseDir  The new template value
251             */
252            public void setTemplate(String tmp, File baseDir)
253            {
254                    VelocityModel m = (VelocityModel) view.getModel();
255                    m.setRawModel(tmp);
256                    try {
257                            view.setToken("BASE_URL", baseDir.toURL());
258                    }
259                    catch (java.net.MalformedURLException e) {
260                            System.out.println(e);
261                    }
262            }
263    
264    
265            /**
266             *  Describe <code>presentQuestion</code> method here.
267             *
268             *@param  q  a <code>Question</code> value
269             */
270            private void _presentQuestion(Question q)
271            {
272                    
273                     HashMap < Object, Object > props =
274                       new HashMap < Object, Object > ();
275                     
276                    props.put(JPanelView.TITLE, "Pavlov " + rb.getString(rb.PAVLOV_QUIZ));//^
277                    //ChapterReference ref = quiz.getChapterReference();
278    
279                    // Set the question text
280                    props.put(QUESTION_TEXT, q.getText());
281                    // Set the answers
282                    
283                     java.util.Vector < String > vec = q.getWrongAnswers ();
284                     // FIXME: trim vec to 3 items, and shuffle
285                     Vector < AnswerAtom > answers = new Vector < AnswerAtom > ();
286                     for (String x:vec) {
287                       AnswerAtom at = new AnswerAtom (false, x);
288                       answers.add (at);
289                     }
290                     
291                    answers.add(new AnswerAtom(true, q.getRightAnswer()));
292                    Collections.shuffle(answers);
293    
294                    AnswerAtom a1 = answers.elementAt(0);
295                    AnswerAtom a2 = answers.elementAt(1);
296                    AnswerAtom a3 = answers.elementAt(2);
297                    AnswerAtom a4 = answers.elementAt(3);
298    
299                    props.put(ANSWER_A, a1.getContent().toString());
300                    props.put(HREF_A, getCorrectString(q, a1));
301                    props.put(ANSWER_B, a2.getContent().toString());
302                    props.put(HREF_B, getCorrectString(q, a2));
303                    props.put(ANSWER_C, a3.getContent().toString());
304                    props.put(HREF_C, getCorrectString(q, a3));
305                    props.put(ANSWER_D, a4.getContent().toString());
306                    props.put(HREF_D, getCorrectString(q, a4));
307    
308                    ChapterReference cr = quiz.getChapterReference();
309                    props.put(BOOK_NAME, cr.getBookName());
310                    props.put(CHAPTER_NAME, cr.getChapterName());
311                    props.put(JPanelView.TITLE,
312                                    rb.getString(rb.PAVLOV_QUIZ) + cr.getBookName() + " : " +
313                                    cr.getChapterName());
314                    props.put(URL_PREFIX, getURLPrefix());
315    
316                    if (q.hasImage()) {
317                            try {
318    
319                                    //URL u = new URL( getURLPrefix()+"diagrams/"+q.getImageFile());
320                                    File f = new File("diagrams/" + q.getImageFile());//^
321                                    URL u = getFileURL(f);
322                                    props.put(QUESTION_IMAGE, u.toString());
323                            }
324                            catch (Exception e) {
325                                    cat.warn("broken image reference", e);
326                                    props.put(QUESTION_IMAGE, "Broken");
327                            }
328                    }
329                    else {
330                            //NullObject no = new NullObject ();
331                            props.put(QUESTION_IMAGE, "");
332                    }
333    
334                    view.addTokens(props);
335            }
336    
337    
338            /**
339             *  Gets the correctString attribute of the QuizController object
340             *
341             *@param  ques  Description of the Parameter
342             *@param  at    Description of the Parameter
343             *@return       The correctString value
344             */
345            protected String getCorrectString(Question ques, AnswerAtom at)
346            {
347                    ChapterReference cr = quiz.getChapterReference();
348                    String bookName = null;
349                    String chapterName = null;
350    
351                    String userName = null;
352                    try {
353                            bookName = encode(cr.getBookName());
354                            chapterName = encode(cr.getChapterName());
355                            userName = encode(quiz.getUserName());
356                    }
357                    catch (java.io.UnsupportedEncodingException ex) {
358                            cat.warn("Converting to UTF-8" + ex);
359                    }
360                    String x =
361                                    ANSWER_EVENT + "?user=" + userName + "&bookName=" + bookName +
362                                    "&chapterName=" + chapterName + "&questionID=" + ques.getID() +
363                                    "&" + ANSWER_MODE + "=";
364                    if (at == null) {
365                            return x + WRONG;
366                    }
367                    if (at.isCorrect()) {
368                            return x + RIGHT;
369                    }
370                    return x + WRONG;
371            }
372    
373            private String encode(String in)
374                    throws java.io.UnsupportedEncodingException
375            {
376                    return URLEncoder.encode(in,"UTF-8");   
377            }
378            
379            /**
380             *  Sets the fileLocations attribute of the QuizController object
381             *
382             *@param  i  The new fileLocations value
383             */
384            public void setFileLocations(int i)
385            {
386                    fileLocations = i;
387            }
388    
389    
390            /**
391             *  Gets the uRLPrefix attribute of the QuizController object
392             *
393             *@return    The uRLPrefix value
394             */
395            public String getURLPrefix()
396            {
397                    if (fileLocations == LOCAL_FILES) {
398                            return "file:";
399                    }
400                    else {
401                            return "http://";
402                    }
403            }
404    
405    
406            /**
407             *  Gets the fileURL attribute of the QuizController object
408             *
409             *@param  f  Description of the Parameter
410             *@return    The fileURL value
411             */
412            public URL getFileURL(File f)
413            {
414                    if (fileLocations == LOCAL_FILES) {
415                            try {
416                                    return f.toURI().toURL();
417                            }
418                            catch (java.net.MalformedURLException ex) {
419                                    cat.warn("getting file URL", ex);
420                                    return null;
421                            }
422                    }
423                    else {
424                            try {
425                                    return new URL(f.toString());
426                                    // FIXME: how to implement this
427                            }
428                            catch (java.net.MalformedURLException ex) {
429                                    cat.warn("getting file URL", ex);
430                                    return null;
431                            }
432                    }
433            }
434    
435    }
436