package de.saring.sportstracker.storage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javafx.scene.paint.Color; import org.jdom2.Attribute; import org.jdom2.DataConversionException; import org.jdom2.Document; import org.jdom2.Element; import de.saring.sportstracker.core.STException; import de.saring.sportstracker.core.STExceptionID; import de.saring.sportstracker.data.Equipment; import de.saring.sportstracker.data.SportSubType; import de.saring.sportstracker.data.SportType; import de.saring.sportstracker.data.SportTypeList; import de.saring.util.gui.javafx.ColorUtils; /** * This class is for reading and writing a SportTypeList object from or to a * XML file. * * @author Stefan Saring * @version 2.0 */ public class XMLSportTypeList { /** * The XSD filename with the structure of the sport type list. */ private static final String XSD_SPORT_TYPES = "sport-types.xsd"; /** * Reads the sport type list from the specified XML file. * Returns an empty list when the file doesn't exists yet. * * @param source name of the XML file to read from * @return the created SportTypeList * @throws STException thrown on read problems */ public SportTypeList readSportTypeList(String source) throws STException { try { // return an empty list if the file doesn't exists yet File fSource = new File(source); if (!fSource.exists()) { return new SportTypeList(); } // create JDOM Document from XML with XSD validation Document document = XMLUtils.getJDOMDocument(fSource, XSD_SPORT_TYPES); ArrayList<SportType> tempSportTypes = new ArrayList<>(); // get root element and read all the contained sport types Element eSportTypeList = document.getRootElement(); eSportTypeList.getChildren("sport-type").forEach(eSportType -> tempSportTypes.add(readSportType(eSportType))); SportTypeList sportTypeList = new SportTypeList(); sportTypeList.clearAndAddAll(tempSportTypes); return sportTypeList; } catch (Exception e) { throw new STException(STExceptionID.XMLSTORAGE_READ_SPORT_TYPE_LIST, "Failed to read sport type list from XML file '" + source + "' ...", e); } } /** * Reads the data from the specified sport-type element and returns the created * SportType object. * * @param eSportType sport-type JDOM element * @return the created SportType object */ private SportType readSportType(Element eSportType) { SportType sportType = new SportType(Integer.parseInt(eSportType.getChildText("id"))); sportType.setName(eSportType.getChildText("name")); sportType.setIcon(eSportType.getChildText("icon")); try { Element eColor = eSportType.getChild("color"); int iRed = eColor.getAttribute("red").getIntValue(); int iGreen = eColor.getAttribute("green").getIntValue(); int iBlue = eColor.getAttribute("blue").getIntValue(); sportType.setColor(Color.rgb(iRed, iGreen, iBlue)); } catch (DataConversionException dce) { throw new IllegalArgumentException("Failed to parse the color of sport type with ID '" + sportType.getId() + "', exception message: " + dce.getMessage()); } // get optional attribute 'record-distance' Attribute aRecDistance = eSportType.getAttribute("record-distance"); if (aRecDistance != null) { try { sportType.setRecordDistance(aRecDistance.getBooleanValue()); } catch (DataConversionException dce) { throw new IllegalArgumentException("Failed to parse the record-distance of sport type with ID '" + sportType.getId() + "', exception message: " + dce.getMessage()); } } // read all contained sport sub types Element eSportSubTypeList = eSportType.getChild("sport-subtype-list"); eSportSubTypeList.getChildren("sport-subtype").forEach(eSportSubType -> { SportSubType sportSubType = new SportSubType(Integer.parseInt(eSportSubType.getChildText("id"))); sportSubType.setName(eSportSubType.getChildText("name")); sportType.getSportSubTypeList().set(sportSubType); }); // read all contained equipment Element eEquipmentList = eSportType.getChild("equipment-list"); if (eEquipmentList != null) { eEquipmentList.getChildren("equipment").forEach(eEquipment -> { Equipment equipment = new Equipment(Integer.parseInt(eEquipment.getChildText("id"))); equipment.setName(eEquipment.getChildText("name")); sportType.getEquipmentList().set(equipment); }); } return sportType; } /** * Writes the sport type list to the specified XML file. * * @param sportTypeList the sport type list to store * @param destination name of xml file to write to * @throws STException thrown on store problems */ public void storeSportTypeList(SportTypeList sportTypeList, String destination) throws STException { // create JDOM element with all sport types Element eSportTypeList = createSportTypeListElement(sportTypeList); // write the element to XML file try { XMLUtils.writeXMLFile(eSportTypeList, destination); } catch (IOException e) { throw new STException(STExceptionID.XMLSTORAGE_STORE_SPORT_TYPE_LIST, "Failed to write sport type list to XML file '" + destination + "' ...", e); } } /** * Creates the "sport-type-list" element with all exercises for the specified * sport type list. */ private Element createSportTypeListElement(SportTypeList sportTypeList) { Element eSportTypeList = new Element("sport-type-list"); // append an "sport-type" element for each sport type sportTypeList.forEach(sportType -> { Element eSportType = new Element("sport-type"); eSportTypeList.addContent(eSportType); // create sport type attributes and elements eSportType.setAttribute("record-distance", String.valueOf(sportType.isRecordDistance())); XMLUtils.addElement(eSportType, "id", String.valueOf(sportType.getId())); XMLUtils.addElement(eSportType, "name", sportType.getName()); XMLUtils.addElement(eSportType, "icon", sportType.getIcon()); Element eColor = new Element("color"); java.awt.Color awtColor = ColorUtils.toAwtColor(sportType.getColor()); eColor.setAttribute("red", String.valueOf(awtColor.getRed())); eColor.setAttribute("green", String.valueOf(awtColor.getGreen())); eColor.setAttribute("blue", String.valueOf(awtColor.getBlue())); eSportType.addContent(eColor); // append an "sport-subtype" element for each sport subtype Element eSportSubTypeList = new Element("sport-subtype-list"); eSportType.addContent(eSportSubTypeList); sportType.getSportSubTypeList().forEach(sportSubType -> { Element eSportSubType = new Element("sport-subtype"); eSportSubTypeList.addContent(eSportSubType); XMLUtils.addElement(eSportSubType, "id", String.valueOf(sportSubType.getId())); XMLUtils.addElement(eSportSubType, "name", sportSubType.getName()); }); // append an "equipment" element for each equipment Element eEquipmentList = new Element("equipment-list"); eSportType.addContent(eEquipmentList); sportType.getEquipmentList().forEach(equipment-> { Element eEquipment = new Element("equipment"); eEquipmentList.addContent(eEquipment); XMLUtils.addElement(eEquipment, "id", String.valueOf(equipment.getId())); XMLUtils.addElement(eEquipment, "name", equipment.getName()); }); }); return eSportTypeList; } }