/* Copyright (C) 2012 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.io.Serializable; import java.net.URL; 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 MnemosyneXMLImporter extends org.xml.sax.helpers.DefaultHandler implements Converter, Serializable { private static final long serialVersionUID = -7871484468353131221L; private long timeOfStart = 0L; public Locator mLocator; private int count = 1; private List<Card> cardList; private final long MILLSECS_PER_DAY = 24 * 60 * 60 * 1000; private StringBuffer characterBuf; private final String TAG = "org.liberty.android.fantastischmemo.MnemosyneXMLImporter"; private Card card; private AMFileUtil amFileUtil; @Inject public MnemosyneXMLImporter(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("mnemosyne")) { try { timeOfStart = Long.parseLong(atts.getValue("time_of_start")); /* Convert to local time */ /* Calendar nc = Calendar.getInstance(); TimeZone tz = nc.getTimeZone(); int offset = tz.getOffset(timeOfStart); timeOfStart -= offset; */ Log.v(TAG, "Time of start: " + timeOfStart); } catch (Exception e) { Log.e(TAG, "parse time_of_start error", e); } } if (localName.equals("item")) { card = new Card(); LearningData learningData = new LearningData(); card.setLearningData(learningData); card.setCategory(new Category()); card.setId(count); card.setOrdinal(count); count += 1; // Id field is not used here. We use "count" variable instead // String idAttr = atts.getValue("id"); String grAttr = atts.getValue("gr"); if (grAttr != null) { learningData.setGrade(Integer.parseInt(grAttr)); } String eAttr = atts.getValue("e"); if (eAttr != null) { learningData.setEasiness(Float.parseFloat(eAttr)); } String acrpAttr = atts.getValue("ac_rp"); String uAttr = atts.getValue("u"); String rtrpAttr = atts.getValue("rt_rp"); if(rtrpAttr != null) { learningData.setRetReps(Integer.parseInt(rtrpAttr)); } if (acrpAttr != null){ int acrp = Integer.parseInt(acrpAttr); if (uAttr != null){ if(Integer.parseInt(uAttr) == 1){ /* Commented out for testing */ // acrp = 0; } } if (Integer.valueOf(rtrpAttr) != 0 && acrp == 0){ /* This is a workaround for the malformed * XML file. */ acrp = Integer.valueOf(rtrpAttr) / 2 + 1; } learningData.setAcqReps(acrp); } String lpsAttr = atts.getValue("lps"); if(lpsAttr != null){ learningData.setLapses(Integer.parseInt(lpsAttr)); } String acqrplAttr = atts.getValue("ac_rp_l"); if(acqrplAttr != null){ learningData.setAcqRepsSinceLapse(Integer.parseInt(acqrplAttr)); } String rtrplAttr = atts.getValue("rt_rp_l"); if(rtrplAttr != null){ learningData.setRetRepsSinceLapse(Integer.parseInt(rtrplAttr)); } String lrpAttr = atts.getValue("l_rp"); if(lrpAttr != null && timeOfStart != 0L) { // Do nothing now } String nrpAttr = atts.getValue("n_rp"); if(nrpAttr != null && lrpAttr != null){ long lrp = timeOfStart * 1000 + Math.round(Double.parseDouble(lrpAttr)) * MILLSECS_PER_DAY; long nrp = timeOfStart * 1000 + Math.round(Double.parseDouble(nrpAttr)) * MILLSECS_PER_DAY; learningData.setLastLearnDate(new Date(lrp)); learningData.setNextLearnDate(new Date(nrp)); } } characterBuf = new StringBuffer(); } public void endElement(String namespaceURI, String localName, String qName) throws SAXException{ if(localName.equals("item")) { cardList.add(card); /* The end of life of itemBuilder */ card= null; } if(localName.equals("cat")) { card.getCategory().setName(characterBuf.toString()); } if(localName.equals("Q")|| localName.equals("Question")) { card.setQuestion(characterBuf.toString()); } if(localName.equals("A")|| localName.equals("Answer")) { card.setAnswer(characterBuf.toString()); } } 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"; } }