/* -----------------------------------------------------------------------
* File: $HeadURL$
* Revision $LastChangedRevision$
* Last Modified: $LastChangedDate$
* Last Change by: $LastChangedBy$
* -----------------------------------------------------------------------
* Copyright (C) 2007 Keith Stribley <devel@thanlwinsoft.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
* -----------------------------------------------------------------------
*/
package org.thanlwinsoft.languagetest.language.test;
import java.io.IOException;
import java.util.LinkedList;
import org.apache.xmlbeans.XmlException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.ui.PlatformUI;
import org.thanlwinsoft.languagetest.MessageUtil;
import org.thanlwinsoft.languagetest.eclipse.LanguageTestPlugin;
import org.thanlwinsoft.schemas.languagetest.module.LangType;
import org.thanlwinsoft.schemas.languagetest.module.TestItemType;
import org.thanlwinsoft.schemas.languagetest.module.LanguageModuleDocument;
import org.thanlwinsoft.schemas.languagetest.module.LanguageModuleType;
import org.thanlwinsoft.schemas.languagetest.history.ModuleHistoryDocument;
import org.thanlwinsoft.schemas.languagetest.history.ModuleHistoryType;
/**
* @author keith
*
*/
public class TestManager
{
private String nativeLang = null;
private String foreignLang = null;
private IProject userProject = null;
private UserConfig config = null;
public final static String LANG_SEPARATOR = "-";
public final static String ID_DATA_SEPARATOR = "-";
public final static String HISTORY_DIR = "TestHistory";
public final static String HISTORY_EXT = ".xml";
/** Construct a test manager for a given user and language selection
*
* @param userProject
* @param nativeLang
* @param foreignLang
*/
public TestManager(IProject userProject, String nativeLang, String foreignLang)
{
this.nativeLang = nativeLang;
this.foreignLang = foreignLang;
this.userProject = userProject;
this.config = new UserConfig(userProject);
}
/** Create a test from the items in the selected modules
*
* @param modules
* @param options
* @return Test object or null if no Test Items were found
*/
public Test createTestFromModuleList(Object [] modules, TestOptions options)
{
options.includeNew = true;
LinkedList<TestItem> items = new LinkedList<TestItem>();
for (int i = 0; i < modules.length; i++)
{
if (modules[i] instanceof IFile)
{
IFile f = (IFile)modules[i];
try
{
LanguageModuleDocument doc =
LanguageModuleDocument.Factory.parse(f.getContents());
LanguageModuleType module = doc.getLanguageModule();
TestHistory history = getModuleTestHistory(module, f.getFullPath());
addModuleItems(items, history, module, f.getRawLocation(), options);
}
catch (IOException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Unable to parse " + f.getName(),e);
}
catch (XmlException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Unable to parse " + f.getName(),e);
}
catch (CoreException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Unable to parse " + f.getName(),e);
}
}
}
Test test = null;
if (items.size() > 0)
{
test = new Test(items, options.type, options.repeatUntilLearnt);
}
return test;
}
/** Create a revision test based on the users test history
*
* @param options
* @return Test object or null if no Test Items were found
*/
public Test revisionTest(TestOptions options)
{
Test test = null;
options.includeNew = false;
LinkedList<TestItem> items = new LinkedList<TestItem>();
try
{
IFolder historyFolder = userProject.getFolder(HISTORY_DIR);
if (historyFolder == null) return null;
IFolder langHistory = historyFolder.getFolder(nativeLang +
LANG_SEPARATOR + foreignLang);
if (langHistory != null)
{
IResource [] members = langHistory.members();
for (int i = 0; i < members.length; i++)
{
if (members[i].isAccessible() && members[i] instanceof IFile)
{
IFile f = (IFile)members[i];
try
{
ModuleHistoryDocument histDoc =
ModuleHistoryDocument.Factory.parse(f.getContents());
ModuleHistoryType historyType = histDoc.getModuleHistory();
LanguageModuleType module =
getModuleFromHistory(historyType);
TestHistory history = new XmlBeansTestHistory(f);
addModuleItems(items, history, module,
new Path(historyType.getPath()), options);
}
catch (XmlException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Unable to parse " + f.getName(),e);
}
catch (IOException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Unable to parse " + f.getName(),e);
}
}
}
}
}
catch (CoreException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
e.getLocalizedMessage(), e);
}
finally
{
if (items.size() > 0)
{
test = new Test(items, options.type, options.repeatUntilLearnt);
}
}
return test;
}
private LanguageModuleType getModuleFromHistory(ModuleHistoryType history)
throws XmlException, IOException, CoreException
{
LanguageModuleType module = null;
String path = history.getPath();
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IFile moduleFile = workspace.getRoot()
.getFileForLocation(new Path(path));
if (moduleFile == null)
{
MessageDialog.openWarning(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell(),
MessageUtil.getString("ModuleNotFoundTitle"),
MessageUtil.getString("ModuleNotFoundMessage", path));
}
else
{
LanguageModuleDocument modDoc =
LanguageModuleDocument.Factory.parse(
moduleFile.getContents());
if (modDoc != null)
{
module = modDoc.getLanguageModule();
}
}
return module;
}
public TestHistory getModuleTestHistory(LanguageModuleType module, IPath modulePath)
{
return getTestHistory(module.getId(), module.getCreationTime(), modulePath);
}
public TestHistory getModuleTestHistory(TestModule module)
{
String id = Integer.toHexString(module.getUniqueId());
return getTestHistory(id, module.getCreationTime(), module.getPath());
}
public TestHistory getTestHistory(String moduleId, long moduleCreationTime, IPath modulePath)
{
XmlBeansTestHistory history = null;
if (userProject != null)
{
try
{
IFolder historyRoot = userProject.getFolder(HISTORY_DIR);
if (!historyRoot.exists())
historyRoot.create(false, true, null);
IFolder historyFolder =
historyRoot.getFolder(nativeLang + LANG_SEPARATOR + foreignLang);
if (historyFolder != null)
{
if (!historyFolder.exists())
{
historyFolder.create(true, true, null);
}
IFile historyFile = historyFolder.getFile(moduleId +
ID_DATA_SEPARATOR + moduleCreationTime + HISTORY_EXT);
if (historyFile != null)
history = new XmlBeansTestHistory(historyFile, modulePath);
}
}
catch (CoreException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Error reading history: " + e.getLocalizedMessage(),e);
}
catch (XmlException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Error reading history: " + e.getLocalizedMessage(),e);
}
catch (IOException e)
{
LanguageTestPlugin.log(IStatus.WARNING,
"Error reading history: " + e.getLocalizedMessage(),e);
}
}
return history;
}
/** add the items for a selected module
*
* @param items
* @param path
* @param module
* @param options
*/
protected void addModuleItems(LinkedList<TestItem> items, TestHistory history,
LanguageModuleType module, IPath modulePath, TestOptions options)
{
XmlBeansTestModule xbtm = new XmlBeansTestModule(modulePath, module);
// find the module's fonts for the relevant languages
FontData nativeFD = null;
FontData foreignFD = null;
for (int l = 0; l < module.sizeOfLangArray(); l++)
{
LangType lt = module.getLangArray(l);
if (lt.getLang().equals(nativeLang) && lt.getFont() != null)
{
nativeFD = new FontData(lt.getFont(),
lt.getFontSize().intValue(),
SWT.NORMAL);
}
else if(lt.getLang().equals(foreignLang) && lt.getFont() != null)
{
foreignFD = new FontData(lt.getFont(),
lt.getFontSize().intValue(),
SWT.NORMAL);
}
}
// add the items
for (int i = 0; i < module.sizeOfTestItemArray(); i++)
{
TestItemType ti = module.getTestItemArray(i);
// test the item against the filters
boolean choose = true;
for (TestItemFilter f : options.getFilters())
{
choose &= f.chooseItem(module, ti);
if (!choose) break;
}
if (!choose) continue;
// see if it matches the type of test
XmlBeansTestItem xbti = new XmlBeansTestItem(ti, nativeLang, foreignLang);
if (xbti.getNativeText() != null && xbti.getForeignText() != null)
{
if (options.type.equals(TestType.LISTENING_FOREIGN_NATIVE) &&
xbti.getImagePath() == null)
{
continue;
}
xbti.setNativeFontData(nativeFD);
xbti.setForeignFontData(foreignFD);
xbti.setModule(xbtm);
if (options.useHistory)
{
addIfAppropriate(history, items, xbti, options);
}
else
{
items.add(xbti);
}
}
}
}
/**
* @param history
* @param items
* @param xbti
* @param options
*/
private void addIfAppropriate(TestHistory history, LinkedList<TestItem> items, XmlBeansTestItem xbti, TestOptions options)
{
try
{
ItemHistory hi = history.getHistoryItem(xbti, options.type);
if (hi == null || hi.testCount == 0)
{
if (options.includeNew)
items.add(xbti);
return;
}
if ((hi.isTestDue(options.type, config) &&
!hi.isDisabled()))
{
items.add(xbti);
}
}
catch (TestHistoryStorageException e)
{
LanguageTestPlugin.log(IStatus.WARNING, e.getLocalizedMessage(),e);
}
}
public String getNativeLang() { return nativeLang; }
public String getForeignLang() { return foreignLang; }
/**
* Generate a description for a pair of language codes separated by a '-'
* @param langPair
* @return the description
*/
public static String getLangPairDescription(String langPair)
{
int separator = langPair.indexOf('-');
if (separator > -1 && separator < langPair.length() - 1)
{
UniversalLanguage ulA = new UniversalLanguage(langPair.substring(0, separator));
UniversalLanguage ulB = new UniversalLanguage(langPair.substring(separator + 1));
return ulA.generateDescription() + " / " + ulB.generateDescription();
}
else
{
return langPair;
}
}
}