package info.bukova.isspst.security;

import info.bukova.isspst.Constants;
import info.bukova.isspst.Module;
import info.bukova.isspst.data.DataModel;
import info.bukova.isspst.data.Permission;
import info.bukova.isspst.data.PermissionType;
import info.bukova.isspst.data.RequirementBase;
import info.bukova.isspst.data.Role;
import info.bukova.isspst.data.User;
import info.bukova.isspst.data.Workgroup;
import info.bukova.isspst.services.Service;
import info.bukova.isspst.services.workgroups.WorkgroupService;

import java.io.Serializable;
import java.util.List;

import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;

@Deprecated
public class IsspstPermissionEvaluator implements PermissionEvaluator {
	
	private WorkgroupService wgService;
	
	public void setWorkgroupService(WorkgroupService wgService) {
		this.wgService = wgService;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public boolean hasPermission(Authentication authentication,
			Object targetDomainObject, Object permission) {
		String perm = "";
		
		if (permission instanceof String) {
			perm = (String) permission;
		}
		
		Permission appPermission = null;
		for (Permission p : Constants.SPECIAL_PERMISSIONS) {
			if (p.getAuthority().equals(perm)) {
				appPermission = p;
			}
		}
		
		if ((targetDomainObject instanceof Service<?>) && (appPermission == null || appPermission.getType() == PermissionType.GLOBAL))
		{
			List<Role> perms = (List<Role>) authentication.getAuthorities();
			return evaluateGlobal((Service<?>) targetDomainObject, perm, perms);
		} else {
			return evaluateSpecial(authentication, targetDomainObject, appPermission);
		}
		
	}
	
	private boolean evaluateSpecial(Authentication auth, Object domainObject, Permission permission) {
		List<Workgroup> userWorkgroups;
		
		if (!(auth.getPrincipal() instanceof User)) {
			return false;
		}
		
		User user = (User)auth.getPrincipal();
		
		if (domainObject instanceof DataModel) {
			return filterDomainObject(user, (DataModel)domainObject, permission);
		}
		
		if (permission.getType() == PermissionType.CENTRE) {
			userWorkgroups = wgService.getUserCentres((User)auth.getPrincipal());
		} else {
			userWorkgroups = wgService.getUserWorkgroups((User)auth.getPrincipal());
		}
		
		for (Workgroup wg : userWorkgroups) {
			List<Role> wgRoles = wgService.getUserWorkgroupRoles(wg, user);
			
			if (wgRoles == null) {
				continue;
			}
			
			for (Role r : wgRoles) {
				for (Permission p : r.getPermissions()) {
					if (p.getAuthority().equals(permission.getAuthority())) {
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	private boolean filterDomainObject(User user, DataModel domainObject, Permission permission) {
		if (!(domainObject instanceof RequirementBase)) {
			return false;
		}
		
		RequirementBase req = (RequirementBase) domainObject;
		Workgroup reqWg;
		
		if (permission.getType() == PermissionType.CENTRE) {
			reqWg = req.getCentre();
		} else {
			reqWg = req.getWorkgroup();
		}
		
		if (wgService.isMember(reqWg, user)) {
			List<Role> roles = wgService.getUserWorkgroupRoles(reqWg, user);
			for (Role r : roles) {
				for (Permission p : r.getPermissions()) {
					if (p.getAuthority().equals(permission.getAuthority())) {
						return true;
					}
				}
			}
		}
		
		return false;
	}

	@Override
	public boolean hasPermission(Authentication authentication,
			Serializable targetId, String targetType, Object permission) {
		return false;
	}
	
	private boolean evaluateGlobal(Service<?> service, String permission, List<Role> perms) {
		
		String moduleId = "";
		String perm = permission;
		
		for (Module m : Constants.MODULES) {
			if (m.getServiceClass() != null && m.getServiceClass().isAssignableFrom(service.getClass())) {
				moduleId = m.getId();
				break;
			}
		}
		
		perm += "_" + moduleId;
		
		for (int i = 0; i < perms.size(); i++) {
			if (!(perms.get(i) instanceof Role)) {
				return false;
			}
			if (perms.get(i).getAuthority().equals(perm)) {
				return true;
			}
			if (perms.get(i).getAuthority().equals(Constants.ROLE_ADMIN)) {
				return true;
			}
		}
		
		return false;
	}

}
