/*
* Jajuk
* Copyright (C) The Jajuk Team
* http://jajuk.info
*
* 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 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.jajuk.services.dj;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jajuk.base.File;
import org.jajuk.base.FileManager;
import org.jajuk.base.Genre;
import org.jajuk.util.Const;
import org.jajuk.util.UtilSystem;
/**
* A proportion (10% JAZZ, 20% ROCK...) digital DJ
*/
public class ProportionDigitalDJ extends DigitalDJ {
/** Set of proportions. */
private List<Proportion> proportions;
/**
* The Constructor.
*
* @param sID
*/
public ProportionDigitalDJ(String sID) {
super(sID);
this.proportions = new ArrayList<Proportion>(10);
}
/*
* (non-Javadoc)
*
* @see org.jajuk.base.DigitalDJ#generatePlaylist()
*/
@Override
public List<File> generatePlaylist() {
List<File> out = getSequence();
if (!bUnicity && out.size() > 0) {
while (out.size() < Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY) {
out.addAll(getSequence());
}
}
return out;
}
/**
* Gets the sequence.
*
* @return a single loop sequence
*/
private List<File> getSequence() {
List<File> out = new ArrayList<File>(100);
Map<Proportion, List<File>> list = new HashMap<Proportion, List<File>>(10);
// get a global shuffle selection, we will keep only tracks with wanted
// genres
List<File> global = FileManager.getInstance().getGlobalShufflePlaylist();
// Select by rate if needed
filterFilesByRate(global);
for (File file : global) {
for (Proportion prop : proportions) {
if (prop.getGenres().contains(file.getTrack().getGenre())) {
List<File> files = list.get(prop);
if (files == null) { // not yet file list
files = new ArrayList<File>(100);
list.put(prop, files);
}
files.add(file);
}
}
}
// check if all properties are represented
if (list.size() < proportions.size()) {
return out; // return void list
}
// now, keep the smallest list before applying proportion
Proportion minProp = null;
int iMinSize = 0;
float fTotal = 0;
for (Entry<Proportion, List<File>> prop : list.entrySet()) {
fTotal += prop.getKey().getProportion();
List<File> files = prop.getValue();
// keep proportion with smallest number of files
if (minProp == null || files.size() < iMinSize) {
minProp = prop.getKey();
iMinSize = files.size();
}
}
// apply proportions
for (Entry<Proportion, List<File>> prop : list.entrySet()) {
List<File> files = prop.getValue();
out.addAll(files.subList(0, (int) (iMinSize * prop.getKey().getProportion())));
}
// complete this shuffle files if total sum < 100%
if (fTotal < 1.0) {
int iNbAdditional = (int) ((1.0 - fTotal) * iMinSize);
for (int i = 0; i < iNbAdditional; i++) {
out.add(global.get((int) (Math.random() * global.size())));
}
}
// shuffle selection
Collections.shuffle(out, UtilSystem.getRandom());
// finally ensure that we don't select more than the max number of tracks
filterFilesByMaxTrack(out);
return out;
}
/**
* Gets the proportions.
*
* @return Proportions
*/
public List<Proportion> getProportions() {
return this.proportions;
}
/**
* (non-Javadoc).
*
* @return the string
*
* @see dj.DigitalDJ#toXML()
*/
@Override
public String toXML() {
StringBuilder sb = new StringBuilder(2000);
sb.append(toXMLGeneralParameters());
sb.append("\t<" + Const.XML_DJ_PROPORTIONS + ">\n");
for (Proportion proportion : proportions) {
String genresDesc = "";
for (Genre genre : proportion.getGenres()) {
genresDesc += genre.getID() + ',';
}
// remove trailing coma
genresDesc = genresDesc.substring(0, genresDesc.length() - 1);
sb.append("\t\t<" + Const.XML_DJ_PROPORTION + " " + Const.XML_DJ_GENRES + "='" + genresDesc
+ "' " + Const.XML_DJ_VALUE + "='" + proportion.getProportion() + "'/>\n");
}
sb.append("\t</" + Const.XML_DJ_PROPORTIONS + ">\n");
sb.append("</" + Const.XML_DJ_DJ + ">\n");
return sb.toString();
}
/**
* Sets the proportions.
*
* @param proportions the new proportions
*/
public void setProportions(List<Proportion> proportions) {
this.proportions = proportions;
}
}