package to.etc.domui.injector;

import org.eclipse.jdt.annotation.Nullable;
import to.etc.domui.dom.html.AbstractPage;
import to.etc.util.PropertyInfo;
import to.etc.webapp.ProgrammerErrorException;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Access checker which uses the type of the value to check access to it.
 *
 * @author <a href="mailto:jal@etc.to">Frits Jalvingh</a>
 * Created on 20-12-18.
 */
public class TypedPropertyAccessChecker implements IInjectedPropertyAccessChecker {
	private Map<Class<?>, ITypedValueAccessChecker<?>> m_checkerMap = Collections.emptyMap();

	public synchronized <T> void register(Class<T> clz, ITypedValueAccessChecker<T> check) {
		Map<Class<?>, ITypedValueAccessChecker<?>> map = new HashMap<>(m_checkerMap);
		if(map.put(clz, check) != null)
			throw new ProgrammerErrorException("Duplicate typed access checker for class " + clz.getName());
		m_checkerMap = Collections.unmodifiableMap(map);
	}

	private synchronized Map<Class<?>, ITypedValueAccessChecker<?>> getCheckerMap() {
		return m_checkerMap;
	}

	@Override
	public boolean isAccessAllowed(PropertyInfo info, AbstractPage page, @Nullable Object value) throws Exception {
		return checkAccessSigh(info, page, value);
	}

	private <T> boolean checkAccessSigh(PropertyInfo info, AbstractPage page, @Nullable Object value) throws Exception {
		if(null == value)
			return true;

		ITypedValueAccessChecker<T> checker = findClassChecker(value.getClass());
		if(null == checker)
			return false;
		return checker.isAccessAllowed(info, page, (T) value);
	}

	@Nullable
	private <T> ITypedValueAccessChecker<T> findClassChecker(Class<?> clz) {
		Map<Class<?>, ITypedValueAccessChecker<?>> map = getCheckerMap();
		Class<?> curr = clz;
		for(;;) {
			if(curr == Object.class || curr == null)
				return null;
			ITypedValueAccessChecker<?> checker = map.get(curr);
			if(null != checker) {
				return (ITypedValueAccessChecker<T>) checker;
			}

			curr = curr.getSuperclass();
		}
	}
}

@@ -266,19 +266,92 @@
 va.util.
-Map
+List;%0Aimport java.util.Map;%0Aimport java.util.concurrent.CopyOnWriteArrayList
 ;%0A%0A/**%0A 
@@ -688,16 +688,114 @@
 Map();%0A%0A
+%09private List%3CITypedValueAccessChecker%3CObject%3E%3E m_anyCheckerList = new CopyOnWriteArrayList%3C%3E();%0A%0A
 %09public 
@@ -1141,24 +1141,130 @@
 p(map);%0A%09%7D%0A%0A
+%09public void registerAny(ITypedValueAccessChecker%3CObject%3E checker) %7B%0A%09%09m_anyCheckerList.add(checker);%0A%09%7D%0A%0A
 %09private syn
@@ -1775,17 +1775,17 @@
 if(null 
-=
+!
 = checke
@@ -1786,16 +1786,18 @@
 checker)
+ %7B
 %0A%09%09%09retu
@@ -1803,31 +1803,134 @@
 urn 
-false;%0A%09%09return checker
+checker.isAccessAllowed(info, page, (T) value);%0A%09%09%7D%0A%09%09for(ITypedValueAccessChecker%3CObject%3E any : m_anyCheckerList) %7B%0A%09%09%09if(any
 .isA
@@ -1953,27 +1953,60 @@
 o, page,
- (T)
  value)
+)%0A%09%09%09%09return true;%0A%09%09%7D%0A%09%09return false
 ;%0A%09%7D%0A%0A%09@

Add generic checker for accessing objects