/*
 * Copyright 2011 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package me.footlights.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;

import com.google.common.collect.Maps;


/**
 * Preferences backed by a Java Properties file, suitable for most platforms.
 *
 * Some platforms (e.g. Android) may prefer platform-specific mechanisms.
 */
public final class FileBackedPreferences extends PreferenceStorageEngine
{
	/** The key used to store the cache directory in Preferences. */
	public static final String CACHE_DIR_KEY = "footlights.cachedir";

	/** The key used to store the location of the Keychain. */
	static final String KEYCHAIN_KEY = "footlights.keychain";

	/** Path separator ('/' on UNIX, '\' on Windows). */ 
	private static final String SEP = System.getProperty("file.separator");

	/** The user's home directory. */
	private static final String HOME = System.getProperty("user.home");


	static FileBackedPreferences loadFromDefaultLocation() throws IOException
	{
		return load(openOrCreateConfigFile("Footlights"));
	}


	/** Load the preferences in a given file. */
	static FileBackedPreferences load(File file) throws IOException
	{
		Properties properties = new Properties();
		if (file.exists())
		{
			InputStream in = new FileInputStream(file); 
			properties.load(in);
			in.close();
		}
    	else file.createNewFile();

		if (!properties.containsKey(CACHE_DIR_KEY))
			properties.setProperty(CACHE_DIR_KEY, file.getParent() + SEP + "cache");

		if (!properties.containsKey(KEYCHAIN_KEY))
			properties.setProperty(KEYCHAIN_KEY, file.getParent() + SEP + "keychain");

		return new FileBackedPreferences(properties, file);
	}


	/** Create the configuration dir and file. */
	private static File openOrCreateConfigFile(String name)
	{
		// The Footlights directory is OS-specific.
		String homeDir = HOME + SEP;

		if (System.getProperty("os.name").contains("Windows"))
			homeDir += ("Application Support" + SEP + "Footlights");
		else
			homeDir += ".footlights";

		// Ensure that the config dir exists.
		File dir = new File(homeDir);
		dir.mkdirs();

		return new File(dir, name + ".properties");
	}


	@Override protected Map<String,?> getAll() { return Maps.fromProperties(properties); }

	protected String getRaw(String name) throws NoSuchElementException
	{
		String value = properties.getProperty(name);

		if (value == null) throw new NoSuchElementException(name);
		return String.copyValueOf(value.toCharArray());
	}

	/** Set a configuration value */
	protected synchronized void set(String name, String value)
	{
		properties.setProperty(name, value);
		dirty = true;
	}


	/** Singleton constructor */
	private FileBackedPreferences(Properties properties, File file)
	{
		this.properties = properties;
		this.configFile = file;
	}


	/** Clean up */
	public void finalize() throws Throwable
	{
		saveConfig();
		super.finalize();
	}


	/** Save the config file */
	protected synchronized void saveConfig() throws IOException
	{
		if (!dirty) return;

		OutputStream out = new FileOutputStream(configFile);
		String headerComment =
			"Configuration options, auto-saved "
			+ java.text.DateFormat.getDateInstance().format(new Date());

		properties.store(out, headerComment);

		dirty = false;
	}


	/** Name of the configuration file */
	private final File configFile;

	/** Actual config options */
	private final Properties properties;

	/** Have any options changed? */
	private boolean dirty;
}

@@ -910,16 +910,109 @@
 rties;%0A%0A
+import me.footlights.plugin.ModifiablePreferences;%0Aimport me.footlights.plugin.Preferences;%0A%0A
 import c
@@ -1247,17 +1247,18 @@
 ferences
- 
+%0A%09
 extends 
@@ -1281,16 +1281,50 @@
 eEngine%0A
+%09implements ModifiablePreferences%0A
 %7B%0A%09/** T
@@ -3363,161 +3363,518 @@
 %0A%0A%09/
-** Set a configuration value */%0A%09protected synchronized void set(String name, String value)%0A%09%7B%0A%09%09properties.setProperty(name, value);%0A%09%09dirty = true;%0A%09%7D%0A
+/ ModifiablePreferences implementation%0A%09/** Set a configuration value */%0A%09@Override public synchronized FileBackedPreferences set(String name, String value)%0A%09%7B%0A%09%09properties.setProperty(name, value);%0A%09%09dirty = true;%0A%09%09return this;%0A%09%7D%0A%0A%09@Override public Preferences set(String k, boolean v) %7B return set(k, Boolean.toString(v)); %7D%0A%09@Override public Preferences set(String k, int v) %7B return set(k, Integer.toString(v)); %7D%0A%09@Override public Preferences set(String k, float v) %7B return set(k, Float.toString(v)); %7D
 %0A%0A%09/

Make FileBackedPreferences modifiable.