package org.erikaredmark.monkeyshines.global;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.erikaredmark.monkeyshines.global.PreferencePersistException;
import org.erikaredmark.monkeyshines.resource.AbsentSoundManager;
import org.erikaredmark.monkeyshines.resource.JavaDefaultSoundManager;
import org.erikaredmark.monkeyshines.resource.SoundManager;
import org.erikaredmark.monkeyshines.resource.WorldResource;
import org.erikaredmark.util.ObservableModel;
/**
*
* Static 'preferences' class that maintains global preference state during the running of
* the application.
* <p/>
* A {@code SoundManager} can register for events if the changes are desired to be able to
* take place in real time.
* <p/>
* Preference changes are not persisted to the filesystem until told to do so. This is prevent
* large numbers of FS writes when a user is playing around with preferences.
*
* @author Erika Redmark
*
*/
public final class SoundSettings {
private static final String CLASS_NAME = "org.erikaredmark.monkeyshines.global.SoundSettings";
private static final Logger LOGGER = Logger.getLogger(CLASS_NAME);
private SoundSettings() { }
// Contained obsevable object for implementing the observable effect
private static final ObservableModel listeningSoundManagers = new ObservableModel();
public static final String PROPERTY_MUSIC = "mus";
public static final String PROPERTY_SOUND = "snd";
// Value from 0 - 100: indicates relative volume of the music that plays
// during the game
private static int musicVolumePercent = MonkeyShinesPreferences.defaultMusicVolume();
// Value from 0 - 100: indicates relative volume of all sound effects
private static int soundVolumePercent = MonkeyShinesPreferences.defaultSoundVolume();
/**
*
* Sets the volume of the music that will play, from 0 percent (no music) to 100 percent (loudest)
*
* @param value
*
* @throws IllegalArgumentException
* if the given value is not between [0, 100]
*
*/
public static void setMusicVolumePercent(final int value) {
if (!(isPercent(value) ) ) throw new IllegalArgumentException("Music volume must be in terms of percent");
int oldValue = musicVolumePercent;
musicVolumePercent = value;
listeningSoundManagers.firePropertyChange(PROPERTY_MUSIC, oldValue, musicVolumePercent);
}
/**
*
* Sets the volume of the sound that will play, from 0 percent (no music) to 100 percent (loudest)
*
* @param value
*
* @throws IllegalArgumentException
* if the given value is not between [0, 100]
*
*/
public static void setSoundVolumePercent(final int value) {
if (!(isPercent(value) ) ) throw new IllegalArgumentException("Sound volume must be in terms of percent");
int oldValue = soundVolumePercent;
soundVolumePercent = value;
listeningSoundManagers.firePropertyChange(PROPERTY_SOUND, oldValue, soundVolumePercent);
}
public static void setVolumePercentForType(int value, final SoundType type) {
switch(type) {
case SOUND:
setSoundVolumePercent(value);
break;
case MUSIC:
setMusicVolumePercent(value);
break;
default:
throw new RuntimeException("Unknown sound type " + type);
}
}
public static int getMusicVolumePercent() { return musicVolumePercent; }
public static int getSoundVolumePercent() { return soundVolumePercent; }
public static int getVolumePercentForType(final SoundType type) {
switch(type) {
case SOUND: return getSoundVolumePercent();
case MUSIC: return getMusicVolumePercent();
default: throw new RuntimeException("Unknown sound type " + type);
}
}
/**
*
* Registers the given sound manager to listen for any changes in settings
*
* @param manager
*
*/
public static void registerSoundManager(SoundManager manager) {
listeningSoundManagers.addPropertyChangeListener(PROPERTY_SOUND, manager);
listeningSoundManagers.addPropertyChangeListener(PROPERTY_MUSIC, manager);
}
/**
*
* Unregisters the given sound manager. This MUST be called before the resource containing the sound manager goes
* out of scope, or there will be a rather large resource leak.
*
* @param manager
*
*/
public static void unregisterSoundManager(SoundManager manager) {
listeningSoundManagers.removePropertyChangeListener(PROPERTY_SOUND, manager);
listeningSoundManagers.removePropertyChangeListener(PROPERTY_MUSIC, manager);
}
private static boolean isPercent(final int value) {
return !(value < 0 || value > 100);
}
/**
*
* Updates preferences file (if possible) with changes. This is called manually so that playing around with
* preferences doesn't cause excessive disk usage. Only call when the preference is okayed or saved by the user.
*
*/
public static void persist() throws PreferencePersistException {
MonkeyShinesPreferences.persistSound();
}
/**
* Factory method for creating an instance of a subtype of {@code
* SoundManager}. The method will attempt to instantiate a sound system
* for the current environment, and if that fails will generate a 'no
* op' sound system. Failures to initialise will be logged automatically.
* <p/>
* If the sound system fails to initialise, it will NOT affect actual
* gameplay. It will just prevent the sounds and music from working
* properly.
* @param worldResource
* @return
*/
public static SoundManager setUpSoundManager(
WorldResource worldResource) {
try
{
SoundManager manager = new JavaDefaultSoundManager(worldResource);
return manager;
} catch (Exception e) {
LOGGER.log(
Level.SEVERE,
"Sound system cannot be initialised; falling back to no sound system." + e.getMessage(),
e
);
return new AbsentSoundManager();
}
}
}