/*******************************************************************************
* Copyright (c) MOBAC developers
*
* 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, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mobac.program.model;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;
import mobac.gui.panels.JProfilesPanel;
import mobac.program.DirectoryManager;
import mobac.program.interfaces.AtlasInterface;
import mobac.program.interfaces.AtlasObject;
import mobac.utilities.I18nUtils;
import mobac.utilities.Utilities;
import org.apache.log4j.Logger;
/**
* A profile is a saved atlas. The available profiles ({@link Profile} instances) are visible in the
* <code>profilesCombo</code> in the {@link JProfilesPanel}.
*/
public class Profile implements Comparable<Profile> {
private static Logger log = Logger.getLogger(Profile.class);
public static final String PROFILE_NAME_REGEX = "[\\w _-]+";
public static final String PROFILE_FILENAME_PREFIX = "mobac-profile-";
public static final Pattern PROFILE_FILENAME_PATTERN = Pattern.compile(PROFILE_FILENAME_PREFIX + "("
+ PROFILE_NAME_REGEX + ").xml");
public static final Profile DEFAULT = new Profile();
private File file;
private String name;
private static Vector<Profile> profiles = new Vector<Profile>();
/**
* Profiles management method
*/
public static void updateProfiles() {
File profilesDir = DirectoryManager.atlasProfilesDir;
final Set<Profile> deletedProfiles = new HashSet<Profile>();
deletedProfiles.addAll(profiles);
profilesDir.list(new FilenameFilter() {
public boolean accept(File dir, String fileName) {
Matcher m = PROFILE_FILENAME_PATTERN.matcher(fileName);
if (m.matches()) {
String profileName = m.group(1);
Profile profile = new Profile(new File(dir, fileName), profileName);
if (!deletedProfiles.remove(profile))
profiles.add(profile);
}
return false;
}
});
for (Profile p : deletedProfiles)
profiles.remove(p);
Collections.sort(profiles);
}
/**
* Profiles management method
*/
public static Vector<Profile> getProfiles() {
updateProfiles();
return profiles;
}
/**
* Load a profile by it's name
*
* @param name
*/
public Profile(String name) {
this(new File(DirectoryManager.atlasProfilesDir, getProfileFileName(name)), name);
}
/**
* Default profile
*/
protected Profile() {
this(new File(DirectoryManager.atlasProfilesDir, "mobac-profile.xml"), "");
}
protected Profile(File file, String name) {
super();
this.file = file;
this.name = name;
}
@Override
public String toString() {
return name;
}
public File getFile() {
return file;
}
public String getName() {
return name;
}
public boolean exists() {
return file.isFile();
}
public void delete() {
if (!file.delete())
file.deleteOnExit();
}
public int compareTo(Profile o) {
return file.compareTo(o.file);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Profile))
return false;
Profile p = (Profile) obj;
return file.equals(p.file);
}
@Override
public int hashCode() {
assert false : "hashCode not designed";
return -1;
}
public void save(AtlasInterface atlasInterface) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Atlas.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
FileOutputStream fo = null;
try {
fo = new FileOutputStream(file);
m.marshal(atlasInterface, fo);
} catch (FileNotFoundException e) {
throw new JAXBException(e);
} finally {
Utilities.closeStream(fo);
}
}
public AtlasInterface load() throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Atlas.class);
Unmarshaller um = context.createUnmarshaller();
um.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(ValidationEvent event) {
ValidationEventLocator loc = event.getLocator();
String file = loc.getURL().getFile();
int lastSlash = file.lastIndexOf('/');
if (lastSlash > 0)
file = file.substring(lastSlash + 1);
int ret = JOptionPane.showConfirmDialog(
null,
String.format(I18nUtils.localizedStringForKey("msg_error_load_atlas_profile"),
event.getMessage(), file, loc.getLineNumber(), loc.getColumnNumber()),
I18nUtils.localizedStringForKey("msg_error_load_atlas_profile_title"),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE);
log.error(event.toString());
return (ret == JOptionPane.YES_OPTION);
}
});
try {
AtlasInterface newAtlas = (AtlasInterface) um.unmarshal(file);
return newAtlas;
} catch (Exception e) {
throw new JAXBException(e.getMessage(), e);
}
}
public static boolean checkAtlas(AtlasInterface atlasInterface) {
return checkAtlasObject(atlasInterface);
}
public static String getProfileFileName(String profileName) {
return PROFILE_FILENAME_PREFIX + profileName + ".xml";
}
private static boolean checkAtlasObject(Object o) {
boolean result = false;
if (o instanceof AtlasObject) {
result |= ((AtlasObject) o).checkData();
}
if (o instanceof Iterable<?>) {
Iterable<?> it = (Iterable<?>) o;
for (Object ao : it) {
result |= checkAtlasObject(ao);
}
}
return result;
}
}