ConfigEntry.java

package eu.javaexperience.settings;

import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicReference;

import eu.javaexperience.collection.CollectionTools;
import eu.javaexperience.io.FileConfigMapper;
import eu.javaexperience.parse.ParsePrimitive;

public abstract class ConfigEntry<T>
{
	FileConfigMapper source;
	
	protected final String key;
	
	protected T defaultValue;
	
	public ConfigEntry(FileConfigMapper owner, String key, T default_value)
	{
		this.source = owner;
		this.key = key;
		this.defaultValue = default_value;
	}
	
	protected ArrayList<ConfigValueChangeListener<T>> listeners = new ArrayList<>();
	
	protected abstract String format(T value);
	protected abstract T parse(String value);
	
	public T getValue()
	{
		String v = source.get(key);
		if(null == v)
		{
			return defaultValue;
		}
		
		T ret = parse(v);
		if(null == ret)
		{
			return defaultValue;
		}
		
		return ret;
	}
	
	public void addListener(ConfigValueChangeListener<T> lst)
	{
		if(null != lst)
		{
			CollectionTools.addLikeSet(listeners, lst);
		}
	}
	
	public boolean isListenerRegistered(ConfigValueChangeListener<T> lst)
	{
		return listeners.contains(lst);
	}
	
	public void removeListener(ConfigValueChangeListener<T> lst)
	{
		listeners.remove(lst);
	}
	
	public void setValue(T obj)
	{
		if(null == obj)
		{
			return;
		}
		
		String save = format(obj);
		if(null == save)
		{
			return;
		}
		
		source.put(key, save);
		
		for(ConfigValueChangeListener<T> c:listeners)
		{
			try
			{
				c.configValueChanged(this, obj);
			}
			catch(Throwable t)
			{
				if(null != t)
				{
					t.printStackTrace();
				}
			}
		}
	}
	
	public static class WaitForReloadListener<T> implements ConfigValueChangeListener<T>
	{
		protected final ConfigEntry<T> entry;
		protected final AtomicReference<Semaphore> waiter  = new AtomicReference<>(new Semaphore(0));
		public WaitForReloadListener(ConfigEntry<T> entry)
		{
			this.entry = entry;
			entry.addListener(this);
		}
		
		@Override
		public void configValueChanged(ConfigEntry<T> cfg, T new_value)
		{
			Semaphore s = waiter.get();
			s.release(Integer.MAX_VALUE/2);
			waiter.set(new Semaphore(0));
		}
		
		public void waitForReload() throws InterruptedException
		{
			Semaphore s = waiter.get();
			s.acquire();
			s.release();
		}
	}
	
	public static class StringConfigEntry extends ConfigEntry<String>
	{
		public StringConfigEntry(FileConfigMapper owner, String key, String default_value)
		{
			super(owner, key, default_value);
		}

		@Override
		protected String format(String value)
		{
			return value;
		}
		
		@Override
		protected String parse(String value)
		{
			return value;
		}
		
	}
	
	public static class TrimmedStringConfigEntry extends ConfigEntry<String>
	{
		public TrimmedStringConfigEntry(FileConfigMapper owner, String key, String default_value)
		{
			super(owner, key, default_value);
		}

		@Override
		protected String format(String value)
		{
			return value.trim();
		}
		
		@Override
		protected String parse(String value)
		{
			return value.trim();
		}
	}
	
	public static class IntegerConfigEntry extends ConfigEntry<Integer>
	{
		public IntegerConfigEntry(FileConfigMapper owner, String key, Integer default_value)
		{
			super(owner, key, default_value);
		}

		@Override
		protected String format(Integer value)
		{
			return value.toString();
		}

		@Override
		protected Integer parse(String value)
		{
			return ParsePrimitive.tryParseInt(value);
		}
	}
}