/*
Copyright (C) 2010 Haowen Ning
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.liberty.android.fantastischmemo.converter;
import android.util.Log;
import org.liberty.android.fantastischmemo.common.AnyMemoDBOpenHelper;
import org.liberty.android.fantastischmemo.common.AnyMemoDBOpenHelperManager;
import org.liberty.android.fantastischmemo.dao.CardDao;
import org.liberty.android.fantastischmemo.entity.Card;
import org.liberty.android.fantastischmemo.entity.Category;
import org.liberty.android.fantastischmemo.entity.LearningData;
import org.liberty.android.fantastischmemo.utils.AMFileUtil;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import java.io.File;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.inject.Inject;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class SupermemoXMLImporter extends org.xml.sax.helpers.DefaultHandler implements Converter{
private static final long serialVersionUID = 8958250001470549241L;
public Locator mLocator;
private List<Card> cardList;
private Card card;
private LearningData ld;
private int count = 1;
private int interval;
private SimpleDateFormat supermemoFormat = new SimpleDateFormat("dd.MM.yy");
private StringBuffer characterBuf;
private final String TAG = "org.liberty.android.fantastischmemo.SupermemoXMLConverter";
private AMFileUtil amFileUtil;
@Inject
public SupermemoXMLImporter(AMFileUtil amFileUtil) {
this.amFileUtil = amFileUtil;
}
@Override
public void convert(String src, String dest) throws Exception{
URL mXMLUrl = new URL("file:///" + src);
cardList = new LinkedList<Card>();
System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setContentHandler(this);
xr.parse(new InputSource(mXMLUrl.openStream()));
if (!new File(dest).exists()) {
amFileUtil.createDbFileWithDefaultSettings(new File(dest));
}
AnyMemoDBOpenHelper helper = AnyMemoDBOpenHelperManager.getHelper(dest);
try {
CardDao cardDao = helper.getCardDao();
cardDao.createCards(cardList);
} finally {
AnyMemoDBOpenHelperManager.releaseHelper(helper);
}
}
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException{
if(localName.equals("SuperMemoElement")){
card = new Card();
card.setCategory(new Category());
ld = new LearningData();
card.setLearningData(ld);
// Set a default interval, in case of malformed the xml file
interval = 0;
}
characterBuf = new StringBuffer();
}
public void endElement(String namespaceURI, String localName, String qName) throws SAXException{
if(localName.equals("SuperMemoElement")){
card.setOrdinal(count);
// If this is a new card and the learning data is like this:
// <LearningData>
// <Repetitions>0</Repetitions>
// <Lapses>0</Lapses>
// <AFactor>4.620</AFactor>
// <UFactor>2.500</UFactor>
// </LearningData>
// We will use the defualt learning data for missing fields.
// Otherwise, we will caluculate it here.
if (ld.getLastLearnDate() != null) {
// Calculate the next learning date from interval
Date nextLearningDate = new Date(ld.getLastLearnDate().getTime() + interval * 24 * 60 * 60 * 1000); // Add days
ld.setNextLearnDate(nextLearningDate);
}
// If an old card get interval 0, then we assume the last grade is 0 as failure card.
if (interval == 0 && ld.getAcqReps() != 0) {
ld.setGrade(0);
}
cardList.add(card);
card = null;
ld = null;
count += 1;
}
if(localName.equals("Question")){
card.setQuestion(characterBuf.toString());
}
if(localName.equals("Answer")){
card.setAnswer(characterBuf.toString());
}
if(localName.equals("Lapses")){
ld.setLapses(Integer.parseInt(characterBuf.toString()));
}
if(localName.equals("Repetitions")){
ld.setAcqReps(Integer.parseInt(characterBuf.toString()));
}
if(localName.equals("Interval")){
interval = Integer.parseInt(characterBuf.toString());
}
if(localName.equals("AFactor")){
double g = Double.parseDouble(characterBuf.toString());
if(g <= 5.5) {
ld.setGrade(2);
} else {
ld.setGrade(3);
}
}
if(localName.equals("UFactor")){
float e = Float.parseFloat(characterBuf.toString());
ld.setEasiness(e);
}
if(localName.equals("LastRepetition")){
try {
Date date = supermemoFormat.parse(characterBuf.toString());
ld.setLastLearnDate(date);
}
catch(ParseException e){
Log.e(TAG, "Parsing date error: " + characterBuf.toString(), e);
}
}
}
public void setDocumentLocator(Locator locator){
mLocator = locator;
}
public void characters(char ch[], int start, int length){
characterBuf.append(ch, start, length);
}
public void startDocument() throws SAXException{
}
public void endDocument() throws SAXException{
}
@Override
public String getSrcExtension() {
return "xml";
}
@Override
public String getDestExtension() {
return "db";
}
}