package gov.nih.nci.system.security;

import gov.nih.nci.security.acegi.external.SecurityHelper;
import gov.nih.nci.system.query.cql.CQLQuery;
import gov.nih.nci.system.query.hibernate.HQLCriteria;
import gov.nih.nci.system.query.nestedcriteria.NestedCriteriaPath;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.impl.CriteriaImpl;

public class SecurityHelperImpl implements SecurityHelper
{
	private Collection<String> readRoleCollection;
	private Collection<String> allRoleCollection;
	
	public SecurityHelperImpl()
	{
		readRoleCollection = new ArrayList<String>();
		readRoleCollection.add("READ");

		allRoleCollection = new ArrayList<String>();
		allRoleCollection.add("*");
	}

	public Map<String, Collection<String>> getPostMethodInvocationSecurityMap(MethodInvocation invocation) {
		String domainObject = getDomainObjectName(invocation.getMethod(),invocation.getArguments());
		
		Map<String, Collection<String>> requiredPrivilageMap = new HashMap<String, Collection<String>>();
		requiredPrivilageMap.put(domainObject, readRoleCollection);
		return requiredPrivilageMap;
	}

	private String getDomainObjectName(Method method, Object[] arguments) {
		String domainObjectName="";
		
		if("getAssociation".equals(method.getName()))
		{
			Class klass = arguments[0].getClass();
			
			while (klass!=Object.class)
			{
			try {
				Field field = klass.getDeclaredField((String)arguments[1]);
				
				Type type = field.getGenericType();
				if (type instanceof ParameterizedType)
				{
					Type t = ((ParameterizedType)type).getActualTypeArguments()[0];
					domainObjectName = ((Class)t).getName();
				}
				else
				{
					domainObjectName = field.getType().getName();
				}
				break;
			} catch (SecurityException e) {
			} catch (NoSuchFieldException e) {
			}
				klass= klass.getSuperclass();
			}
		}
		else if("query".equals(method.getName()) || "getQueryRowCount".equals(method.getName()))
		{
			if(arguments.length == 3)
			{
				domainObjectName = (String)arguments[2];
			}
			else if(arguments[0] instanceof CQLQuery)
			{
				domainObjectName = ((CQLQuery)arguments[0]).getTarget().getName();
			}
			else if(arguments[0] instanceof DetachedCriteria)
			{
				CriteriaImpl crit = (CriteriaImpl)((DetachedCriteria)arguments[0]).getExecutableCriteria(null);
				domainObjectName = crit.getEntityOrClassName();
			}
			else if(arguments[0] instanceof HQLCriteria)
			{
				String hql = ((HQLCriteria)arguments[0]).getHqlString();
				int index = hql.indexOf(" from ");
				hql = hql.substring(index+" from ".length()).trim()+" ";
				domainObjectName = hql.substring(0,hql.indexOf(' ')).trim();
			}
			else if(arguments[0] instanceof NestedCriteriaPath)
			{
				String path = ((NestedCriteriaPath)arguments[0]).getpathString();
				String[] tokens=path.split(",");
				domainObjectName = tokens[0];
			}
		}
		else if("search".equals(method.getName()))
		{
			if(arguments[0] instanceof Class)
			{
				domainObjectName = ((Class)arguments[0]).getName();
			}
			else if(arguments[0] instanceof String)
			{
				String path = (String)arguments[0];
				String[] tokens=path.split(",");
				domainObjectName = tokens[0];
			}
		}
		return domainObjectName;
		
	}

	public Map<String, Collection<String>> getPreMethodInvocationSecurityMap(MethodInvocation invocation) {
		String domainObject = getDomainObjectName(invocation.getMethod(),invocation.getArguments());
		
		Map<String, Collection<String>> requiredPrivilageMap = new HashMap<String, Collection<String>>();
		requiredPrivilageMap.put(domainObject, readRoleCollection);
		return requiredPrivilageMap;
	}

	public Map<String, Collection<String>> getPostMethodInvocationSecurityMap(MethodInvocation arg0, Object arg1) {
		
		return getPreMethodInvocationSecurityMap(arg0);
	}
	
}

@@ -1500,16 +1500,17 @@
 ctName=%22
+*
 %22;%0A%09%09%0A%09%09

Allow user to access methods which are not secured