/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion 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.
*/
package illarion.client.resources;
import gnu.trove.map.hash.TIntObjectHashMap;
import illarion.client.util.IdWrapper;
import illarion.common.util.FastMath;
import org.illarion.engine.assets.SoundsManager;
import org.illarion.engine.sound.Music;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* The song factory, so the main storage for background music. While this sounds like a another child of the
* RecycleFactory, it is not one. This Factory works independent from the RecycleFactory,
* because there is only one song at time played anyway.
*
* @author Martin Karing <nitram@illarion.org>
*/
public final class SongFactory implements ResourceFactory<IdWrapper<String>> {
/**
* The singleton instance of the SongFactory.
*/
@Nonnull
private static final SongFactory INSTANCE = new SongFactory();
/**
* The root path to the music track files.
*/
@Nonnull
private static final String SONG_DIR = "music/";
/**
* Get the singleton instance of the sound factory.
*
* @return the singleton instance
*/
@Nonnull
@Contract(pure = true)
public static SongFactory getInstance() {
return INSTANCE;
}
/**
* The storage for the songs and the variations of the songs.
*/
@Nullable
private TIntObjectHashMap<List<String>> songs;
/**
* Constructor of the factory. Starts to loading of table file containing the songs.
*/
private SongFactory() {
// nothing to do
}
/**
* Get a song from a id. This function also selects what variation of a song shall be used.
*
* @param id id of the song that is needed
* @param manager the manager that actually supplies the music
* @return {@code null} if the song was not found, if there is just one song with this id, the song is returned,
* in case there are multiple variations of this song, one is selected randomly and returned
*/
@Nullable
@Contract(pure = true)
public Music getSong(int id, @Nonnull SoundsManager manager) {
if (songs != null) {
// select a variant at random
List<String> clipList = songs.get(id);
if (clipList != null) {
int variant = FastMath.nextRandomInt(0, clipList.size());
String variantRef = clipList.get(variant);
if (variantRef != null) {
return manager.getMusic(variantRef);
}
}
}
return null;
}
/**
* The initialization function prepares this factory to receive data.
*/
@Override
public void init() {
songs = new TIntObjectHashMap<>();
}
/**
* Optimize the table after the loading sequence has finished.
*/
@Override
public void loadingFinished() {
}
/**
* Add a song to this factory.
*/
@Override
public void storeResource(@Nonnull IdWrapper<String> resource) {
if (songs == null) {
throw new IllegalStateException("Factory was not initialized yet.");
}
int clipID = resource.getId();
String music = resource.getObject();
List<String> clipList = songs.get(clipID);
if (clipList == null) {
clipList = new ArrayList<>();
songs.put(clipID, clipList);
}
clipList.add(SONG_DIR + music);
}
/**
* Get a list of all the song names present.
*
* @return a newly created list that contains the list
*/
@Nonnull
@Contract(pure = true)
public List<String> getSongNames() {
if (songs == null) {
throw new IllegalStateException("Factory was not initialized yet.");
}
List<String> result = new ArrayList<>();
songs.forEachValue(object -> {
result.addAll(object);
return true;
});
return result;
}
/**
* Load a specific music track.
*
* @param manager the manager used to load the track
* @param song the name of the song to load
*/
public void loadSong(@Nonnull SoundsManager manager, @Nonnull String song) {
manager.getMusic(song);
}
}