This time, I will try to make it clear.
I have run it for 2 days. No problem.
But there are still lots of TODO.
The version now is 0.1
I will try to give it a name and write a detail readme about how to use it.
Of course need finish the TODO in the program.
/*
* Config.java
* Created on Sep 29, 2004
* TODO Write the log to file.
*/
package com.henry.vocabulary;
import java.io.*;
import java.util.logging.*;
import java.util.*;
/**
* @author henry.pan
* TODO Add unit test for this class
*/
public class Config {
private static Logger logger = Logger.getLogger("Config");
private static String configFile = "config.ini";
/* here is the config and the default value */
private static String wordsFileName = "words.txt";
private static int sleepInterval = 6000 * 2;
/**
* @return The config of the file storing the words.
*/
public static String getWordsFileName() {
return wordsFileName;
}
public static int getSleepInterval() {
return sleepInterval;
}
/**
* Read configuration from config file.
* Config file is defined.
*/
public static void getTheConfiguration() {
File file = new File(configFile);
if (!file.exists()) {
logger.severe("The config file does not exist!" + Calendar.getInstance().getTime());
}
try {
StringBuffer sb = new StringBuffer();
BufferedReader br = new BufferedReader(new FileReader(configFile));
String s;
String[] configValues;
while ((s = br.readLine()) != null) {
if (s.equals("")) {
continue;
}
if (s.substring(0,0).equals("#")) {
continue;
}
configValues = s.split("=");
parseConfigValue(configValues);
}
} catch (IOException ioe) {
logger.severe("Error when reading confi file!");
logger.severe(ioe.getStackTrace().toString());
logger.severe(ioe.toString());
}
}
/**
* @param configValues The config paire values.
* configValues[0] is the config name
* configValues[1] is the config value
*/
private static void parseConfigValue(String[] configValues) {
assert configValues.length > 1 : "The config format is incorrect!";
try {
if (configValues[0].trim().toLowerCase() == "WordsFile") {
wordsFileName = configValues[1].trim();
}
if (configValues[0].trim().toLowerCase() == "SleepInterval") {
sleepInterval = Integer.parseInt( configValues[1].trim());
}
} catch (Exception e) {
logger.severe("The configuration's format is incorrect!");
logger.severe(e.getStackTrace().toString());
logger.severe(e.toString());
}
}
}
/*
* MainFrame.java
* Created on Sep 28, 2004
*
*/
package com.henry.vocabulary;
import java.awt.*;
import java.awt.event.*;
import java.util.Calendar;
import java.util.logging.*;
import javax.swing.*;
/*******************************************************************************
* Title:
*
*
* Description:
*
*
* Copyright: Copyright (c) 2004
*
*
* Company:
*
* @author Henry *
* @version 1.0
* TODO Add unit test for this class
*/
public class MainFrame extends JFrame {
Logger logger = Logger.getLogger("MainWin");
/* Used to manipulate the words */
WordsReview wr = new WordsReview();
JPanel contentPane;
GridBagLayout gridBagLayout1 = new GridBagLayout();
JTextField word = new JTextField();
JRadioButton remember = new JRadioButton();
JRadioButton forget = new JRadioButton();
JButton next = new JButton();
ButtonGroup buttonGroup1 = new ButtonGroup(); /* Construct the frame */
public MainFrame() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
wordsInit();
} catch (Exception e) {
e.printStackTrace();
}
}
/* Component initialization */
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
word.setFont(new java.awt.Font("Dialog", 0, 16));
word.setSelectionStart(0);
word.setText("");
contentPane.setLayout(gridBagLayout1);
this.setSize(new Dimension(600, 300));
this.setTitle("TAFU Vocabulary");
remember.setFont(new java.awt.Font("Dialog", 0, 16));
remember.setText("I remember it well.");
forget.setFont(new java.awt.Font("Dialog", 0, 16));
remember.setSelected(true);
forget.setText("I forget it.");
next.setFont(new java.awt.Font("Dialog", 0, 16));
next.setText("Next");
next.addActionListener(new Frame1_next_actionAdapter(this));
contentPane.add(word, new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
17, 9, 0, 31), 494, 39));
contentPane.add(remember, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE,
new Insets(26, 0, 1, 0), 0, 0));
contentPane.add(forget, new GridBagConstraints(1, 1, 1, 2, 0.0, 0.0,
GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE,
new Insets(25, 0, 37, 0), 0, 0));
contentPane.add(next, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
0, 9, 59, 13), 44, 11));
buttonGroup1.add(forget);
buttonGroup1.add(remember);
}
/* Overridden so we can exit when window is closed */
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
logger.info("Close the window!");
try {
wr.saveToFile();
} catch (Exception ex) {
System.out.println(ex.getStackTrace());
System.out.println(ex);
}
System.exit(0);
}
}
private void wordsInit() {
try {
wr.readFromFile();
getNextWord();
} catch (Exception e) {
System.out.println(e.getStackTrace());
System.out.println(e);
}
}
private void getNextWord() {
String s = this.wr.getWord();
if (s == null) {
this.setVisible(false);
this.wr.saveToFile();
while (s == null) {
logger.info("Get a null word. No word needs review now. Goto Sleep." + Calendar.getInstance().getTime());
try {
Thread.sleep(Config.getSleepInterval());
logger.info(" -- After sleep --" + Calendar.getInstance().getTime());
this.wr.readFromFile();
s = this.wr.getWord();
} catch (InterruptedException ie) {
System.out.println(ie.getStackTrace());
System.out.println(ie);
}
}
this.setVisible(true);
}
this.word.setText(s);
this.remember.setSelected(true);
}
void next_actionPerformed(ActionEvent e) {
if (this.forget.isSelected()) {
wr.saveWord(false);
} else {
wr.saveWord(true);
}
getNextWord();
}
}
class Frame1_next_actionAdapter implements java.awt.event.ActionListener {
MainFrame adaptee;
Frame1_next_actionAdapter(MainFrame adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.next_actionPerformed(e);
}
}
/*
* MainWin.java
* Created on Sep 28, 2004
*/
package com.henry.vocabulary;
import javax.swing.UIManager;
import java.awt.*;
/*******************************************************************************
* Title:
*
*
* Description:
*
*
* Copyright: Copyright (c) 2004
*
*
* Company:
*
* @author not attributable *
* @version 1.0
* TODO Make sure there is only one instance running.
*/
public class MainWin {
boolean packFrame = false;
/* Construct the application */
public MainWin() {
MainFrame frame = new MainFrame();
/*
* Validate frames that have preset sizes
* Pack frames that have useful preferred size info, e.g. from their
* layout
*/
if (packFrame) {
frame.pack();
} else {
frame.validate();
}
/* Center the window */
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2,
(screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
}
/* Main method */
public static void main(String[] args) {
boolean assertionsEnabled = false;
/* Note intentioal side effect of assignment. */
assert assertionsEnabled = true;
if (!assertionsEnabled) {
throw new RuntimeException("Assertions disabled");
}
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
new MainWin();
System.out.println("Exit the MainWin.main().");
}
}
/*******************************************************************************
* Word.java
*
* Created on 2004-9-26
*/
package com.henry.vocabulary;
import java.util.*;
import java.text.*;
public class Word {
private static final SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
private static final int[] memoryCurveMinute = {10, 30, 60, 180, 300, 500};
private static final int[] memoryCurveDay = { 1, 2, 4, 8, 12, 20, 36, 54, 87,
160, 360 ,680};
private String _wordValue;
private Date _nextReviewTime;
private int _reviewTimes;
private int _forgetTimes;
/**
* *
*
* @param _wordValue
* The _wordValue to set.
*/
public void setWordValue(String _wordValue) {
this._wordValue = _wordValue;
}
/**
* *
*
* @return Returns the _wordValue.
*/
public String getWordValue() {
return _wordValue;
}
public Word(String wordValue, String nextReviewTime, int reviewTimes,
int forgetTimes) {
try {
setWordValue(wordValue);
_nextReviewTime = format.parse(nextReviewTime);
_reviewTimes = reviewTimes;
_forgetTimes = forgetTimes;
} catch (ParseException pe) {
System.out.println("The input is not a date!");
throw new RuntimeException(pe);
}
}
public Word(String strWord) {
try {
String[] values = strWord.split(",");
setWordValue(values[0]);
if(values.length > 2) {
_nextReviewTime = format.parse(values[1]);
_reviewTimes = Integer.parseInt(values[2].trim());
} else {
Calendar yesterday = Calendar.getInstance();
yesterday.add(Calendar.DATE, -1);
_nextReviewTime = yesterday.getTime();
_reviewTimes = 0;
}
if (values.length > 3) {
/* For compatible to the old version */
_forgetTimes = Integer.parseInt(values[3]);
} else {
_forgetTimes = 0;
}
} catch (ParseException pe) {
System.out.println("The input is not a date!");
throw new RuntimeException(pe);
}
}
public void forget() {
Calendar nextTime = Calendar.getInstance();
nextTime.add(Calendar.MINUTE, -1);
_nextReviewTime = nextTime.getTime();
_reviewTimes = 0;
_forgetTimes++;
}
public void remember() {
Calendar nextTime = Calendar.getInstance();
if (this._reviewTimes < memoryCurveMinute.length) {
nextTime.add(Calendar.MINUTE, memoryCurveMinute[_reviewTimes]);
} else if (_reviewTimes - memoryCurveMinute.length < memoryCurveDay.length) {
nextTime.add(Calendar.DATE, memoryCurveDay[_reviewTimes - memoryCurveMinute.length]);
} else {
nextTime.add(Calendar.YEAR, 100); /* Never need review this word */
}
if(nextTime.get(Calendar.DATE) != Calendar.getInstance().get(Calendar.DATE)) {
nextTime.set(Calendar.HOUR, 0);
nextTime.set(Calendar.MINUTE, 0);
nextTime.set(Calendar.SECOND, 0);
}
_nextReviewTime = nextTime.getTime();
_reviewTimes++;
}
public String toString() {
String s = getWordValue() + "," + format.format(_nextReviewTime) + ","
+ _reviewTimes + "," + _forgetTimes;
return s;
}
/**
* Judge if this word need to be reviewed now. * Comment for isNeedReview
*/
public boolean isNeedReview() {
if (this._nextReviewTime.after(Calendar.getInstance().getTime())) {
return false;
}
return true;
}
public boolean equals (Object o) {
if (this._wordValue.equalsIgnoreCase(((Word)o).getWordValue())) {
return true;
}
return false;
}
public boolean isNeedNotReviewAnyMore() {
Calendar later50Years = Calendar.getInstance();
later50Years.add(Calendar.YEAR, 50);
if (this._nextReviewTime.after(later50Years.getTime())) {
return true;
}
return false;
}
}
/*
* WordsReview.java
*
* Created on 2004-9-26
*
*
*/
package com.henry.vocabulary;
import java.util.*;
import java.util.logging.*;
import java.io.*;
/**
* TODO Add unit test for this class
*
* @author Henry *
*/
public class WordsReview {
static Logger logger = Logger.getLogger("WordsReview");
List wordList = null;
List wordNeedReviewList = null;
Word currentWord = null;
Map wordMap = null;
/**
* *
*
* @param fileName
*/
private void readFromFile(String fileName) {
assert (this.wordList != null) : "Doesnt init the wordList when readFromFile.";
createWordsFileIfItNotExist();
StringBuffer sb = null;
BufferedReader br = null;
try {
sb = new StringBuffer();
br = new BufferedReader(new FileReader(fileName));
String s;
while ((s = br.readLine()) != null) {
this.currentWord = new Word(s);
if (!this.wordMap.containsKey(this.currentWord.getWordValue())) {
this.wordMap.put(this.currentWord.getWordValue(),
this.currentWord);
this.wordList.add(this.currentWord);
if (this.currentWord.isNeedReview()) {
this.wordNeedReviewList.add(this.currentWord);
}
} else {
this.currentWord = (Word) this.wordMap.get(this.currentWord
.getWordValue());
this.currentWord.forget();
}
}
this.currentWord = null;
br.close();
} catch (FileNotFoundException e) {
System.out.println(e);
System.out.println(e.getStackTrace());
} catch (IOException ioe) {
System.out.println(ioe);
System.out.println(ioe.getStackTrace());
} finally {
/* br.close(); */
}
}
/*
* TODO After create the words file. Add the advertise words in the file.
* Such as http://blog.csdn.net/tafu
*
* TODO Put this function out of here.
*/
private void createWordsFileIfItNotExist() {
File f = new File(Config.getWordsFileName());
if (!f.exists()) {
try {
f.createNewFile();
} catch (IOException ioe) {
logger.severe("Cannot create file to save the words!"
+ Calendar.getInstance().getTime());
logger.severe(ioe.getStackTrace().toString());
logger.severe(ioe.toString());
}
}
}
/**
* *
*
* @param fileName
*/
private void saveToFile(String fileName) {
try {
PrintWriter printWriter = new PrintWriter(new BufferedWriter(
new FileWriter(fileName)));
Iterator iterator = this.wordList.iterator();
while (iterator.hasNext()) {
printWriter.println((Word) iterator.next());
}
printWriter.close();
} catch (IOException ioe) {
System.out.println(ioe.getStackTrace());
System.out.println(ioe);
}
}
public void saveToFile() {
this.saveToFile(Config.getWordsFileName());
}
/**
* * Get a word, which needs to be reviewed. *
*
* @return
*/
public String getWord() {
if (this.wordNeedReviewList.isEmpty()) {
return null;
}
Random random = new Random();
int ramdonIndex = random.nextInt() % this.wordNeedReviewList.size();
if (ramdonIndex < 0) {
ramdonIndex = -ramdonIndex;
}
currentWord = (Word) this.wordNeedReviewList.get(ramdonIndex);
return currentWord.getWordValue();
}
public void saveWord(boolean isRemember) {
if (this.currentWord == null) {
System.out.println("Should not come here!");
System.out.println("When you call saveWord to save the word, ");
System.out.println(" you should get the word first.");
return;
}
if (!isRemember) {
this.currentWord.forget();
} else {
this.currentWord.remember();
}
this.wordNeedReviewList.remove(this.currentWord);
if (this.currentWord.isNeedNotReviewAnyMore()) {
this.wordList.remove(this.currentWord);
this.wordMap.remove(this.currentWord.getWordValue());
}
this.currentWord = null;
}
public void regenerateNeedReviewList() {
this.wordNeedReviewList = new ArrayList();
for (int i = 0; i < this.wordList.size(); i++) {
if (((Word) this.wordList.get(i)).isNeedReview()) {
this.wordNeedReviewList.add((Word) this.wordList.get(i));
}
}
this.currentWord = null;
}
public void readFromFile() {
this.wordList = new ArrayList();
this.wordNeedReviewList = new LinkedList();
this.wordMap = new HashMap();
this.readFromFile(Config.getWordsFileName());
}
}
/*
* WordTest.java
* Created on Sep 30, 2004
*
*/
package com.henry.vocabulary.junit;
import junit.framework.TestCase;
import com.henry.vocabulary.*;
import java.util.*;
import java.text.*;
/**
* @author henry.pan
*
*/
public class WordTest extends TestCase {
/*
* @see TestCase#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
}
/*
* @see TestCase#tearDown()
*/
protected void tearDown() throws Exception {
super.tearDown();
}
public void testSetWordValue() {
Word w = new Word("testWord");
w.setWordValue("newValue");
TestCase.assertEquals("newValue",w.getWordValue());
w = null;
}
public void testGetWordValue() {
Word w = new Word("testWord");
TestCase.assertEquals("testWord",w.getWordValue());
w = null;
}
public void testForget() {
Word w = new Word("testWord");
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -1);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:");
String s = df.format(calendar.getTime());
w.forget();
/* System.out.println(w); */
/* System.out.println("testWord," + s + "\d\d,0,\d+"); */
TestCase.assertTrue(w.toString().matches("testWord," + s + "\d\d,0,\d+"));
w.forget();
w.remember();
w.remember();
w.forget();
TestCase.assertTrue(w.toString().matches("testWord," + s + "\d\d,0,\d+"));
w = null;
}
public void testRemember() {
}
public void testIsNeedReview() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -1);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = df.format(calendar.getTime());
Word w = new Word("testWord," + s + ",3,2");
TestCase.assertTrue(w.isNeedReview());
w = null;
}
/*
* Class under test for boolean equals(Object)
*/
public void testEqualsObject() {
Word w1 = new Word("testWord");
Word w2 = new Word("testWord");
w1.forget();
w2.remember();
TestCase.assertTrue(w1.equals(w2));
}
public void testIsNeedNotReviewAnyMore() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 100);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = df.format(calendar.getTime());
Word w = new Word("testWord," + s + "3,2");
TestCase.assertTrue(w.isNeedNotReviewAnyMore());
w = null;
}
}
//==========================================
And the test data in words.txt file.
distract,2004-10-01 00:00:00,7,0
marvel,2004-10-01 00:00:00,7,0
vaunt,2004-10-01 00:00:00,7,3
syllabus,2004-10-01 00:00:00,7,0
typo,2004-10-01 00:00:00,7,0
parallel,2004-10-01 00:00:00,7,0
paradigm,2004-10-01 00:00:00,7,0
mediocre,2004-10-01 00:00:00,7,2
stuck,2004-10-01 00:00:00,7,0
auxiliary,2004-10-01 00:00:00,7,1
somehow,2004-10-01 00:00:00,7,1
even number,2004-10-01 00:00:00,7,0
lore,2004-10-01 00:00:00,7,1
compel,2004-10-01 00:00:00,7,1
inclination,2004-10-01 00:00:00,7,1
garble,2004-10-01 00:00:00,7,1
innate,2004-10-01 00:00:00,7,0
imperative,2004-10-01 00:00:00,7,0
even up,2004-10-01 00:00:00,7,1
preemptive,2004-10-01 00:00:00,7,0
fathom,2004-10-01 00:00:00,7,0
moon cake,2004-10-01 00:00:00,7,0
chug,2004-10-01 00:00:00,7,0
unnecessary,2004-10-01 00:00:00,7,0
state,2004-10-01 00:00:00,7,0
largely,2004-10-01 00:00:00,7,0
elaborate,2004-10-01 00:00:00,7,0
gliph,2004-10-01 00:00:00,7,0
pug,2004-10-01 00:00:00,7,0
recipe,2004-10-01 00:00:00,7,0
adjective,2004-10-01 00:00:00,7,0
spam,2004-10-01 00:00:00,7,0
loaf,2004-10-01 00:00:00,7,0
circus,2004-10-01 00:00:00,7,0
incessantly,2004-10-01 00:00:00,7,1
cannibalize,2004-10-01 00:00:00,7,0
eligible,2004-10-01 00:00:00,7,0
parenthetic,2004-10-01 00:00:00,7,1
cue,2004-10-01 00:00:00,7,0
rejuvenate,2004-10-01 12:00:00,7,0
back away,2004-10-01 12:00:00,7,0
ballistic,2004-10-01 12:00:00,7,0
interrogate,2004-10-01 12:00:00,7,0
introspect,2004-10-01 12:00:00,7,0
plop,2004-10-01 12:00:00,7,0
self-aware,2004-10-01 12:00:00,7,0
deduction,2004-09-30 21:48:56,6,0
reimbursement,2004-09-30 21:51:09,6,0
relic,2004-09-30 21:51:13,6,0
unilateral,2004-09-30 21:53:23,6,0
loiter,2004-09-30 21:53:18,6,0
symptom,2004-09-30 18:39:04,5,0
conspire,2004-09-30 21:38:59,5,0
incubation,2004-09-30 21:41:03,5,0
ridiculous,2004-09-30 17:43:11,4,0
overextended,2004-09-30 20:13:37,4,0
summit,2004-09-30 20:15:39,4,1
endorse,2004-09-30 20:15:56,4,1