package com.limegroup.gnutella.settings;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.limegroup.gnutella.ErrorService;
import com.limegroup.gnutella.simpp.SimppManager;
public class SimppSettingsManager {
private static final Log LOG = LogFactory.getLog(SimppSettingsManager.class);
/**
* The properties we crete from the string we get via simpp message
*/
private Properties _simppProps;
/**
* A cache of the values we had for the settings before the simpp settings
* were applied to them.
* <p>
* Note: This is a utility added to allow LimeWire to revert to non-simpp
* settings, ie. the user pref settings.
* Note 2: See note in revertToUserPrefs method
*/
private final HashMap /* Setting -> String*/ _userPrefs;
/**
* A mapping of simppKeys to simppValues which have not been initialized
* yet. Newly created settings must check with this map to see if they
* should load defualt value or the simpp value
*/
private final HashMap /* String -> String */ _remainderSimppSettings;
/**
* true if we have not applied the simpp settings, or have since reverted to
* them, false otherwise
*/
private boolean _usingUserPrefs;
/**
* The instance
*/
private static SimppSettingsManager INSTANCE;
//constructor
private SimppSettingsManager() {
_usingUserPrefs = true; //we are using defualt settings by default
String simppSettings = SimppManager.instance().getPropsString();
if(simppSettings == null)
throw new IllegalArgumentException("SimppManager unexpected state");
_userPrefs = new HashMap();
_remainderSimppSettings = new HashMap();
updateSimppSettings(simppSettings);
}
//instance
public static synchronized SimppSettingsManager instance() {
if(INSTANCE == null)
INSTANCE = new SimppSettingsManager();
return INSTANCE;
}
/**
* Call this method with the verified simppSettings which are used to
* replace other settings if they exist in the system.
*/
public void updateSimppSettings(String simppSettings) {
byte[] settings = null;
try {
settings = simppSettings.getBytes("UTF-8");
} catch (UnsupportedEncodingException uex) {
ErrorService.error(uex);
return;
}
ByteArrayInputStream bais = new ByteArrayInputStream(settings);
_simppProps = new Properties();
try {
_simppProps.load(bais);
} catch(IOException iox) {
LOG.error("IOX reading simpp properties", iox);
return;
}
activateSimppSettings();
}
/**
* Call this method if you want to activate the settings to the ones in
* this.simppProps
*/
public void activateSimppSettings() {
LOG.debug("activating new settings");
synchronized(_simppProps) {
Set set = _simppProps.entrySet();
for(Iterator iter = set.iterator(); iter.hasNext() ; ) {
Map.Entry currEntry = (Map.Entry)iter.next();
String settingKey = (String)currEntry.getKey();
Setting simppSetting = getSimppSettingForKey(settingKey);
String simppValue = (String)currEntry.getValue();
//If this setting is null, it means that the SettingsFactory has
//not loaded this setting yet. Let's cache the value in a
//hashmap which will be referenced everytime a setting is
//created
if(simppSetting == null) {//remember it for later
_remainderSimppSettings.put(settingKey, simppValue);
continue;
}
if(LOG.isDebugEnabled()) {
LOG.debug("setting:"+simppSetting);
LOG.debug("simpp value:"+simppValue);
}
if(!simppSetting.isSimppEnabled())
continue;
//get the default/current value and cache it
String userSetValue = (String)simppSetting.getValueAsString();
if(LOG.isDebugEnabled())
LOG.debug("current value:"+userSetValue);
_userPrefs.put(simppSetting, userSetValue);
//set the setting to the value that simpp says
simppSetting.setValue(simppValue);
}
}//end of synchronized block
_usingUserPrefs = false;
}
/**
* Call this method if you want to restore the values of the settings the
* activateSimppSettings method set.
*
* Note: As of now, nothing will cause this method to be called, we could
* save a little memory by not having this method, and not having the
* _userPrefs map around, but it may be useful...who knows where this code
* will go...
*/
public void revertToUserPrefs() {
if(_usingUserPrefs) //we are already at default values
return;
synchronized(_simppProps) {
Set set = _simppProps.keySet();
for(Iterator iter = set.iterator(); iter.hasNext() ; ) {
Setting currSetting = (Setting)iter.next();
String userSetValue = (String)_userPrefs.get(currSetting);
currSetting.loadValue(userSetValue);
}
} //end of synchronized
_usingUserPrefs = true;
}
/**
* @return the simpp value for a simppkey from the map that remembers simpp
* settings which have not been loaded yet. Removes the entry from the
* mapping since it is no longer needed, now that the setting has been
* created.
*/
String getRemanentSimppValue(String simppKey) {
synchronized(_simppProps) {
return (String)_remainderSimppSettings.remove(simppKey);
}
}
/**
* Appends the setings and userPref to the map holding the cached user
* preferecnces
*/
void cacheUserPref(Setting setting, String userPref) {
synchronized(_simppProps) {
_userPrefs.put(setting, userPref);
}
}
/////////////////////////////private helpers////////////////////////////
private Setting getSimppSettingForKey(String simppKey) {
LimeProps limeProps = LimeProps.instance();
return limeProps.getSimppSetting(simppKey);
}
}