001 /* PAVLOV -- Multiple Choice Study System
002 * Copyright (C) 2000 - 2004 T.J. Willis
003 *
004 * This program is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU General Public License
006 * as published by the Free Software Foundation; either version 2
007 * of the License, or (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program; if not, write to the Free Software
016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
017 *
018 * $Header: /cvsroot/pavlov/net/sourceforge/pavlov/library/Chapter.java,v 1.7 2004/07/01 05:50:20 tj_willis Exp $
019 */
020 package net.sourceforge.pavlov.library;
021 import java.util.*;
022 import java.io.*;
023 import org.apache.log4j.*;
024
025 /**
026 * Describes a chapter, which contains questions.
027 *
028 * @author <a href="mailto:tj_willis@users.sourceforge.net"></a>
029 * @version 1.0
030 * @see Question
031 * @see Book
032 * @see Library
033 * @has 1 Has 1..n net.sourceforge.pavlov.library.Question
034 */
035 public final class Chapter extends LibraryDocument
036 implements AbstractChapter, Serializable, Comparable {
037 /** Filename for a descriptive image. */
038 private String coverFile;
039 /** Holds the questions, keyed off of Question.id */
040 private TreeMap<String,Question> questions;
041
042 /** Creates an untitled chapter. */
043 public Chapter() {
044 this("Untitled");
045 }
046
047 private void init(){
048 questions = new TreeMap<String, Question>();
049 }
050
051 /**
052 * Creates a new <code>Chapter</code> instance.
053 *
054 * @param newName a <code>String</code> value
055 */
056 public Chapter(String newName){
057 setName(newName);
058 init();
059 }
060
061 /**
062 * Gets the question with the specified ID or null if it doesn't exist.
063 * @param id a <code>String</code> value
064 * @return a <code>Question</code> value
065 */
066 public Question getQuestion(final String id) {
067 return questions.get(id);
068 }
069
070 public int compareTo(Object obj){
071 Chapter c = (Chapter)obj;
072 return getName().compareTo(c.getName());
073 }
074
075 /**
076 * Describe <code>setQuestions</code> method here.
077 *
078 */
079 public void setQuestions(Collection<Question> list) {
080 questions.clear();
081 for(Question da : list) {
082 if(da==null) continue;
083 addQuestion(da);
084 }
085 }
086
087 /**
088 * Number of questions this chapter contains.
089 * @return an <code>int</code> value
090 */
091 public int getNumberOfQuestions() {
092 return questions.size();
093 }
094
095 /**
096 * Returns the title of this chapter.
097 * @return a <code>String</code> value
098 * @deprecated Use getName()
099 */
100 @Deprecated public String getTitle() {
101 return getName();
102 }
103
104 /**
105 * Sets the title of this chapter.
106 * @param n a <code>String</code> value
107 * @deprecated Use setTitle()
108 */
109 @Deprecated public void setTitle(String n) {
110 setName(n);
111 }
112
113 /**
114 * Returns the filename for a descriptive image.
115 * @return a <code>String</code> value
116 */
117 public String getCover() {
118 return coverFile;
119 }
120
121 /**
122 * Sets the filename for a descriptive image.
123 * @param n a <code>String</code> value
124 */
125 public void setCover(String n) {
126 coverFile = n;
127 }
128
129 /**
130 * Adds a question using it's ID as the key
131 * @param b a <code>Question</code> value
132 */
133 public void addQuestion(Question b) {
134 questions.put(b.getID(), b);
135 }
136
137 /**
138 * Dumps the chapter in XML format to the
139 * given writer. Dumps all questions too.
140 * @param writer a <code>java.io.Writer</code> value
141 * @exception java.io.IOException if an error occurs
142 */
143 public void toXML(java.io.Writer writer)
144 throws java.io.IOException {
145 Collection<Question> v = getQuestionsCollection();
146
147 writer.write("\t\t<CHAPTER NAME=\"" + getName() + "\" AUTHOR=\"" + author + "\" COVER=\"" + coverFile + "\">\n");
148 writer.write("\t\t<TOPICS>" + description + "</TOPICS>\n");
149
150 for(Question da : v) {
151 da.toXML(writer);
152 }
153 writer.write("\t\t</CHAPTER>\n");
154 }
155
156 /**
157 * Returns all questions as a Collection
158 * @return a <code>Collection</code> value
159 * @deprecated
160 */
161 @Deprecated public Collection<Question> getQuestionsCollection() {
162 return questions.values();
163 }
164
165 /**
166 * Returns the chapter's questions as a read-only collection.
167 * @return a <code>Collection</code> value
168 */
169 public Collection<Question> getQuestionsReadOnly(){
170 return Collections.unmodifiableCollection(getQuestionsCollection());
171 }
172
173 /**
174 * Describe <code>getQuestions</code> method here.
175 *
176 * @return a <code>Hashtable</code> value
177 */
178 public TreeMap<String, Question> getQuestions(){
179 return questions;
180 }
181
182 /**
183 * Returns the chapter's title
184 * @return a <code>String</code> value
185 */
186 public String toString() {
187 return getName();
188 }
189
190 /**
191 * Describe <code>makeBlankChapter</code> method here.
192 *
193 * @return a <code>Chapter</code> value
194 */
195 public static Chapter makeBlankChapter()
196 {
197 Chapter n = new Chapter();
198 n.setAuthor("Unknown");
199 n.setTitle("Unknown");
200 n.setCover("Unknown");
201 n.setCover("No description");
202 Question q = Question.makeBlankQuestion();
203 n.addQuestion(q.deepCopy());
204 return n;
205 }
206
207 /**
208 * Returns true if the given object is a chapter and all its elements
209 * are equal to mine.
210 *
211 * @param obj an <code>Object</code> value
212 * @return a <code>boolean</code> value
213 */
214 public boolean equals(Object obj)
215 {
216 if(obj==null && this!=null) return false;
217 if(obj!=null && this==null) return false;
218 if(obj==null && this==null) return true;
219
220 if( !(obj instanceof Chapter) ) return false;
221 Chapter q = (Chapter) obj;
222
223 if(getAuthor() == null && q.getAuthor() !=null) return false;
224 if(getName() == null && q.getName() !=null) return false;
225 if(getCover()== null && q.getCover() !=null) return false;
226 if(getDescription() == null && q.getDescription() !=null) return false;
227 if(getQuestions() == null && q.getQuestions() !=null) return false;
228
229 // FIXED: these should be .equals()
230 // whee... my first bug caught by JUnit! :)
231 if(getAuthor()!=null)
232 if( !getAuthor().equals(q.getAuthor())) return false;
233 if(getName()!=null)
234 if( !getName().equals(q.getName())) return false;
235 if(getCover()!=null)
236 if( !getCover().equals(q.getCover())) return false;
237 if(getDescription()!=null)
238 if( !getDescription().equals(q.getDescription())) return false;
239 if(getQuestions()!=null)
240 if( !getQuestions().equals(q.getQuestions())) return false;
241
242 return true;
243 }
244
245
246 /**
247 * Uses a nifty trick from "Design Patterns in Java" to make a
248 * completely independent copy of this chapter. Useful in chapter
249 * editors.
250 *
251 * @return a <code>Chapter</code> value
252 */
253 public Chapter deepCopy()
254 {
255 try {
256 ByteArrayOutputStream b = new ByteArrayOutputStream();
257 ObjectOutputStream out = new ObjectOutputStream(b);
258 out.writeObject(this);
259 ByteArrayInputStream bIn = new ByteArrayInputStream(b.toByteArray());
260 ObjectInputStream oi = new ObjectInputStream(bIn);
261 return ( (Chapter)oi.readObject());
262 } catch (IOException e) {
263 return null;
264 } catch (ClassNotFoundException e1){
265 return null;
266 }
267 }
268
269
270 }
271