package com.hammurapi.common.concurrent;

import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import com.hammurapi.common.Context;

public abstract class AbstractSubSet<KP> implements PropertySet<KP> {
	
	private PropertySet<KP> master;
	
	private KP prefix;
	
	protected abstract KP buildPath(KP prefix, KP key);
	
	protected AbstractSubSet(PropertySet<KP> master, KP prefix) {
		super();
		this.master = master;
		this.prefix = prefix;
	}

	public void clear() {
		master.subset(prefix).clear();
	}
	
	public Object get(KP key) {
		return master.get(buildPath(prefix, key));
	}

	public Object get(KP key, Object defaultValue) {
		return master.get(buildPath(prefix, key), defaultValue);
	}

	public <T> T get(KP key, Class<T> type) {
		return master.get(buildPath(prefix, key), type);
	}

	public <T> T get(KP key, Class<T> type, T defaultValue) {
		return master.get(buildPath(prefix, key), type, defaultValue);
	}

	public Object get(KP key, long timeout, TimeUnit unit) {
		return master.get(buildPath(prefix, key), timeout, unit);
	}

	public Object get(KP key, Object defaultValue, long timeout, TimeUnit unit) {
		return master.get(buildPath(prefix, key), defaultValue, timeout, unit);
	}

	public <T> T get(KP key, Class<T> type, long timeout, TimeUnit unit) {
		return master.get(buildPath(prefix, key), type, timeout, unit);
	}

	public <T> T get(KP key, Class<T> type, T defaultValue, long timeout, TimeUnit unit) {
		return master.get(buildPath(prefix, key), type, defaultValue, timeout, unit);
	}

	public void cook(KP key, Callable<?> callable) {
		master.cook(buildPath(prefix, key), callable);
	}

	public void cook(KP key, Callable<?> callable, long delay, TimeUnit timeUnit) {
		master.cook(buildPath(prefix, key), callable, delay, timeUnit);
	}

	public void cooking(KP key, Future<?> future) {
		master.cooking(buildPath(prefix, key), future);
	}

	public void cancel(KP key) {
		master.cancel(buildPath(prefix, key));
	}

	public void cancelAll() {
		master.subset(prefix).cancelAll();
	}

	public <T> T getAdapter(Class<T> targetType, Context context) {
		return master.subset(prefix).getAdapter(targetType, context);
	}

	public Set<KP> keySet() {
		return master.subset(prefix).keySet();
	}

	public PropertySet<KP> subset(KP prefix) {
		return master.subset(buildPath(this.prefix, prefix));
	}

	public void remove(KP key) {
		master.remove(buildPath(prefix, key));
	}

	public void mount(KP prefix, PropertySet<KP> source) {
		master.mount(buildPath(this.prefix, prefix), source);
	}

	public void unmount(KP prefix) {
		master.unmount(buildPath(this.prefix, prefix));
	}

	public void setAll(PropertySet<KP> source) {
		master.subset(prefix).setAll(source);
	}

	public void set(KP key, Object value) {
		master.set(buildPath(prefix, key), value);
	}

	public void setInvocable(KP key, Invocable<PropertySet<KP>, ?, KP, ?> invocable) {
		master.setInvocable(buildPath(prefix, key), invocable);
	}

	public void lazy(KP key, Callable<?> callable) {
		master.lazy(buildPath(prefix, key), callable);
	}

	public Object invoke(KP key, Object... args) {
		return master.invoke(buildPath(prefix, key), args);
	}

	public Object shadowInvoke(KP key, Object... args) {
		return master.shadowInvoke(key, args);
	}

	public Object shadowGet(KP key) {
		return master.shadowGet(key);
	}

	public Object shadowGet(KP key, Object defaultValue) {
		return master.shadowGet(key, defaultValue);
	}

	public <T> T shadowGet(KP key, Class<T> type) {
		return master.shadowGet(key, type);
	}

	public <T> T shadowGet(KP key, Class<T> type, T defaultValue) {
		return master.shadowGet(key, type, defaultValue);
	}
	

	public Object shadowGet(KP key, long timeout, TimeUnit unit) {
		return master.shadowGet(key, timeout, unit);
	}

	public Object shadowGet(KP key, Object defaultValue, long timeout, TimeUnit unit) {
		return master.shadowGet(key, defaultValue, timeout, unit);
	}

	public <T> T shadowGet(KP key, Class<T> type, long timeout, TimeUnit unit) {
		return master.shadowGet(key, type, timeout, unit);
	}

	public <T> T shadowGet(KP key, Class<T> type, T defaultValue, long timeout, TimeUnit unit) {
		return master.shadowGet(key, type, defaultValue, timeout, unit);
	}
	
	@Override
	public PropertySet<KP> createVersion() {
		throw new UnsupportedOperationException();
	}
	
}
