package org.lysty.dao;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.n3.nanoxml.IXMLElement;
import net.n3.nanoxml.XMLElement;
import org.apache.log4j.Logger;
import org.lysty.core.PlaylistGenerator;
import org.lysty.core.StrategyFactory;
import org.lysty.core.XMLSerializable;
import org.lysty.db.DBHandler;
import org.lysty.exceptions.InvalidXMLException;
import org.lysty.strategies.StrategyConfiguration;
/**
* Selection profile of songs
*
* @author NuwanSam
*
*/
public class SongSelectionProfile implements XMLSerializable {
private static final String XML_SEL_PROFILE = "selection_profile";
private static final String XML_ATTRIB_SELPROF_SIZE = "size";
private static final String XML_ATTRIB_SELPROF_SIZETYPE = "sizetype";
private static final String XML_SONG = "song";
private static final String XML_ATTRIB_SONG_ID = "id";
private static final String XML_ATTRIB_SONG_FILEPATH = "file";
private static final String XML_ATTRIB_SONG_RELPOS = "relpos";
public static final int SIZE_TYPE_TIME = 1;
public static final int SIZE_TYPE_LENGTH = 0;
private static final String XML_ELEM_STRATEGY = "strategy";
private static final String XML_ATTRIB_STRATEGY_CLASS = "class";
private static final String XML_ELEM_STRATEGY_CONFIG = "strategy_config";
private static final String XML_ELEM_SONGS = "songs";
private static final String XML_ATTRIB_IS_CIRCULAR = "is_circular";
private static Logger logger = Logger.getLogger(SongSelectionProfile.class);
String name;
int size;
int sizeType;
File file; // save location
Map<Song, Integer> relPosMap; // relative position of each song in the list;
StrategyConfiguration strategyConfig;
PlaylistGenerator strategy;
private boolean circular;
/**
* @return the strategyConfig
*/
public StrategyConfiguration getStrategyConfig() {
return strategyConfig;
}
/**
* @param strategyConfig
* the strategyConfig to set
*/
public void setStrategyConfig(StrategyConfiguration strategyConfig) {
this.strategyConfig = strategyConfig;
}
/**
* @return the strategy
*/
public PlaylistGenerator getStrategy() {
return strategy;
}
/**
* @param strategy
* the strategy to set
*/
public void setStrategy(PlaylistGenerator strategy) {
this.strategy = strategy;
}
public SongSelectionProfile() {
relPosMap = new HashMap<Song, Integer>();
}
public SongSelectionProfile(File file) {
setFile(file);
}
/**
* @return the file
*/
public File getFile() {
return file;
}
/**
* @param file
* the file to set
*/
public void setFile(File file) {
this.file = file;
}
/**
* @return the size
*/
public int getSize() {
return size;
}
/**
* @param size
* the size to set
*/
public void setSize(int size) {
this.size = size;
}
/**
* @return the sizeType
*/
public int getSizeType() {
return sizeType;
}
/**
* @param sizeType
* the sizeType to set
*/
public void setSizeType(int sizeType) {
this.sizeType = sizeType;
}
/**
* @return the relPosMap
*/
public Map<Song, Integer> getRelPosMap() {
return relPosMap;
}
/**
* @param relPosMap
* the relPosMap to set
*/
public void setRelPosMap(Map<Song, Integer> relPosMap) {
this.relPosMap = relPosMap;
}
public void updateRelPosMap(List<Song> songs) {
if (sizeType == SIZE_TYPE_LENGTH)
size = songs.size();
relPosMap.clear();
for (int i = 0; i < songs.size(); i++) {
if (songs.get(i) != null) {
relPosMap.put(songs.get(i), i);
}
}
}
@Override
public IXMLElement getXml() {
XMLElement xmlSelProf = new XMLElement();
xmlSelProf.setName(XML_SEL_PROFILE);
xmlSelProf.setAttribute(XML_ATTRIB_SELPROF_SIZE, getSize() + "");
xmlSelProf
.setAttribute(XML_ATTRIB_SELPROF_SIZETYPE, getSizeType() + "");
xmlSelProf.setAttribute(XML_ATTRIB_IS_CIRCULAR, isCircular() ? "true"
: "false");
Map<Song, Integer> songs = getRelPosMap();
Iterator<Entry<Song, Integer>> it = songs.entrySet().iterator();
Entry<Song, Integer> entry;
XMLElement xmlSong;
XMLElement xmlSongs = new XMLElement();
xmlSongs.setName(XML_ELEM_SONGS);
while (it.hasNext()) {
entry = it.next();
xmlSong = new XMLElement();
xmlSong.setName(XML_SONG);
xmlSong.setAttribute(XML_ATTRIB_SONG_ID, entry.getKey().getId()
+ "");
xmlSong.setAttribute(XML_ATTRIB_SONG_FILEPATH, entry.getKey()
.getFilepath());
xmlSong.setAttribute(XML_ATTRIB_SONG_RELPOS, entry.getValue() + "");
xmlSongs.addChild(xmlSong);
}
xmlSelProf.addChild(xmlSongs);
XMLElement xmlStrategy = new XMLElement();
xmlStrategy.setName(XML_ELEM_STRATEGY);
xmlStrategy.setAttribute(XML_ATTRIB_STRATEGY_CLASS, strategy.getClass()
.getName());
xmlStrategy.addChild(strategyConfig.getXml());
xmlSelProf.addChild(xmlStrategy);
return xmlSelProf;
}
@Override
public void loadFromXml(IXMLElement xmlElement) throws InvalidXMLException {
try {
setSize(Integer.parseInt(xmlElement.getAttribute(
XML_ATTRIB_SELPROF_SIZE, null)));
setSizeType(Integer.parseInt(xmlElement.getAttribute(
XML_ATTRIB_SELPROF_SIZETYPE, null)));
setIsCircular("true".equalsIgnoreCase(xmlElement.getAttribute(
XML_ATTRIB_IS_CIRCULAR, null)));
IXMLElement strategyElement = (IXMLElement) xmlElement
.getChildrenNamed(XML_ELEM_STRATEGY).get(0);
String strategyClass = strategyElement.getAttribute(
XML_ATTRIB_STRATEGY_CLASS, null);
strategy = StrategyFactory.getStrategyByClassName(strategyClass);
IXMLElement strategyConfigElement = (IXMLElement) strategyElement
.getChildrenNamed(XML_ELEM_STRATEGY_CONFIG).get(0);
strategyConfig = new StrategyConfiguration(strategyConfigElement);
IXMLElement songsElement = (IXMLElement) xmlElement
.getChildrenNamed(XML_ELEM_SONGS).get(0);
Enumeration<IXMLElement> e = songsElement.enumerateChildren();
IXMLElement songElement;
Song song;
int relPos;
while (e.hasMoreElements()) {
songElement = e.nextElement();
song = DBHandler.getInstance().getSong(
new File(songElement.getAttribute(
XML_ATTRIB_SONG_FILEPATH, null)));
relPos = Integer.parseInt(songElement.getAttribute(
XML_ATTRIB_SONG_RELPOS, null));
relPosMap.put(song, relPos);
}
} catch (Exception e) {
logger.error("Error parsing partila playlist file", e);
throw new InvalidXMLException();
}
}
public void setIsCircular(boolean isCircular) {
circular = isCircular;
}
public boolean isCircular() {
return circular;
}
public List<Song> getPartialPlaylist() {
List<Song> playlist = new ArrayList<Song>(size);
for (int i = 0; i < size; i++) {
playlist.add(null);
}
Iterator<Entry<Song, Integer>> it = relPosMap.entrySet().iterator();
Entry<Song, Integer> entry;
while (it.hasNext()) {
entry = it.next();
playlist.set(entry.getValue(), entry.getKey());
}
return playlist;
}
public void setRelPosMap(List<Song> partials) {
Song song;
for (int i = 0; i < partials.size(); i++) {
song = partials.get(i);
if (song != null) {
if (song.getId() == 0) {
// song was not taken from db. try to get from db
// happens when the indexer was run after the song was added
// for play as a file
Song indexedSong = DBHandler.getInstance().getSong(
song.getFile());
if (indexedSong != null) {
song = indexedSong;
}
}
relPosMap.put(song, i);
}
}
}
}